Class: DrivingPhysics::Wheel

Inherits:
Object
  • Object
show all
Defined in:
lib/driving_physics/wheel.rb

Overview

Rotational complements to acc/vel/pos alpha - angular acceleration omega - angular velocity (radians / s) theta - radians

Constant Summary collapse

DENSITY =

Note, this is not the density of solid rubber. This density yields a sensible mass for a wheel / tire combo at common radius and width, assuming a uniform density e.g. 25kg at 350mm R x 200mm W

0.325

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, radius: 350, width: 200, density: DENSITY, temp: nil, mass: nil, mu_s: 1.1, mu_k: 0.7, omega_friction: 0.002) ⇒ Wheel

Returns a new instance of Wheel.



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/driving_physics/wheel.rb', line 100

def initialize(env,
               radius: 350, width: 200, density: DENSITY,
               temp: nil, mass: nil,
               mu_s: 1.1, mu_k: 0.7,
               omega_friction: 0.002)
  @env = env
  @radius = radius.to_f # mm
  @radius_m = @radius / 1000
  @width  = width.to_f  # mm
  @width_m = @width / 1000
  @mu_s = mu_s.to_f # static friction
  @mu_k = mu_k.to_f # kinetic friction
  @omega_friction = omega_friction # scales with speed
  @density = mass.nil? ? density : self.class.density(mass, volume_l)
  @temp = temp.to_f || @env.air_temp
end

Instance Attribute Details

#densityObject (readonly)

Returns the value of attribute density.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def density
  @density
end

#envObject (readonly)

Returns the value of attribute env.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def env
  @env
end

#mu_kObject (readonly)

Returns the value of attribute mu_k.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def mu_k
  @mu_k
end

#mu_sObject (readonly)

Returns the value of attribute mu_s.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def mu_s
  @mu_s
end

#omega_frictionObject (readonly)

Returns the value of attribute omega_friction.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def omega_friction
  @omega_friction
end

#radiusObject (readonly)

Returns the value of attribute radius.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def radius
  @radius
end

#radius_mObject (readonly)

Returns the value of attribute radius_m.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def radius_m
  @radius_m
end

#tempObject (readonly)

Returns the value of attribute temp.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def temp
  @temp
end

#widthObject (readonly)

Returns the value of attribute width.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def width
  @width
end

#width_mObject (readonly)

Returns the value of attribute width_m.



97
98
99
# File 'lib/driving_physics/wheel.rb', line 97

def width_m
  @width_m
end

Class Method Details

.alpha(torque, inertia) ⇒ Object

angular acceleration



59
60
61
# File 'lib/driving_physics/wheel.rb', line 59

def self.alpha(torque, inertia)
  torque / inertia
end

.density(mass, volume_l) ⇒ Object



42
43
44
# File 'lib/driving_physics/wheel.rb', line 42

def self.density(mass, volume_l)
  mass.to_f / volume_l
end

.force(axle_torque, radius_m) ⇒ Object



28
29
30
# File 'lib/driving_physics/wheel.rb', line 28

def self.force(axle_torque, radius_m)
  axle_torque / radius_m.to_f
end

.force_vector(torque, radius) ⇒ Object

vectors only



86
87
88
89
90
91
92
93
94
95
# File 'lib/driving_physics/wheel.rb', line 86

def self.force_vector(torque, radius)
  if !torque.is_a?(Vector) or torque.size != 3
    raise(ArgumentError, "torque must be a 3D vector")
  end
  if !radius.is_a?(Vector) or radius.size != 2
    raise(ArgumentError, "radius must be a 2D vector")
  end
  radius = Vector[radius[0], radius[1], 0]
  radius.cross(torque) / radius.dot(radius)
end

.mass(radius_m, width_m, density) ⇒ Object



46
47
48
# File 'lib/driving_physics/wheel.rb', line 46

def self.mass(radius_m, width_m, density)
  density * volume_l(radius_m, width_m)
end

.moment_of_inertiaObject

I = 1/2 (m)(r^2) for a disk



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

def self.rotational_inertia(radius_m, mass)
  mass * radius_m**2 / 2.0
end

.rotational_inertia(radius_m, mass) ⇒ Object

I = 1/2 (m)(r^2) for a disk



51
52
53
# File 'lib/driving_physics/wheel.rb', line 51

def self.rotational_inertia(radius_m, mass)
  mass * radius_m**2 / 2.0
end

.tangential(rotational, radius_m) ⇒ Object Also known as: tangential_a, tangential_v, tangential_p



63
64
65
# File 'lib/driving_physics/wheel.rb', line 63

def self.tangential(rotational, radius_m)
  rotational * radius_m
end

.torque_vector(force, radius) ⇒ Object

vectors only



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/driving_physics/wheel.rb', line 73

def self.torque_vector(force, radius)
  if !force.is_a?(Vector) or force.size != 2
    raise(ArgumentError, "force must be a 2D vector")
  end
  if !radius.is_a?(Vector) or radius.size != 2
    raise(ArgumentError, "radius must be a 2D vector")
  end
  force = Vector[force[0], force[1], 0]
  radius = Vector[radius[0], radius[1], 0]
  force.cross(radius)
end

.traction(normal_force, cof) ⇒ Object

  • the traction force opposes the axle torque / drive force thus, driving the car forward

  • if the drive force exceeds the traction force, slippage occurs

  • slippage reduces the available traction force further

  • if the drive force is not reduced, the slippage increases until resistance forces equal the drive force



24
25
26
# File 'lib/driving_physics/wheel.rb', line 24

def self.traction(normal_force, cof)
  normal_force * cof
end

.volume(radius_m, width_m) ⇒ Object

in m^3



33
34
35
# File 'lib/driving_physics/wheel.rb', line 33

def self.volume(radius_m, width_m)
  Math::PI * radius_m ** 2 * width_m.to_f
end

.volume_l(radius_m, width_m) ⇒ Object

in L



38
39
40
# File 'lib/driving_physics/wheel.rb', line 38

def self.volume_l(radius_m, width_m)
  volume(radius_m, width_m) * 1000
end

Instance Method Details

#force(axle_torque) ⇒ Object



159
160
161
# File 'lib/driving_physics/wheel.rb', line 159

def force(axle_torque)
  self.class.force(axle_torque, @radius_m)
end

#heat!(amount_deg_c) ⇒ Object



132
133
134
# File 'lib/driving_physics/wheel.rb', line 132

def heat!(amount_deg_c)
  @temp += amount_deg_c
end

#inertial_loss(axle_torque, total_driven_mass) ⇒ Object

inertial loss in terms of axle torque when used as a drive wheel



176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/driving_physics/wheel.rb', line 176

def inertial_loss(axle_torque, total_driven_mass)
  drive_force = self.force(axle_torque)
  force_loss = 0
  # The force loss depends on the acceleration, but the acceleration
  # depends on the force loss.  Converge the value via 5 round trips.
  # This is a rough way to compute an integral and should be accurate
  # to 8+ digits.
  5.times {
    acc = DrivingPhysics.acc(drive_force - force_loss, total_driven_mass)
    alpha = acc / @radius_m
    force_loss = self.inertial_torque(alpha) / @radius_m
  }
  force_loss * @radius_m
end

#inertial_torque(alpha) ⇒ Object

how much torque to accelerate rotational inertia at alpha



164
165
166
# File 'lib/driving_physics/wheel.rb', line 164

def inertial_torque(alpha)
  alpha * self.rotational_inertia
end

#massObject



136
137
138
# File 'lib/driving_physics/wheel.rb', line 136

def mass
  self.class.mass(@radius_m, @width_m, @density)
end

#rotational_inertiaObject Also known as: moment_of_inertia



150
151
152
# File 'lib/driving_physics/wheel.rb', line 150

def rotational_inertia
  self.class.rotational_inertia(@radius_m, self.mass)
end

#to_sObject



117
118
119
120
121
122
123
124
125
# File 'lib/driving_physics/wheel.rb', line 117

def to_s
  [[format("%d mm (R) x %d mm (W)", @radius, @width),
    format("Mass: %.1f kg %.3f kg/L", self.mass, @density),
    format("cF: %.1f / %.1f", @mu_s, @mu_k),
   ].join(" | "),
   [format("Temp: %.1f C", @temp),
   ].join(" | "),
  ].join("\n")
end

#tractable_torque(nf, static: true) ⇒ Object

this doesn’t take inertial losses or internal frictional losses into account. input torque required to saturate traction will be higher than what this method returns



171
172
173
# File 'lib/driving_physics/wheel.rb', line 171

def tractable_torque(nf, static: true)
  traction(nf, static: static) * @radius_m
end

#traction(nf, static: true) ⇒ Object



155
156
157
# File 'lib/driving_physics/wheel.rb', line 155

def traction(nf, static: true)
  self.class.traction(nf, static ? @mu_s : @mu_k)
end

#volumeObject

in m^3



141
142
143
# File 'lib/driving_physics/wheel.rb', line 141

def volume
  self.class.volume(@radius_m, @width_m)
end

#volume_lObject

in L



146
147
148
# File 'lib/driving_physics/wheel.rb', line 146

def volume_l
  self.class.volume_l(@radius_m, @width_m)
end

#wear!(amount_mm) ⇒ Object



127
128
129
130
# File 'lib/driving_physics/wheel.rb', line 127

def wear!(amount_mm)
  @radius -= amount_mm
  @radius_m = @radius / 1000
end