ruby-player 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|