ruby-player 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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