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.
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/Guardfile +5 -0
- data/README.md +10 -17
- data/TODO.md +1 -12
- data/examples/simple_example.rb +27 -0
- data/{spec → examples}/world/test.cfg +0 -0
- data/{spec → examples}/world/test.world +5 -5
- data/lib/ruby-player.rb +12 -5
- data/lib/ruby-player/client.rb +136 -42
- data/lib/ruby-player/common.rb +44 -7
- data/lib/ruby-player/constants.rb +584 -0
- data/lib/ruby-player/dev_addr.rb +59 -0
- data/lib/ruby-player/device.rb +60 -0
- data/lib/ruby-player/header.rb +81 -0
- data/lib/ruby-player/position2d.rb +161 -91
- data/lib/ruby-player/ranger.rb +118 -88
- data/lib/ruby-player/version.rb +1 -1
- data/ruby-player.gemspec +3 -1
- data/spec/client_spec.rb +145 -11
- data/spec/position2d_spec.rb +115 -46
- data/spec/ranger_spec.rb +132 -41
- metadata +36 -28
- data/lib/ruby-player/c_type.rb +0 -36
- data/lib/ruby-player/c_type/bbox3d_t.rb +0 -24
- data/lib/ruby-player/c_type/client_t.rb +0 -36
- data/lib/ruby-player/c_type/devaddr.rb +0 -24
- data/lib/ruby-player/c_type/device_t.rb +0 -35
- data/lib/ruby-player/c_type/diagnostic.rb +0 -22
- data/lib/ruby-player/c_type/pose3d_t.rb +0 -27
- data/lib/ruby-player/c_type/position2d_t.rb +0 -32
- data/lib/ruby-player/c_type/ranger_t.rb +0 -42
- data/lib/ruby-player/c_type/sockaddr_in_t.rb +0 -24
data/lib/ruby-player/ranger.rb
CHANGED
@@ -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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
24
|
+
# Range data [m]
|
25
|
+
# @return [Array] fot each sensor
|
26
|
+
attr_reader :rangers
|
39
27
|
|
40
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
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
|
-
|
100
|
+
send_message(PLAYER_MSGTYPE_REQ, PLAYER_RANGER_REQ_SET_CONFIG, data.pack("G*"))
|
82
101
|
end
|
83
102
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
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
|
data/lib/ruby-player/version.rb
CHANGED
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 "
|
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
|
-
@
|
6
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
23
|
-
@cl.closed?.should be_false
|
44
|
+
cl.closed?.should be_false
|
24
45
|
end
|
46
|
+
end
|
25
47
|
|
26
|
-
|
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
|
-
|
30
|
-
|
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
|
data/spec/position2d_spec.rb
CHANGED
@@ -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
|
-
@
|
6
|
-
@
|
7
|
-
|
8
|
-
@
|
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
|
-
|
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
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
29
|
-
|
30
|
-
@pos2d.
|
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
|
-
|
33
|
-
|
34
|
-
@pos2d.
|
35
|
-
|
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
|
-
|
40
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
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
|
-
|
56
|
-
@pos2d.
|
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
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
75
|
-
@
|
142
|
+
def should_send_message(*args)
|
143
|
+
@pos2d.should_receive(:send_message)
|
144
|
+
.with(*args)
|
76
145
|
end
|
77
146
|
end
|