rosruby 0.0.1

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.
Files changed (57) hide show
  1. data/bin/rubyroscore +5 -0
  2. data/lib/ros.rb +25 -0
  3. data/lib/ros/duration.rb +63 -0
  4. data/lib/ros/graph_manager.rb +408 -0
  5. data/lib/ros/log.rb +72 -0
  6. data/lib/ros/master.rb +408 -0
  7. data/lib/ros/master_proxy.rb +256 -0
  8. data/lib/ros/message.rb +65 -0
  9. data/lib/ros/name.rb +88 -0
  10. data/lib/ros/node.rb +442 -0
  11. data/lib/ros/package.rb +144 -0
  12. data/lib/ros/parameter_manager.rb +127 -0
  13. data/lib/ros/parameter_subscriber.rb +47 -0
  14. data/lib/ros/publisher.rb +96 -0
  15. data/lib/ros/rate.rb +41 -0
  16. data/lib/ros/ros.rb +10 -0
  17. data/lib/ros/roscore.rb +29 -0
  18. data/lib/ros/service.rb +37 -0
  19. data/lib/ros/service_client.rb +83 -0
  20. data/lib/ros/service_server.rb +92 -0
  21. data/lib/ros/slave_proxy.rb +153 -0
  22. data/lib/ros/subscriber.rb +119 -0
  23. data/lib/ros/tcpros/client.rb +108 -0
  24. data/lib/ros/tcpros/header.rb +89 -0
  25. data/lib/ros/tcpros/message.rb +74 -0
  26. data/lib/ros/tcpros/server.rb +137 -0
  27. data/lib/ros/tcpros/service_client.rb +104 -0
  28. data/lib/ros/tcpros/service_server.rb +132 -0
  29. data/lib/ros/time.rb +109 -0
  30. data/lib/ros/topic.rb +47 -0
  31. data/lib/ros/xmlrpcserver.rb +40 -0
  32. data/samples/add_two_ints_client.rb +25 -0
  33. data/samples/add_two_ints_server.rb +20 -0
  34. data/samples/gui.rb +126 -0
  35. data/samples/sample_log.rb +16 -0
  36. data/samples/sample_param.rb +20 -0
  37. data/samples/sample_publisher.rb +20 -0
  38. data/samples/sample_subscriber.rb +19 -0
  39. data/scripts/genmsg_ruby.py +1135 -0
  40. data/scripts/genmsg_ruby.pyc +0 -0
  41. data/scripts/gensrv_ruby.py +105 -0
  42. data/scripts/gensrv_ruby.pyc +0 -0
  43. data/scripts/rosruby_genmsg.py +67 -0
  44. data/scripts/run-test.rb +21 -0
  45. data/test/test_header.rb +36 -0
  46. data/test/test_log.rb +45 -0
  47. data/test/test_master_proxy.rb +73 -0
  48. data/test/test_message.rb +13 -0
  49. data/test/test_node.rb +166 -0
  50. data/test/test_package.rb +10 -0
  51. data/test/test_param.rb +27 -0
  52. data/test/test_pubsub.rb +154 -0
  53. data/test/test_rate.rb +16 -0
  54. data/test/test_service.rb +34 -0
  55. data/test/test_slave_proxy.rb +49 -0
  56. data/test/test_time.rb +39 -0
  57. metadata +170 -0
@@ -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
@@ -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
+