rosruby 0.0.1

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