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.
- 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
|