driving_physics 0.0.1.2 → 0.0.2.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: ef486c39982798a7331f49f601e648d520a65977161180631cc4c5d3340a9011
4
- data.tar.gz: 9e30b74ae34cb77a711d5d9631983b0c070872900123a1dde2d3dd03bdab854b
3
+ metadata.gz: 89628c4f71193088741435eb426419edf7c9ac78cad2169c4718f2a365db0881
4
+ data.tar.gz: a229fa52ed29f6dcb8eab0513e845732e0735dd272e516e4f26603aeabe7f312
5
5
  SHA512:
6
- metadata.gz: 46eaf512dad64ca39ec20451d7acce1b1819ecd64125ee858f92c26e5edd7b0ec0e7ef01af8f73daa0d37868e0ffd76bd3b29478093219cd906d8d9e38026bcd
7
- data.tar.gz: ae2e01ae8e7986c9d2e659ff5a0934ed5359e20cf2757d7724118bb59e0fb0199180249815f2f28f55f48a2336511a0b43f0d6fab042ed5d20a5ab6a897baef1
6
+ metadata.gz: 42a6061d1ef6e2c989e5fb88141e8a84daaafc3c9a2f31e057d2fb7a384fbaa1c195d05deab18b2703fd5e79b539557543ec8eaf8632cd2a5f776359c7c3e340
7
+ data.tar.gz: 2860d2b6c17c5d4e9d73868de36bdcf48341d74712666c109d422c97975899b0fde2248b58c060d02e02561ba3dff471d7b66c694a44e5d143108a20f828e477
data/README.md CHANGED
@@ -10,8 +10,27 @@ 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
+ ### mruby Support
14
+
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
17
+ implications for a codebase that wants to support both sides. Supporting
18
+ mruby here meant:
19
+
20
+ 1. Editing the codebase (minimally) to remove *mruby-deadends*.
21
+ 2. Creating `rake` tasks to process normal .rb files into *mruby-compatible*
22
+ .rb files
23
+ 3. Assembling all needed library .rb files into a master .rb file
24
+ 4. Compiling the library to bytecode
25
+ 5. Executing a toplevel/main script against the library
26
+ 6. Optionally executing toplevel/main bytecode against the library
27
+
28
+ See the main Rakefile near the top for mruby stuff.
29
+
30
+ ### Library Features
31
+
13
32
  * Spinning: rotational inertia and friction / hysteresis
14
- * Tires: traction force via friction and the normal force
33
+ * Tires: traction force via friction (static and kinetic) and the normal force
15
34
  * Vectors: 2D Vector forces and 3D Vector torques
16
35
  * Motor: torque curves, rotating mass with friction
17
36
  * Gearbox: gear ratios, final drive, rotating mass with friction
data/Rakefile CHANGED
@@ -16,6 +16,90 @@ end
16
16
 
17
17
  task default: :test
18
18
 
19
+ #
20
+ # mruby
21
+ #
22
+
23
+ MRBLIB_DIR = File.join %w[mruby mrblib]
24
+ MRBLIB_FILE = File.join(MRBLIB_DIR, 'driving_physics.rb')
25
+ MRBLIB_MRB = File.join(MRBLIB_DIR, 'driving_physics.mrb')
26
+ MRUBY_DEMO_DIR = File.join %w[demo mruby]
27
+
28
+ def write_mruby(input_file, output_file = MRBLIB_FILE, append: false)
29
+ file_obj = File.open(output_file, append ? 'a' : 'w')
30
+ line_count = 0
31
+
32
+ File.readlines(input_file).each { |line|
33
+ next if line.match /\A *(?:require|autoload)/
34
+ file_obj.write(line)
35
+ line_count += 1
36
+ }
37
+ file_obj.close
38
+ line_count
39
+ end
40
+
41
+ file MRBLIB_FILE do
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|
45
+ file = File.join('lib', 'driving_physics', "#{name}.rb")
46
+ line_count += write_mruby(file, MRBLIB_FILE, append: true)
47
+ puts "wrote #{file} to #{MRBLIB_FILE}"
48
+ }
49
+ puts "wrote #{line_count} lines to #{MRBLIB_FILE}"
50
+ end
51
+
52
+ file MRBLIB_MRB => MRBLIB_FILE do
53
+ rb_file = File.join(%w[mruby mrblib driving_physics.rb])
54
+ mrb_file = File.join(%w[mruby mrblib driving_physics.mrb])
55
+ sh 'mrbc', rb_file
56
+ puts format("%s: %d bytes (created %s)",
57
+ mrb_file, File.size(mrb_file), File.birthtime(mrb_file))
58
+ end
59
+
60
+ file MRUBY_DEMO_DIR do
61
+ mkdir_p MRUBY_DEMO_DIR
62
+ end
63
+
64
+ desc "Map/Filter/Reduce lib/**/*.rb to mruby/mrblib/driving_physics.rb"
65
+ task mrblib: MRBLIB_FILE
66
+
67
+ desc "Compile mruby/mrblib/driving_physics.rb to .mrb bytecode"
68
+ task mrbc: MRBLIB_MRB
69
+
70
+ %w[disk tire motor gearbox powertrain car].each { |name|
71
+ demo_file = File.join(MRUBY_DEMO_DIR, "#{name}.rb")
72
+ demo_mrb = File.join(MRUBY_DEMO_DIR, "#{name}.mrb")
73
+
74
+ file demo_file => MRUBY_DEMO_DIR do
75
+ write_mruby(File.join('demo', "#{name}.rb"), demo_file)
76
+ end
77
+
78
+ file demo_mrb => demo_file do
79
+ sh 'mrbc', demo_file
80
+ end
81
+
82
+ desc "run demo/#{name}.rb via mruby"
83
+ task "demo_#{name}" => [demo_file, MRBLIB_MRB] do
84
+ sh 'mruby', '-r', MRBLIB_MRB, demo_file
85
+ end
86
+
87
+ desc "run demo/#{name}.rb via mruby bytecode"
88
+ task "mrb_#{name}" => [demo_mrb, MRBLIB_MRB] do
89
+ sh 'mruby', '-r', MRBLIB_MRB, '-b', demo_mrb
90
+ end
91
+ }
92
+
93
+ desc "Remove generated .rb and .mrb files"
94
+ task :clean do
95
+ [MRBLIB_DIR, MRUBY_DEMO_DIR].each { |dir|
96
+ Dir[File.join(dir, '*rb')].each { |file|
97
+ rm file unless File.directory?(file)
98
+ }
99
+ }
100
+ end
101
+
102
+
19
103
  #
20
104
  # METRICS
21
105
  #
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1.2
1
+ 0.0.2.1
data/demo/car.rb CHANGED
@@ -41,6 +41,9 @@ clutch = :ok
41
41
  phase = :ignition
42
42
  flag = false
43
43
  rpm = 0
44
+
45
+
46
+
44
47
  puts <<EOF
45
48
 
46
49
  #
@@ -59,7 +62,7 @@ num_ticks.times { |i|
59
62
  rpm = DrivingPhysics.rpm(crank_omega)
60
63
 
61
64
  if i % 100 == 0 or rpm > motor.idle_rpm
62
- puts Timer.display(i)
65
+ puts Timer.display(ms: i)
63
66
  puts format("%d rad %d rad/s %d rad/s/s",
64
67
  crank_theta, crank_omega, crank_alpha)
65
68
  puts format("%d RPM %d Nm starter torque", rpm, motor.starter_torque)
@@ -111,7 +114,7 @@ EOF
111
114
  crank_torque = car.powertrain.motor.torque(rpm)
112
115
 
113
116
  if flag or (i < 5000 and i % 100 == 0) or (i % 1000 == 0)
114
- puts Timer.display(i)
117
+ puts Timer.display(ms: i)
115
118
  puts format(" Tire: %.1f r/s/s %.2f r/s %.3f r",
116
119
  tire_alpha, tire_omega, tire_theta)
117
120
  puts format(" Car: %.1f m/s/s %.2f m/s %.3f m (%.1f MPH)",
data/demo/gearbox.rb CHANGED
@@ -21,10 +21,11 @@ alpha = 0.0
21
21
  omega = 0.0
22
22
  theta = 0.0
23
23
 
24
+ num_ticks = duration * env.hz + 1
24
25
  start = Timer.now
25
- paused = 0
26
+ paused = 0.0
26
27
 
27
- (duration * env.hz + 1).times { |i|
28
+ num_ticks.times { |i|
28
29
  # just for info, not used in the simulation
29
30
  friction = gearbox.spinner.rotating_friction(omega)
30
31
 
@@ -41,7 +42,7 @@ paused = 0
41
42
  (i < 100 and i % 10 == 0) or
42
43
  (i < 1000 and i % 100 == 0) or
43
44
  i % 1000 == 0
44
- puts Timer.display(i)
45
+ puts Timer.display(ms: i)
45
46
  puts format("RPM %d Torque: %.3f Nm (%d Nm) Friction: %.3f Nm",
46
47
  DrivingPhysics.rpm(omega), net_torque, torque, friction)
47
48
  puts format("%.1f rad %.1f rad/s %.1f rad/s/s", theta, omega, alpha)
data/demo/motor.rb CHANGED
@@ -82,12 +82,11 @@ num_ticks.times { |i|
82
82
  omega += alpha * env.tick
83
83
  theta += omega * env.tick
84
84
 
85
- net_torque = motor.implied_torque(alpha)
85
+ # prevent silly oscillations due to ticks or tiny floating point errors
86
+ omega = 0 if omega < 0.0001
86
87
 
87
- # prevent silly oscillations due to tiny floating point errors
88
- omega = 0 if omega < 0.00001
88
+ net_torque = motor.implied_torque(alpha)
89
89
  rpm = DrivingPhysics.rpm(omega)
90
-
91
90
  power = DrivingPhysics.power(net_torque, omega)
92
91
 
93
92
  if rpm > motor.idle_rpm and status == :ignition
@@ -122,7 +121,7 @@ num_ticks.times { |i|
122
121
  (i < 10_000 and i % 500 == 0) or
123
122
  (i % 5000 == 0) or
124
123
  (status == :idling and i % 100 == 0)
125
- puts Timer.display(i)
124
+ puts Timer.display(ms: i)
126
125
  puts format("Throttle: %.1f%%", motor.throttle * 100)
127
126
  puts format("%d RPM %.1f Nm (%d Nm) %.1f kW Friction: %.1f Nm",
128
127
  DrivingPhysics.rpm(omega),
@@ -130,7 +129,7 @@ num_ticks.times { |i|
130
129
  torque,
131
130
  power / 1000,
132
131
  motor.spinner.rotating_friction(omega))
133
- puts format("%d rad %.1f rad/s %.1f rad/s/s", theta, omega, alpha)
132
+ puts format("%.3f rad/s/s %.2f rad/s %.1f rad", alpha, omega, theta)
134
133
  puts
135
134
 
136
135
  paused += CLI.pause if flag
@@ -0,0 +1,81 @@
1
+
2
+ include DrivingPhysics
3
+
4
+ env = Environment.new
5
+ disk = Disk.new(env)
6
+
7
+ puts env
8
+ puts disk
9
+ puts
10
+
11
+ axle_torque = 50
12
+ alpha = disk.alpha(axle_torque)
13
+ drive_force = disk.force(axle_torque)
14
+
15
+ puts [format("Axle torque: %.1f Nm", axle_torque),
16
+ format(" Alpha: %.1f rad/s/s", alpha),
17
+ format("Drive force: %.1f N", drive_force),
18
+ ].join("\n")
19
+ puts
20
+
21
+ puts "* Spin up the disk with #{axle_torque} Nm of torque"
22
+ puts "* Cut the power at some point"
23
+ puts "* Observe"
24
+ CLI.pause
25
+
26
+ duration = 750 # sec
27
+
28
+ dist = 0.0 # meters
29
+ speed = 0.0 # meters/s
30
+
31
+ theta = 0.0 # radians
32
+ omega = 0.0 # radians/s
33
+
34
+ paused = 0.0 # seconds
35
+ num_ticks = duration * env.hz + 1
36
+ flag = false # to display current stats
37
+ start = Timer.now
38
+
39
+ num_ticks.times { |i|
40
+ # shut off the powah!
41
+ if i == 18_950
42
+ flag = true
43
+ puts '#'
44
+ puts '# CUT POWER'
45
+ puts '#'
46
+ puts
47
+ axle_torque = 0
48
+ end
49
+
50
+ rotating_friction = disk.rotating_friction(omega)
51
+ net_torque = axle_torque + rotating_friction
52
+ net_force = disk.force(net_torque)
53
+
54
+ # rotational kinematics
55
+ alpha = disk.alpha(net_torque)
56
+ omega += alpha * env.tick
57
+ omega = 0.0 if omega.abs < 0.0001
58
+ theta += omega * env.tick
59
+
60
+ if flag or i < 10 or
61
+ (i < 20_000 and i%1000 == 0) or
62
+ (i % 10_000 == 0) or
63
+ i == duration * env.hz - 1
64
+
65
+ puts Timer.display(ms: i)
66
+ puts format(" Torque: %.1f Nm (%d Nm) Friction: %.1f Nm",
67
+ net_torque, axle_torque, rotating_friction)
68
+ puts format("Radians: %.1f r %.2f r/s %.3f r/s^2", theta, omega, alpha)
69
+ puts format(" Revs: %d revs %d revs/s %d rpm",
70
+ DrivingPhysics.revs(theta),
71
+ DrivingPhysics.revs(omega),
72
+ DrivingPhysics.rpm(omega))
73
+ puts
74
+ if flag
75
+ paused += CLI.pause
76
+ flag = false
77
+ end
78
+ end
79
+ }
80
+
81
+ puts Timer.summary(start, num_ticks, paused)
@@ -0,0 +1,137 @@
1
+
2
+ # next fun idea: PID controller
3
+
4
+ include DrivingPhysics
5
+
6
+ env = Environment.new
7
+ motor = Motor.new(env)
8
+ puts env
9
+ puts motor
10
+ puts
11
+
12
+ puts "Rev it up!"
13
+ motor.throttle = 1.0
14
+ [:torque, :power].each { |run|
15
+ puts
16
+ puts run.to_s.upcase + ':'
17
+
18
+ 800.upto(7000) { |rpm|
19
+ next unless rpm % 200 == 0
20
+ omega = DrivingPhysics.omega(rpm)
21
+ torque = motor.torque(rpm)
22
+ case run
23
+ when :torque
24
+ count = (torque.to_f / 10).round
25
+ char = 'T'
26
+ val = torque.round.to_s.rjust(5, ' ')
27
+ fmt = "%s Nm"
28
+ when :power
29
+ power = DrivingPhysics.power(torque, omega)
30
+ kw = power.to_f / 1000
31
+ count = (kw / 5).round
32
+ char = 'P'
33
+ val = kw.round(1).to_s.rjust(5, ' ')
34
+ fmt = "%s kW"
35
+ else
36
+ raise "unknown"
37
+ end
38
+ puts format("%s RPM: #{fmt}\t%s",
39
+ rpm.to_s.rjust(4, ' '),
40
+ val,
41
+ char * count)
42
+ }
43
+ }
44
+
45
+ puts
46
+ puts "Now, the simulation begins..."
47
+ puts "---"
48
+ puts "* Spin the motor up to #{motor.idle_rpm} RPM with the starter motor."
49
+ puts "* Rev it up with the throttle."
50
+ puts "* Let it die."
51
+ CLI.pause
52
+
53
+ alpha = 0.0
54
+ omega = 0.0
55
+ theta = 0.0
56
+
57
+ duration = 60
58
+
59
+ status = :ignition
60
+ rpm = 0
61
+
62
+ paused = 0.0
63
+ num_ticks = duration * env.hz + 1
64
+ start = Timer.now
65
+
66
+ num_ticks.times { |i|
67
+ # this is an input torque; alpha is determined after inertia and friction
68
+ torque = case status
69
+ when :ignition
70
+ motor.starter_torque
71
+ when :running, :off_throttle, :idling
72
+ motor.torque(rpm)
73
+ else
74
+ 0
75
+ end
76
+
77
+ # Motor#alpha incorporates inertia and friction
78
+ alpha = motor.alpha(torque, omega: omega)
79
+ omega += alpha * env.tick
80
+ theta += omega * env.tick
81
+
82
+ # prevent silly oscillations due to ticks or tiny floating point errors
83
+ omega = 0 if omega < 0.0001
84
+
85
+ net_torque = motor.implied_torque(alpha)
86
+ rpm = DrivingPhysics.rpm(omega)
87
+ power = DrivingPhysics.power(net_torque, omega)
88
+
89
+ if rpm > motor.idle_rpm and status == :ignition
90
+ status = :running
91
+ flag = true
92
+ end
93
+
94
+ if rpm > 7000 and status == :running
95
+ status = :off_throttle
96
+ motor.throttle = 0.0
97
+ flag = true
98
+ end
99
+
100
+ if rpm < 1000 and status == :off_throttle
101
+ status = :idling
102
+ motor.throttle = 0.06
103
+ flag = true
104
+ end
105
+
106
+ if status == :idling
107
+ if rpm < 999
108
+ motor.throttle += (1.0 - motor.throttle) * 0.005
109
+ elsif rpm > 1001
110
+ motor.throttle -= motor.throttle * 0.005
111
+ end
112
+ end
113
+
114
+ if flag or
115
+ (i < 10) or
116
+ (i < 100 and i % 10 == 0) or
117
+ (i < 1000 and i % 100 == 0) or
118
+ (i < 10_000 and i % 500 == 0) or
119
+ (i % 5000 == 0) or
120
+ (status == :idling and i % 100 == 0)
121
+ puts Timer.display(ms: i)
122
+ puts format("Throttle: %.1f%%", motor.throttle * 100)
123
+ puts format("%d RPM %.1f Nm (%d Nm) %.1f kW Friction: %.1f Nm",
124
+ DrivingPhysics.rpm(omega),
125
+ net_torque,
126
+ torque,
127
+ power / 1000,
128
+ motor.spinner.rotating_friction(omega))
129
+ puts format("%.3f rad/s/s %.2f rad/s %.1f rad", alpha, omega, theta)
130
+ puts
131
+
132
+ paused += CLI.pause if flag
133
+ flag = false
134
+ end
135
+ }
136
+
137
+ puts Timer.summary(start, num_ticks, paused)
@@ -103,7 +103,7 @@ module DrivingPhysics
103
103
  end
104
104
 
105
105
  def corner_mass
106
- Rational(self.total_mass) / @num_tires
106
+ self.total_mass / @num_tires
107
107
  end
108
108
 
109
109
  # per tire
@@ -1,5 +1,5 @@
1
1
  require 'driving_physics/environment'
2
- require 'driving_physics/vector_force'
2
+ #require 'driving_physics/vector_force'
3
3
 
4
4
  module DrivingPhysics
5
5
  # radius is always in meters
@@ -110,11 +110,11 @@ module DrivingPhysics
110
110
 
111
111
  def initialize(env)
112
112
  @env = env
113
- @radius = 350/1000r # m
114
- @width = 200/1000r # m
113
+ @radius = 0.35
114
+ @width = 0.2
115
115
  @density = DENSITY
116
- @base_friction = 5/100_000r # constant resistance to rotation
117
- @omega_friction = 5/100_000r # scales with omega
116
+ @base_friction = 5.0/100_000 # constant resistance to rotation
117
+ @omega_friction = 5.0/100_000 # scales with omega
118
118
  yield self if block_given?
119
119
  end
120
120
 
@@ -27,8 +27,8 @@ module DrivingPhysics
27
27
  # represent all rotating mass
28
28
  @spinner = Disk.new(env) { |m|
29
29
  m.radius = 0.15
30
- m.base_friction = 5/1000r
31
- m.omega_friction = 15/100_000r
30
+ m.base_friction = 5.0/1000
31
+ m.omega_friction = 15.0/100_000
32
32
  m.mass = 15
33
33
  }
34
34
  @fixed_mass = 30 # kg
@@ -25,8 +25,8 @@ module DrivingPhysics
25
25
  @spinner = Disk.new(@env) { |fly|
26
26
  fly.radius = 0.25 # m
27
27
  fly.mass = 75 # kg
28
- fly.base_friction = 5/1000r
29
- fly.omega_friction = 2/10_000r
28
+ fly.base_friction = 5.0/1000
29
+ fly.omega_friction = 2.0/10_000
30
30
  }
31
31
  @starter_torque = 500 # Nm
32
32
  @idle_rpm = 1000 # RPM
@@ -75,11 +75,8 @@ module DrivingPhysics
75
75
  raise(Stall, "RPM #{rpm}") if rpm < @rpms.first
76
76
  raise(OverRev, "RPM #{rpm}") if rpm > @rpms.last
77
77
 
78
- last_rpm = 99999
79
- last_tq = -1
80
- torque = nil
78
+ last_rpm, last_tq, torque = 99999, -1, nil
81
79
 
82
- # ew; there must be a better way
83
80
  @rpms.each_with_index { |r, i|
84
81
  tq = @torques[i]
85
82
  if last_rpm <= rpm and rpm <= r
@@ -87,8 +84,7 @@ module DrivingPhysics
87
84
  torque = last_tq + (tq - last_tq) * proportion
88
85
  break
89
86
  end
90
- last_rpm = r
91
- last_tq = tq
87
+ last_rpm, last_tq = r, tq
92
88
  }
93
89
  raise(SanityCheck, "RPM #{rpm}") if torque.nil?
94
90
 
@@ -101,3 +97,54 @@ module DrivingPhysics
101
97
  end
102
98
  end
103
99
  end
100
+
101
+
102
+ # TODO: starter motor
103
+ # Starter motor is power limited, not torque limited
104
+ # Consider:
105
+ # * 2.2 kW (3.75:1 gear reduction)
106
+ # * 1.8 kW (4.4:1 gear reduction)
107
+ # On a workbench, a starter will draw 80 to 90 amps. However, during actual
108
+ # start-up of an engine, a starter will draw 250 to 350 amps.
109
+ # from https://www.motortrend.com/how-to/because-theres-more-to-a-starter-than-you-realize/
110
+
111
+ # V - Potential, voltage
112
+ # I - Current, amperage
113
+ # R - Resistance, ohms
114
+ # P - Power, wattage
115
+
116
+ # Ohm's law: I = V / R (where R is held constant)
117
+ # P = I * V
118
+ # For resistors (where R is helod constant)
119
+ # = I^2 * R
120
+ # = V^2 / R
121
+
122
+
123
+ # torque proportional to A
124
+ # speed proportional to V
125
+
126
+
127
+ # batteries are rated in terms of CCA - cold cranking amps
128
+
129
+ # P = I * V
130
+ # V = 12 (up to 14ish)
131
+ # I = 300
132
+ # P = 3600 or 3.6 kW
133
+
134
+
135
+ # A starter rated at e.g. 2.2 kW will use more power on initial cranking
136
+ # Sometimes up to 500 amperes are required, and some batteries will provide
137
+ # over 600 cold cranking amps
138
+
139
+
140
+ # Consider:
141
+
142
+ # V = 12
143
+ # R = resistance of battery, wiring, starter motor
144
+ # L = inductance (approx 0)
145
+ # I = current through motor
146
+ # Vc = proportional to omega
147
+
148
+ # rated power - Vc * I
149
+ # input power - V * I
150
+ # input power that is unable to be converted to output power is wasted as heat
@@ -0,0 +1,45 @@
1
+ module DrivingPhysics
2
+ module CLI
3
+ # returns user input as a string
4
+ def self.prompt(msg = '')
5
+ print msg + ' ' unless msg.empty?
6
+ print '> '
7
+ $stdin.gets.chomp
8
+ end
9
+
10
+ # press Enter to continue, ignore input, return elapsed time
11
+ def self.pause(msg = '')
12
+ t = Timer.now
13
+ puts msg unless msg.empty?
14
+ puts ' [ Press Enter ]'
15
+ $stdin.gets
16
+ Timer.since(t)
17
+ end
18
+ end
19
+
20
+ module Timer
21
+ def self.now
22
+ Time.now
23
+ end
24
+
25
+ def self.since(t)
26
+ self.now - t
27
+ end
28
+
29
+ def self.elapsed(&work)
30
+ t = self.now
31
+ return yield, self.since(t)
32
+ end
33
+
34
+ # HH:MM:SS.mmm
35
+ def self.display(seconds: 0, ms: 0)
36
+ ms += (seconds * 1000).round if seconds > 0
37
+ DrivingPhysics.elapsed_display(ms)
38
+ end
39
+
40
+ def self.summary(start, num_ticks, paused = 0)
41
+ elapsed = self.since(start) - paused
42
+ format("%.3f s (%d ticks/s)", elapsed, num_ticks.to_f / elapsed)
43
+ end
44
+ end
45
+ end
@@ -26,14 +26,14 @@ module DrivingPhysics
26
26
 
27
27
  def initialize(env)
28
28
  @env = env
29
- @radius = 350/1000r # m
30
- @width = 200/1000r # m
29
+ @radius = 0.35
30
+ @width = 0.2
31
31
  @density = DENSITY
32
32
  @temp = @env.air_temp
33
- @mu_s = 11/10r # static friction
34
- @mu_k = 7/10r # kinetic friction
35
- @base_friction = 5/10_000r
36
- @omega_friction = 5/100_000r # scales with speed
33
+ @mu_s = 1.1 # static friction
34
+ @mu_k = 0.7 # kinetic friction
35
+ @base_friction = 5.0/10_000
36
+ @omega_friction = 5.0/100_000
37
37
  @roll_cof = DrivingPhysics::ROLL_COF
38
38
 
39
39
  yield self if block_given?
data/test/disk.rb CHANGED
@@ -50,6 +50,7 @@ describe D do
50
50
  inertia = D.rotational_inertia(0.35, 25.0)
51
51
  expect(D.alpha scalar_torque, inertia).must_be_within_epsilon 653.061
52
52
 
53
+ skip # Vector
53
54
  vector_torque = Vector[0, 0, 1000]
54
55
  vector_alpha = D.alpha vector_torque, inertia
55
56
  expect(vector_alpha).must_be_instance_of Vector
@@ -60,6 +61,7 @@ describe D do
60
61
 
61
62
  describe "Disk.torque_vector" do
62
63
  it "calculates a torque in the 3rd dimension given 2D force and radius" do
64
+ skip # Vector
63
65
  force = Vector[1000, 0]
64
66
  radius = Vector[0, 5]
65
67
  torque = D.torque_vector(force, radius)
@@ -71,6 +73,7 @@ describe D do
71
73
 
72
74
  describe "Disk.force_vector" do
73
75
  it "calculates a (3D) force given 3D torque and 2D radius" do
76
+ skip # Vector
74
77
  # let's invert the Disk.torque_vector case from above:
75
78
  torque = Vector[0, 0, 5000]
76
79
  radius = Vector[0, 5]
data/test/tire.rb CHANGED
@@ -11,6 +11,7 @@ describe T do
11
11
  scalar_t = T.traction(scalar_nf, cof)
12
12
  expect(scalar_t).must_equal 10780.0
13
13
 
14
+ skip # Vector
14
15
  vector_nf = Vector[9800, 0]
15
16
  vector_t = T.traction(vector_nf, cof)
16
17
  expect(vector_t).must_equal Vector[10780.0, 0.0]
@@ -62,6 +63,7 @@ describe T do
62
63
  inertia = T.rotational_inertia(0.35, 25.0)
63
64
  expect(T.alpha scalar_torque, inertia).must_be_within_epsilon 653.061
64
65
 
66
+ skip # Vector
65
67
  vector_torque = Vector[0, 0, 1000]
66
68
  vector_alpha = T.alpha vector_torque, inertia
67
69
  expect(vector_alpha).must_be_instance_of Vector
@@ -72,6 +74,7 @@ describe T do
72
74
 
73
75
  describe "Tire.torque_vector" do
74
76
  it "calculates a torque in the 3rd dimension given 2D force and radius" do
77
+ skip # Vector
75
78
  force = Vector[1000, 0]
76
79
  radius = Vector[0, 5]
77
80
  torque = T.torque_vector(force, radius)
@@ -84,6 +87,7 @@ describe T do
84
87
  describe "Tire.force_vector" do
85
88
  it "calculates a (3D) force given 3D torque and 2D radius" do
86
89
  # let's invert the Tire.torque_vector case from above:
90
+ skip # Vector
87
91
  torque = Vector[0, 0, 5000]
88
92
  radius = Vector[0, 5]
89
93
  force = T.force_vector(torque, radius)
@@ -154,6 +158,7 @@ describe T do
154
158
  expect(@tire.traction scalar_nf).must_equal 10780.0
155
159
  expect(@tire.traction scalar_nf, static: false).must_equal 6860.0
156
160
 
161
+ skip # Vector
157
162
  vector_nf = Vector[9800, 0]
158
163
  expect(@tire.traction vector_nf).must_equal Vector[10780.0, 0.0]
159
164
  expect(@tire.traction vector_nf, static: false).
@@ -173,6 +178,7 @@ describe T do
173
178
  expect(kin_tq).must_be_within_epsilon 2401.0
174
179
 
175
180
  # not sure about how torque vectors work, but the "math" "works":
181
+ skip # Vector
176
182
  vector_nf = Vector[9800, 0]
177
183
  expect(@tire.tractable_torque(vector_nf)[0]).
178
184
  must_be_within_epsilon 3773.0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: driving_physics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.2
4
+ version: 0.0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Hull
@@ -23,6 +23,8 @@ files:
23
23
  - demo/disk.rb
24
24
  - demo/gearbox.rb
25
25
  - demo/motor.rb
26
+ - demo/mruby/disk.rb
27
+ - demo/mruby/motor.rb
26
28
  - demo/powertrain.rb
27
29
  - demo/scalar_force.rb
28
30
  - demo/tire.rb
@@ -36,6 +38,7 @@ files:
36
38
  - lib/driving_physics/gearbox.rb
37
39
  - lib/driving_physics/imperial.rb
38
40
  - lib/driving_physics/motor.rb
41
+ - lib/driving_physics/mruby.rb
39
42
  - lib/driving_physics/power.rb
40
43
  - lib/driving_physics/powertrain.rb
41
44
  - lib/driving_physics/scalar_force.rb