ruby-player 0.0.1 → 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.
@@ -14,61 +14,80 @@
14
14
 
15
15
  module Player
16
16
  # The ranger proxy provides an interface to the ranger sensors built into robots
17
- class Ranger
18
- include CType
19
- include Common
20
-
21
- module C
22
- extend FFI::Library
23
- ffi_lib "playerc"
24
-
25
- attach_function :playerc_ranger_create, [:pointer, :int], :pointer
26
- attach_function :playerc_ranger_destroy, [:pointer], :void
27
- attach_function :playerc_ranger_subscribe, [:pointer, :int], :int
28
- attach_function :playerc_ranger_unsubscribe, [:pointer], :int
29
-
30
- attach_function :playerc_ranger_power_config, [:pointer, :uint8], :int
31
- attach_function :playerc_ranger_intns_config, [:pointer, :uint8], :int
32
- attach_function :playerc_ranger_set_config, [:pointer] + [:double] * 7, :int
33
- attach_function :playerc_ranger_get_config, [:pointer] + [:pointer] * 7, :int
34
- end
17
+ # TODO Implement PLAYER_RANGER_DATA_RANGESTAMPED and PLAYER_RANGER_DATA_INTNSTAMPED
18
+ #
19
+ # @example
20
+ # ranger = robot.subscribe(:ranger, index: 0)
21
+ # ranger.rangers #=> [0.2, 0.1, 0.2]
22
+ class Ranger < Device
35
23
 
36
- def initialize(client, index)
37
- @ranger = RangerStruct.new(C.playerc_ranger_create(client, index))
38
- try_with_error C.playerc_ranger_subscribe(@ranger, PLAYER_OPEN_MODE)
24
+ # Range data [m]
25
+ # @return [Array] fot each sensor
26
+ attr_reader :rangers
39
27
 
40
- ObjectSpace.define_finalizer(self, Ranger.finilazer(@ranger))
28
+ # Intensity data [m].
29
+ # @return [Array] fot each sensor
30
+ attr_reader :intensities
31
+
32
+ # Configuration of ranger
33
+ # @see set_config
34
+ attr_reader :config
35
+
36
+ def initialize(addr, client, log_level)
37
+ super
38
+ @rangers = []
39
+ @intensities = []
40
+ @geom[:sensors] = []
41
+ @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 }
42
+ end
43
+
44
+ # Query ranger geometry
45
+ # @return self
46
+ def query_geom
47
+ send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_GET_GEOM)
48
+ self
49
+ end
50
+
51
+ # Turn on ranger
52
+ # @return self
53
+ def turn_on!
54
+ send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_POWER, [1].pack("N"))
55
+ self
56
+ end
57
+
58
+ # Turn off ranger
59
+ def turn_off!
60
+ send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_POWER, [0].pack("N"))
61
+ self
41
62
  end
42
63
 
43
- # Count of sensors
44
- # Return [Integer] count
45
- def element_count
46
- @ranger[:element_count]
64
+ def intensity_enable!
65
+ send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_INTNS, [1].pack("N"))
66
+ self
47
67
  end
48
68
 
49
- # Power control
50
- # @param enable nil or false power off
51
- def power_enable=(enable)
52
- try_with_error C.playerc_ranger_power_config(@ranger, enable ? 1 : 0)
69
+ def intensity_disable!
70
+ send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_INTNS, [0].pack("N"))
71
+ self
53
72
  end
54
73
 
55
- # Enable intensity
56
- # @param enable nil or false disable
57
- def intensity_enable=(enable)
58
- try_with_error C.playerc_ranger_intns_config(@ranger, enable ? 1 : 0)
74
+ # Query ranger configuration
75
+ def query_config
76
+ send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_GET_CONFIG)
77
+ self
59
78
  end
60
79
 
61
80
  # Set config of ranger
62
81
  # @param [Hash] config params for setup
63
- # @option :min_angle start angle of scans [rad]
64
- # @option :max_angle end angle of scans
65
- # @option :angular_res scan resolution [rad]
66
- # @option :min_range maximum range [m]
67
- # @option :max_range minimum range [m]
68
- # @option :range_res range resolution [m]
69
- # @option :frequency scanning frequency [Hz]
82
+ # @option config :min_angle start angle of scans [rad]
83
+ # @option config :max_angle end angle of scans
84
+ # @option config :angular_res scan resolution [rad]
85
+ # @option config :min_range maximum range [m]
86
+ # @option config :max_range minimum range [m]
87
+ # @option config :range_res range resolution [m]
88
+ # @option config :frequency scanning frequency [Hz]
70
89
  def set_config(config)
71
- args = [
90
+ data = [
72
91
  config[:min_angle].to_f || @ranger[:min_angle],
73
92
  config[:max_angle].to_f || @ranger[:max_angle],
74
93
  config[:angular_res].to_f || @ranger[:angular_res],
@@ -78,59 +97,70 @@ module Player
78
97
  config[:frequecy].to_f || @ranger[:frequecy]
79
98
  ]
80
99
 
81
- try_with_error C.playerc_ranger_set_config(@ranger, *args)
100
+ send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_SET_CONFIG, data.pack("G*"))
82
101
  end
83
102
 
84
- # Configuration of ranger
85
- # @see set_config
86
- def config
87
- try_with_error C.playerc_ranger_get_config(@ranger, *([nil] * 7))
88
- {
89
- min_range: @ranger[:min_angle],
90
- max_range: @ranger[:max_angle],
91
- angular_res: @ranger[:angular_res],
92
- min_range: @ranger[:min_range],
93
- max_range: @ranger[:max_range],
94
- range_res: @ranger[:range_res],
95
- frequecy: @ranger[:frequecy]
96
- }
97
- end
98
-
99
- # Range data [m]
100
- # @return [Array] fot each sensor
101
- def ranges
102
- @ranger[:ranges].read_array_of_type(
103
- FFI::Type::DOUBLE,
104
- :read_double,
105
- @ranger[:ranges_count]
106
- )
103
+ def fill(hdr, msg)
104
+ case hdr.subtype
105
+ when PLAYER_RANGER_DATA_RANGE
106
+ data = msg.unpack("NNG*")
107
+ @rangers = data[2..-1]
108
+ debug "Get rangers #{@rangers.inspect}"
109
+ when PLAYER_RANGER_DATA_INTNS
110
+ data = msg.unpack("NNG*")
111
+ @intensities = data[2..-1]
112
+ debug "Get intensities #{@rangers.inspect}"
113
+ when PLAYER_RANGER_DATA_GEOM
114
+ read_geom(msg)
115
+ else
116
+ unexpected_message hdr
117
+ end
107
118
  end
108
119
 
109
- # Intensity data [m].
110
- # @return [Array] fot each sensor
111
- def intensities
112
- @ranger[:intensities].read_array_of_type(
113
- FFI::Type::DOUBLE,
114
- :read_double,
115
- @ranger[:intensities_count]
116
- )
120
+ def handle_response(hdr, msg)
121
+ case hdr.subtype
122
+ when PLAYER_RANGER_REQ_GET_GEOM
123
+ read_geom(msg)
124
+ when 2..4
125
+ nil
126
+ when PLAYER_RANGER_REQ_GET_CONFIG
127
+ data = msg.unpack("G*")
128
+ [:min_angle, :max_angle, :angular_res, :min_range, :max_range, :range_res, :frequecy].each_with_index do |k,i|
129
+ @config[k] = data[i]
130
+ end
131
+ else
132
+ unexpected_message hdr
133
+ end
117
134
  end
118
135
 
119
- # Scan bearings in the XY plane [radians].
120
- # @return [Array] fot each sensor
121
- def bearings
122
- @ranger[:bearings].read_array_of_type(
123
- FFI::Type::DOUBLE,
124
- :read_double,
125
- @ranger[:bearings_count]
126
- )
127
- end
136
+ private
137
+ def read_geom(msg)
138
+ super(msg[0,72])
139
+
140
+ p_count = msg[72,8].unpack("NN")
141
+ p_count = p_count[0] + p_count[1] * 256
142
+ poses = msg[80, 48*p_count].unpack("G" + (6*p_count).to_s)
143
+
144
+ s_count = msg[80 + 48*p_count, 8].unpack("NN")
145
+ s_count = s_count[0] + s_count[1] * 256
146
+ sizes = msg[88 + 48*p_count, 24*s_count].unpack("G" +(3* s_count).to_s)
147
+
148
+ p_count.times do |i|
149
+ @geom[:sensors][i] ||= {}
150
+ [:px, :py, :pz, :proll, :ppitch, :pyaw].each_with_index do |k,j|
151
+ @geom[:sensors][i][k] = poses[6*i + j]
152
+ end
153
+ debug("Get poses for ##{i} sensor: px=%.2f, py=%.2f, pz=%.2f, proll=%.2f, ppitch=%.2f, pyaw=%.2f" % @geom[:sensors][i].values[0,6])
154
+ end
155
+
156
+ s_count.times do |i|
157
+ @geom[:sensors][i] ||= {}
158
+ [:sw, :sl, :sh].each_with_index do |k,j|
159
+ @geom[:sensors][i][k] = sizes[3*i + j]
160
+ end
161
+ debug("Get sizes for ##{i} sensor: sw=%.2f, sl=%.2f, sh=%.2f" % @geom[:sensors][i].values[6,3])
162
+ end
128
163
 
129
- def Ranger.finilazer(ranger)
130
- lambda{
131
- try_with_error C.playerc_ranger_unsubscribe(pos)
132
- C.playerc_ranger_destroy(pos)
133
- }
134
164
  end
135
165
  end
136
166
  end
@@ -13,5 +13,5 @@
13
13
  # GNU General Public License for more details.
14
14
 
15
15
  module Player
16
- VERSION = "0.0.1"
16
+ VERSION = "0.1.0"
17
17
  end
data/ruby-player.gemspec CHANGED
@@ -18,10 +18,12 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.required_ruby_version = '>= 1.9.2'
20
20
 
21
- s.add_runtime_dependency "ffi", '~>1.0.0'
21
+ s.add_runtime_dependency "isna", '~>0.0.4'
22
+
22
23
  s.add_development_dependency "rspec", '~> 2.7'
23
24
  s.add_development_dependency "rake", '~> 0.9'
24
25
  s.add_development_dependency "pry"
25
26
  s.add_development_dependency "yard"
26
27
  s.add_development_dependency "redcarpet"
28
+ s.add_development_dependency 'guard-rspec'
27
29
  end
data/spec/client_spec.rb CHANGED
@@ -1,32 +1,166 @@
1
1
  require "ruby-player"
2
2
 
3
+ include Player
3
4
  describe Player::Client do
4
5
  before do
5
- @cl = Player::Client.new("localhost")
6
- end
6
+ @socket = mock("Socket")
7
+
8
+ TCPSocket.stub!(:new).with("localhost", 6665).and_return(@socket)
9
+ @socket.stub! :flush
10
+ Time.stub!(:now).and_return(0)
11
+
12
+ @socket.should_receive(:read).with(PLAYER_IDENT_STRLEN).and_return("Mock player for 3.1-svn")
13
+
14
+ should_send_message(
15
+ hdr(0,0,1,0, PLAYER_MSGTYPE_REQ,PLAYER_PLAYER_REQ_DATAMODE, 0.0, 0, 4),
16
+ [PLAYER_DATAMODE_PULL].pack("N")
17
+ )
7
18
 
8
- it "should raise error if connection doesn't success" do
9
- lambda{ Player::Client.new("localhost", 6666) }.should raise_error(StandardError,
10
- "connect call on [localhost:6666] failed with error [111:Connection refused]")
19
+ @cl = Player::Client.new("localhost", log_level: "debug")
11
20
  end
12
21
 
22
+ # it "should raise error if connection doesn't success" do
23
+ # lambda{ Player::Client.new(host: "localhost", post: 6666) }.should raise_error(StandardError,
24
+ # "connect call on [localhost:6666] failed with error [111:Connection refused]")
25
+ # end
26
+
13
27
  it "should have close method" do
28
+ @socket.should_receive(:closed?).and_return(false)
14
29
  @cl.closed?.should be_false
30
+
31
+ @socket.should_receive(:closed?).and_return(true)
32
+ @socket.should_receive(:close)
15
33
  @cl.close
16
34
  @cl.closed?.should be_true
17
35
  end
18
36
 
19
37
  it "should have block for connection" do
20
- @cl.close
38
+ @socket.stub!(:read)
39
+ @socket.stub!(:write)
40
+ @socket.should_receive(:closed?).and_return(false)
41
+ @socket.should_receive(:close)
42
+
21
43
  Player::Client.connect("localhost") do |cl|
22
- @cl = cl
23
- @cl.closed?.should be_false
44
+ cl.closed?.should be_false
24
45
  end
46
+ end
25
47
 
26
- @cl.closed?.should be_true
48
+ describe "Device manage" do
49
+ before do
50
+ #subscribe two position2d
51
+ should_request_data
52
+ should_read_message(
53
+ hdr(0, 0, PLAYER_PLAYER_CODE, 0, PLAYER_MSGTYPE_RESP_ACK, PLAYER_PLAYER_REQ_DEV, 0.0, 0, 35),
54
+ [0, 0, PLAYER_POSITION2D_CODE, 0, PLAYER_OPEN_MODE, 5, 5].pack("N*") + "mock"
55
+ )
56
+
57
+ @dev_1 = mock("dev_1")
58
+ @cl.should_receive(:make_device).and_return(@dev_1)
59
+ @dev_1.stub!(:addr).and_return(Player::DevAddr.decode([0, 6665, PLAYER_POSITION2D_CODE, 0].pack("N*")))
60
+
61
+ should_read_message(
62
+ hdr(0, 0, PLAYER_PLAYER_CODE, 0, PLAYER_MSGTYPE_RESP_ACK, PLAYER_PLAYER_REQ_DEV, 0.0, 0, 35),
63
+ [0, 0, PLAYER_POSITION2D_CODE, 1, PLAYER_OPEN_MODE, 5, 5].pack("N*") + "mock"
64
+ )
65
+
66
+ @dev_2 = mock("dev_2")
67
+ @dev_2.stub!(:addr).and_return(Player::DevAddr.decode([0, 6665, PLAYER_POSITION2D_CODE, 1].pack("N*")))
68
+ @cl.should_receive(:make_device).and_return(@dev_2)
69
+
70
+ should_recive_sync
71
+ @cl.read!
72
+ end
73
+
74
+ it "should read data and fill deivice" do
75
+ hdr, msg =
76
+ hdr(0, 6665, 4, 0, PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE, 0.0, 0, 52),
77
+ [0, 0, 0, 0, 0, 0, 0].pack("GGGGGGN")
78
+ should_request_data
79
+
80
+ should_read_message(hdr, msg)
81
+
82
+ should_recive_sync
83
+ @dev_1.should_receive(:fill).with(hdr, msg)
84
+
85
+ @cl.read!
86
+ end
87
+
88
+ it "should recive response and handle deivice" do
89
+ hdr, msg =
90
+ hdr(0, 6665, 4, 1, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_GET_GEOM, 0.0, 0, 72),
91
+ ([0.0]*9).pack("G*")
92
+
93
+ should_request_data
94
+
95
+ should_read_message(hdr, msg)
96
+
97
+ should_recive_sync
98
+ @dev_2.should_receive(:handle_response).with(hdr, msg)
99
+
100
+ @cl.read!
101
+ end
102
+ end
103
+
104
+ describe "Subscribe" do
105
+ def mock_subscribe(code, index=0)
106
+ should_send_message(
107
+ hdr(0, 0, 1, 0, PLAYER_MSGTYPE_REQ, PLAYER_PLAYER_REQ_DEV, 0.0, 0, 28),
108
+ [0, 0, code, index, PLAYER_OPEN_MODE, 0, 0].pack("N*")
109
+ )
110
+
111
+ should_request_data
112
+
113
+ should_read_message(
114
+ hdr(16777343, 6665, PLAYER_PLAYER_CODE, 0, PLAYER_MSGTYPE_RESP_ACK, PLAYER_PLAYER_REQ_DEV, 0.0, 0, 35),
115
+ [0, 6665, code, index, PLAYER_OPEN_MODE, 5, 5].pack("N*") + "mock"
116
+ )
117
+
118
+ should_recive_sync
119
+ end
120
+
121
+ it "should describe to position2d:0" do
122
+ mock_subscribe(PLAYER_POSITION2D_CODE)
123
+
124
+ pos2d = @cl.subscribe("position2d")
125
+ pos2d.addr.interface_name.should eql("position2d")
126
+ pos2d.addr.index.should eql(0)
127
+ end
128
+
129
+ it "should describe to ranger:1" do
130
+ mock_subscribe(PLAYER_RANGER_CODE, 1)
131
+
132
+ ranger = @cl.subscribe(:ranger, index: 1)
133
+ ranger.addr.interface_name.should eql("ranger")
134
+ ranger.addr.index.should eql(1)
135
+ end
136
+ end
137
+
138
+ private
139
+ def hdr(*ary)
140
+ Player::Header.from_a(ary)
141
+ end
142
+
143
+ def should_send_message(hdr, msg)
144
+ @socket.should_receive(:write).with(hdr.encode)
145
+ @socket.should_receive(:write).with(msg)
146
+ end
147
+
148
+ def should_read_message(hdr, msg)
149
+ @socket.should_receive(:read).with(PLAYERXDR_MSGHDR_SIZE).and_return(hdr.encode)
150
+ @socket.should_receive(:read).with(hdr.size).and_return(msg)
151
+ end
152
+
153
+ def should_request_data
154
+ should_send_message(
155
+ hdr(0, 0, 1, 0, PLAYER_MSGTYPE_REQ, PLAYER_PLAYER_REQ_DATA, 0.0, 0, 0),
156
+ ""
157
+ )
27
158
  end
28
159
 
29
- after do
30
- @cl.close unless @cl.closed?
160
+ def should_recive_sync
161
+ should_read_message(
162
+ hdr(0, 0, 1, 0, PLAYER_MSGTYPE_SYNCH, 0, 0.0, 0, 0),
163
+ ""
164
+ )
31
165
  end
32
166
  end
@@ -1,77 +1,146 @@
1
1
  require "ruby-player"
2
2
 
3
+ include Player
3
4
  describe Player::Position2d do
4
5
  before do
5
- @cl = Player::Client.connect("localhost")
6
- @pos2d = @cl[:position2d, 0]
7
- @pos2d.stop
8
- @cl.read
6
+ @client = mock("Client")
7
+ @client.stub!(:write)
8
+
9
+ @pos2d = Player::Position2d.new(
10
+ Player::DevAddr.new(host: 0, robot:0, interface: 4, index: 0),
11
+ @client,
12
+ :debug
13
+ )
14
+ end
15
+
16
+ it 'should have default values' do
17
+ @pos2d.position.should eql(px:0.0, py:0.0, pa:0.0, vx:0.0, vy:0.0, va:0.0, stall: 0)
18
+ @pos2d.geom.should eql(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)
19
+ end
20
+
21
+ it 'should query geometry' do
22
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_GET_GEOM)
23
+ @pos2d.query_geom
24
+ end
25
+
26
+ it 'should set motor power state' do
27
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, [0].pack("N"))
28
+ @pos2d.turn_off!
29
+
30
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_MOTOR_POWER, [1].pack("N"))
31
+ @pos2d.turn_on!
32
+ end
33
+
34
+ it 'should set velocity mode' do
35
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, [1].pack("N"))
36
+ @pos2d.separate_speed_control!
37
+
38
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_VELOCITY_MODE, [0].pack("N"))
39
+ @pos2d.direct_speed_control!
40
+ end
41
+
42
+ it 'should set control mode' do
43
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_POSITION_MODE, [1].pack("N"))
44
+ @pos2d.speed_control!
45
+
46
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_POSITION_MODE, [0].pack("N"))
47
+ @pos2d.position_control!
9
48
  end
10
49
 
11
50
  it 'should set odometry' do
12
- pending "Don't work with Player/Stage"
13
51
  new_od = { px: 1.0, py: 2.0, pa: 3 }
52
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SET_ODOM, new_od.values.pack("GGG"))
14
53
  @pos2d.set_odometry(new_od)
54
+ end
55
+
56
+ it 'should reset odometry' do
57
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_RESET_ODOM)
15
58
  @pos2d.reset_odometry
16
-
17
- sleep(1.0)
18
- @cl.read
59
+ end
19
60
 
20
- @pos2d.odometry.should eql(new_od)
61
+ it 'should set PID params for speed' do
62
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SPEED_PID, [1, 2, 3].pack("GGG"))
63
+ @pos2d.set_speed_pid(kp: 1, ki: 2, kd: 3)
21
64
  end
22
65
 
23
- it 'should move' do
24
- pos = @pos2d.odometry
25
- speed = {vx: -0.4, vy: 0.2, va: -0.1 }
26
- @pos2d.set_speed(speed)
66
+ it 'should set PID params for position' do
67
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_POSITION_PID, [1, 2, 3].pack("GGG"))
68
+ @pos2d.set_position_pid(kp: 1, ki: 2, kd: 3)
69
+ end
70
+
71
+ it 'should set speed profile parameters' do
72
+ should_send_message(PLAYER_MSGTYPE_REQ, PLAYER_POSITION2D_REQ_SPEED_PROF, [1, 2].pack("GG"))
73
+ @pos2d.set_speed_profile(speed: 1, acc: 2)
74
+ end
75
+
76
+ it 'should fill position data' do
77
+ pos = {
78
+ px: 0.0, py: 1.0, pa: 2.0,
79
+ vx: 3.0, vy: 4.0, va: 5.0,
80
+ stall: 1
81
+ }
82
+ @pos2d.fill(
83
+ Player::Header.from_a([0,0,4,0, PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_STATE, 0.0, 0, 52]),
84
+ pos.values.pack("GGGGGGN")
85
+ )
86
+ @pos2d.position.should eql(pos)
87
+ end
27
88
 
28
- sleep(1.1)
29
- @cl.read
30
- @pos2d.speed.should eq(speed)
89
+ it 'should fill geom data' do
90
+ geom = {px: 1.0, py: 2.0, pz: 3.0, proll: 4.0, ppitch: 5.0, pyaw: 6.0, sw: 7.0, sl: 8.0, sh: 9.0}
91
+ @pos2d.fill(
92
+ Player::Header.from_a([0,0,4,0, PLAYER_MSGTYPE_DATA, PLAYER_POSITION2D_DATA_GEOM, 0.0, 0, 72]),
93
+ geom.values.pack("G*")
94
+ )
95
+ @pos2d.geom.should eql(geom)
96
+ end
31
97
 
32
- #change position
33
- @pos2d.odometry[:px].should be_within(0.1).of(pos[:px] + speed[:vx]*Math.cos(pos[:pa]) - speed[:vy]*Math.sin(pos[:pa]))
34
- @pos2d.odometry[:py].should be_within(0.1).of(pos[:py] + speed[:vx]*Math.sin(pos[:pa]) + speed[:vy]*Math.cos(pos[:pa]))
35
- Math.sin(@pos2d.odometry[:pa]).should be_within(0.1).of(Math.sin(pos[:pa] + speed[:va]))
98
+ it 'should get geom by request' do
99
+ geom = {px: 1.0, py: 2.0, pz: 3.0, proll: 4.0, ppitch: 5.0, pyaw: 6.0, sw: 7.0, sl: 8.0, sh: 9.0}
100
+ @pos2d.handle_response(
101
+ Player::Header.from_a([0,0,4,0, PLAYER_MSGTYPE_RESP_ACK, PLAYER_POSITION2D_REQ_GET_GEOM, 0.0, 0, 72]),
102
+ geom.values.pack("G*")
103
+ )
104
+ @pos2d.geom.should eql(geom)
36
105
  end
37
106
 
107
+ it 'should set speed' do
108
+ speed = {vx: -0.4, vy: 0.2, va: -0.1, stall: 1 }
109
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL, speed.values.pack("GGGN"))
38
110
 
39
- it 'should move like car' do
40
- pos = @pos2d.odometry
111
+ @pos2d.set_speed(speed)
112
+ end
113
+
114
+ it 'should set speed like car' do
41
115
  speed = { vx: 0.4, a: 0.3 }
116
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_CAR, speed.values.pack("GG"))
117
+
42
118
  @pos2d.set_car(speed)
119
+ end
43
120
 
44
- sleep(1.1)
45
- @cl.read
46
- @pos2d.speed.should eq(vx: 0.4, vy: 0.0, va: 0.3)
121
+ it 'should set speed head' do
122
+ speed = { vx: 0.4, a: 0.3 }
123
+ should_send_message(PLAYER_MSGTYPE_CMD, PLAYER_POSITION2D_CMD_VEL_HEAD, speed.values.pack("GG"))
47
124
 
48
- #change position
49
- @pos2d.odometry[:px].should be_within(0.1).of(pos[:px] + speed[:vx]*Math.cos(pos[:pa]))
50
- @pos2d.odometry[:py].should be_within(0.1).of(pos[:py] + speed[:vx]*Math.sin(pos[:pa]))
51
- Math.sin(@pos2d.odometry[:pa]).should be_within(0.1).of(Math.sin(pos[:pa] + speed[:a]))
125
+ @pos2d.set_speed_head(speed)
52
126
  end
53
127
 
54
128
  it 'should have stop' do
55
- # Move robot
56
- @pos2d.set_speed(vx: 1.0, vy: 0.5, va: -0.2)
57
- @cl.read
58
- @pos2d.speed.should eql(vx: 1.0, vy: 0.5, va: -0.2)
59
- @pos2d.stoped?.should be_false
60
-
61
- # Stop robot
62
- @pos2d.stop
63
- @cl.read
64
- @pos2d.speed.should eql(vx: 0.0, vy: 0.0, va: 0.0)
65
- @pos2d.stoped?.should be_true
129
+ @pos2d.should_receive(:set_speed).with(vx: 0, vy: 0, va: 0)
130
+ @pos2d.stop!
66
131
  end
67
132
 
68
- it 'should turn on motor' do
69
- pending "Don't work with Player/Stage"
70
- @pos2d.enable.should be_false
71
- @pos2d.enable = true
133
+ it 'should not puts warn message for ACK subtypes 2..9' do
134
+ @pos2d.should_not_receive(:unexpected_message)
135
+ (2..9).each do |i|
136
+ @pos2d.handle_response(
137
+ Player::Header.from_a([0,0,4,0, PLAYER_MSGTYPE_RESP_ACK, i, 0.0, 0, 0]),
138
+ "")
139
+ end
72
140
  end
73
141
 
74
- after do
75
- @cl.close unless @cl.closed?
142
+ def should_send_message(*args)
143
+ @pos2d.should_receive(:send_message)
144
+ .with(*args)
76
145
  end
77
146
  end