ruby-player 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,17 @@
1
+ # Ruby Player - Ruby client library for Player (tools for robots)
2
+ #
3
+ # Copyright (C) 2012 Aleksey Timin
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
1
15
  module Player
2
16
  PLAYERXDR_DEVADDR_SIZE = 16
3
17
  PLAYERXDR_MSGHDR_SIZE = PLAYERXDR_DEVADDR_SIZE + 24
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -14,6 +14,7 @@
14
14
  require "socket"
15
15
 
16
16
  module Player
17
+ # Basic class for all intrefaces
17
18
  class Device
18
19
  include Common
19
20
 
@@ -33,7 +34,6 @@ module Player
33
34
  raise_error "Method `handle_response` isn't implemented for `#{self.class}`"
34
35
  end
35
36
 
36
- private
37
37
  def send_message(type, subtype, msg="")
38
38
  @client.write( Header.new(
39
39
  dev_addr: @addr,
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -149,19 +149,19 @@ module Player
149
149
  private
150
150
  def read_state(msg)
151
151
  fill_hash!(@state, msg.unpack("NNN"))
152
- debug("Get gripper state state=%d, beams=%d, stored=%d" % @state.values)
152
+ debug "Get state: " + hash_to_sft(@state)
153
153
  end
154
154
 
155
155
  def read_geom(msg)
156
156
  data = msg.unpack("G12NN")
157
157
  fill_hash!(@geom[:pose], data)
158
- debug "Get gripper pose: " + pose_to_s(@geom[:pose])
158
+ debug "Get pose: " + hash_to_sft(@geom[:pose])
159
159
 
160
160
  fill_hash!(@geom[:outer_size], data)
161
- debug "Get gripper outer size: " + size_to_s(@geom[:outer_size])
161
+ debug "Get outer size: " + hash_to_sft(@geom[:outer_size])
162
162
 
163
163
  fill_hash!(@geom[:inner_size], data)
164
- debug "Get gripper inner size: " + size_to_s(@geom[:inner_size])
164
+ debug "Get inner size: " + hash_to_sft(@geom[:inner_size])
165
165
 
166
166
  @geom[:number_beams] = data.shift
167
167
  @geom[:capacity] = data.shift
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -13,6 +13,7 @@
13
13
  # GNU General Public License for more details.
14
14
 
15
15
  module Player
16
+ # Header of message
16
17
  class Header
17
18
  include Common
18
19
 
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -43,7 +43,7 @@ module Player
43
43
  @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
44
  end
45
45
 
46
- # Depricated alias for data
46
+ # @deprecated Use {#state}
47
47
  def position
48
48
  warn "Method `position` is deprecated. Pleas use `data` for access to position"
49
49
  state
@@ -58,17 +58,29 @@ module Player
58
58
 
59
59
  # Turn on motor
60
60
  # @return self
61
- def turn_on!
61
+ def power_on!
62
62
  send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, [1].pack("N"))
63
63
  self
64
64
  end
65
65
 
66
+ # @deprecated Use {#power_on!}
67
+ def turn_on!
68
+ warn "Method `turn_on!` is deprecated. Pleas use `power_on!`"
69
+ power_on!
70
+ end
71
+
66
72
  # Turn off motor
67
- def turn_off!
73
+ def power_off!
68
74
  send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, [0].pack("N"))
69
75
  self
70
76
  end
71
77
 
78
+ # @deprecated Use {#power_off!}
79
+ def turn_off!
80
+ warn "Method `turn_off!` is deprecated. Pleas use `power_off!`"
81
+ power_off!
82
+ end
83
+
72
84
  def direct_speed_control!
73
85
  send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, [0].pack("N"))
74
86
  self
@@ -90,10 +102,10 @@ module Player
90
102
  end
91
103
 
92
104
  # Set odometry of robot.
93
- # @param [Hash] odometry
94
- # @option odometry :px x position (m)
95
- # @option odometry :py y position (m)
96
- # @option odometry :pa angle (rad).
105
+ # @param [Hash] odom odometry
106
+ # @option odom :px x position (m)
107
+ # @option odom :py y position (m)
108
+ # @option odom :pa angle (rad).
97
109
  # @return self
98
110
  def set_odometry(odom)
99
111
  data = [
@@ -248,12 +260,12 @@ module Player
248
260
  private
249
261
  def read_state(msg)
250
262
  fill_hash!(@state, msg.unpack("GGGGGGN"))
251
- debug("Get state px=%.2f py=%.2f pa=%.2f; vx=%.2f, vy=%.2f, va=%.2f, stall=%d" % @state.values)
263
+ debug "Get state: " + hash_to_sft(@state)
252
264
  end
253
265
 
254
266
  def read_geom(msg)
255
267
  fill_hash!(@geom, msg.unpack("G*"))
256
- debug "Get geom " + geom_to_s(@geom)
268
+ debug "Get geom: " + hash_to_sft(@geom)
257
269
  end
258
270
  end
259
271
  end
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -96,7 +96,7 @@ module Player
96
96
  private
97
97
  def read_state(msg)
98
98
  fill_hash!(@state, msg.unpack("NggggN"))
99
- debug("Get power state valid=%x volts=%.2f, percent=%.2f, joules=%.2f; watts=%.2f, charging=%d" % @state.values)
99
+ debug "Get state: " + hash_to_sft(@state)
100
100
  end
101
101
  end
102
102
  end
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -18,19 +18,13 @@ module Player
18
18
  #
19
19
  # @example
20
20
  # ranger = robot.subscribe(:ranger, index: 0)
21
- # ranger.rangers #=> [0.2, 0.1, 0.2]
21
+ # ranger[0].range #=> 0.2
22
22
  class Ranger < Device
23
+ include Enumerable
23
24
 
24
- # Range data [m]
25
- # @return [Array] fot each sensor
26
- attr_reader :rangers
27
-
28
- # Intensity data [m].
29
- # @return [Array] fot each sensor
30
- attr_reader :intensities
31
25
 
32
26
  # Configuration of ranger
33
- # @see set_config
27
+ # @see #set_config
34
28
  attr_reader :config
35
29
 
36
30
 
@@ -40,12 +34,23 @@ module Player
40
34
 
41
35
  def initialize(addr, client)
42
36
  super
43
- @rangers = []
44
- @intensities = []
45
- @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, sensors: []}
37
+ @sensors = []
38
+ @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 }
46
39
  @config = { min_angle: 0.0, max_angle: 0.0, angular_res: 0.0, min_range: 0.0, max_range: 0.0, range_res: 0.0, frequecy: 0.0 }
47
40
  end
41
+
42
+ # @deprecated use `ranger.collect { |r| r.range }
43
+ def rangers
44
+ warn "Method `rangers` is deprecated. Pleas use `ranger.collect { |r| r.state[:range] }`"
45
+ @sensors.collect { |s| s.range }
46
+ end
48
47
 
48
+ # @deprecated use `ranger.collect { |r| r.intensity }
49
+ def intensities
50
+ warn "Method `intensities` is deprecated. Pleas use `ranger.collect { |r| r.state[:intensity] }`"
51
+ @sensors.collect { |s| s.intensity }
52
+ end
53
+
49
54
  # Query ranger geometry
50
55
  # @return self
51
56
  def query_geom
@@ -55,17 +60,29 @@ module Player
55
60
 
56
61
  # Turn on ranger
57
62
  # @return self
58
- def turn_on!
63
+ def power_on!
59
64
  send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_POWER, [1].pack("N"))
60
65
  self
61
66
  end
62
67
 
68
+ # @deprecated Use {#power_on!}
69
+ def turn_on!
70
+ warn "Method `turn_on!` is deprecated. Pleas use `power_on!`"
71
+ power_on!
72
+ end
73
+
63
74
  # Turn off ranger
64
- def turn_off!
75
+ def power_off!
65
76
  send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_POWER, [0].pack("N"))
66
77
  self
67
78
  end
68
79
 
80
+ # @deprecated Use {#power_off!}
81
+ def turn_off!
82
+ warn "Method `turn_off!` is deprecated. Pleas use `power_off!`"
83
+ power_off!
84
+ end
85
+
69
86
  def intensity_enable!
70
87
  send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_INTNS, [1].pack("N"))
71
88
  self
@@ -109,12 +126,18 @@ module Player
109
126
  case hdr.subtype
110
127
  when PLAYER_RANGER_DATA_RANGE
111
128
  data = msg.unpack("NNG*")
112
- @rangers = data[2..-1]
113
- debug "Get rangers #{@rangers.inspect}"
129
+ data[2..-1].each_with_index do |r, i|
130
+ self[i].state[:range] = r
131
+ end
132
+
133
+ debug "Get rangers #{@sensors.collect { |s| s.state[:range] }}"
114
134
  when PLAYER_RANGER_DATA_INTNS
115
135
  data = msg.unpack("NNG*")
116
- @intensities = data[2..-1]
117
- debug "Get intensities #{@rangers.inspect}"
136
+ data[2..-1].each_with_index do |ints, i|
137
+ self[i].state[:intensity] = ints
138
+ end
139
+
140
+ debug "Get intensities #{@sensors.collect { |s| s.state[:intensity]}}"
118
141
  when PLAYER_RANGER_DATA_GEOM
119
142
  read_geom(msg)
120
143
  else
@@ -135,6 +158,14 @@ module Player
135
158
  end
136
159
  end
137
160
 
161
+ def [](index)
162
+ @sensors[index] ||= Sensor.new(index, self)
163
+ end
164
+
165
+ def each
166
+ @sensors.each { |s| yield s }
167
+ end
168
+
138
169
  private
139
170
  def read_config(msg)
140
171
  fill_hash!(@config, msg.unpack("G*"))
@@ -143,7 +174,7 @@ module Player
143
174
  def read_geom(msg)
144
175
  data = msg[0,72].unpack("G*")
145
176
  fill_hash!(@geom, data)
146
- debug("Get geom: " + geom_to_s(@geom))
177
+ debug "Get geom: " + hash_to_sft(@geom)
147
178
 
148
179
 
149
180
  p_count = msg[72,8].unpack("NN")
@@ -155,21 +186,18 @@ module Player
155
186
  sizes = msg[88 + 48*p_count, 24*s_count].unpack("G" +(3* s_count).to_s)
156
187
 
157
188
  p_count.times do |i|
158
- @geom[:sensors][i] ||= {}
159
- [:px, :py, :pz, :proll, :ppitch, :pyaw].each_with_index do |k,j|
160
- @geom[:sensors][i][k] = poses[6*i + j]
161
- end
162
- debug("Get poses for ##{i} sensor: px=%.2f, py=%.2f, pz=%.2f, proll=%.2f, ppitch=%.2f, pyaw=%.2f" % @geom[:sensors][i].values[0,6])
189
+ [:px, :py, :pz, :proll, :ppitch, :pyaw]
190
+ .each_with_index { |k,j| self[i].geom[k] = poses[6*i + j] }
191
+ debug("Get poses for ##{i} sensor: px=%.2f, py=%.2f, pz=%.2f, proll=%.2f, ppitch=%.2f, pyaw=%.2f" % @sensors[i].geom.values[0,6])
163
192
  end
164
193
 
165
194
  s_count.times do |i|
166
- @geom[:sensors][i] ||= {}
167
- [:sw, :sl, :sh].each_with_index do |k,j|
168
- @geom[:sensors][i][k] = sizes[3*i + j]
169
- end
170
- debug("Get sizes for ##{i} sensor: sw=%.2f, sl=%.2f, sh=%.2f" % @geom[:sensors][i].values[6,3])
195
+ [:sw, :sl, :sh]
196
+ .each_with_index { |k,j| self[i].geom[k] = sizes[3*i + j] }
197
+ debug("Get sizes for ##{i} sensor: sw=%.2f, sl=%.2f, sh=%.2f" % @sensors[i].geom.values[6,3])
171
198
  end
172
199
 
173
200
  end
201
+
174
202
  end
175
203
  end
@@ -0,0 +1,43 @@
1
+ # Ruby Player - Ruby client library for Player (tools for robots)
2
+ #
3
+ # Copyright (C) 2012 Aleksey Timin
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ module Player
16
+ class Sensor
17
+
18
+ # State of sensor
19
+ # @return [Hash] { :range, :intensity }
20
+ attr_reader :state
21
+ attr_reader :geom
22
+
23
+ def initialize(index, ranger)
24
+ @index, @ranger = index, ranger
25
+ @state = { ranger: 0.0, intensity: 0.0 }
26
+ @geom = {px: 0.0, py: 0.0, pz: 0.0, proll: 0.0, ppitch: 0.0, pyaw: 0.0,
27
+ sw: 0.0, sl: 0.0, sh: 0.0
28
+ }
29
+ end
30
+
31
+ # Range data [m]
32
+ # @return [Float]
33
+ def range
34
+ @state[:range]
35
+ end
36
+
37
+ # Intensity data [m].
38
+ # @return [Float]
39
+ def intensity
40
+ @state[:intensity]
41
+ end
42
+ end
43
+ end
@@ -1,6 +1,6 @@
1
1
  # Ruby Player - Ruby client library for Player (tools for robots)
2
2
  #
3
- # Copyright (C) 2012 Timin Aleksey
3
+ # Copyright (C) 2012 Aleksey Timin
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -13,5 +13,5 @@
13
13
  # GNU General Public License for more details.
14
14
 
15
15
  module Player
16
- VERSION = "0.3.0"
16
+ VERSION = "0.4.0"
17
17
  end
@@ -0,0 +1,129 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ include Player
4
+ describe Player::ActArray do
5
+ before do
6
+ client = mock_client
7
+
8
+ @actarray = Player::ActArray.new(
9
+ Player::DevAddr.new(host: 0, robot:0, interface: PLAYER_ACTARRAY_CODE, index: 0),
10
+ client
11
+ )
12
+
13
+ mock_sending_message(@actarray)
14
+ end
15
+
16
+ it 'should have default state' do
17
+ @actarray.state.should eql(motor_state: 0)
18
+ @actarray.geom.should eql(px: 0.0, py: 0.0, pz: 0.0, proll: 0.0, ppitch: 0.0, pyaw: 0.0)
19
+ end
20
+
21
+ it 'should set power state for all actuators' do
22
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_POWER, [0].pack("N"))
23
+ @actarray.power_off!
24
+
25
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_POWER, [1].pack("N"))
26
+ @actarray.power_on!
27
+ end
28
+
29
+ it 'should set brakes state for all actuators' do
30
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_BRAKES, [0].pack("N"))
31
+ @actarray.brakes_off!
32
+
33
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_BRAKES, [1].pack("N"))
34
+ @actarray.brakes_on!
35
+ end
36
+
37
+ it 'should query geometry' do
38
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_GET_GEOM)
39
+ @actarray.query_geom
40
+ end
41
+
42
+
43
+ it 'should set position for all joints' do
44
+ data = [3, 1.0, 2.0, 3.0]
45
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_MULTI_POS, data.pack("Ng*"))
46
+ @actarray.set_positions(data[1..-1])
47
+ end
48
+
49
+ it 'should set speed for all joints' do
50
+ data = [2, 2.0, 3.0]
51
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_MULTI_SPEED, data.pack("Ng*"))
52
+ @actarray.set_speeds(data[1..-1])
53
+ end
54
+
55
+ it 'should tell all joint go to nome' do
56
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_HOME, [-1].pack("N"))
57
+ @actarray.go_home!
58
+ end
59
+
60
+
61
+ it 'should tell all joints to attempt to move with the given current.' do
62
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_CURRENT, [-1, 0.3].pack("Ng"))
63
+ @actarray.set_current_all(0.3)
64
+ end
65
+
66
+ it 'should tell a joint to attempt to move with the given current.' do
67
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_CURRENT, [0, 0.3].pack("Ng"))
68
+ @actarray[0].set_current(0.3)
69
+ end
70
+
71
+ it 'should set current for all joints' do
72
+ data = [2, 2.0, 3.0]
73
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_ACTARRAY_CMD_MULTI_CURRENT, data.pack("Ng*"))
74
+ @actarray.set_currents(data[1..-1])
75
+ end
76
+
77
+ it 'should implement Enumerable' do
78
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_ACCEL, [0, 0.3].pack("Ng"))
79
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_ACTARRAY_REQ_ACCEL, [1, 0.3].pack("Ng"))
80
+ @actarray[0].set_accel_config(0.3)
81
+ @actarray[1].set_accel_config(0.3)
82
+
83
+ @actarray.each_with_index { |a,i| a.joint.should eql(i) }
84
+ @actarray.count.should eql(2)
85
+ end
86
+
87
+ it 'should fill state data' do
88
+ state = [2, 0, 1.0, 2.0, 3.0, 4.0, PLAYER_ACTARRAY_ACTSTATE_IDLE,
89
+ 5.0, 6.0, 7.0, 8.0, PLAYER_ACTARRAY_ACTSTATE_MOVING,
90
+ 1]
91
+
92
+ msg = state.pack("NNg4Ng4NN")
93
+ @actarray.fill(
94
+ Player::Header.from_a([0,0,PLAYER_ACTARRAY_CODE,0, PLAYER_MSGTYPE_DATA, PLAYER_ACTARRAY_DATA_STATE, 0.0, 0, msg.bytesize]),
95
+ msg
96
+ )
97
+
98
+ @actarray[0].state.should eql(position: 1.0, speed: 2.0, acceleration: 3.0, current: 4.0, state: PLAYER_ACTARRAY_ACTSTATE_IDLE)
99
+ @actarray[1].state.should eql(position: 5.0, speed: 6.0, acceleration: 7.0, current: 8.0, state: PLAYER_ACTARRAY_ACTSTATE_MOVING)
100
+ @actarray.state[:motor_state].should eql(1)
101
+ end
102
+
103
+ it 'should get geom by request' do
104
+ geom = [2, 0,
105
+ PLAYER_ACTARRAY_TYPE_LINEAR, 2.0, 0.1, 0.2, 0.3, 1.0, 2.0, 3.0, 0.0, 0.5, 1.0, 0.0, 2.0, 0,
106
+ PLAYER_ACTARRAY_TYPE_ROTARY, 4.0, 1.1, 1.2, 1.3, 1.1, 2.1, 3.1, 0.0, 0.5, 1.0, 1.0, 1.0, 1,
107
+ 0.5, 0.6, 0.7, 1.5, 1.6, 1.7]
108
+
109
+ msg = geom.pack("NNNgG6g5NNgG6g5NG6")
110
+ @actarray.handle_response(
111
+ Player::Header.from_a([0,0,PLAYER_ACTARRAY_CODE,0, PLAYER_MSGTYPE_RESP_ACK, PLAYER_ACTARRAY_REQ_GET_GEOM, 0.0, 0, msg.bytesize]),
112
+ msg
113
+ )
114
+
115
+ @actarray[0].geom.should eql(type: PLAYER_ACTARRAY_TYPE_LINEAR, length: 2.0,
116
+ proll: 0.1, ppitch: 0.2, pyaw: 0.3,
117
+ px: 1.0, py: 2.0, pz: 3.0,
118
+ min: 0.0, centre: 0.5, max: 1.0, home: 0.0,
119
+ config_speed: 2.0, hasbreaks: 0)
120
+
121
+ @actarray[1].geom.should eql(type: PLAYER_ACTARRAY_TYPE_ROTARY, length: 4.0,
122
+ proll: 1.1, ppitch: 1.2, pyaw: 1.3,
123
+ px: 1.1, py: 2.1, pz: 3.1,
124
+ min: 0.0, centre: 0.5, max: 1.0, home: 1.0,
125
+ config_speed: 1.0, hasbreaks: 1)
126
+
127
+ @actarray.geom.should eql(px: 0.5, py: 0.6, pz: 0.7, proll: 1.5, ppitch: 1.6, pyaw: 1.7)
128
+ end
129
+ end