rosruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/rubyroscore +5 -0
- data/lib/ros.rb +25 -0
- data/lib/ros/duration.rb +63 -0
- data/lib/ros/graph_manager.rb +408 -0
- data/lib/ros/log.rb +72 -0
- data/lib/ros/master.rb +408 -0
- data/lib/ros/master_proxy.rb +256 -0
- data/lib/ros/message.rb +65 -0
- data/lib/ros/name.rb +88 -0
- data/lib/ros/node.rb +442 -0
- data/lib/ros/package.rb +144 -0
- data/lib/ros/parameter_manager.rb +127 -0
- data/lib/ros/parameter_subscriber.rb +47 -0
- data/lib/ros/publisher.rb +96 -0
- data/lib/ros/rate.rb +41 -0
- data/lib/ros/ros.rb +10 -0
- data/lib/ros/roscore.rb +29 -0
- data/lib/ros/service.rb +37 -0
- data/lib/ros/service_client.rb +83 -0
- data/lib/ros/service_server.rb +92 -0
- data/lib/ros/slave_proxy.rb +153 -0
- data/lib/ros/subscriber.rb +119 -0
- data/lib/ros/tcpros/client.rb +108 -0
- data/lib/ros/tcpros/header.rb +89 -0
- data/lib/ros/tcpros/message.rb +74 -0
- data/lib/ros/tcpros/server.rb +137 -0
- data/lib/ros/tcpros/service_client.rb +104 -0
- data/lib/ros/tcpros/service_server.rb +132 -0
- data/lib/ros/time.rb +109 -0
- data/lib/ros/topic.rb +47 -0
- data/lib/ros/xmlrpcserver.rb +40 -0
- data/samples/add_two_ints_client.rb +25 -0
- data/samples/add_two_ints_server.rb +20 -0
- data/samples/gui.rb +126 -0
- data/samples/sample_log.rb +16 -0
- data/samples/sample_param.rb +20 -0
- data/samples/sample_publisher.rb +20 -0
- data/samples/sample_subscriber.rb +19 -0
- data/scripts/genmsg_ruby.py +1135 -0
- data/scripts/genmsg_ruby.pyc +0 -0
- data/scripts/gensrv_ruby.py +105 -0
- data/scripts/gensrv_ruby.pyc +0 -0
- data/scripts/rosruby_genmsg.py +67 -0
- data/scripts/run-test.rb +21 -0
- data/test/test_header.rb +36 -0
- data/test/test_log.rb +45 -0
- data/test/test_master_proxy.rb +73 -0
- data/test/test_message.rb +13 -0
- data/test/test_node.rb +166 -0
- data/test/test_package.rb +10 -0
- data/test/test_param.rb +27 -0
- data/test/test_pubsub.rb +154 -0
- data/test/test_rate.rb +16 -0
- data/test/test_service.rb +34 -0
- data/test/test_slave_proxy.rb +49 -0
- data/test/test_time.rb +39 -0
- metadata +170 -0
data/lib/ros/log.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# ros/log.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
# == Logger for ROS
|
8
|
+
#
|
9
|
+
# creates /rosout publisher and combine Ruby Logger
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'ros'
|
13
|
+
require 'rosgraph_msgs/Log'
|
14
|
+
require 'logger'
|
15
|
+
|
16
|
+
module ROS
|
17
|
+
|
18
|
+
# == Logging class for ROS
|
19
|
+
# This class enable double logging: ROS Logging system and ruby log.
|
20
|
+
class Log
|
21
|
+
|
22
|
+
# topic name of rosout
|
23
|
+
ROSOUT_TOPIC='/rosout'
|
24
|
+
|
25
|
+
##
|
26
|
+
# start publishing /rosout and
|
27
|
+
# make a ruby logger instance for local output
|
28
|
+
# @param [Node] node {Node} instance
|
29
|
+
# @param [IO] output local output. $stdout is default
|
30
|
+
def initialize(node, output=$stdout)
|
31
|
+
@node = node
|
32
|
+
@rosout = @node.advertise(ROSOUT_TOPIC, Rosgraph_msgs::Log,
|
33
|
+
:no_resolve=>true)
|
34
|
+
@ruby_dict = {'FATAL'=>Logger::FATAL,
|
35
|
+
'ERROR'=>Logger::ERROR,
|
36
|
+
'WARN'=>Logger::WARN,
|
37
|
+
'INFO'=>Logger::INFO,
|
38
|
+
'DEBUG'=>Logger::DEBUG}
|
39
|
+
@msg_dict = {'FATAL'=>::Rosgraph_msgs::Log::FATAL,
|
40
|
+
'ERROR'=>::Rosgraph_msgs::Log::ERROR,
|
41
|
+
'WARN'=>::Rosgraph_msgs::Log::WARN,
|
42
|
+
'INFO'=>::Rosgraph_msgs::Log::INFO,
|
43
|
+
'DEBUG'=>::Rosgraph_msgs::Log::DEBUG}
|
44
|
+
@local_logger = Logger.new(output)
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# outputs log messages with level and informations which
|
49
|
+
# rosout needs.
|
50
|
+
# @param [String] severity log level: one of 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'
|
51
|
+
# @param [String] message your message
|
52
|
+
# @param [String] file file name in which called this method
|
53
|
+
# @param [String] function function name in which called this method
|
54
|
+
# @param [Integer] line line number in which called this method
|
55
|
+
# @return [Log] self
|
56
|
+
def log(severity, message, file='', function='', line=0)
|
57
|
+
@local_logger.log(@ruby_dict[severity], message, @node.node_name)
|
58
|
+
msg = Rosgraph_msgs::Log.new
|
59
|
+
msg.msg = message
|
60
|
+
msg.header.stamp = ::ROS::Time.now
|
61
|
+
msg.header.frame_id = 'rosout'
|
62
|
+
msg.level = @msg_dict[severity]
|
63
|
+
msg.name = @node.node_name
|
64
|
+
msg.file = file
|
65
|
+
msg.function = function
|
66
|
+
msg.line = line
|
67
|
+
msg.topics = @node.get_published_topics
|
68
|
+
@rosout.publish(msg)
|
69
|
+
self
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/ros/master.rb
ADDED
@@ -0,0 +1,408 @@
|
|
1
|
+
# ros/master.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# == ruby ROS Master
|
9
|
+
#
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'xmlrpc/client'
|
13
|
+
require 'ros/xmlrpcserver'
|
14
|
+
require 'ros/name'
|
15
|
+
require 'ros/slave_proxy'
|
16
|
+
|
17
|
+
module ROS
|
18
|
+
|
19
|
+
# ROS Master
|
20
|
+
# @see http://ros.org/wiki/ROS/Master_API
|
21
|
+
#
|
22
|
+
class Master
|
23
|
+
|
24
|
+
include Name
|
25
|
+
|
26
|
+
# ROS parameter
|
27
|
+
class Parameter
|
28
|
+
|
29
|
+
# @param [String] key parameter key string
|
30
|
+
# @param [Object] value parameter value for key
|
31
|
+
def initialize(key, value)
|
32
|
+
@key = key
|
33
|
+
@value = value
|
34
|
+
end
|
35
|
+
attr_accessor :key
|
36
|
+
attr_accessor :value
|
37
|
+
end
|
38
|
+
|
39
|
+
# parameter subscriber
|
40
|
+
class ParameterSubscriber
|
41
|
+
|
42
|
+
# @param [String] caller_id caller_id of subscriber node
|
43
|
+
# @param [String] api XMLRPC URI of subscriber
|
44
|
+
# @param [String] key key for parameter
|
45
|
+
def initialize(caller_id, api, key)
|
46
|
+
@caller_id = caller_id
|
47
|
+
@api = api
|
48
|
+
@key = key
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_accessor :caller_id
|
52
|
+
attr_accessor :key
|
53
|
+
attr_accessor :api
|
54
|
+
end
|
55
|
+
|
56
|
+
# service server
|
57
|
+
class ServiceServer
|
58
|
+
|
59
|
+
# @param [String] caller_id caller_id of service server
|
60
|
+
# @param [String] service_name name of service
|
61
|
+
# @param [String] api XMLRPC URI of service server node
|
62
|
+
# @param [String] service_api Service URI
|
63
|
+
def initialize(caller_id, service_name, api, service_api)
|
64
|
+
@caller_id = caller_id
|
65
|
+
@name = service_name
|
66
|
+
@api = api
|
67
|
+
@service_api = service_api
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_accessor :caller_id
|
71
|
+
attr_accessor :name
|
72
|
+
attr_accessor :service_api
|
73
|
+
attr_accessor :api
|
74
|
+
end
|
75
|
+
|
76
|
+
# subscriber of topic
|
77
|
+
class Subscriber
|
78
|
+
|
79
|
+
# @param [String] caller_id caller_id of subscriber node
|
80
|
+
# @param [String] topic_name name of topic
|
81
|
+
# @param [String] api XMLRPC URI of subscriber node
|
82
|
+
def initialize(caller_id, topic_name, topic_type, api)
|
83
|
+
@caller_id = caller_id
|
84
|
+
@name = topic_name
|
85
|
+
@type = topic_type
|
86
|
+
@api = api
|
87
|
+
end
|
88
|
+
|
89
|
+
attr_accessor :caller_id
|
90
|
+
attr_accessor :name
|
91
|
+
attr_accessor :type
|
92
|
+
attr_accessor :api
|
93
|
+
end
|
94
|
+
|
95
|
+
class Publisher
|
96
|
+
# @param [String] caller_id caller_id of publisher node
|
97
|
+
# @param [String] topic_name name of topic
|
98
|
+
# @param [String] api XMLRPC URI of publisher node
|
99
|
+
def initialize(caller_id, topic_name, topic_type, api)
|
100
|
+
@caller_id = caller_id
|
101
|
+
@name = topic_name
|
102
|
+
@type = topic_type
|
103
|
+
@api = api
|
104
|
+
end
|
105
|
+
|
106
|
+
attr_accessor :caller_id
|
107
|
+
attr_accessor :name
|
108
|
+
attr_accessor :type
|
109
|
+
attr_accessor :api
|
110
|
+
end
|
111
|
+
|
112
|
+
# kill old node if the same caller_id node is exits.
|
113
|
+
# @param [String] caller_id new node's caller_id
|
114
|
+
# @param [String] api new node's XMLRPC URI
|
115
|
+
def kill_same_name_node(caller_id, api)
|
116
|
+
delete_api = nil
|
117
|
+
[@publishers, @subscribers, @services].each do |list|
|
118
|
+
list.each do |pub|
|
119
|
+
if pub.caller_id == caller_id and pub.api != api
|
120
|
+
delete_api = pub.api
|
121
|
+
break
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
if delete_api
|
126
|
+
proxy = SlaveProxy.new('/master', delete_api)
|
127
|
+
begin
|
128
|
+
proxy.shutdown("registered new node #{delete_api}")
|
129
|
+
rescue
|
130
|
+
end
|
131
|
+
# delete
|
132
|
+
[@publishers, @subscribers, @services].each do |list|
|
133
|
+
list.delete_if {|x| x.api == delete_api}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# @param [String] master_uri uri of master
|
139
|
+
def initialize(master_uri=ENV['ROS_MASTER_URI'])
|
140
|
+
@master_uri = master_uri
|
141
|
+
uri = URI.parse(@master_uri)
|
142
|
+
@services = []
|
143
|
+
@publishers = []
|
144
|
+
@subscribers = []
|
145
|
+
@parameters = []
|
146
|
+
@param_subscribers = []
|
147
|
+
@server = XMLRPCServer.new(uri.port, uri.host)
|
148
|
+
|
149
|
+
@server.set_default_handler do |method, *args|
|
150
|
+
puts "unhandled call with #{method}, #{args}"
|
151
|
+
[0, "I DON'T KNOW", 0]
|
152
|
+
end
|
153
|
+
|
154
|
+
@server.add_handler('registerService') do |caller_id, service_name, service_api, caller_api|
|
155
|
+
service_name = canonicalize_name(service_name)
|
156
|
+
kill_same_name_node(caller_id, caller_api)
|
157
|
+
@services.push(ServiceServer.new(caller_id, service_name, caller_api, service_api))
|
158
|
+
[1, "registered", 0]
|
159
|
+
end
|
160
|
+
|
161
|
+
@server.add_handler('unregisterService') do |caller_id, service_name, service_api|
|
162
|
+
service_name = canonicalize_name(service_name)
|
163
|
+
before = @services.length
|
164
|
+
@services.delete_if {|x| x.name == service_name and x.caller_id == caller_id}
|
165
|
+
after = @services.length
|
166
|
+
[1, "deleted", before - after]
|
167
|
+
end
|
168
|
+
|
169
|
+
@server.add_handler('registerSubscriber') do |caller_id, topic_name, type, api|
|
170
|
+
topic_name = canonicalize_name(topic_name)
|
171
|
+
kill_same_name_node(caller_id, api)
|
172
|
+
@subscribers.push(Subscriber.new(caller_id, topic_name, type, api))
|
173
|
+
pub_apis = @publishers.select {|x|x.name == topic_name and x.type == type}.map {|x| x.api }
|
174
|
+
[1, "registered", pub_apis]
|
175
|
+
end
|
176
|
+
|
177
|
+
@server.add_handler('unregisterSubscriber') do |caller_id, topic_name, api|
|
178
|
+
topic_name = canonicalize_name(topic_name)
|
179
|
+
before = @subscribers.length
|
180
|
+
@subscribers.delete_if {|x| x.name == topic_name and x.caller_id == caller_id}
|
181
|
+
after = @subscribers.length
|
182
|
+
[1, "deleted", before - after]
|
183
|
+
end
|
184
|
+
|
185
|
+
@server.add_handler('registerPublisher') do |caller_id, topic_name, type, api|
|
186
|
+
topic_name = canonicalize_name(topic_name)
|
187
|
+
kill_same_name_node(caller_id, api)
|
188
|
+
@publishers.push(Publisher.new(caller_id, topic_name, type, api))
|
189
|
+
sub_apis = @subscribers.select {|x|x.name == topic_name and x.type == type}.map {|x| x.api }
|
190
|
+
pub_apis = @publishers.select {|x|x.name == topic_name and x.type == type}.map {|x| x.api }
|
191
|
+
proxy = SlaveProxy.new('/master', api)
|
192
|
+
begin
|
193
|
+
proxy.publisher_update(topic_name, pub_apis)
|
194
|
+
rescue
|
195
|
+
end
|
196
|
+
if not sub_apis
|
197
|
+
sub_apis = []
|
198
|
+
end
|
199
|
+
[1, "registered", sub_apis]
|
200
|
+
end
|
201
|
+
|
202
|
+
@server.add_handler('unregisterPublisher') do |caller_id, topic_name, api|
|
203
|
+
topic_name = canonicalize_name(topic_name)
|
204
|
+
before = @publishers.length
|
205
|
+
@publishers.delete_if {|x| x.name == topic_name and x.caller_id == caller_id}
|
206
|
+
pub_apis = @publishers.select {|x|x.name == topic_name and x.caller_id == caller_id}.map {|x| x.api }
|
207
|
+
proxy = SlaveProxy.new('/master', api)
|
208
|
+
begin
|
209
|
+
code, status, ignore = proxy.publisher_update(topic_name, pub_apis)
|
210
|
+
rescue
|
211
|
+
#
|
212
|
+
end
|
213
|
+
after = @publishers.length
|
214
|
+
[1, "deleted", before - after]
|
215
|
+
end
|
216
|
+
|
217
|
+
@server.add_handler('getPid') do |caller_id|
|
218
|
+
[1, "ok", $$]
|
219
|
+
end
|
220
|
+
|
221
|
+
@server.add_handler('lookupNode') do |caller_id, node_name|
|
222
|
+
pub = @publishers.select {|x| x.caller_id == node_name}
|
223
|
+
sub = @subscribers.select {|x| x.caller_id == node_name}
|
224
|
+
service = @services.select {|x| x.caller_id == node_name}
|
225
|
+
if not pub.empty?
|
226
|
+
[1, "found", pub.first.api]
|
227
|
+
elsif not sub.empty?
|
228
|
+
[1, "found", sub.first.api]
|
229
|
+
elsif not service.empty?
|
230
|
+
[1, "found", service.first.api]
|
231
|
+
else
|
232
|
+
[0, "not found", 0]
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
@server.add_handler('getPublishedTopics') do |caller_id, subgraph|
|
237
|
+
if subgraph == ''
|
238
|
+
[1, "ok", @publishers.map {|x| [x.name, x.type]}]
|
239
|
+
else
|
240
|
+
[1, "ok", @publishers.select {|x| not x.caller_id.scan(/^#{subgraph}/).empty?}
|
241
|
+
.map {|x| [x.name, x.type]}]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
@server.add_handler('getSystemState') do |caller_id|
|
246
|
+
def convert_info_to_list(info)
|
247
|
+
list = []
|
248
|
+
info.keys.each do |key|
|
249
|
+
list.push([key, info[key]])
|
250
|
+
end
|
251
|
+
list
|
252
|
+
end
|
253
|
+
|
254
|
+
pub_info = {}
|
255
|
+
@publishers.each do |pub|
|
256
|
+
if pub_info[pub.name]
|
257
|
+
pub_info[pub.name].push(pub.caller_id)
|
258
|
+
else
|
259
|
+
pub_info[pub.name]= [pub.caller_id]
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
sub_info = {}
|
264
|
+
@subscribers.each do |sub|
|
265
|
+
if sub_info[sub.name]
|
266
|
+
sub_info[sub.name].push(sub.caller_id)
|
267
|
+
else
|
268
|
+
sub_info[sub.name]= [sub.caller_id]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
ser_info = {}
|
273
|
+
@services.each do |ser|
|
274
|
+
if ser_info[ser.name]
|
275
|
+
ser_info[ser.name].push(ser.caller_id)
|
276
|
+
else
|
277
|
+
ser_info[ser.name]= [ser.caller_id]
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
[1, "ok", [convert_info_to_list(pub_info),
|
282
|
+
convert_info_to_list(sub_info),
|
283
|
+
convert_info_to_list(ser_info)]]
|
284
|
+
end
|
285
|
+
|
286
|
+
@server.add_handler('getUri') do |caller_id|
|
287
|
+
[1, "ok", @master_uri]
|
288
|
+
end
|
289
|
+
|
290
|
+
@server.add_handler('lookupService') do |caller_id, service|
|
291
|
+
ser = @services.select {|x| x.name == service}
|
292
|
+
if ser.empty?
|
293
|
+
[0, "fail", 0]
|
294
|
+
else
|
295
|
+
[1, "ok", ser.first.service_api]
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
## parameters
|
300
|
+
@server.add_handler('deleteParam') do |caller_id, key|
|
301
|
+
key = canonicalize_name(key)
|
302
|
+
before = @parameters.length
|
303
|
+
@parameters.delete_if {|x| x.key == key}
|
304
|
+
after = @parameters.length
|
305
|
+
|
306
|
+
if before == after
|
307
|
+
[0, "[#{key}] is not exists", 0]
|
308
|
+
else
|
309
|
+
[1, "ok", 0]
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
@server.add_handler('setParam') do |caller_id, key, value|
|
314
|
+
key = canonicalize_name(key)
|
315
|
+
exist_param = @parameters.select {|x| x.key == key}
|
316
|
+
if exist_param.empty?
|
317
|
+
@parameters.push(Parameter.new(key, value))
|
318
|
+
else
|
319
|
+
exist_param.first.value = value
|
320
|
+
end
|
321
|
+
@param_subscribers.each do |x|
|
322
|
+
if x.key == key
|
323
|
+
begin
|
324
|
+
proxy = SlaveProxy.new('/master', x.api)
|
325
|
+
proxy.param_update(key, value)
|
326
|
+
rescue
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
[1, "ok", 0]
|
331
|
+
end
|
332
|
+
|
333
|
+
@server.add_handler('getParam') do |caller_id, key|
|
334
|
+
key = canonicalize_name(key)
|
335
|
+
param = @parameters.select {|x| x.key == key}
|
336
|
+
if param.empty?
|
337
|
+
[0, "no such param [#{key}]", 0]
|
338
|
+
else
|
339
|
+
[1, "ok", param.first.value]
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
@server.add_handler('searchParam') do |caller_id, key|
|
344
|
+
key = canonicalize_name(key)
|
345
|
+
if key == ''
|
346
|
+
param = @parameters
|
347
|
+
else
|
348
|
+
param = @parameters.select {|x| not x.key.scan(/#{key}/).empty?}
|
349
|
+
end
|
350
|
+
if param.empty?
|
351
|
+
[-1, "no param", 0]
|
352
|
+
else
|
353
|
+
[1, "ok", param.first.key]
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
@server.add_handler('subscribeParam') do |caller_id, caller_api, key|
|
358
|
+
key = canonicalize_name(key)
|
359
|
+
@param_subscribers.push(ParameterSubscriber.new(caller_id, caller_api, key))
|
360
|
+
params = @parameters.select {|x| x.key == key}
|
361
|
+
if params.empty?
|
362
|
+
[1, "ok", []]
|
363
|
+
else
|
364
|
+
[1, "ok", params.map {|x| x.value}]
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
@server.add_handler('unsubscribeParam') do |caller_id, caller_api, key|
|
369
|
+
key = canonicalize_name(key)
|
370
|
+
before = @param_subscribers.length
|
371
|
+
@param_subscribers.delete_if {|x| x.api == caller_api and x.key == key}
|
372
|
+
after = @param_subscribers.length
|
373
|
+
[1, "ok", before - after]
|
374
|
+
end
|
375
|
+
|
376
|
+
@server.add_handler('hasParam') do |caller_id, key|
|
377
|
+
key = canonicalize_name(key)
|
378
|
+
params = @parameters.select {|x| x.key == key}
|
379
|
+
if params.empty?
|
380
|
+
[0, "no", false]
|
381
|
+
else
|
382
|
+
[1, "ok", params.first.value]
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
@server.add_handler('getParamNames') do |caller_id|
|
387
|
+
[1, "ok", @parameters.map{|x| x.key}]
|
388
|
+
end
|
389
|
+
|
390
|
+
# not documented api
|
391
|
+
@server.add_handler('getTopicTypes') do |caller_id|
|
392
|
+
[1, "ok", @publishers.map {|x| [x.name, x.type]} | @subscribers.map {|x| [x.name, x.type]}]
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
|
397
|
+
# start server and set default parameters
|
398
|
+
def start
|
399
|
+
puts "=== starting Ruby ROS master @#{@master_uri} ==="
|
400
|
+
@parameters.push(Parameter.new('/rosversion', '1.8.6'))
|
401
|
+
@parameters.push(Parameter.new('/rosdistro', 'fuerte'))
|
402
|
+
|
403
|
+
@server.serve
|
404
|
+
self
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|