driving_physics 0.0.2.1 → 0.0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89628c4f71193088741435eb426419edf7c9ac78cad2169c4718f2a365db0881
4
- data.tar.gz: a229fa52ed29f6dcb8eab0513e845732e0735dd272e516e4f26603aeabe7f312
3
+ metadata.gz: 9b9159b499a0082d5af3ef926fceab925572552978b50d020b71bc51df7506fb
4
+ data.tar.gz: 183eaae3e07e24f38bb1417d96a6310eebfd288a1300d4e8bab96f008abbf3e5
5
5
  SHA512:
6
- metadata.gz: 42a6061d1ef6e2c989e5fb88141e8a84daaafc3c9a2f31e057d2fb7a384fbaa1c195d05deab18b2703fd5e79b539557543ec8eaf8632cd2a5f776359c7c3e340
7
- data.tar.gz: 2860d2b6c17c5d4e9d73868de36bdcf48341d74712666c109d422c97975899b0fde2248b58c060d02e02561ba3dff471d7b66c694a44e5d143108a20f828e477
6
+ metadata.gz: 9a19ba4646abe21f30ca12c88f43e9ddc7083028e96504260f0277b167af5374364967b1617ab83744f824d6d2aa513ef38627d23ad5e9ccc8ff7e017b8a2ac8
7
+ data.tar.gz: 5357970cd547b12727bfc20c408df27a07d3aaac5d5b9042cbb10fc98c85484eb7bf054e140158f7e8695ef6c30eb18961fdd6979b4d0e3ab6c343f7767fc296
data/README.md CHANGED
@@ -10,14 +10,28 @@ using `Vector` class from `matrix.rb` in stdlib.
10
10
 
11
11
  This is very much a **Work In Progress**. Implemented so far:
12
12
 
13
+ ### Library Features
14
+
15
+ * Spinning: rotational inertia and friction / hysteresis
16
+ * Tires: traction force via friction (static and kinetic) and the normal force
17
+ * Vectors: 2D Vector forces and 3D Vector torques
18
+ * Motor: torque curves, rotating mass with friction
19
+ * Gearbox: gear ratios, final drive, rotating mass with friction
20
+ * Powertrain: combines motor and gearbox
21
+ * Car: 4 tires, powertrain, extra mass presents a load to the powertrain
22
+ * Acceleration: via drive traction from "first principles"
23
+ * Variable clutch and throttle
24
+ * Engine braking
25
+ * Power and Energy
26
+
13
27
  ### mruby Support
14
28
 
15
- This is big. This library is primarily a Ruby library, intended for use with
16
- CRuby (MRI), JRuby, etc. **mruby** is the redheaded stepchild, with severe
29
+ This library is primarily a Ruby library, intended for use with CRuby (MRI),
30
+ JRuby, etc. **mruby** is the redheaded stepchild, with significant
17
31
  implications for a codebase that wants to support both sides. Supporting
18
32
  mruby here meant:
19
33
 
20
- 1. Editing the codebase (minimally) to remove *mruby-deadends*.
34
+ 1. Editing the codebase (minimally) to avoid and remove *mruby-deadends*.
21
35
  2. Creating `rake` tasks to process normal .rb files into *mruby-compatible*
22
36
  .rb files
23
37
  3. Assembling all needed library .rb files into a master .rb file
@@ -27,17 +41,6 @@ mruby here meant:
27
41
 
28
42
  See the main Rakefile near the top for mruby stuff.
29
43
 
30
- ### Library Features
31
-
32
- * Spinning: rotational inertia and friction / hysteresis
33
- * Tires: traction force via friction (static and kinetic) and the normal force
34
- * Vectors: 2D Vector forces and 3D Vector torques
35
- * Motor: torque curves, rotating mass with friction
36
- * Gearbox: gear ratios, final drive, rotating mass with friction
37
- * Powertrain: combines motor and gearbox
38
- * Car: 4 tires, powertrain, extra mass presents a load to the powertrain
39
- * Acceleration: via drive traction from "first principles"
40
-
41
44
  ## Rationale
42
45
 
43
46
  This is a toy project intended to scratch a personal itch: I want to create
data/Rakefile CHANGED
@@ -40,8 +40,8 @@ end
40
40
 
41
41
  file MRBLIB_FILE do
42
42
  line_count = write_mruby(File.join(%w[lib driving_physics.rb]), MRBLIB_FILE)
43
- %w[mruby environment imperial power
44
- disk tire motor gearbox powertrain car].each { |name|
43
+ %w[cli environment imperial power timer
44
+ disk tire motor gearbox powertrain car pid_controller].each { |name|
45
45
  file = File.join('lib', 'driving_physics', "#{name}.rb")
46
46
  line_count += write_mruby(file, MRBLIB_FILE, append: true)
47
47
  puts "wrote #{file} to #{MRBLIB_FILE}"
@@ -67,7 +67,7 @@ task mrblib: MRBLIB_FILE
67
67
  desc "Compile mruby/mrblib/driving_physics.rb to .mrb bytecode"
68
68
  task mrbc: MRBLIB_MRB
69
69
 
70
- %w[disk tire motor gearbox powertrain car].each { |name|
70
+ %w[disk tire motor gearbox powertrain car pid_controller].each { |name|
71
71
  demo_file = File.join(MRUBY_DEMO_DIR, "#{name}.rb")
72
72
  demo_mrb = File.join(MRUBY_DEMO_DIR, "#{name}.mrb")
73
73
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2.1
1
+ 0.0.3.1
data/demo/car.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'driving_physics/car'
2
+ require 'driving_physics/cockpit'
2
3
  require 'driving_physics/imperial'
3
4
  require 'driving_physics/cli'
4
5
 
@@ -10,13 +11,16 @@ puts env
10
11
  tire = Tire.new(env)
11
12
  motor = Motor.new(env)
12
13
  gearbox = Gearbox.new(env)
13
- powertrain = Powertrain.new(motor, gearbox)
14
+ powertrain = Powertrain.new(motor: motor, gearbox: gearbox)
14
15
  car = Car.new(tire: tire, powertrain: powertrain) { |c|
15
16
  c.body_mass = 850.0
16
17
  c.frontal_area = 2.5
17
18
  c.cd = 0.5
18
19
  }
19
20
  puts car
21
+
22
+ cockpit = Cockpit.new(car)
23
+ puts cockpit
20
24
  CLI.pause
21
25
 
22
26
  duration = 120
@@ -31,18 +35,19 @@ tire_theta = 0.0
31
35
 
32
36
  crank_alpha = 0.0
33
37
  crank_omega = 0.0
34
- crank_theta = 0.0
35
38
 
36
39
  start = Timer.now
37
40
  paused = 0.0
38
41
  num_ticks = duration * env.hz + 1
39
42
 
40
- clutch = :ok
43
+ rev_match = :ok
41
44
  phase = :ignition
45
+ gearbox.clutch = 0.0 # clutch in to fire up motor
42
46
  flag = false
43
- rpm = 0
44
-
45
47
 
48
+ rpm, crank_torque = 0, 0
49
+ axle_torque, drive_force, net_force = 0, 0, 0
50
+ ar, rr, rf, ir = 0, 0, 0, 0
46
51
 
47
52
  puts <<EOF
48
53
 
@@ -54,24 +59,15 @@ EOF
54
59
 
55
60
  num_ticks.times { |i|
56
61
  if phase == :ignition
57
- # ignition phase
58
62
  crank_alpha = motor.alpha(motor.starter_torque, omega: crank_omega)
59
63
  crank_omega += crank_alpha * env.tick
60
- crank_theta += crank_omega * env.tick
61
64
 
62
65
  rpm = DrivingPhysics.rpm(crank_omega)
63
66
 
64
- if i % 100 == 0 or rpm > motor.idle_rpm
65
- puts Timer.display(ms: i)
66
- puts format("%d rad %d rad/s %d rad/s/s",
67
- crank_theta, crank_omega, crank_alpha)
68
- puts format("%d RPM %d Nm starter torque", rpm, motor.starter_torque)
69
- puts
70
- end
71
-
72
- if rpm > motor.idle_rpm
73
- car.gear = 1
74
- car.throttle = 1.0
67
+ if rpm > motor.idle
68
+ flag = true
69
+ cockpit.gear = 1
70
+ cockpit.throttle_pedal = 1.0
75
71
  phase = :running
76
72
 
77
73
  puts <<EOF
@@ -82,23 +78,19 @@ num_ticks.times { |i|
82
78
 
83
79
  EOF
84
80
  end
85
- elsif phase == :running
86
- # track crank_alpha/omega/theta
87
-
88
- # cut throttle after 60 s
89
- car.throttle = 0 if i > 60 * env.hz and car.throttle == 1.0
90
-
81
+ elsif phase == :running or phase == :off_throttle
91
82
  ar = car.air_force(speed)
92
83
  rr = car.tire_rolling_force(tire_omega)
93
84
  rf = car.tire_rotational_force(tire_omega)
94
85
 
95
86
  # note, this fails if we're in neutral
96
- force = car.drive_force(rpm) + ar + rr + rf
87
+ drive_force = car.drive_force(rpm, axle_omega: tire_omega)
88
+ net_force = drive_force + ar + rr + rf
97
89
 
98
- ir = car.tire_inertial_force(force)
99
- force += ir
90
+ ir = car.tire_inertial_force(net_force)
91
+ net_force += ir
100
92
 
101
- acc = DrivingPhysics.acc(force, car.total_mass)
93
+ acc = DrivingPhysics.acc(net_force, car.total_mass)
102
94
  speed += acc * env.tick
103
95
  dist += speed * env.tick
104
96
 
@@ -108,71 +100,89 @@ EOF
108
100
 
109
101
  crank_alpha = tire_alpha / car.powertrain.gearbox.ratio
110
102
  crank_omega += crank_alpha * env.tick
111
- crank_theta += crank_omega * env.tick
112
-
113
- axle_torque = car.powertrain.axle_torque(rpm)
114
- crank_torque = car.powertrain.motor.torque(rpm)
115
-
116
- if flag or (i < 5000 and i % 100 == 0) or (i % 1000 == 0)
117
- puts Timer.display(ms: i)
118
- puts format(" Tire: %.1f r/s/s %.2f r/s %.3f r",
119
- tire_alpha, tire_omega, tire_theta)
120
- puts format(" Car: %.1f m/s/s %.2f m/s %.3f m (%.1f MPH)",
121
- acc, speed, dist, Imperial.mph(speed))
122
- puts format(" Motor: %d RPM %.1f Nm", rpm, crank_torque)
123
- puts format(" Axle: %.1f Nm (%d N) Net Force: %.1f N",
124
- axle_torque, car.drive_force(rpm), force)
125
- puts "Resist: " + format(%w[Air Roll Spin Inertial].map { |s|
126
- "#{s}: %.1f N"
127
- }.join(' '), ar, rr, rf, ir)
128
- puts
129
- flag = false
130
- end
131
103
 
132
104
  # tire_omega determines new rpm
133
- new_rpm = car.powertrain.crank_rpm(tire_omega)
134
- new_clutch, proportion = car.powertrain.gearbox.match_rpms(rpm, new_rpm)
105
+ new_rpm = gearbox.crank_rpm(tire_omega, crank_rpm: rpm)
106
+ new_rev_match, clutch, proportion = Cockpit.rev_match(rpm, new_rpm)
135
107
 
136
- if new_clutch != clutch
108
+ if new_rev_match != rev_match
137
109
  flag = true
138
- puts format("Clutch: [%s] %d RPM is %.1f%% from %d RPM",
139
- new_clutch, new_rpm, proportion * 100, rpm)
140
- clutch = new_clutch
141
- paused += CLI.pause
110
+ puts format("Rev Match: [%s] %d RPM is %.1f%% from %d RPM",
111
+ new_rev_match, new_rpm, proportion * 100, rpm)
112
+ # puts format("Recommend clutch to %.1f%%", clutch * 100)
113
+ rev_match = new_rev_match
142
114
  end
143
115
 
144
- case new_clutch
145
- when :ok
146
- rpm = new_rpm
147
- when :mismatch
116
+ clutch_diff = clutch - gearbox.clutch
117
+ if clutch_diff.abs > 0.1
148
118
  flag = true
149
- puts '#'
150
- puts '# LURCH!'
151
- puts '#'
152
- puts
153
- rpm = new_rpm
119
+ puts format("Clutch: %.1f%% Recommended Clutch: %.1f%%",
120
+ gearbox.clutch * 100, clutch * 100)
154
121
  end
155
- next_gear = car.powertrain.gearbox.next_gear(rpm)
156
- if next_gear != gearbox.gear
122
+ # the clutch pedal will reflect this change
123
+ gearbox.clutch += clutch_diff * 0.5
124
+
125
+ # update the motor RPM based on new clutch
126
+ new_rpm = gearbox.crank_rpm(tire_omega, crank_rpm: rpm)
127
+ rpm = new_rpm if new_rpm > motor.idle
128
+
129
+ new_gear = cockpit.choose_gear(rpm)
130
+ if new_gear != cockpit.gear
131
+ flag = true
132
+ puts "Gear Change: #{new_gear}"
133
+ cockpit.gear = new_gear
134
+ end
135
+
136
+ # cut throttle after 60 s
137
+ if i > 60 * env.hz and car.throttle == 1.0
157
138
  flag = true
158
- puts "Gear Change: #{next_gear}"
159
- car.gear = next_gear
160
- paused += CLI.pause
139
+ phase = :off_throttle
140
+ cockpit.throttle_pedal = 0
161
141
  end
162
142
 
163
143
  # maintain idle when revs drop
164
- if car.throttle == 0 and rpm < motor.idle_rpm
144
+ if cockpit.throttle_pedal == 0 and rpm < motor.idle
165
145
  phase = :idling
166
146
  car.gear = 0
167
- paused += CLI.pause
168
147
  end
169
148
 
149
+ print "===\n\n" if flag
170
150
 
171
151
  elsif phase == :idling
172
- # fake
173
- rpm = motor.idle_rpm
152
+ # fake; exit
153
+ rpm = motor.idle
174
154
  break
175
155
  end
156
+
157
+ if flag or (i < 5000 and i % 100 == 0) or (i % 1000 == 0)
158
+ puts Timer.display(ms: i)
159
+ puts format(" Phase: %s", phase)
160
+ puts format(" Tire: %.3f r/s/s %.2f r/s %.1f r",
161
+ tire_alpha, tire_omega, tire_theta)
162
+ puts format(" Car: %.3f m/s/s %.2f m/s %.1f m (%.1f MPH)",
163
+ acc, speed, dist, Imperial.mph(speed))
164
+ if phase == :ignition
165
+ puts format(" Motor: %d RPM Starter: %d Nm Friction: %.1f Nm",
166
+ rpm, motor.starter_torque, motor.friction(crank_omega))
167
+ else
168
+ crank_torque = car.powertrain.motor.torque(rpm)
169
+ puts format(" Motor: %d RPM %.1f Nm Friction: %.1f Nm",
170
+ rpm, crank_torque, motor.friction(crank_omega))
171
+ end
172
+ puts format("Gearbox: %s", gearbox.inputs)
173
+ if phase != :ignition
174
+ axle_torque = car.powertrain.axle_torque(rpm, axle_omega: tire_omega)
175
+ puts format(" Axle: %.1f Nm (%d N) Net Force: %.1f N",
176
+ axle_torque, drive_force, net_force)
177
+ end
178
+ puts " Resist: " + format(%w[Air Roll Spin Inertial].map { |s|
179
+ "#{s}: %.1f N"
180
+ }.join(' '), ar, rr, rf, ir)
181
+ puts cockpit
182
+ puts
183
+ paused += CLI.pause if flag
184
+ flag = false
185
+ end
176
186
  }
177
187
 
178
188
  puts Timer.summary(start, num_ticks, paused)
data/demo/motor.rb CHANGED
@@ -48,7 +48,7 @@ motor.throttle = 1.0
48
48
  puts
49
49
  puts "Now, the simulation begins..."
50
50
  puts "---"
51
- puts "* Spin the motor up to #{motor.idle_rpm} RPM with the starter motor."
51
+ puts "* Spin the motor up to #{motor.idle} RPM with the starter motor."
52
52
  puts "* Rev it up with the throttle."
53
53
  puts "* Let it die."
54
54
  CLI.pause
@@ -89,7 +89,7 @@ num_ticks.times { |i|
89
89
  rpm = DrivingPhysics.rpm(omega)
90
90
  power = DrivingPhysics.power(net_torque, omega)
91
91
 
92
- if rpm > motor.idle_rpm and status == :ignition
92
+ if rpm > motor.idle and status == :ignition
93
93
  status = :running
94
94
  flag = true
95
95
  end
@@ -106,10 +106,13 @@ num_ticks.times { |i|
106
106
  flag = true
107
107
  end
108
108
 
109
+ # we don't need no PID control
109
110
  if status == :idling
110
- if rpm < 999
111
+ if rpm.round <= 999
111
112
  motor.throttle += (1.0 - motor.throttle) * 0.005
112
- elsif rpm > 1001
113
+ elsif rpm.round == 1000
114
+ motor.throttle += (rand - 0.5) * 0.0005
115
+ else
113
116
  motor.throttle -= motor.throttle * 0.005
114
117
  end
115
118
  end
data/demo/mruby/car.rb ADDED
@@ -0,0 +1,184 @@
1
+
2
+ include DrivingPhysics
3
+
4
+ env = Environment.new
5
+ puts env
6
+
7
+ tire = Tire.new(env)
8
+ motor = Motor.new(env)
9
+ gearbox = Gearbox.new(env)
10
+ powertrain = Powertrain.new(motor: motor, gearbox: gearbox)
11
+ car = Car.new(tire: tire, powertrain: powertrain) { |c|
12
+ c.body_mass = 850.0
13
+ c.frontal_area = 2.5
14
+ c.cd = 0.5
15
+ }
16
+ puts car
17
+
18
+ cockpit = Cockpit.new(car)
19
+ puts cockpit
20
+ CLI.pause
21
+
22
+ duration = 120
23
+
24
+ acc = 0.0
25
+ speed = 0.0
26
+ dist = 0.0
27
+
28
+ tire_alpha = 0.0
29
+ tire_omega = 0.0
30
+ tire_theta = 0.0
31
+
32
+ crank_alpha = 0.0
33
+ crank_omega = 0.0
34
+
35
+ start = Timer.now
36
+ paused = 0.0
37
+ num_ticks = duration * env.hz + 1
38
+
39
+ rev_match = :ok
40
+ phase = :ignition
41
+ gearbox.clutch = 0.0 # clutch in to fire up motor
42
+ flag = false
43
+
44
+ rpm, crank_torque = 0, 0
45
+ axle_torque, drive_force, net_force = 0, 0, 0
46
+ ar, rr, rf, ir = 0, 0, 0, 0
47
+
48
+ puts <<EOF
49
+
50
+ #
51
+ # IGNITION
52
+ #
53
+
54
+ EOF
55
+
56
+ num_ticks.times { |i|
57
+ if phase == :ignition
58
+ crank_alpha = motor.alpha(motor.starter_torque, omega: crank_omega)
59
+ crank_omega += crank_alpha * env.tick
60
+
61
+ rpm = DrivingPhysics.rpm(crank_omega)
62
+
63
+ if rpm > motor.idle
64
+ flag = true
65
+ cockpit.gear = 1
66
+ cockpit.throttle_pedal = 1.0
67
+ phase = :running
68
+
69
+ puts <<EOF
70
+
71
+ #
72
+ # RUNNING
73
+ #
74
+
75
+ EOF
76
+ end
77
+ elsif phase == :running or phase == :off_throttle
78
+ ar = car.air_force(speed)
79
+ rr = car.tire_rolling_force(tire_omega)
80
+ rf = car.tire_rotational_force(tire_omega)
81
+
82
+ # note, this fails if we're in neutral
83
+ drive_force = car.drive_force(rpm, axle_omega: tire_omega)
84
+ net_force = drive_force + ar + rr + rf
85
+
86
+ ir = car.tire_inertial_force(net_force)
87
+ net_force += ir
88
+
89
+ acc = DrivingPhysics.acc(net_force, car.total_mass)
90
+ speed += acc * env.tick
91
+ dist += speed * env.tick
92
+
93
+ tire_alpha = acc / car.tire.radius
94
+ tire_omega += tire_alpha * env.tick
95
+ tire_theta += tire_omega * env.tick
96
+
97
+ crank_alpha = tire_alpha / car.powertrain.gearbox.ratio
98
+ crank_omega += crank_alpha * env.tick
99
+
100
+ # tire_omega determines new rpm
101
+ new_rpm = gearbox.crank_rpm(tire_omega, crank_rpm: rpm)
102
+ new_rev_match, clutch, proportion = Cockpit.rev_match(rpm, new_rpm)
103
+
104
+ if new_rev_match != rev_match
105
+ flag = true
106
+ puts format("Rev Match: [%s] %d RPM is %.1f%% from %d RPM",
107
+ new_rev_match, new_rpm, proportion * 100, rpm)
108
+ # puts format("Recommend clutch to %.1f%%", clutch * 100)
109
+ rev_match = new_rev_match
110
+ end
111
+
112
+ clutch_diff = clutch - gearbox.clutch
113
+ if clutch_diff.abs > 0.1
114
+ flag = true
115
+ puts format("Clutch: %.1f%% Recommended Clutch: %.1f%%",
116
+ gearbox.clutch * 100, clutch * 100)
117
+ end
118
+ # the clutch pedal will reflect this change
119
+ gearbox.clutch += clutch_diff * 0.5
120
+
121
+ # update the motor RPM based on new clutch
122
+ new_rpm = gearbox.crank_rpm(tire_omega, crank_rpm: rpm)
123
+ rpm = new_rpm if new_rpm > motor.idle
124
+
125
+ new_gear = cockpit.choose_gear(rpm)
126
+ if new_gear != cockpit.gear
127
+ flag = true
128
+ puts "Gear Change: #{new_gear}"
129
+ cockpit.gear = new_gear
130
+ end
131
+
132
+ # cut throttle after 60 s
133
+ if i > 60 * env.hz and car.throttle == 1.0
134
+ flag = true
135
+ phase = :off_throttle
136
+ cockpit.throttle_pedal = 0
137
+ end
138
+
139
+ # maintain idle when revs drop
140
+ if cockpit.throttle_pedal == 0 and rpm < motor.idle
141
+ phase = :idling
142
+ car.gear = 0
143
+ end
144
+
145
+ print "===\n\n" if flag
146
+
147
+ elsif phase == :idling
148
+ # fake; exit
149
+ rpm = motor.idle
150
+ break
151
+ end
152
+
153
+ if flag or (i < 5000 and i % 100 == 0) or (i % 1000 == 0)
154
+ puts Timer.display(ms: i)
155
+ puts format(" Phase: %s", phase)
156
+ puts format(" Tire: %.3f r/s/s %.2f r/s %.1f r",
157
+ tire_alpha, tire_omega, tire_theta)
158
+ puts format(" Car: %.3f m/s/s %.2f m/s %.1f m (%.1f MPH)",
159
+ acc, speed, dist, Imperial.mph(speed))
160
+ if phase == :ignition
161
+ puts format(" Motor: %d RPM Starter: %d Nm Friction: %.1f Nm",
162
+ rpm, motor.starter_torque, motor.friction(crank_omega))
163
+ else
164
+ crank_torque = car.powertrain.motor.torque(rpm)
165
+ puts format(" Motor: %d RPM %.1f Nm Friction: %.1f Nm",
166
+ rpm, crank_torque, motor.friction(crank_omega))
167
+ end
168
+ puts format("Gearbox: %s", gearbox.inputs)
169
+ if phase != :ignition
170
+ axle_torque = car.powertrain.axle_torque(rpm, axle_omega: tire_omega)
171
+ puts format(" Axle: %.1f Nm (%d N) Net Force: %.1f N",
172
+ axle_torque, drive_force, net_force)
173
+ end
174
+ puts " Resist: " + format(%w[Air Roll Spin Inertial].map { |s|
175
+ "#{s}: %.1f N"
176
+ }.join(' '), ar, rr, rf, ir)
177
+ puts cockpit
178
+ puts
179
+ paused += CLI.pause if flag
180
+ flag = false
181
+ end
182
+ }
183
+
184
+ puts Timer.summary(start, num_ticks, paused)
data/demo/mruby/motor.rb CHANGED
@@ -45,7 +45,7 @@ motor.throttle = 1.0
45
45
  puts
46
46
  puts "Now, the simulation begins..."
47
47
  puts "---"
48
- puts "* Spin the motor up to #{motor.idle_rpm} RPM with the starter motor."
48
+ puts "* Spin the motor up to #{motor.idle} RPM with the starter motor."
49
49
  puts "* Rev it up with the throttle."
50
50
  puts "* Let it die."
51
51
  CLI.pause
@@ -86,7 +86,7 @@ num_ticks.times { |i|
86
86
  rpm = DrivingPhysics.rpm(omega)
87
87
  power = DrivingPhysics.power(net_torque, omega)
88
88
 
89
- if rpm > motor.idle_rpm and status == :ignition
89
+ if rpm > motor.idle and status == :ignition
90
90
  status = :running
91
91
  flag = true
92
92
  end
@@ -103,10 +103,13 @@ num_ticks.times { |i|
103
103
  flag = true
104
104
  end
105
105
 
106
+ # we don't need no PID control
106
107
  if status == :idling
107
- if rpm < 999
108
+ if rpm.round <= 999
108
109
  motor.throttle += (1.0 - motor.throttle) * 0.005
109
- elsif rpm > 1001
110
+ elsif rpm.round == 1000
111
+ motor.throttle += (rand - 0.5) * 0.0005
112
+ else
110
113
  motor.throttle -= motor.throttle * 0.005
111
114
  end
112
115
  end