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.
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)