driving_physics 0.0.0.2 → 0.0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/demo/tire.rb CHANGED
@@ -1,169 +1,87 @@
1
1
  require 'driving_physics/tire'
2
+ require 'driving_physics/imperial'
3
+ require 'driving_physics/cli'
2
4
 
3
5
  include DrivingPhysics
4
6
 
5
- t = Tire.new
6
- t.condition.debug_temp = false
7
-
8
- # drive time
9
- mins = 45
10
-
11
- drive_map = {
12
- acc: {
13
- label: "ACCELERATING",
14
- g: 0.5,
15
- fuel: 0.0002, # kg consumed / tick
16
- small_slide: 1, # m/s of wheelspin
17
- big_slide: 10,
18
- seconds: 1,
19
- next_sector: :brake,
20
- },
21
- brake: {
22
- label: "BRAKING",
23
- g: 1.0,
24
- fuel: 0.00001,
25
- small_slide: 0.5,
26
- big_slide: 2,
27
- seconds: 1,
28
- next_sector: :corner,
29
- },
30
- corner: {
31
- label: "CORNERING",
32
- g: 0.8,
33
- fuel: 0.0001,
34
- small_slide: 0.5,
35
- big_slide: 5,
36
- seconds: 2,
37
- next_sector: :acc,
38
- },
39
- }
40
-
41
- slide_speed = 0
42
- sliding = false
43
- mass = 900.0
44
- ambient_temp = 25
45
- critical_temp = 100
46
-
47
- drive_time = 0 # how many ticks elapsed in the current sector
48
- sector_map = drive_map[:acc]
49
- puts "ACCELERATING"
50
- puts "---"
51
-
52
- cooldown = false
53
- pushing = false
54
-
55
- # 100 ticks / sec
56
- (mins * 60 * 100).times { |i|
57
- drive_time += 1
58
-
59
- dynamic_g = sector_map[:g]
60
-
61
- if t.condition.temp_c <= 80 and cooldown
62
- puts "ENDING COOLDOWN"
63
- cooldown = false
64
- elsif t.condition.temp_c >= 110 and Random.rand(100) >= 90
65
- puts "COOLING DOWN"
66
- cooldown = true
67
- end
68
- dynamic_g -= 0.2 if cooldown
69
-
70
- if pushing
71
- # stop pushing at very high temp
72
- # 1/1000 chance to stop pushing
73
- if cooldown
74
- puts "ENDING PUSH BECAUSE COOLDOWN"
75
- pushing = false
76
- else
77
- if t.condition.temp_c >= critical_temp and Random.rand(1000) >= 999
78
- puts "ENDING PUSH"
79
- pushing = false
80
- else
81
- dynamic_g += 0.2
82
- end
83
- end
84
- else
85
- if !cooldown and
86
- t.condition.temp_c <= critical_temp and
87
- Random.rand(1000) >= 999
88
-
89
- puts "PUSHING!"
90
- pushing = true
91
- dynamic_g += 0.2
92
- end
93
- end
94
-
95
- if sliding
96
- # 5% chance to end the slide
97
- if Random.rand(100) >= 95
98
- puts " -= CAUGHT THE SLIDE! =-"
99
- sliding = false
100
- slide_speed = 0
101
- end
102
- else
103
- # 1% chance to start a small slide
104
- # 0.1% chance to start a big slide
105
- if Random.rand(100) >= 99
106
- puts " -= SMALL SLIDE! =-"
107
- sliding = true
108
- slide_speed = sector_map[:small_slide]
109
- elsif Random.rand(1000) >= 999
110
- puts " -= BIG SLIDE! =-"
111
- sliding = true
112
- slide_speed = sector_map[:big_slide]
113
- end
114
- end
115
-
116
- # fuel consumption
117
- # 5L of fuel should last 5 minutes
118
- # ~3.5 kg of fuel consumption
119
- # 1.2e-4 kg / tick
120
- mass -= sector_map[:fuel]
121
-
122
- begin
123
- t.condition.tick!(ambient_temp: ambient_temp, g: dynamic_g,
124
- slide_speed: slide_speed,
125
- mass: mass, tire_mass: 12, critical_temp: critical_temp)
126
-
127
- if i % 10 == 0
128
- condition = if pushing
129
- "Pushing"
130
- elsif cooldown
131
- "Cooldown"
132
- else
133
- "Normal"
134
- end
135
-
136
- puts [sector_map[:label].ljust(12, ' '),
137
- '%.2f' % dynamic_g,
138
- '%.1f' % slide_speed,
139
- '%.3f' % t.condition.temp_c,
140
- ].join(' ')
141
- end
142
- if i % 600 == 0
143
- puts
144
- puts "Condition: #{condition}"
145
- puts "Mass: #{'%.2f' % mass} kg"
146
- if t.condition.tread_mm > 0
147
- puts "Tread remaining: #{'%.3f' % t.condition.tread_mm}"
148
- else
149
- puts "Cords remaining: #{'%.3f' % t.condition.cords_mm}"
150
- end
151
- puts "Heat cycles: #{t.condition.heat_cycles}"
152
- puts DrivingPhysics.elapsed_display(i * 10)
153
- puts "[Enter] to continue"
154
- gets
155
- end
156
- rescue Tire::Condition::Error => e
157
- puts "FATAL:"
158
- puts [e.class, e.message].join(': ')
159
- break
160
- end
161
-
162
- if drive_time > sector_map[:seconds] * 100
163
- sector_map = drive_map[sector_map[:next_sector]]
164
- drive_time = 0
7
+ env = Environment.new
8
+ tire = Tire.new(env)
9
+ puts env
10
+ puts tire
11
+ puts
12
+
13
+ duration = 100 # sec
14
+ axle_torque = 500 # N*m
15
+ supported_mass = 1500 # kg
16
+
17
+ puts "Given:"
18
+ puts "* #{axle_torque} Nm axle torque"
19
+ puts "* #{supported_mass} kg supported mass"
20
+ puts "* 4 tires"
21
+ puts "* #{duration} seconds"
22
+ puts
23
+
24
+ total_mass = supported_mass + 4 * tire.mass
25
+ corner_mass = Rational(total_mass) / 4
26
+ normal_force = corner_mass * env.g
27
+
28
+ puts "Therefore:"
29
+ puts format("* %.1f kg total mass", total_mass)
30
+ puts format("* %.1f kg per corner", corner_mass)
31
+ puts format("* %.1f N normal force", normal_force)
32
+ puts
33
+
34
+ traction = tire.traction(normal_force)
35
+ drive_force = tire.force(axle_torque)
36
+
37
+ puts "Tires:"
38
+ puts format("* %.1f N traction", traction)
39
+ puts format("* %.1f N drive force", drive_force)
40
+
41
+ CLI.pause
42
+
43
+ acc = 0.0 # meters/s/s
44
+ speed = 0.0 # meters/s
45
+ dist = 0.0 # meters
46
+
47
+ alpha = 0.0 # radians/s/s
48
+ omega = 0.0 # radians/s
49
+ theta = 0.0 # radians
50
+
51
+ start = Timer.now
52
+ paused = 0.0
53
+ num_ticks = duration * env.hz + 1
54
+
55
+ num_ticks.times { |i|
56
+ torque = tire.net_tractable_torque(axle_torque,
57
+ mass: total_mass,
58
+ omega: omega,
59
+ normal_force: normal_force)
60
+ force = tire.force(torque)
61
+
62
+ # translational kinematics
63
+ acc = DrivingPhysics.acc(force, total_mass)
64
+ speed += acc * env.tick
65
+ dist += speed * env.tick
66
+ mph = Imperial.mph(speed)
67
+
68
+ # rotational kinematics
69
+ alpha = acc / tire.radius
70
+ omega += alpha * env.tick
71
+ theta += omega * env.tick
72
+
73
+ if i < 10 or
74
+ (i < 20_000 and i%1000 == 0) or
75
+ (i % 10_000 == 0)
76
+
77
+ puts DrivingPhysics.elapsed_display(i)
78
+ puts format(" Tire: %.1f r %.2f r/s %.3f r/s^2", theta, omega, alpha)
79
+ puts format(" Car: %.1f m %.2f m/s %.3f m/s^2 (%d mph)",
80
+ dist, speed, acc, mph)
81
+ puts format("Torque: %.1f Nm (%d N) Loss: %.1f%%",
82
+ torque, force, (1.0 - torque / axle_torque) * 100)
165
83
  puts
166
- puts sector_map[:label]
167
- puts '---'
168
84
  end
169
85
  }
86
+
87
+ puts Timer.summary(start, num_ticks, paused)
data/demo/vector_force.rb CHANGED
@@ -1,26 +1,56 @@
1
1
  require 'driving_physics/vector_force'
2
+ require 'driving_physics/environment'
3
+ require 'driving_physics/cli'
2
4
 
3
- DP = DrivingPhysics
5
+ include DrivingPhysics
6
+
7
+ env = Environment.new
8
+ puts env
4
9
 
5
- p = Vector[0, 0] # m
6
- v = Vector[0, 0] # m/s
7
10
  mass = 1000 # kg
8
- weight = mass * DP::G # N
11
+ weight = mass * env.g # N
12
+ drive_force = DrivingPhysics.random_unit_vector * 7000 # N
9
13
  duration = 100 # seconds
10
- drive_force = DP.random_unit_vector * 7000 # N
11
- tick = 1.0 / DP::HZ
12
14
 
13
- (duration * DP::HZ).times { |i|
14
- nf = drive_force + DP::VectorForce.all_resistance(v, dir: v, nf_mag: weight)
15
+ puts format("Force: %d N Dir: %s",
16
+ drive_force.magnitude,
17
+ DrivingPhysics.compass_dir(drive_force.normalize))
18
+ puts format("Mass: %d kg for %d seconds", mass, duration)
19
+ CLI.pause
20
+
21
+ acc = Vector[0, 0] # m/s/s
22
+ vel = Vector[0, 0] # m/s
23
+ pos = Vector[0, 0] # m
24
+
25
+ num_ticks = duration * env.hz + 1
26
+
27
+ flag = false
28
+ phase = :accelerate
29
+ paused = 0.0
30
+ start = Timer.now
15
31
 
16
- a = DP.a(nf, mass)
17
- v = DP.v(a, v, dt: tick)
18
- p = DP.p(v, p, dt: tick)
32
+ num_ticks.times { |i|
33
+ net_force = drive_force +
34
+ VectorForce.all_resistance(vel, dir: vel, nf_mag: weight)
19
35
 
20
- if i % DP::HZ == 0
21
- puts [i / DP::HZ,
22
- format("%.2f m/s", v.magnitude),
23
- format("%.2f m", p.magnitude),
24
- ].join("\t")
36
+ acc = DrivingPhysics.acc(net_force, mass)
37
+ vel += acc * env.tick
38
+ pos += vel * env.tick
39
+
40
+ if phase == :accelerate and vel.magnitude > 100
41
+ flag = true
42
+ phase = :coast
43
+ drive_force = Vector[0, 0]
44
+ end
45
+
46
+ if flag or (i % 1000 == 0)
47
+ puts format("%d %.3f m/s/s %.2f m/s %.1f m",
48
+ i.to_f / env.hz, acc.magnitude, vel.magnitude, pos.magnitude)
49
+ if flag
50
+ paused = CLI.pause
51
+ flag = false
52
+ end
25
53
  end
26
54
  }
55
+
56
+ puts Timer.summary(start, num_ticks, paused)