rapiro_wrapper 0.1.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +138 -0
  9. data/Rakefile +5 -0
  10. data/bin/rapiro_wrapper +147 -0
  11. data/lib/rapiro_wrapper.rb +23 -0
  12. data/lib/rapiro_wrapper/body.rb +43 -0
  13. data/lib/rapiro_wrapper/command.rb +19 -0
  14. data/lib/rapiro_wrapper/commander.rb +28 -0
  15. data/lib/rapiro_wrapper/led.rb +4 -0
  16. data/lib/rapiro_wrapper/led/eyes.rb +23 -0
  17. data/lib/rapiro_wrapper/servo_motor.rb +27 -0
  18. data/lib/rapiro_wrapper/servo_motor/head.rb +21 -0
  19. data/lib/rapiro_wrapper/servo_motor/left_foot_pitch.rb +21 -0
  20. data/lib/rapiro_wrapper/servo_motor/left_foot_yaw.rb +21 -0
  21. data/lib/rapiro_wrapper/servo_motor/left_hand_grip.rb +21 -0
  22. data/lib/rapiro_wrapper/servo_motor/left_sholder_pitch.rb +18 -0
  23. data/lib/rapiro_wrapper/servo_motor/left_sholder_roll.rb +18 -0
  24. data/lib/rapiro_wrapper/servo_motor/right_foot_pitch.rb +21 -0
  25. data/lib/rapiro_wrapper/servo_motor/right_foot_yaw.rb +21 -0
  26. data/lib/rapiro_wrapper/servo_motor/right_hand_grip.rb +21 -0
  27. data/lib/rapiro_wrapper/servo_motor/right_sholder_pitch.rb +18 -0
  28. data/lib/rapiro_wrapper/servo_motor/right_sholder_roll.rb +14 -0
  29. data/lib/rapiro_wrapper/servo_motor/waist.rb +21 -0
  30. data/lib/rapiro_wrapper/version.rb +4 -0
  31. data/rapiro_wrapper.gemspec +27 -0
  32. data/spec/integration/base_spec.rb +577 -0
  33. data/spec/rapiro_wrapper/body_spec.rb +77 -0
  34. data/spec/rapiro_wrapper/command_spec.rb +54 -0
  35. data/spec/rapiro_wrapper/commander_spec.rb +111 -0
  36. data/spec/rapiro_wrapper/led/eyes_spec.rb +38 -0
  37. data/spec/rapiro_wrapper/servo_moter/head_spec.rb +248 -0
  38. data/spec/rapiro_wrapper/servo_moter/left_foot_pitch_spec.rb +261 -0
  39. data/spec/rapiro_wrapper/servo_moter/left_foot_yaw_spec.rb +256 -0
  40. data/spec/rapiro_wrapper/servo_moter/left_hand_grip_spec.rb +256 -0
  41. data/spec/rapiro_wrapper/servo_moter/left_sholder_pitch_spec.rb +134 -0
  42. data/spec/rapiro_wrapper/servo_moter/left_sholder_roll_spec.rb +150 -0
  43. data/spec/rapiro_wrapper/servo_moter/right_foot_pitch_spec.rb +261 -0
  44. data/spec/rapiro_wrapper/servo_moter/right_foot_yaw_spec.rb +256 -0
  45. data/spec/rapiro_wrapper/servo_moter/right_hand_grip_spec.rb +256 -0
  46. data/spec/rapiro_wrapper/servo_moter/right_sholder_pitch_spec.rb +134 -0
  47. data/spec/rapiro_wrapper/servo_moter/right_sholder_roll_spec.rb +150 -0
  48. data/spec/rapiro_wrapper/servo_moter/waist_spec.rb +248 -0
  49. data/spec/rapiro_wrapper/servo_moter_spec.rb +64 -0
  50. data/spec/rapiro_wrapper/version_spec.rb +11 -0
  51. data/spec/spec_helper.rb +4 -0
  52. metadata +199 -0
@@ -0,0 +1,28 @@
1
+ require 'serialport'
2
+
3
+ module RapiroWrapper
4
+ # Commander class for RAPIRO
5
+ class Commander
6
+ def initialize(device = '/dev/ttyAMA0')
7
+ @serial = SerialPort.new(device, 57_600)
8
+ end
9
+
10
+ def execute!(commands, duration = 10)
11
+ write(sequences(commands, duration))
12
+ rescue
13
+ write('#M0')
14
+ end
15
+
16
+ def sequences(commands, duration = 10)
17
+ RapiroWrapper::Command.new(commands).to_sequence(duration)
18
+ end
19
+
20
+ def self.dryrun(commands, duration = 10)
21
+ RapiroWrapper::Command.new(commands).to_sequence(duration)
22
+ end
23
+
24
+ def write(sequences)
25
+ @serial.write(sequences)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,4 @@
1
+ module RapiroWrapper
2
+ class Led
3
+ end
4
+ end
@@ -0,0 +1,23 @@
1
+ module RapiroWrapper
2
+ # Eyes class for RAPIRO
3
+ class Eyes < Led
4
+ def initialize(param = nil)
5
+ if param.nil?
6
+ @value = '#000080'
7
+ elsif param =~ /^#([0-9a-fA-F]{2}){3}$/
8
+ @value = param
9
+ elsif param.instance_of?(Hash) && param.key?(:red) && param.key?(:green) && param.key?(:blue)
10
+ @value = format('#%02x%02x%02x', *param.values_at(:red, :green, :blue))
11
+ else
12
+ fail ArgumentError
13
+ end
14
+ end
15
+
16
+ def to_code
17
+ vary = @value.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/)
18
+ .to_a
19
+ vary.shift
20
+ format('R%03dG%03dB%03d', *vary.map { |v| Integer("0x#{v}") })
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module RapiroWrapper
2
+ # SurvoMotor class for RAPIRO
3
+ class ServoMotor
4
+ def initialize
5
+ fail NotImplementedError
6
+ end
7
+
8
+ def to_code
9
+ format('S%02dA%03d', self.class.const_get(:NO), @value)
10
+ end
11
+
12
+ def self.code(options = {})
13
+ new(options).to_code
14
+ end
15
+
16
+ def self.find_servos
17
+ subclasses = []
18
+ ObjectSpace.each_object(singleton_class) do |k|
19
+ subclasses << k if k.superclass == self
20
+ end
21
+ subclasses.sort! do |a, b|
22
+ a.const_get(:NO) <=> b.const_get(:NO)
23
+ end
24
+ subclasses
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # Head class for RAPIRO
3
+ class Head < ServoMotor
4
+ NO = 0
5
+ DEFAULT = 90
6
+ MIN = 0
7
+ MAX = 180
8
+
9
+ def initialize(left: nil, right: nil)
10
+ fail ArgumentError if left && right
11
+ if left
12
+ @value = DEFAULT + left
13
+ elsif right
14
+ @value = DEFAULT - right
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # LeftFootPitch class for RAPIRO
3
+ class LeftFootPitch < ServoMotor
4
+ NO = 11
5
+ DEFAULT = 90
6
+ MIN = 70
7
+ MAX = 110
8
+
9
+ def initialize(close: nil, open: nil)
10
+ fail ArgumentError if open && close
11
+ if close
12
+ @value = MAX - close
13
+ elsif open
14
+ @value = MIN + open
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # LeftFootYaw class for RAPIRO
3
+ class LeftFootYaw < ServoMotor
4
+ NO = 10
5
+ DEFAULT = 90
6
+ MIN = 50
7
+ MAX = 110
8
+
9
+ def initialize(close: nil, open: nil)
10
+ fail ArgumentError if open && close
11
+ if close
12
+ @value = MAX - close
13
+ elsif open
14
+ @value = MIN + open
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # LeftHandGrip for RAPIRO
3
+ class LeftHandGrip < ServoMotor
4
+ NO = 7
5
+ DEFAULT = 90
6
+ MIN = 60
7
+ MAX = 110
8
+
9
+ def initialize(hold: nil, open: nil)
10
+ fail ArgumentError if open && hold
11
+ if hold
12
+ @value = MAX - hold
13
+ elsif open
14
+ @value = MIN + open
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module RapiroWrapper
2
+ # LeftSholderPitch class for RAPIRO
3
+ class LeftSholderPitch < ServoMotor
4
+ NO = 6
5
+ DEFAULT = 50
6
+ MIN = 50
7
+ MAX = 140
8
+
9
+ def initialize(up: nil)
10
+ if up
11
+ @value = MIN + up
12
+ else
13
+ @value = DEFAULT
14
+ end
15
+ fail ArgumentError unless @value.between?(MIN, MAX)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module RapiroWrapper
2
+ # LeftSholderRoll for RAPIRO
3
+ class LeftSholderRoll < ServoMotor
4
+ NO = 5
5
+ DEFAULT = 180
6
+ MIN = 0
7
+ MAX = 180
8
+
9
+ def initialize(up: nil)
10
+ if up
11
+ @value = MAX - up
12
+ else
13
+ @value = DEFAULT
14
+ end
15
+ fail ArgumentError unless @value.between?(MIN, MAX)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # RightFootPitch class for RAPIRO
3
+ class RightFootPitch < ServoMotor
4
+ NO = 9
5
+ DEFAULT = 90
6
+ MIN = 70
7
+ MAX = 110
8
+
9
+ def initialize(close: nil, open: nil)
10
+ fail ArgumentError if open && close
11
+ if close
12
+ @value = MIN + close
13
+ elsif open
14
+ @value = MAX - open
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # RightFootYaw class for RAPIRO
3
+ class RightFootYaw < ServoMotor
4
+ NO = 8
5
+ DEFAULT = 90
6
+ MIN = 70
7
+ MAX = 130
8
+
9
+ def initialize(close: nil, open: nil)
10
+ fail ArgumentError if open && close
11
+ if close
12
+ @value = MIN + close
13
+ elsif open
14
+ @value = MAX - open
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # RightHandGrip class for RAPIRO
3
+ class RightHandGrip < ServoMotor
4
+ NO = 4
5
+ DEFAULT = 90
6
+ MIN = 60
7
+ MAX = 110
8
+
9
+ def initialize(hold: nil, open: nil)
10
+ fail ArgumentError if open && hold
11
+ if hold
12
+ @value = MIN + hold
13
+ elsif open
14
+ @value = MAX - open
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module RapiroWrapper
2
+ # RightSholderPitch class for RAPIRO
3
+ class RightSholderPitch < ServoMotor
4
+ NO = 3
5
+ DEFAULT = 130
6
+ MIN = 40
7
+ MAX = 130
8
+
9
+ def initialize(up: nil)
10
+ if up
11
+ @value = MAX - up
12
+ else
13
+ @value = DEFAULT
14
+ end
15
+ fail ArgumentError unless @value.between?(MIN, MAX)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module RapiroWrapper
2
+ # RightSholderRoll class for RAPIRO
3
+ class RightSholderRoll < ServoMotor
4
+ NO = 2
5
+ DEFAULT = 0
6
+ MIN = 0
7
+ MAX = 180
8
+
9
+ def initialize(up: DEFAULT)
10
+ @value = up
11
+ fail ArgumentError unless @value.between?(MIN, MAX)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ module RapiroWrapper
2
+ # Waist class for RAPIRO
3
+ class Waist < ServoMotor
4
+ NO = 1
5
+ DEFAULT = 90
6
+ MIN = 0
7
+ MAX = 180
8
+
9
+ def initialize(left: nil, right: nil)
10
+ fail ArgumentError if left && right
11
+ if left
12
+ @value = DEFAULT + left
13
+ elsif right
14
+ @value = DEFAULT - right
15
+ else
16
+ @value = DEFAULT
17
+ end
18
+ fail ArgumentError unless @value.between?(MIN, MAX)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ # Wrapper module for Rapiro
2
+ module RapiroWrapper
3
+ VERSION = '0.1.0'
4
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rapiro_wrapper/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rapiro_wrapper'
8
+ spec.version = RapiroWrapper::VERSION
9
+ spec.authors = ['Takahiro HAMAGUCHI']
10
+ spec.email = ['tk.hamaguchi@gmail.com']
11
+ spec.summary = 'A gem providing access to Rapiro with SerialPort'
12
+ spec.description = 'A gem providing access to Rapiro with SerialPort.'
13
+ spec.homepage = 'https://github.com/tk-hamaguchi/rapiro_wrapper.git'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_runtime_dependency 'serialport', '~> 1.3'
24
+ spec.add_development_dependency 'rspec', '~> 3.1'
25
+ spec.add_development_dependency 'simplecov', '~> 0.9'
26
+ spec.add_development_dependency 'rubocop', '~> 0.29.0'
27
+ end
@@ -0,0 +1,577 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'RAPIRO' do
4
+ let(:serial) { double }
5
+
6
+ before do
7
+ allow(SerialPort).to receive(:new) { serial }
8
+ allow(serial).to receive(:write)
9
+ end
10
+
11
+ it 'decide on a pose' do
12
+ rapiro = RapiroWrapper::Body.new
13
+
14
+ commander = rapiro.instance_variable_get(:@commander)
15
+ expect(commander).to be_instance_of RapiroWrapper::Commander
16
+
17
+ serial = commander.instance_variable_get(:@serial)
18
+ expect(serial).to eq serial
19
+
20
+ expect(rapiro).to respond_to :head=
21
+ expect(rapiro).to respond_to :head
22
+ expect(rapiro).to respond_to :waist=
23
+ expect(rapiro).to respond_to :waist
24
+ expect(rapiro).to respond_to :right_sholder_roll=
25
+ expect(rapiro).to respond_to :right_sholder_roll
26
+ expect(rapiro).to respond_to :right_sholder_pitch=
27
+ expect(rapiro).to respond_to :right_sholder_pitch
28
+ expect(rapiro).to respond_to :right_hand_grip=
29
+ expect(rapiro).to respond_to :right_hand_grip
30
+ expect(rapiro).to respond_to :left_sholder_roll=
31
+ expect(rapiro).to respond_to :left_sholder_roll
32
+ expect(rapiro).to respond_to :left_sholder_pitch=
33
+ expect(rapiro).to respond_to :left_sholder_pitch
34
+ expect(rapiro).to respond_to :left_hand_grip=
35
+ expect(rapiro).to respond_to :left_hand_grip
36
+ expect(rapiro).to respond_to :right_foot_yaw=
37
+ expect(rapiro).to respond_to :right_foot_yaw
38
+ expect(rapiro).to respond_to :right_foot_pitch=
39
+ expect(rapiro).to respond_to :right_foot_pitch
40
+ expect(rapiro).to respond_to :left_foot_yaw=
41
+ expect(rapiro).to respond_to :left_foot_yaw
42
+ expect(rapiro).to respond_to :left_foot_pitch=
43
+ expect(rapiro).to respond_to :left_foot_pitch
44
+
45
+ expect(rapiro).to respond_to :eyes=
46
+ expect(rapiro).to respond_to :eyes
47
+
48
+ expect(rapiro).to respond_to :sequences
49
+ expect(rapiro.sequences).to eq(
50
+ '#P' \
51
+ 'S00A090' \
52
+ 'S01A090' \
53
+ 'S02A000' \
54
+ 'S03A130' \
55
+ 'S04A090' \
56
+ 'S05A180' \
57
+ 'S06A050' \
58
+ 'S07A090' \
59
+ 'S08A090' \
60
+ 'S09A090' \
61
+ 'S10A090' \
62
+ 'S11A090' \
63
+ 'R000G000B128' \
64
+ 'T010')
65
+
66
+ expect(serial).to receive(:write).with(
67
+ '#P' \
68
+ 'S00A090' \
69
+ 'S01A090' \
70
+ 'S02A000' \
71
+ 'S03A130' \
72
+ 'S04A090' \
73
+ 'S05A180' \
74
+ 'S06A050' \
75
+ 'S07A090' \
76
+ 'S08A090' \
77
+ 'S09A090' \
78
+ 'S10A090' \
79
+ 'S11A090' \
80
+ 'R000G000B128' \
81
+ 'T010')
82
+ rapiro.execute!
83
+
84
+ rapiro.head = { left: 40 }
85
+ expect(serial).to receive(:write).with(
86
+ '#P' \
87
+ 'S00A130' \
88
+ 'S01A090' \
89
+ 'S02A000' \
90
+ 'S03A130' \
91
+ 'S04A090' \
92
+ 'S05A180' \
93
+ 'S06A050' \
94
+ 'S07A090' \
95
+ 'S08A090' \
96
+ 'S09A090' \
97
+ 'S10A090' \
98
+ 'S11A090' \
99
+ 'R000G000B128' \
100
+ 'T010')
101
+ rapiro.execute!
102
+
103
+ rapiro.head = { right: 20 }
104
+ expect(serial).to receive(:write).with(
105
+ '#P' \
106
+ 'S00A070' \
107
+ 'S01A090' \
108
+ 'S02A000' \
109
+ 'S03A130' \
110
+ 'S04A090' \
111
+ 'S05A180' \
112
+ 'S06A050' \
113
+ 'S07A090' \
114
+ 'S08A090' \
115
+ 'S09A090' \
116
+ 'S10A090' \
117
+ 'S11A090' \
118
+ 'R000G000B128' \
119
+ 'T010')
120
+ rapiro.execute!
121
+
122
+ rapiro.waist = { left: 20 }
123
+ expect(serial).to receive(:write).with(
124
+ '#P' \
125
+ 'S00A070' \
126
+ 'S01A110' \
127
+ 'S02A000' \
128
+ 'S03A130' \
129
+ 'S04A090' \
130
+ 'S05A180' \
131
+ 'S06A050' \
132
+ 'S07A090' \
133
+ 'S08A090' \
134
+ 'S09A090' \
135
+ 'S10A090' \
136
+ 'S11A090' \
137
+ 'R000G000B128' \
138
+ 'T010')
139
+ rapiro.execute!
140
+
141
+ rapiro.waist = { right: 40 }
142
+ expect(serial).to receive(:write).with(
143
+ '#P' \
144
+ 'S00A070' \
145
+ 'S01A050' \
146
+ 'S02A000' \
147
+ 'S03A130' \
148
+ 'S04A090' \
149
+ 'S05A180' \
150
+ 'S06A050' \
151
+ 'S07A090' \
152
+ 'S08A090' \
153
+ 'S09A090' \
154
+ 'S10A090' \
155
+ 'S11A090' \
156
+ 'R000G000B128' \
157
+ 'T010')
158
+ rapiro.execute!
159
+
160
+ rapiro.right_sholder_roll = { up: 40 }
161
+ expect(serial).to receive(:write).with(
162
+ '#P' \
163
+ 'S00A070' \
164
+ 'S01A050' \
165
+ 'S02A040' \
166
+ 'S03A130' \
167
+ 'S04A090' \
168
+ 'S05A180' \
169
+ 'S06A050' \
170
+ 'S07A090' \
171
+ 'S08A090' \
172
+ 'S09A090' \
173
+ 'S10A090' \
174
+ 'S11A090' \
175
+ 'R000G000B128' \
176
+ 'T010')
177
+ rapiro.execute!
178
+
179
+ rapiro.right_sholder_roll = { up: 120 }
180
+ expect(serial).to receive(:write).with(
181
+ '#P' \
182
+ 'S00A070' \
183
+ 'S01A050' \
184
+ 'S02A120' \
185
+ 'S03A130' \
186
+ 'S04A090' \
187
+ 'S05A180' \
188
+ 'S06A050' \
189
+ 'S07A090' \
190
+ 'S08A090' \
191
+ 'S09A090' \
192
+ 'S10A090' \
193
+ 'S11A090' \
194
+ 'R000G000B128' \
195
+ 'T010')
196
+ rapiro.execute!
197
+
198
+ rapiro.right_sholder_pitch = { up: 30 }
199
+ expect(serial).to receive(:write).with(
200
+ '#P' \
201
+ 'S00A070' \
202
+ 'S01A050' \
203
+ 'S02A120' \
204
+ 'S03A100' \
205
+ 'S04A090' \
206
+ 'S05A180' \
207
+ 'S06A050' \
208
+ 'S07A090' \
209
+ 'S08A090' \
210
+ 'S09A090' \
211
+ 'S10A090' \
212
+ 'S11A090' \
213
+ 'R000G000B128' \
214
+ 'T010')
215
+ rapiro.execute!
216
+
217
+ rapiro.right_sholder_pitch = { up: 80 }
218
+ expect(serial).to receive(:write).with(
219
+ '#P' \
220
+ 'S00A070' \
221
+ 'S01A050' \
222
+ 'S02A120' \
223
+ 'S03A050' \
224
+ 'S04A090' \
225
+ 'S05A180' \
226
+ 'S06A050' \
227
+ 'S07A090' \
228
+ 'S08A090' \
229
+ 'S09A090' \
230
+ 'S10A090' \
231
+ 'S11A090' \
232
+ 'R000G000B128' \
233
+ 'T010')
234
+ rapiro.execute!
235
+
236
+ rapiro.right_hand_grip = { open: 10 }
237
+ expect(serial).to receive(:write).with(
238
+ '#P' \
239
+ 'S00A070' \
240
+ 'S01A050' \
241
+ 'S02A120' \
242
+ 'S03A050' \
243
+ 'S04A100' \
244
+ 'S05A180' \
245
+ 'S06A050' \
246
+ 'S07A090' \
247
+ 'S08A090' \
248
+ 'S09A090' \
249
+ 'S10A090' \
250
+ 'S11A090' \
251
+ 'R000G000B128' \
252
+ 'T010')
253
+ rapiro.execute!
254
+
255
+ rapiro.right_hand_grip = { hold: 20 }
256
+ expect(serial).to receive(:write).with(
257
+ '#P' \
258
+ 'S00A070' \
259
+ 'S01A050' \
260
+ 'S02A120' \
261
+ 'S03A050' \
262
+ 'S04A080' \
263
+ 'S05A180' \
264
+ 'S06A050' \
265
+ 'S07A090' \
266
+ 'S08A090' \
267
+ 'S09A090' \
268
+ 'S10A090' \
269
+ 'S11A090' \
270
+ 'R000G000B128' \
271
+ 'T010')
272
+ rapiro.execute!
273
+
274
+ rapiro.left_sholder_roll = { up: 20 }
275
+ expect(serial).to receive(:write).with(
276
+ '#P' \
277
+ 'S00A070' \
278
+ 'S01A050' \
279
+ 'S02A120' \
280
+ 'S03A050' \
281
+ 'S04A080' \
282
+ 'S05A160' \
283
+ 'S06A050' \
284
+ 'S07A090' \
285
+ 'S08A090' \
286
+ 'S09A090' \
287
+ 'S10A090' \
288
+ 'S11A090' \
289
+ 'R000G000B128' \
290
+ 'T010')
291
+ rapiro.execute!
292
+
293
+ rapiro.left_sholder_roll = { up: 90 }
294
+ expect(serial).to receive(:write).with(
295
+ '#P' \
296
+ 'S00A070' \
297
+ 'S01A050' \
298
+ 'S02A120' \
299
+ 'S03A050' \
300
+ 'S04A080' \
301
+ 'S05A090' \
302
+ 'S06A050' \
303
+ 'S07A090' \
304
+ 'S08A090' \
305
+ 'S09A090' \
306
+ 'S10A090' \
307
+ 'S11A090' \
308
+ 'R000G000B128' \
309
+ 'T010')
310
+ rapiro.execute!
311
+
312
+ rapiro.left_sholder_pitch = { up: 70 }
313
+ expect(serial).to receive(:write).with(
314
+ '#P' \
315
+ 'S00A070' \
316
+ 'S01A050' \
317
+ 'S02A120' \
318
+ 'S03A050' \
319
+ 'S04A080' \
320
+ 'S05A090' \
321
+ 'S06A120' \
322
+ 'S07A090' \
323
+ 'S08A090' \
324
+ 'S09A090' \
325
+ 'S10A090' \
326
+ 'S11A090' \
327
+ 'R000G000B128' \
328
+ 'T010')
329
+ rapiro.execute!
330
+
331
+ rapiro.left_sholder_pitch = { up: 10 }
332
+ expect(serial).to receive(:write).with(
333
+ '#P' \
334
+ 'S00A070' \
335
+ 'S01A050' \
336
+ 'S02A120' \
337
+ 'S03A050' \
338
+ 'S04A080' \
339
+ 'S05A090' \
340
+ 'S06A060' \
341
+ 'S07A090' \
342
+ 'S08A090' \
343
+ 'S09A090' \
344
+ 'S10A090' \
345
+ 'S11A090' \
346
+ 'R000G000B128' \
347
+ 'T010')
348
+ rapiro.execute!
349
+
350
+ rapiro.left_hand_grip = { open: 0 }
351
+ expect(serial).to receive(:write).with(
352
+ '#P' \
353
+ 'S00A070' \
354
+ 'S01A050' \
355
+ 'S02A120' \
356
+ 'S03A050' \
357
+ 'S04A080' \
358
+ 'S05A090' \
359
+ 'S06A060' \
360
+ 'S07A060' \
361
+ 'S08A090' \
362
+ 'S09A090' \
363
+ 'S10A090' \
364
+ 'S11A090' \
365
+ 'R000G000B128' \
366
+ 'T010')
367
+ rapiro.execute!
368
+
369
+ rapiro.left_hand_grip = { hold: 0 }
370
+ expect(serial).to receive(:write).with(
371
+ '#P' \
372
+ 'S00A070' \
373
+ 'S01A050' \
374
+ 'S02A120' \
375
+ 'S03A050' \
376
+ 'S04A080' \
377
+ 'S05A090' \
378
+ 'S06A060' \
379
+ 'S07A110' \
380
+ 'S08A090' \
381
+ 'S09A090' \
382
+ 'S10A090' \
383
+ 'S11A090' \
384
+ 'R000G000B128' \
385
+ 'T010')
386
+ rapiro.execute!
387
+
388
+ rapiro.right_foot_yaw = { close: 10 }
389
+ expect(serial).to receive(:write).with(
390
+ '#P' \
391
+ 'S00A070' \
392
+ 'S01A050' \
393
+ 'S02A120' \
394
+ 'S03A050' \
395
+ 'S04A080' \
396
+ 'S05A090' \
397
+ 'S06A060' \
398
+ 'S07A110' \
399
+ 'S08A080' \
400
+ 'S09A090' \
401
+ 'S10A090' \
402
+ 'S11A090' \
403
+ 'R000G000B128' \
404
+ 'T010')
405
+ rapiro.execute!
406
+
407
+ rapiro.right_foot_yaw = { open: 20 }
408
+ expect(serial).to receive(:write).with(
409
+ '#P' \
410
+ 'S00A070' \
411
+ 'S01A050' \
412
+ 'S02A120' \
413
+ 'S03A050' \
414
+ 'S04A080' \
415
+ 'S05A090' \
416
+ 'S06A060' \
417
+ 'S07A110' \
418
+ 'S08A110' \
419
+ 'S09A090' \
420
+ 'S10A090' \
421
+ 'S11A090' \
422
+ 'R000G000B128' \
423
+ 'T010')
424
+ rapiro.execute!
425
+
426
+ rapiro.right_foot_pitch = { open: 30 }
427
+ expect(serial).to receive(:write).with(
428
+ '#P' \
429
+ 'S00A070' \
430
+ 'S01A050' \
431
+ 'S02A120' \
432
+ 'S03A050' \
433
+ 'S04A080' \
434
+ 'S05A090' \
435
+ 'S06A060' \
436
+ 'S07A110' \
437
+ 'S08A110' \
438
+ 'S09A080' \
439
+ 'S10A090' \
440
+ 'S11A090' \
441
+ 'R000G000B128' \
442
+ 'T010')
443
+ rapiro.execute!
444
+
445
+ rapiro.right_foot_pitch = { close: 0 }
446
+ expect(serial).to receive(:write).with(
447
+ '#P' \
448
+ 'S00A070' \
449
+ 'S01A050' \
450
+ 'S02A120' \
451
+ 'S03A050' \
452
+ 'S04A080' \
453
+ 'S05A090' \
454
+ 'S06A060' \
455
+ 'S07A110' \
456
+ 'S08A110' \
457
+ 'S09A070' \
458
+ 'S10A090' \
459
+ 'S11A090' \
460
+ 'R000G000B128' \
461
+ 'T010')
462
+ rapiro.execute!
463
+
464
+ rapiro.left_foot_yaw = { open: 0 }
465
+ expect(serial).to receive(:write).with(
466
+ '#P' \
467
+ 'S00A070' \
468
+ 'S01A050' \
469
+ 'S02A120' \
470
+ 'S03A050' \
471
+ 'S04A080' \
472
+ 'S05A090' \
473
+ 'S06A060' \
474
+ 'S07A110' \
475
+ 'S08A110' \
476
+ 'S09A070' \
477
+ 'S10A050' \
478
+ 'S11A090' \
479
+ 'R000G000B128' \
480
+ 'T010')
481
+ rapiro.execute!
482
+
483
+ rapiro.left_foot_yaw = { close: 10 }
484
+ expect(serial).to receive(:write).with(
485
+ '#P' \
486
+ 'S00A070' \
487
+ 'S01A050' \
488
+ 'S02A120' \
489
+ 'S03A050' \
490
+ 'S04A080' \
491
+ 'S05A090' \
492
+ 'S06A060' \
493
+ 'S07A110' \
494
+ 'S08A110' \
495
+ 'S09A070' \
496
+ 'S10A100' \
497
+ 'S11A090' \
498
+ 'R000G000B128' \
499
+ 'T010')
500
+ rapiro.execute!
501
+
502
+ rapiro.left_foot_pitch = { open: 30 }
503
+ expect(serial).to receive(:write).with(
504
+ '#P' \
505
+ 'S00A070' \
506
+ 'S01A050' \
507
+ 'S02A120' \
508
+ 'S03A050' \
509
+ 'S04A080' \
510
+ 'S05A090' \
511
+ 'S06A060' \
512
+ 'S07A110' \
513
+ 'S08A110' \
514
+ 'S09A070' \
515
+ 'S10A100' \
516
+ 'S11A100' \
517
+ 'R000G000B128' \
518
+ 'T010')
519
+ rapiro.execute!
520
+
521
+ rapiro.left_foot_pitch = { close: 0 }
522
+ expect(serial).to receive(:write).with(
523
+ '#P' \
524
+ 'S00A070' \
525
+ 'S01A050' \
526
+ 'S02A120' \
527
+ 'S03A050' \
528
+ 'S04A080' \
529
+ 'S05A090' \
530
+ 'S06A060' \
531
+ 'S07A110' \
532
+ 'S08A110' \
533
+ 'S09A070' \
534
+ 'S10A100' \
535
+ 'S11A110' \
536
+ 'R000G000B128' \
537
+ 'T010')
538
+ rapiro.execute!
539
+
540
+ rapiro.eyes = '#808000'
541
+ expect(serial).to receive(:write).with(
542
+ '#P' \
543
+ 'S00A070' \
544
+ 'S01A050' \
545
+ 'S02A120' \
546
+ 'S03A050' \
547
+ 'S04A080' \
548
+ 'S05A090' \
549
+ 'S06A060' \
550
+ 'S07A110' \
551
+ 'S08A110' \
552
+ 'S09A070' \
553
+ 'S10A100' \
554
+ 'S11A110' \
555
+ 'R128G128B000' \
556
+ 'T010')
557
+ rapiro.execute!
558
+
559
+ expect(serial).to receive(:write).with(
560
+ '#P' \
561
+ 'S00A070' \
562
+ 'S01A050' \
563
+ 'S02A120' \
564
+ 'S03A050' \
565
+ 'S04A080' \
566
+ 'S05A090' \
567
+ 'S06A060' \
568
+ 'S07A110' \
569
+ 'S08A110' \
570
+ 'S09A070' \
571
+ 'S10A100' \
572
+ 'S11A110' \
573
+ 'R128G128B000' \
574
+ 'T128')
575
+ rapiro.execute!(128)
576
+ end
577
+ end