driving_physics 0.0.2.1 → 0.0.3.1

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/test/vector_force.rb CHANGED
@@ -1,52 +1,91 @@
1
1
  require 'minitest/autorun'
2
2
  require 'driving_physics/vector_force'
3
3
 
4
- include DrivingPhysics
4
+ describe DrivingPhysics do
5
+ describe "random_centered_zero" do
6
+ it "generates uniformly random numbers centered on zero" do
7
+ hsh = {}
8
+ 110_000.times {
9
+ num = DrivingPhysics.random_centered_zero(5)
10
+ hsh[num] ||= 0
11
+ hsh[num] += 1
12
+ }
13
+ # note, this will fail occasionally due to chance
14
+ hsh.values.each { |count|
15
+ expect(count).must_be(:>=, 9000)
16
+ expect(count).must_be(:<=, 11000)
17
+ }
18
+ end
5
19
 
6
- describe VectorForce do
7
- before do
8
- @drive_force = Vector[7000.0, 0.0]
9
- @v = Vector[3.0, 0]
10
- @mass = 1000
11
- @weight = @mass * G
20
+ it "coerces magnitude=0 to magnitude=1" do
21
+ a = Array.new(999) { DrivingPhysics.random_centered_zero(0) }
22
+ expect(a.all? { |i| i == 0 }).must_equal false
23
+ end
12
24
  end
13
25
 
14
- it "generates uniformly random numbers centered on zero" do
15
- hsh = {}
16
- 110_000.times {
17
- num = DrivingPhysics.random_centered_zero(5)
18
- hsh[num] ||= 0
19
- hsh[num] += 1
20
- }
21
- # note, this will fail occasionally due to chance
22
- hsh.values.each { |count|
23
- expect(count).must_be(:>=, 9000)
24
- expect(count).must_be(:<=, 11000)
25
- }
26
+ describe "random_unit_vector" do
27
+ it "generates a random unit vector" do
28
+ low_res = DrivingPhysics.random_unit_vector(2, resolution: 1)
29
+ if low_res[0] == 0.0
30
+ expect(low_res[1].abs).must_equal 1.0
31
+ elsif low_res[0].abs == 1.0
32
+ expect(low_res[1]).must_equal 0.0
33
+ elsif low_res[0].abs.round(3) == 0.707
34
+ expect(low_res[1].abs.round(3)) == 0.707
35
+ else
36
+ p low_res
37
+ raise "unexpected"
38
+ end
39
+
40
+ 9.times {
41
+ high_res = DrivingPhysics.random_unit_vector(3, resolution: 9)
42
+ expect(high_res.magnitude).must_be_within_epsilon 1.0
43
+ }
44
+ end
26
45
  end
27
46
 
28
- it "coerces magnitude=0 to magnitude=1" do
29
- a = Array.new(999) { DrivingPhysics.random_centered_zero(0) }
30
- expect(a.all? { |i| i == 0 }).must_equal false
47
+ describe "torque_vector" do
48
+ it "calculates a torque in the 3rd dimension given 2D force and radius" do
49
+ force = Vector[1000, 0]
50
+ radius = Vector[0, 5]
51
+ torque = DrivingPhysics.torque_vector(force, radius)
52
+ expect(torque).must_be_instance_of Vector
53
+ expect(torque.size).must_equal 3
54
+ expect(torque[2]).must_be_within_epsilon 5000.0
55
+ end
31
56
  end
32
57
 
33
- it "generates a random unit vector" do
34
- low_res = DrivingPhysics.random_unit_vector(2, resolution: 1)
35
- if low_res[0] == 0.0
36
- expect(low_res[1].abs).must_equal 1.0
37
- elsif low_res[0].abs == 1.0
38
- expect(low_res[1]).must_equal 0.0
39
- elsif low_res[0].abs.round(3) == 0.707
40
- expect(low_res[1].abs.round(3)) == 0.707
41
- else
42
- p low_res
43
- raise "unexpected"
58
+ describe "force_vector" do
59
+ it "calculates a (3D) force given 3D torque and 2D radius" do
60
+ # let's invert the DrivingPhysics.torque_vector case from above:
61
+ torque = Vector[0, 0, 5000]
62
+ radius = Vector[0, 5]
63
+ force = DrivingPhysics.force_vector(torque, radius)
64
+ expect(force).must_be_instance_of Vector
65
+ expect(force.size).must_equal 3
66
+ expect(force[0]).must_be_within_epsilon 1000.0
67
+
68
+ # now let's rotate the radius into the x-dimension
69
+ # right hand rule, positive torque means thumb into screen, clockwise
70
+ # negative-x radius means positive-y force
71
+ torque = Vector[0, 0, 500]
72
+ radius = Vector[-5, 0]
73
+ force = DrivingPhysics.force_vector(torque, radius)
74
+ expect(force).must_be_instance_of Vector
75
+ expect(force.size).must_equal 3
76
+ expect(force[1]).must_be_within_epsilon 100.0
44
77
  end
78
+ end
79
+ end
45
80
 
46
- 9.times {
47
- high_res = DrivingPhysics.random_unit_vector(3, resolution: 9)
48
- expect(high_res.magnitude).must_be_within_epsilon 1.0
49
- }
81
+ include DrivingPhysics
82
+
83
+ describe VectorForce do
84
+ before do
85
+ @drive_force = Vector[7000.0, 0.0]
86
+ @v = Vector[3.0, 0]
87
+ @mass = 1000
88
+ @weight = @mass * G
50
89
  end
51
90
 
52
91
  it "calculates air resistance as the square of velocity" do
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.2.1
4
+ version: 0.0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Hull
@@ -9,7 +9,21 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 1980-01-01 00:00:00.000000000 Z
12
- dependencies: []
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: device_control
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
13
27
  description: WIP
14
28
  email:
15
29
  executables: []
@@ -23,8 +37,9 @@ files:
23
37
  - demo/disk.rb
24
38
  - demo/gearbox.rb
25
39
  - demo/motor.rb
26
- - demo/mruby/disk.rb
40
+ - demo/mruby/car.rb
27
41
  - demo/mruby/motor.rb
42
+ - demo/pid_controller.rb
28
43
  - demo/powertrain.rb
29
44
  - demo/scalar_force.rb
30
45
  - demo/tire.rb
@@ -33,19 +48,25 @@ files:
33
48
  - lib/driving_physics.rb
34
49
  - lib/driving_physics/car.rb
35
50
  - lib/driving_physics/cli.rb
51
+ - lib/driving_physics/cockpit.rb
36
52
  - lib/driving_physics/disk.rb
37
53
  - lib/driving_physics/environment.rb
38
54
  - lib/driving_physics/gearbox.rb
39
55
  - lib/driving_physics/imperial.rb
40
56
  - lib/driving_physics/motor.rb
41
57
  - lib/driving_physics/mruby.rb
58
+ - lib/driving_physics/pid_controller.rb
42
59
  - lib/driving_physics/power.rb
43
60
  - lib/driving_physics/powertrain.rb
44
61
  - lib/driving_physics/scalar_force.rb
62
+ - lib/driving_physics/timer.rb
45
63
  - lib/driving_physics/tire.rb
46
64
  - lib/driving_physics/vector_force.rb
47
65
  - test/disk.rb
48
66
  - test/driving_physics.rb
67
+ - test/gearbox.rb
68
+ - test/motor.rb
69
+ - test/powertrain.rb
49
70
  - test/scalar_force.rb
50
71
  - test/tire.rb
51
72
  - test/vector_force.rb
@@ -68,8 +89,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
89
  - !ruby/object:Gem::Version
69
90
  version: '0'
70
91
  requirements: []
71
- rubygems_version: 3.2.26
92
+ rubygems_version: 3.4.4
72
93
  signing_key:
73
94
  specification_version: 4
74
- summary: WIP
95
+ summary: 'Physics from first principles: mass, friction, rotation, etc'
75
96
  test_files: []
data/demo/mruby/disk.rb DELETED
@@ -1,81 +0,0 @@
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)