ruby-player 0.4.1 → 0.5.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.
- data/NEWS.md +10 -0
- data/README.md +10 -1
- data/TODO.md +4 -2
- data/examples/simple_example.rb +1 -1
- data/lib/ruby-player/actarray.rb +10 -4
- data/lib/ruby-player/actuator.rb +28 -0
- data/lib/ruby-player/blob.rb +79 -0
- data/lib/ruby-player/blob_finder.rb +150 -0
- data/lib/ruby-player/client.rb +21 -12
- data/lib/ruby-player/common.rb +10 -6
- data/lib/ruby-player/constants.rb +1 -0
- data/lib/ruby-player/dev_addr.rb +1 -1
- data/lib/ruby-player/device.rb +1 -2
- data/lib/ruby-player/gripper.rb +26 -5
- data/lib/ruby-player/header.rb +1 -1
- data/lib/ruby-player/position2d.rb +67 -18
- data/lib/ruby-player/power.rb +31 -1
- data/lib/ruby-player/ranger.rb +20 -20
- data/lib/ruby-player/version.rb +1 -1
- data/lib/ruby-player.rb +2 -0
- data/spec/actarray_spec.rb +8 -0
- data/spec/actuator_spec.rb +20 -0
- data/spec/blob_finder_spec.rb +96 -0
- data/spec/blob_spec.rb +63 -0
- data/spec/client_spec.rb +47 -6
- data/spec/dev_addr_spec.rb +51 -0
- data/spec/device_spec.rb +27 -0
- data/spec/gripper_spec.rb +14 -4
- data/spec/header_spec.rb +61 -0
- data/spec/position2d_spec.rb +38 -0
- data/spec/power_spec.rb +20 -0
- data/spec/ranger_spec.rb +0 -2
- metadata +24 -17
@@ -14,6 +14,7 @@
|
|
14
14
|
|
15
15
|
module Player
|
16
16
|
# The position2d proxy provides an interface to a mobile robot base
|
17
|
+
# TODO: Implement PLAYER_POSITION2D_CMD_POS command
|
17
18
|
#
|
18
19
|
# @example
|
19
20
|
# # get proxy object
|
@@ -43,6 +44,54 @@ module Player
|
|
43
44
|
@geom = {px: 0.0, py: 0.0, pz: 0.0, proll: 0.0, ppitch: 0.0, pyaw: 0.0, sw: 0.0, sl: 0.0, sh: 0.0}
|
44
45
|
end
|
45
46
|
|
47
|
+
# X position [m]
|
48
|
+
# @return [Float]
|
49
|
+
def px
|
50
|
+
state[:px]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Y position [m]
|
54
|
+
# @return [Float]
|
55
|
+
def py
|
56
|
+
state[:py]
|
57
|
+
end
|
58
|
+
|
59
|
+
# Yaw [rad]
|
60
|
+
# @return [Float]
|
61
|
+
def pa
|
62
|
+
state[:pa]
|
63
|
+
end
|
64
|
+
|
65
|
+
# X speed [m/s]
|
66
|
+
# @return [Float]
|
67
|
+
def vx
|
68
|
+
state[:vx]
|
69
|
+
end
|
70
|
+
|
71
|
+
# Y speed [m/s]
|
72
|
+
# @return [Float]
|
73
|
+
def vy
|
74
|
+
state[:vy]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Yaw speed [rad/s]
|
78
|
+
# @return [Float]
|
79
|
+
def va
|
80
|
+
state[:va]
|
81
|
+
end
|
82
|
+
|
83
|
+
# State of motor
|
84
|
+
# @return [Boolean] true - on
|
85
|
+
def power?
|
86
|
+
state[:stall] != 0
|
87
|
+
end
|
88
|
+
|
89
|
+
# @deprecated Use {#power?}
|
90
|
+
def power
|
91
|
+
warn "Method `power` is deprecated. Pleas use `power?`"
|
92
|
+
power?
|
93
|
+
end
|
94
|
+
|
46
95
|
# @deprecated Use {#state}
|
47
96
|
def position
|
48
97
|
warn "Method `position` is deprecated. Pleas use `data` for access to position"
|
@@ -50,14 +99,14 @@ module Player
|
|
50
99
|
end
|
51
100
|
|
52
101
|
# Query robot geometry
|
53
|
-
# @return self
|
102
|
+
# @return [Position2d] self
|
54
103
|
def query_geom
|
55
104
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_GET_GEOM)
|
56
105
|
self
|
57
106
|
end
|
58
107
|
|
59
108
|
# Turn on motor
|
60
|
-
# @return self
|
109
|
+
# @return [Position2d] self
|
61
110
|
def power_on!
|
62
111
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, [1].pack("N"))
|
63
112
|
self
|
@@ -70,6 +119,7 @@ module Player
|
|
70
119
|
end
|
71
120
|
|
72
121
|
# Turn off motor
|
122
|
+
# @return [Position2d] self
|
73
123
|
def power_off!
|
74
124
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, [0].pack("N"))
|
75
125
|
self
|
@@ -81,21 +131,25 @@ module Player
|
|
81
131
|
power_off!
|
82
132
|
end
|
83
133
|
|
134
|
+
# @return [Position2d] self
|
84
135
|
def direct_speed_control!
|
85
136
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, [0].pack("N"))
|
86
137
|
self
|
87
138
|
end
|
88
139
|
|
140
|
+
# @return [Position2d] self
|
89
141
|
def separate_speed_control!
|
90
142
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, [1].pack("N"))
|
91
143
|
self
|
92
144
|
end
|
93
145
|
|
146
|
+
# @return [Position2d] self
|
94
147
|
def position_control!
|
95
148
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_POSITION_MODE, [0].pack("N"))
|
96
149
|
self
|
97
150
|
end
|
98
151
|
|
152
|
+
# @return [Position2d] self
|
99
153
|
def speed_control!
|
100
154
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_POSITION_MODE, [1].pack("N"))
|
101
155
|
self
|
@@ -106,7 +160,7 @@ module Player
|
|
106
160
|
# @option odom :px x position (m)
|
107
161
|
# @option odom :py y position (m)
|
108
162
|
# @option odom :pa angle (rad).
|
109
|
-
# @return self
|
163
|
+
# @return [Position2d] self
|
110
164
|
def set_odometry(odom)
|
111
165
|
data = [
|
112
166
|
odom[:px].to_f,
|
@@ -123,7 +177,7 @@ module Player
|
|
123
177
|
# @option params :kp P
|
124
178
|
# @option params :ki I
|
125
179
|
# @option params :kd D
|
126
|
-
# @return self
|
180
|
+
# @return [Position2d] self
|
127
181
|
def set_speed_pid(params={})
|
128
182
|
data = [
|
129
183
|
params[:kp].to_f,
|
@@ -139,7 +193,7 @@ module Player
|
|
139
193
|
# @option params :kp P
|
140
194
|
# @option params :ki I
|
141
195
|
# @option params :kd D
|
142
|
-
# @return self
|
196
|
+
# @return [Position2d] self
|
143
197
|
def set_position_pid(params={})
|
144
198
|
data = [
|
145
199
|
params[:kp].to_f,
|
@@ -154,7 +208,7 @@ module Player
|
|
154
208
|
# @param [Hash] params profile prarams
|
155
209
|
# @option params :spped max speed (m/s)
|
156
210
|
# @option params :acc max acceleration (m/s^2)
|
157
|
-
# @return self
|
211
|
+
# @return [Position2d] self
|
158
212
|
def set_speed_profile(params={})
|
159
213
|
data = [
|
160
214
|
params[:speed].to_f,
|
@@ -166,7 +220,7 @@ module Player
|
|
166
220
|
end
|
167
221
|
|
168
222
|
# Reset odometry to zero
|
169
|
-
# @return self
|
223
|
+
# @return [Position2d] self
|
170
224
|
def reset_odometry
|
171
225
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_RESET_ODOM)
|
172
226
|
self
|
@@ -178,7 +232,7 @@ module Player
|
|
178
232
|
# @option speeds :vy sideways speed (m/s); this field is used by omni-drive robots only.
|
179
233
|
# @option speeds :va rotational speed (rad/s).
|
180
234
|
# @option speeds :stall state of motor
|
181
|
-
# @return self
|
235
|
+
# @return [Position2d] self
|
182
236
|
def set_speed(speeds)
|
183
237
|
data = [
|
184
238
|
speeds[:vx] || @state[:vx],
|
@@ -194,6 +248,7 @@ module Player
|
|
194
248
|
# @param [Hash] speeds
|
195
249
|
# @option speeds :vx forward speed (m/s)
|
196
250
|
# @option speeds :a turning angle (rad).
|
251
|
+
# @return [Position2d] self
|
197
252
|
def set_car(speeds)
|
198
253
|
data = [
|
199
254
|
speeds[:vx] || @state[:vx],
|
@@ -208,6 +263,7 @@ module Player
|
|
208
263
|
# @param [Hash] speeds
|
209
264
|
# @option speeds :vx forward speed (m/s)
|
210
265
|
# @option speeds :a absolutle angle (rad).
|
266
|
+
# @return [Position2d] self
|
211
267
|
def set_speed_head(speeds)
|
212
268
|
data = [
|
213
269
|
speeds[:vx] || @state[:vx],
|
@@ -217,15 +273,8 @@ module Player
|
|
217
273
|
self
|
218
274
|
end
|
219
275
|
|
220
|
-
|
221
|
-
# State of motor
|
222
|
-
# @return [Boolean] true - on
|
223
|
-
def power
|
224
|
-
@state[:stall] == 1
|
225
|
-
end
|
226
|
-
|
227
276
|
# Stop robot set speed to 0
|
228
|
-
# @return self
|
277
|
+
# @return [Position2d] self
|
229
278
|
def stop!
|
230
279
|
set_speed(vx: 0, vy: 0, va: 0)
|
231
280
|
end
|
@@ -260,12 +309,12 @@ module Player
|
|
260
309
|
private
|
261
310
|
def read_state(msg)
|
262
311
|
fill_hash!(@state, msg.unpack("GGGGGGN"))
|
263
|
-
debug "
|
312
|
+
debug "Got state: " + hash_to_sft(@state)
|
264
313
|
end
|
265
314
|
|
266
315
|
def read_geom(msg)
|
267
316
|
fill_hash!(@geom, msg.unpack("G*"))
|
268
|
-
debug "
|
317
|
+
debug "Got geom: " + hash_to_sft(@geom)
|
269
318
|
end
|
270
319
|
end
|
271
320
|
end
|
data/lib/ruby-player/power.rb
CHANGED
@@ -37,17 +37,47 @@ module Player
|
|
37
37
|
super
|
38
38
|
@state = { valid: 0, volts: 0.0, percent: 0.0, joules: 0.0, watts: 0.0, charging: 0 }
|
39
39
|
end
|
40
|
+
|
41
|
+
# Battery voltage [V].
|
42
|
+
# @see #state
|
43
|
+
# @retrun [Float]
|
44
|
+
def volts
|
45
|
+
state[:volts]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Percent of full charge [%].
|
49
|
+
# @see #state
|
50
|
+
# @retrun [Float]
|
51
|
+
def percent
|
52
|
+
state[:percent]
|
53
|
+
end
|
40
54
|
|
55
|
+
# Energy stored [J].
|
56
|
+
# @see #state
|
57
|
+
# @retrun [Float]
|
58
|
+
def joules
|
59
|
+
state[:joules]
|
60
|
+
end
|
61
|
+
|
62
|
+
# Estimated current energy consumption (negative values) or aquisition (positive values) [W].
|
63
|
+
# @see #state
|
64
|
+
# @retrun [Float]
|
65
|
+
def watts
|
66
|
+
state[:watts]
|
67
|
+
end
|
68
|
+
|
41
69
|
# Request to change the charging policy
|
42
70
|
# @param [Hash] policy
|
43
71
|
# @option policy [Boolean] :enable_input boolean controlling recharging
|
44
72
|
# @option policy [Boolean] :enable_output bolean controlling whether others can recharge from this device
|
73
|
+
# @return [Power] self
|
45
74
|
def set_charging_policy(policy={})
|
46
75
|
data = [
|
47
76
|
policy[:enable_input] ? 1 : 0,
|
48
77
|
policy[:enable_output] ? 1 : 0
|
49
78
|
]
|
50
79
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_POWER_REQ_SET_CHARGING_POLICY, data.pack("NN"))
|
80
|
+
self
|
51
81
|
end
|
52
82
|
|
53
83
|
# Check volts valid
|
@@ -96,7 +126,7 @@ module Player
|
|
96
126
|
private
|
97
127
|
def read_state(msg)
|
98
128
|
fill_hash!(@state, msg.unpack("NggggN"))
|
99
|
-
debug "
|
129
|
+
debug "Got state: " + hash_to_sft(@state)
|
100
130
|
end
|
101
131
|
end
|
102
132
|
end
|
data/lib/ruby-player/ranger.rb
CHANGED
@@ -41,25 +41,25 @@ module Player
|
|
41
41
|
|
42
42
|
# @deprecated use `ranger.collect { |r| r.range }
|
43
43
|
def rangers
|
44
|
-
warn "Method `rangers` is deprecated. Pleas use `ranger.collect { |r| r.
|
44
|
+
warn "Method `rangers` is deprecated. Pleas use `ranger.collect { |r| r.range }`"
|
45
45
|
@sensors.collect { |s| s.range }
|
46
46
|
end
|
47
47
|
|
48
48
|
# @deprecated use `ranger.collect { |r| r.intensity }
|
49
49
|
def intensities
|
50
|
-
warn "Method `intensities` is deprecated. Pleas use `ranger.collect { |r| r.
|
50
|
+
warn "Method `intensities` is deprecated. Pleas use `ranger.collect { |r| r.intensity }`"
|
51
51
|
@sensors.collect { |s| s.intensity }
|
52
52
|
end
|
53
53
|
|
54
54
|
# Query ranger geometry
|
55
|
-
# @return self
|
55
|
+
# @return [Ranger] self
|
56
56
|
def query_geom
|
57
57
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_GET_GEOM)
|
58
58
|
self
|
59
59
|
end
|
60
60
|
|
61
61
|
# Turn on ranger
|
62
|
-
# @return self
|
62
|
+
# @return [Ranger] self
|
63
63
|
def power_on!
|
64
64
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_POWER, [1].pack("N"))
|
65
65
|
self
|
@@ -72,6 +72,7 @@ module Player
|
|
72
72
|
end
|
73
73
|
|
74
74
|
# Turn off ranger
|
75
|
+
# @return [Ranger] self
|
75
76
|
def power_off!
|
76
77
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_POWER, [0].pack("N"))
|
77
78
|
self
|
@@ -83,17 +84,20 @@ module Player
|
|
83
84
|
power_off!
|
84
85
|
end
|
85
86
|
|
87
|
+
# @return [Ranger] self
|
86
88
|
def intensity_enable!
|
87
89
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_INTNS, [1].pack("N"))
|
88
90
|
self
|
89
91
|
end
|
90
92
|
|
93
|
+
# @return [Ranger] self
|
91
94
|
def intensity_disable!
|
92
95
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_INTNS, [0].pack("N"))
|
93
96
|
self
|
94
97
|
end
|
95
98
|
|
96
99
|
# Query ranger configuration
|
100
|
+
# @return [Ranger] self
|
97
101
|
def query_config
|
98
102
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_GET_CONFIG)
|
99
103
|
self
|
@@ -108,18 +112,11 @@ module Player
|
|
108
112
|
# @option config :max_range minimum range [m]
|
109
113
|
# @option config :range_res range resolution [m]
|
110
114
|
# @option config :frequency scanning frequency [Hz]
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
config[:max_angle].to_f || @ranger[:max_angle],
|
115
|
-
config[:angular_res].to_f || @ranger[:angular_res],
|
116
|
-
config[:min_range].to_f || @ranger[:min_range],
|
117
|
-
config[:max_range].to_f || @ranger[:max_range],
|
118
|
-
config[:range_res].to_f || @ranger[:range_res],
|
119
|
-
config[:frequecy].to_f || @ranger[:frequecy]
|
120
|
-
]
|
121
|
-
|
115
|
+
# @return [Ranger] self
|
116
|
+
def set_config(config={})
|
117
|
+
data = to_a_by_default(config, @config)
|
122
118
|
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_SET_CONFIG, data.pack("G*"))
|
119
|
+
self
|
123
120
|
end
|
124
121
|
|
125
122
|
def fill(hdr, msg)
|
@@ -130,14 +127,14 @@ module Player
|
|
130
127
|
self[i].state[:range] = r
|
131
128
|
end
|
132
129
|
|
133
|
-
debug "
|
130
|
+
debug "Got rangers #{@sensors.collect { |s| s.state[:range] }}"
|
134
131
|
when PLAYER_RANGER_DATA_INTNS
|
135
132
|
data = msg.unpack("NNG*")
|
136
133
|
data[2..-1].each_with_index do |ints, i|
|
137
134
|
self[i].state[:intensity] = ints
|
138
135
|
end
|
139
136
|
|
140
|
-
debug "
|
137
|
+
debug "Got intensities #{@sensors.collect { |s| s.state[:intensity]}}"
|
141
138
|
when PLAYER_RANGER_DATA_GEOM
|
142
139
|
read_geom(msg)
|
143
140
|
else
|
@@ -158,6 +155,9 @@ module Player
|
|
158
155
|
end
|
159
156
|
end
|
160
157
|
|
158
|
+
# Get sensor
|
159
|
+
# @param [Integer] index
|
160
|
+
# @retrun [Sensor] sensor
|
161
161
|
def [](index)
|
162
162
|
@sensors[index] ||= Sensor.new(index, self)
|
163
163
|
end
|
@@ -174,7 +174,7 @@ module Player
|
|
174
174
|
def read_geom(msg)
|
175
175
|
data = msg[0,72].unpack("G*")
|
176
176
|
fill_hash!(@geom, data)
|
177
|
-
debug "
|
177
|
+
debug "Got geom: " + hash_to_sft(@geom)
|
178
178
|
|
179
179
|
|
180
180
|
p_count = msg[72,8].unpack("NN")
|
@@ -188,13 +188,13 @@ module Player
|
|
188
188
|
p_count.times do |i|
|
189
189
|
[:px, :py, :pz, :proll, :ppitch, :pyaw]
|
190
190
|
.each_with_index { |k,j| self[i].geom[k] = poses[6*i + j] }
|
191
|
-
debug("
|
191
|
+
debug("Got poses for ##{i} sensor: px=%.2f, py=%.2f, pz=%.2f, proll=%.2f, ppitch=%.2f, pyaw=%.2f" % @sensors[i].geom.values[0,6])
|
192
192
|
end
|
193
193
|
|
194
194
|
s_count.times do |i|
|
195
195
|
[:sw, :sl, :sh]
|
196
196
|
.each_with_index { |k,j| self[i].geom[k] = sizes[3*i + j] }
|
197
|
-
debug("
|
197
|
+
debug("Got sizes for ##{i} sensor: sw=%.2f, sl=%.2f, sh=%.2f" % @sensors[i].geom.values[6,3])
|
198
198
|
end
|
199
199
|
|
200
200
|
end
|
data/lib/ruby-player/version.rb
CHANGED
data/lib/ruby-player.rb
CHANGED
@@ -25,6 +25,8 @@ require "ruby-player/client"
|
|
25
25
|
#interfaces
|
26
26
|
require "ruby-player/actuator"
|
27
27
|
require "ruby-player/actarray"
|
28
|
+
require "ruby-player/blob"
|
29
|
+
require "ruby-player/blob_finder"
|
28
30
|
require "ruby-player/gripper"
|
29
31
|
require "ruby-player/position2d"
|
30
32
|
require "ruby-player/power"
|
data/spec/actarray_spec.rb
CHANGED
@@ -18,6 +18,14 @@ describe Player::ActArray do
|
|
18
18
|
@actarray.geom.should eql(px: 0.0, py: 0.0, pz: 0.0, proll: 0.0, ppitch: 0.0, pyaw: 0.0)
|
19
19
|
end
|
20
20
|
|
21
|
+
it 'should have :power? method' do
|
22
|
+
@actarray.should_receive(:state).and_return(motor_state: 0)
|
23
|
+
@actarray.power?.should be_false
|
24
|
+
|
25
|
+
@actarray.should_receive(:state).and_return(motor_state: 1)
|
26
|
+
@actarray.power?.should be_true
|
27
|
+
end
|
28
|
+
|
21
29
|
it 'should set power state for all actuators' do
|
22
30
|
should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_POWER, [0].pack("N"))
|
23
31
|
@actarray.power_off!
|
data/spec/actuator_spec.rb
CHANGED
@@ -28,6 +28,26 @@ describe Player::Actuator do
|
|
28
28
|
)
|
29
29
|
end
|
30
30
|
|
31
|
+
it 'should have #position attr' do
|
32
|
+
@act.should_receive(:state).and_return(position: 1.2)
|
33
|
+
@act.position.should eql(1.2)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should have #speed attr' do
|
37
|
+
@act.should_receive(:state).and_return(speed: 1.8)
|
38
|
+
@act.speed.should eql(1.8)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should have #acceleration attr' do
|
42
|
+
@act.should_receive(:state).and_return(acceleration: 0.2)
|
43
|
+
@act.acceleration.should eql(0.2)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should have #current attr' do
|
47
|
+
@act.should_receive(:state).and_return(current: 3.2)
|
48
|
+
@act.current.should eql(3.2)
|
49
|
+
end
|
50
|
+
|
31
51
|
it 'should set speed config ' do
|
32
52
|
should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_SPEED, [0, 0.2].pack("Ng"))
|
33
53
|
@act.set_speed_config(0.2)
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
include Player
|
4
|
+
describe Player::BlobFinder do
|
5
|
+
before do
|
6
|
+
client = mock_client
|
7
|
+
|
8
|
+
@bf = Player::BlobFinder.new(
|
9
|
+
Player::DevAddr.new(host: 0, robot:0, interface: PLAYER_BLOBFINDER_CODE, index: 0),
|
10
|
+
client
|
11
|
+
)
|
12
|
+
|
13
|
+
mock_sending_message(@bf)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should have default state' do
|
17
|
+
@bf.state.should eql(width: 0, height: 0, blobs: [])
|
18
|
+
@bf.color.should eql(channel: 0, rmin: 0, rmax: 0, gmin: 0, gmax: 0, bmin: 0, bmax: 0)
|
19
|
+
@bf.imager_params.should eql(brightness: 0, contrast: 0, colormode: 0, autogain: 0)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should query color' do
|
23
|
+
should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_BLOBFINDER_REQ_GET_COLOR)
|
24
|
+
@bf.query_color
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should set color' do
|
28
|
+
color = [0, 1, 251, 2, 252, 3, 253]
|
29
|
+
should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_BLOBFINDER_REQ_SET_COLOR, color.pack("N*"))
|
30
|
+
@bf.set_color(channel: 0, rmin: 1, rmax: 251, gmin: 2, gmax: 252, bmin: 3, bmax: 253)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should set imager params' do
|
34
|
+
params = [100, 200, 3, 1]
|
35
|
+
should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_BLOBFINDER_REQ_SET_IMAGER_PARAMS, params.pack("N*"))
|
36
|
+
@bf.set_imager_params(brightness: 100, contrast: 200, colormode: 3, autogain: 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should have #width attr' do
|
40
|
+
@bf.should_receive(:state).and_return(width: 23)
|
41
|
+
@bf.width.should eql(23)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should have #height attr' do
|
45
|
+
@bf.should_receive(:state).and_return(height: 40)
|
46
|
+
@bf.height.should eql(40)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should have #blobs attr' do
|
50
|
+
@bf.should_receive(:state).and_return(blobs: [nil])
|
51
|
+
@bf.blobs.should eql([nil])
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should fill blobs data' do
|
55
|
+
blobs = [10, 20, 2, 0,
|
56
|
+
0, 222, 20, 5, 4, 10, 10, 20, 20, 0.5,
|
57
|
+
1, 111, 40, 5, 8, 20, 30, 40, 50, 2.5]
|
58
|
+
msg = blobs.pack("NNNNN9gN9g")
|
59
|
+
|
60
|
+
@bf.fill(
|
61
|
+
Player::Header.from_a([0,0,PLAYER_BLOBFINDER_CODE, 0,
|
62
|
+
PLAYER_MSGTYPE_DATA, PLAYER_BLOBFINDER_DATA_BLOBS, 0.0, 0, msg.bytesize]),
|
63
|
+
msg
|
64
|
+
)
|
65
|
+
@bf.width.should eql(10)
|
66
|
+
@bf.height.should eql(20)
|
67
|
+
@bf[0].state.values.should eql(blobs[4,10])
|
68
|
+
@bf[1].state.values.should eql(blobs[14,10])
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should include Enumerable' do
|
72
|
+
@bf.state[:blobs] = Array.new(10) { |i| Blob.new(i, nil) }
|
73
|
+
@bf.map { |b| b.should be_kind_of(Blob) }
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should get color config by request' do
|
77
|
+
color = [1, 1, 2, 3, 4, 5, 6 ]
|
78
|
+
|
79
|
+
msg = color.pack("N*")
|
80
|
+
@bf.handle_response(
|
81
|
+
Player::Header.from_a([0,0,PLAYER_BLOBFINDER_CODE, 0, PLAYER_MSGTYPE_RESP_ACK, PLAYER_BLOBFINDER_REQ_GET_COLOR, 0.0, 0, msg.bytesize]),
|
82
|
+
msg
|
83
|
+
)
|
84
|
+
|
85
|
+
@bf.color.should eql(channel: 1, rmin: 1, rmax: 2, gmin: 3, gmax: 4, bmin: 5, bmax: 6)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should not puts warn message for ACK subtypes 1,2' do
|
89
|
+
@bf.should_not_receive(:unexpected_message)
|
90
|
+
(1..2).each do |i|
|
91
|
+
@bf.handle_response(
|
92
|
+
Player::Header.from_a([0,0,PLAYER_BLOBFINDER_CODE,0, PLAYER_MSGTYPE_RESP_ACK, i, 0.0, 0, 0]),
|
93
|
+
"")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/spec/blob_spec.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe Player::Blob do
|
4
|
+
before do
|
5
|
+
@blob = Player::Blob.new(nil, nil)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should have default values' do
|
9
|
+
@blob.state.should eql(id: 0, color: 0, area: 0, x: 0, y: 0, left: 0, right: 0, top: 0, bottom: 0, range: 0.0)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should have #id attr' do
|
13
|
+
@blob.should_receive(:state).and_return(id: 23)
|
14
|
+
@blob.id.should eql(23)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should have #color attr' do
|
18
|
+
@blob.should_receive(:state).and_return(color: 0xfff)
|
19
|
+
@blob.color.should eql(0xfff)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should have #area attr' do
|
23
|
+
@blob.should_receive(:state).and_return(area: 100)
|
24
|
+
@blob.area.should eql(100)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should have #x attr' do
|
28
|
+
@blob.should_receive(:state).and_return(x: 10)
|
29
|
+
@blob.x.should eql(10)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should have #y attr' do
|
33
|
+
@blob.should_receive(:state).and_return(y: 20)
|
34
|
+
@blob.y.should eql(20)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should have #left attr' do
|
38
|
+
@blob.should_receive(:state).and_return(left: 15)
|
39
|
+
@blob.left.should eql(15)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should have #right attr' do
|
43
|
+
@blob.should_receive(:state).and_return(right: 30)
|
44
|
+
@blob.right.should eql(30)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should have #top attr' do
|
48
|
+
@blob.should_receive(:state).and_return(top: 45)
|
49
|
+
@blob.top.should eql(45)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should have #bottom attr' do
|
53
|
+
@blob.should_receive(:state).and_return(bottom: 35)
|
54
|
+
@blob.bottom.should eql(35)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should have #ranger attr' do
|
58
|
+
@blob.should_receive(:state).and_return(range: 0.2)
|
59
|
+
@blob.range.should eql(0.2)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|