lignite 0.3.0 → 0.4.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bf1b7c4214285394b080eee7ac292b74a02583ec
4
- data.tar.gz: 2e8eceb5bb0058722da49642ac252c9054f3582b
3
+ metadata.gz: ce4cca8022a372bfd1ee229725d3a538376c6d54
4
+ data.tar.gz: 7957e5d6aa35cf8551752d3a324f2cef141bd466
5
5
  SHA512:
6
- metadata.gz: 7dba38b35d34ffbafce9c5788c792f12d598623d4862dbfa0f3a3ed99c1c31c490495619cef96970047e9622832d0c92ae97cbfc9282a5e3c52a0f2e06992114
7
- data.tar.gz: dddf6c17fd11bd751b111d6c03e70c6114a5333a3acd61ee7fe4dd8958195ab7c3b5c44260144b5e2bea2d3945a8b2621b36d278fc55a5b08d969766a81e417a
6
+ metadata.gz: fdf692daad988853107d65e5ebf31da38e0c6bd5d4bf6819e9b0e8e8ca5a140fe95bdf51d32db8c556f1e07298f3671aa389e8c994ff2293f087ae1c237cf1a7
7
+ data.tar.gz: c5a98aedfde6259e69cdadbed737ee7fa1eed93d505a42489ee99a2a64ff8dcadabbdd8c1f4d7bca0a7cb004fc18caaa4cc33f61275153789a63386404896d18
@@ -2,11 +2,39 @@ inherit_from: rubocop-suse.yml
2
2
 
3
3
  AllCops:
4
4
  TargetRubyVersion: 2.1
5
+ Exclude:
6
+ - 'vendor/**/*'
7
+ - '.git/**/*'
8
+ - lib/lignite/ev3_ops.rb
5
9
 
6
10
  Naming/FileName:
7
11
  Exclude:
8
12
  - spec/data/*.rb
9
13
 
10
14
  Layout/IndentHeredoc:
15
+ Enabled: false
16
+
17
+ Performance/RedundantBlockCall:
18
+ Enabled: false
19
+
20
+ Style/SymbolArray:
21
+ Enabled: false
22
+
23
+ Metrics/BlockLength:
11
24
  Exclude:
12
25
  - lignite.gemspec
26
+ - lib/lignite/ev3_tool.rb
27
+ - spec/**/*.rb
28
+
29
+ Metrics/ClassLength:
30
+ Exclude:
31
+ - lib/lignite/ev3_tool.rb
32
+ - lib/lignite/motors.rb
33
+
34
+ Metrics/MethodLength:
35
+ Max: 25
36
+
37
+ Metrics/ModuleLength:
38
+ Exclude:
39
+ # generated
40
+ - lib/lignite/enums.rb
data/NEWS.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## unreleased
4
4
 
5
+ ## 0.4.0, 2018-03-04
6
+
7
+ - Generate Ev3Ops ahead of time, enabling YARD docs for them,
8
+ reducing startup time
9
+ - Fixed `ev3tool ls`, `ls-l`, `start`, all broken in 0.3.0
10
+
5
11
  ## 0.3.0, 2018-03-02
6
12
 
7
13
  - Added Tap and Replay to simulate a real robot with YAML files for tests
data/Rakefile CHANGED
@@ -1,6 +1,27 @@
1
- task default: :test
1
+ task default: [:test, :rubocop, :yard]
2
2
 
3
3
  desc "Run tests"
4
4
  task :test do
5
5
  system "rspec"
6
6
  end
7
+
8
+ desc "Run RuboCop"
9
+ task :rubocop do
10
+ system "rubocop --display-cop-names"
11
+ end
12
+
13
+ desc "Generate YARD documentation"
14
+ task :yard do
15
+ system "yardoc --use-cache"
16
+ end
17
+
18
+ EV3_YML = "data/ev3.yml".freeze
19
+ GENERATOR = "tools/ops_from_yml".freeze
20
+ OPS = "lib/lignite/ev3_ops.rb".freeze
21
+
22
+ desc "Regenerate the EV3 assembler operations"
23
+ task ops: OPS
24
+
25
+ file OPS => [EV3_YML, GENERATOR] do |t|
26
+ sh GENERATOR, t.prerequisites.first, t.name
27
+ end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -1,151 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- require "lignite"
3
- require "thor"
4
- require "fileutils"
5
- include Lignite::Bytes
2
+ require "lignite/ev3_tool"
6
3
 
7
- # The VM current working directory is /home/root/lms2012/sys
8
- # which is not very useful. A better default is /home/root/lms2012/prjs
9
- # which is displayed on the 2nd tab of the brick UI.
10
- EV3TOOL_HOME = "../prjs".freeze
11
-
12
- def phandles
13
- handles = sc.list_open_handles
14
- puts "OPEN HANDLES: ", hexdump(handles)
15
- end
16
-
17
- class Ev3Tool < Thor
18
- desc "upload LOCAL_FILENAME [BRICK_FILENAME]", "upload a program or a file"
19
- map "ul" => "upload"
20
- def upload(local_filename, brick_filename = nil)
21
- data = File.read(local_filename, encoding: Encoding::BINARY)
22
- unless brick_filename
23
- prj = File.basename(local_filename, ".rbf")
24
- brick_filename = "#{EV3TOOL_HOME}/#{prj}/#{prj}.rbf"
25
- end
26
- handle = sc.begin_download(data.bytesize, brick_filename)
27
- sc.continue_download(handle, data)
28
- end
29
-
30
- desc "download BRICK_FILENAME [LOCAL_FILENAME]", "download a file"
31
- map "dl" => "download"
32
- def download(brick_filename, local_filename = nil)
33
- local_filename ||= File.basename(brick_filename)
34
- fsize, handle, data = sc.begin_upload(4096, brick_filename)
35
- File.open(local_filename, "w") do |f|
36
- loop do
37
- f.write(data)
38
- fsize -= data.bytesize
39
- break if fsize.zero?
40
- handle, data = sc.continue_upload(handle, 4096)
41
- end
42
- end
43
- end
44
-
45
- desc "list-files DIRNAME", "list DIRNAME in a long format"
46
- map "ls-l" => "list-files"
47
- def list_files(name)
48
- name ||= EV3TOOL_HOME
49
- name = "#{EV3TOOL_HOME}/#{name}" unless name.start_with?("/")
50
-
51
- result = ""
52
- fsize, handle, data = sc.list_files(4096, name)
53
- loop do
54
- result += data
55
- fsize -= data.bytesize
56
- break if fsize.zero?
57
- handle, data = sc.continue_list_files(handle, 4096)
58
- end
59
- result
60
- rescue Lignite::VMError
61
- nil
62
- end
63
-
64
- desc "ls DIRNAME", "list DIRNAME in a short format"
65
- def ls(name)
66
- raw = list_files(name)
67
- return nil if raw.nil?
68
-
69
- raw.lines.map do |l|
70
- l = l.chomp
71
- next nil if ["./", "../"].include?(l)
72
- next l if l.end_with?("/")
73
- # skip checksum + space + size + space
74
- l[32 + 1 + 8 + 1..-1]
75
- end.compact
76
- end
77
-
78
- desc "start NAME", "start a program"
79
- def start(name)
80
- if name.include?("/")
81
- name = "#{EV3TOOL_HOME}/#{name}" unless name.start_with?("/")
82
- else
83
- name = "#{EV3TOOL_HOME}/#{name}/#{name}.rbf"
84
- end
85
-
86
- unless file_exist?(name)
87
- $stderr.puts "File #{name.inspect} not found"
88
- exit 1
89
- end
90
-
91
- slot = Lignite::USER_SLOT
92
- no_debug = 0
93
- dc.block do
94
- # these are local variables
95
- data32 :size
96
- data32 :ip
97
- file_load_image(slot, name, :size, :ip)
98
- program_start(slot, :size, :ip, no_debug)
99
- end
100
- end
101
-
102
- desc "stop", "stop a running program"
103
- def stop
104
- dc.program_stop(Lignite::USER_SLOT)
105
- end
106
-
107
- no_commands do
108
- def file_exist?(name)
109
- dirname = File.dirname(name)
110
- filename = File.basename(name)
111
- files = ls(dirname) || []
112
- files.include?(filename)
113
- end
114
-
115
- def assisted_connection
116
- Lignite::Connection.create
117
- rescue => e
118
- fn = Lignite::Connection::Bluetooth.config_filename
119
- $stderr.puts <<MSG
120
- Could not connect to EV3.
121
- Use a USB cable or configure a Bluetooth address in #{fn.inspect}.
122
- Details:
123
- #{e.message}
124
- MSG
125
-
126
- template = Lignite::Connection::Bluetooth.template_config_filename
127
- if !File.exist?(fn) && File.exist?(template)
128
- FileUtils.mkdir_p(File.dirname(fn))
129
- FileUtils.install(template, fn)
130
- $stderr.puts "(A template config file has been copied for your convenience)"
131
- end
132
- exit 1
133
- end
134
-
135
- def sc
136
- return @sc if @sc
137
- @sc = Lignite::SystemCommands.new(conn)
138
- end
139
-
140
- def dc
141
- return @dc if @dc
142
- @dc = Lignite::DirectCommands.new(conn)
143
- end
144
-
145
- def conn
146
- @conn ||= assisted_connection
147
- end
148
- end
149
- end
150
-
151
- Ev3Tool.start(ARGV)
4
+ Lignite::Ev3Tool.start(ARGV)
@@ -1,15 +1,17 @@
1
1
  #!/usr/bin/ruby
2
-
3
- # https://www.lego.com/mindstorms/build-a-robot/bobb3e
4
- # A Bobcat® like two-tracked forklift
5
-
6
2
  require "lignite"
7
3
 
4
+ # A Bobcat like two-tracked forklift.
5
+ # https://www.lego.com/mindstorms/build-a-robot/bobb3e
8
6
  class Bobbee
7
+ # The pair of motors driving the tracks
9
8
  # @return [Lignite::Motors]
10
9
  attr_reader :drive
10
+ # The motor lifting the fork
11
11
  # @return [Lignite::Motors]
12
12
  attr_reader :lift
13
+ # Interface to all other commands
14
+ # @return [Lignite::DirectCommands]
13
15
  attr_reader :dc
14
16
 
15
17
  def initialize(drive: Lignite::PORT_B | Lignite::PORT_C,
@@ -21,33 +23,34 @@ class Bobbee
21
23
  @dc = dc
22
24
  end
23
25
 
26
+ # @param speed [Integer] -100..100
24
27
  # @param turn [Integer] -200..200
25
- def time_sync(speed, turn, ms, brake = Lignite::BRAKE, wait: true)
26
- # 1500 ms is about 1 boost square at speed 100
27
- drive.time_sync(-speed, turn, ms, brake)
28
- end
29
-
30
- # @param turn [Integer] -200..200
28
+ # turn 0 (straight)
29
+ # - 900 (2.5 * 360) degrees is about 1 boost square
30
+ # turn 200 (full right)
31
+ # - 2400 degrees is a full turn, 600 deg is an about-right turn
32
+ # where the center of rotation is the battery-cover of the brick,
33
+ # or between the rear axles.
34
+ # turn 100 (semi right)
35
+ # - 4800 degrees is a full turn, about one of the rear axles
36
+ # @param degrees [Integer] degrees to turn the motors
37
+ # (complicated by gears and *turn*, which see)
38
+ # @param brake [BRAKE,COAST]
39
+ # @param wait [Boolean] work around my ignorance of motor readiness
31
40
  def step_sync(speed, turn, degrees, brake = Lignite::BRAKE, wait: true)
32
- # turn 0 (straight)
33
- # - 900 (2.5 * 360) degrees is about 1 boost square
34
- # turn 200 (full right)
35
- # - 2400 degrees is a full turn, 600 deg is an about-right turn
36
- # where the center of rotation is the battery-cover of the brick,
37
- # or between the rear axles.
38
- # turn 100 (semi right)
39
- # - 4800 degrees is a full turn, about one of the rear axles
40
41
  drive.step_sync(-speed, turn, degrees, brake)
41
42
  drive.ready if wait
42
43
  end
43
44
 
44
45
  LIFT_FULL = 220
45
46
 
47
+ # Raise the fork from the ground up
46
48
  def raise(wait: true)
47
49
  lift.step_power(30, 10, LIFT_FULL - 20, 10)
48
50
  lift.ready if wait
49
51
  end
50
52
 
53
+ # Raise the fork one third of the way from the ground up
51
54
  def third_raise(wait: true)
52
55
  lift.step_power(30, 10, LIFT_FULL / 3 - 20, 10)
53
56
  lift.ready if wait
@@ -56,6 +59,7 @@ class Bobbee
56
59
  sleep 3
57
60
  end
58
61
 
62
+ # Lower the fork from above to the ground
59
63
  def lower(wait: true)
60
64
  lift.step_power(-1, 10, LIFT_FULL - 20, 10) # , Lignite::COAST)
61
65
  lift.ready if wait
@@ -64,107 +68,125 @@ class Bobbee
64
68
  sleep 3
65
69
  end
66
70
 
71
+ # Lower the fork one third of the way from above to the ground
67
72
  def third_lower(wait: true)
68
73
  lift.step_power(-1, 10, LIFT_FULL / 3 - 20, 10)
69
74
  lift.ready if wait
70
75
  end
71
76
 
77
+ # Beep
72
78
  def beep(ms = 300)
73
79
  dc.sound_tone(20, 1760, ms)
74
80
  dc.sound_ready
75
81
  end
76
82
 
83
+ # steps to move 1 square on the Boost mat
77
84
  SQUARE_STEPS = 920
78
- def f(steps = SQUARE_STEPS)
85
+
86
+ # Drive forward 1 square on the Boost mat
87
+ def forward(steps = SQUARE_STEPS)
79
88
  step_sync(50, 0, steps)
80
89
  beep
81
90
  sleep 3
82
91
  end
83
92
 
84
- def b(steps = SQUARE_STEPS)
93
+ # Drive backward 1 square on the Boost mat
94
+ def back(steps = SQUARE_STEPS)
85
95
  step_sync(-50, 0, back_factor(steps))
86
96
  beep
87
97
  sleep 3
88
98
  end
89
99
 
90
- # it moves faster when going backwards!?
100
+ # Compensation factor when moving backward
91
101
  def back_factor(n)
102
+ # why? maybe the center of mass affects it
92
103
  (n * 0.95).to_i
93
104
  end
94
105
 
106
+ # If we want to turn inside a Boost mat square,
107
+ # we cannot simply make a turn since the center of rotation of the robot
108
+ # is between the rear axles which is not in the center of the square.
109
+ # So we need to move forward a bit, turn, and move back the same amount.
95
110
  ROTATION_OFFSET = 350
96
- def f1
97
- f(ROTATION_OFFSET)
111
+
112
+ def align_centers_for_turning(&turn_block)
113
+ forward(ROTATION_OFFSET)
114
+ beep(100)
115
+
116
+ turn_block.call
117
+
118
+ back(ROTATION_OFFSET)
98
119
  beep(100)
99
120
  end
100
121
 
122
+ # Motor degrees needed to turn the robot 90 degrees when using turn=200
101
123
  TURN_90_AT_200_STEPS = 600
102
- def l2
124
+
125
+ # Turn 90 degrees left, simply by moving tracks in opposite directions
126
+ def left_immediate
103
127
  step_sync(50, -200, TURN_90_AT_200_STEPS)
104
128
  beep(100)
105
129
  sleep 3
106
130
  end
107
131
 
108
- def r2
132
+ # Turn 90 degrees right, simply by moving tracks in opposite directions
133
+ def right_immediate
109
134
  step_sync(50, 200, TURN_90_AT_200_STEPS)
110
135
  beep(100)
111
136
  sleep 3
112
137
  end
113
138
 
114
- def f3
115
- b(ROTATION_OFFSET)
116
- beep(100)
117
- end
118
-
119
- def l
120
- # a 3 part maneuver: forward, left, and back-a-little
121
- # to turn 1 BS left
122
- f1
123
- l2
124
- f3
139
+ # Turn 90 degrees left, starting and ending inside a Boost mat square
140
+ def left
141
+ align_centers_for_turning do
142
+ left_immediate
143
+ end
125
144
  end
126
145
 
127
- def r
128
- # a 3 part maneuver: forward, right, and back-a-little
129
- # to turn 1 BS right
130
- f1
131
- r2
132
- f3
146
+ # Turn 90 degrees right, starting and ending inside a Boost mat square
147
+ def right
148
+ align_centers_for_turning do
149
+ right_immediate
150
+ end
133
151
  end
134
152
  end
135
153
 
136
154
  bb = Bobbee.new
137
- # 1 BS
138
- # bb.time_sync(100, 0, 1500)
139
155
 
140
- # Put Bobb3e on the blue arrow. Move it one square left, and forward.
141
- # Put the container on a raised platform on the "twins" square.
142
- # Put a raised platform on the "fire" square
156
+ # Put Bobb3e (B) on the blue arrow (^). Move it one square left, and forward.
157
+ # Put the container on a raised platform on the "twins" square (T).
158
+ # Put a raised platform on the "fire" square (F).
159
+ #
160
+ # ..F
161
+ # ...
162
+ # B.T
163
+ # .^.
143
164
  def from_twins_to_fire(bb)
144
165
  bb.instance_exec do
145
166
  beep
146
167
 
168
+ 2.times { third_raise }
169
+
170
+ right
171
+ forward
147
172
  third_raise
148
- third_raise
149
- r
150
- f
151
- third_raise
152
- b
153
- l
173
+ back
174
+ left
154
175
  # we're at the starting position, but carrying the load
155
176
 
156
177
  # move towards the recipient
157
- f; f; r
178
+ 2.times { forward }
179
+ right
158
180
 
159
181
  # deliver and unload
160
- f
182
+ forward
161
183
  third_lower
162
- b
184
+ back
163
185
 
164
186
  # resting position
165
- l; b; b
166
- third_lower
167
- third_lower
187
+ left
188
+ 2.times { back }
189
+ 2.times { third_lower }
168
190
  end
169
191
  end
170
192
 
@@ -172,37 +194,37 @@ def from_fire_to_twins(bb)
172
194
  bb.instance_exec do
173
195
  beep
174
196
 
175
- third_raise
176
- third_raise
197
+ 2.times { third_raise }
177
198
 
178
199
  # move towards the load
179
- f; f; r
200
+ 2.times { forward }
201
+ right
180
202
 
181
203
  # load
182
- f
204
+ forward
183
205
  third_raise
184
- b
206
+ back
185
207
 
186
208
  # starting position
187
- l; b; b
209
+ left
210
+ 2.times { back }
188
211
 
189
212
  # deliver
190
- r
191
- f
213
+ right
214
+ forward
192
215
  third_lower
193
- b
194
- l
216
+ back
217
+ left
195
218
 
196
219
  # resting position
197
- third_lower
198
- third_lower
220
+ 2.times { third_lower }
199
221
  end
200
222
  end
201
223
 
202
224
  def calibrate_forward_and_back(bb)
203
225
  bb.instance_exec do
204
- f; f; f; f
205
- b; b; b; b
226
+ 4.times { forward }
227
+ 4.times { back }
206
228
  end
207
229
  end
208
230