Module: DrivingPhysics

Defined in:
lib/driving_physics.rb,
lib/driving_physics/wheel.rb,
lib/driving_physics/imperial.rb,
lib/driving_physics/environment.rb,
lib/driving_physics/scalar_force.rb,
lib/driving_physics/vector_force.rb

Defined Under Namespace

Modules: Imperial, ScalarForce, VectorForce, VectorZeroBackport Classes: Environment, Wheel

Constant Summary collapse

HZ =

environmental defaults

1000
TICK =
Rational(1) / HZ
G =

m/s^2

9.8
AIR_TEMP =

deg c

25
AIR_DENSITY =

kg / m^3

1.29
PETROL_DENSITY =

kg / L TODO: move to car.rb

0.71
FRONTAL_AREA =

defaults for resistance forces

2.2
DRAG_COF =

m^2, based roughly on 2000s-era Chevrolet Corvette

0.3
DRAG =

based roughly on 2000s-era Chevrolet Corvette

0.4257
ROT_COF =

air_resistance at 1 m/s given above numbers

12.771
ROLL_COF =

if rotating resistance matches air resistance at 30 m/s

0.01
SECS_PER_MIN =

constants

60
MINS_PER_HOUR =
60
SECS_PER_HOUR =
SECS_PER_MIN * MINS_PER_HOUR

Class Method Summary collapse

Class Method Details

.acc(force, mass) ⇒ Object

acceleration; F=ma force can be a scalar or a Vector



55
56
57
# File 'lib/driving_physics.rb', line 55

def self.acc(force, mass)
  force / mass.to_f
end

.accum(init, rate, dt: TICK) ⇒ Object Also known as: vel, pos, omega, theta

init and rate can be scalar or Vector but must match this provides the general form for determining velocity and position



61
62
63
# File 'lib/driving_physics.rb', line 61

def self.accum(init, rate, dt: TICK)
  init + rate * dt
end

.compass_dir(unit_vector) ⇒ Object

,0 E 0, N .9,.1 ENE .1,.9 NNE



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/driving_physics/vector_force.rb', line 43

def self.compass_dir(unit_vector)
  horz = case
         when unit_vector[0] < -0.001 then 'W'
         when unit_vector[0] > 0.001 then 'E'
         else ''
         end

  vert = case
         when unit_vector[1] < -0.001 then 'S'
         when unit_vector[1] > 0.001 then 'N'
         else ''
         end

  dir = [vert, horz].join
  if dir.length == 2
    # detect and include bias
    if (unit_vector[0].abs - unit_vector[1].abs).abs > 0.2
      bias = unit_vector[0].abs > unit_vector[1].abs ? horz : vert
      dir = [bias, dir].join
    end
  end
  dir
end

.elapsed_display(elapsed_ms) ⇒ Object



38
39
40
41
42
43
44
45
46
47
# File 'lib/driving_physics.rb', line 38

def self.elapsed_display(elapsed_ms)
  elapsed_s, ms = elapsed_ms.divmod 1000

  h = elapsed_s / SECS_PER_HOUR
  elapsed_s -= h * SECS_PER_HOUR
  m, s = elapsed_s.divmod SECS_PER_MIN

  [[h, m, s].map { |i| i.to_s.rjust(2, '0') }.join(':'),
   ms.to_s.rjust(3, '0')].join('.')
end

.kph(meters_per_sec) ⇒ Object



49
50
51
# File 'lib/driving_physics.rb', line 49

def self.kph(meters_per_sec)
  meters_per_sec.to_f * SECS_PER_HOUR / 1000
end

.random_centered_zero(magnitude) ⇒ Object

e.g. given 5, yields a uniformly random number from -5 to +5



18
19
20
21
# File 'lib/driving_physics/vector_force.rb', line 18

def self.random_centered_zero(magnitude)
  m = [magnitude.abs, 1].max
  Random.rand(m * 2 + 1) - m
end

.random_unit_vector(dimensions = 2, resolution: 9) ⇒ Object



23
24
25
26
27
28
29
30
# File 'lib/driving_physics/vector_force.rb', line 23

def self.random_unit_vector(dimensions = 2, resolution: 9)
  begin
    v = Vector.elements(Array.new(dimensions) {
                          random_centered_zero(resolution)
                        })
  end while v.zero?
  v.normalize
end

.rot_90(vec, clockwise: true) ⇒ Object

Raises:

  • (Vector::ZeroVectorError)


32
33
34
35
36
# File 'lib/driving_physics/vector_force.rb', line 32

def self.rot_90(vec, clockwise: true)
  raise(Vector::ZeroVectorError) if vec.zero?
  raise(ArgumentError, "vec should be size 2") unless vec.size == 2
  clockwise ? Vector[vec[1], -1 * vec[0]] : Vector[-1 * vec[1], vec[0]]
end