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/package.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
# ros/package.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
# == ROS Package manager
|
8
|
+
#
|
9
|
+
# This is used for adding RUBYLIB path.
|
10
|
+
# This file will provide rospack functions, in the future
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'rexml/document'
|
14
|
+
|
15
|
+
module ROS
|
16
|
+
|
17
|
+
# This is used for adding RUBYLIB path.
|
18
|
+
#
|
19
|
+
class Package
|
20
|
+
|
21
|
+
##
|
22
|
+
# at first check the rospack's cache, if found use it.
|
23
|
+
# if not found, check all package path.
|
24
|
+
# @param [String] cache_file cache file of rospack
|
25
|
+
# @return [Array] fullpath list of all packages
|
26
|
+
def self.read_cache_or_find_all(cache_file="#{ENV['HOME']}/.ros/rospack_cache")
|
27
|
+
if File.exists?(cache_file)
|
28
|
+
f = File.open(cache_file)
|
29
|
+
root_line = f.gets.chop
|
30
|
+
package_path_line = f.gets.chop
|
31
|
+
if root_line == "#ROS_ROOT=#{ENV['ROS_ROOT']}" and
|
32
|
+
package_path_line == "#ROS_PACKAGE_PATH=#{ENV['ROS_PACKAGE_PATH']}"
|
33
|
+
packages = {}
|
34
|
+
while line = f.gets
|
35
|
+
packages[File.basename(line.chop)] = line.chop
|
36
|
+
end
|
37
|
+
packages
|
38
|
+
else
|
39
|
+
self.find_all_packages
|
40
|
+
end
|
41
|
+
else
|
42
|
+
self.find_all_packages
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# search all packages that has manifest.xml
|
48
|
+
# @param [Hash] packages current found packages
|
49
|
+
# @param [Array] roots root directories for searching
|
50
|
+
# @return [Array] fullpath list of all packages
|
51
|
+
def self.find_all_packages(packages={}, roots=ENV['ROS_PACKAGE_PATH'].split(':').push(ENV['ROS_ROOT']))
|
52
|
+
roots.each do |root|
|
53
|
+
if File.exists?("#{root}/manifest.xml")
|
54
|
+
packages[File.basename(root)] = root
|
55
|
+
else
|
56
|
+
if File.exists?(root)
|
57
|
+
Dir.foreach(root) do |path|
|
58
|
+
if path != "." and path != ".."
|
59
|
+
full_path = "#{root}/#{path}"
|
60
|
+
if File.directory?(full_path)
|
61
|
+
self.find_all_packages(packages, [full_path])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
packages
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# all package path hash
|
73
|
+
#
|
74
|
+
@@all_packages = self.read_cache_or_find_all
|
75
|
+
|
76
|
+
|
77
|
+
##
|
78
|
+
# get the depend packages of the arg
|
79
|
+
# @param [String] package find depends packages of this package
|
80
|
+
# @param [Array] packages current found depends
|
81
|
+
# @return [Array] packages
|
82
|
+
def self.depends(package, packages=[])
|
83
|
+
file = File.open("#{@@all_packages[package]}/manifest.xml")
|
84
|
+
doc = REXML::Document.new(file)
|
85
|
+
doc.elements.each('/package/depend') do |element|
|
86
|
+
depend_package = element.attributes['package']
|
87
|
+
if not packages.include?(depend_package)
|
88
|
+
packages.push(depend_package)
|
89
|
+
self.depends(depend_package, packages)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
packages
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
##
|
97
|
+
# get the current program's package
|
98
|
+
# @return [String] name of running programs's package
|
99
|
+
def self.find_this_package
|
100
|
+
path = File::dirname(File.expand_path($PROGRAM_NAME))
|
101
|
+
while path != '/'
|
102
|
+
if File.exists?("#{path}/manifest.xml")
|
103
|
+
return File::basename(path)
|
104
|
+
end
|
105
|
+
path = File::dirname(path)
|
106
|
+
end
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# add package's [lib/, msg_gen/ruby, srv_gen/ruby] to '$:'.
|
112
|
+
# this enables load ruby files easily
|
113
|
+
# @param [String] package name of package
|
114
|
+
def self.add_path_of_package(package)
|
115
|
+
path = @@all_packages[package]
|
116
|
+
["#{path}/msg_gen/ruby", "#{path}/srv_gen/ruby", "#{path}/lib"].each do |path|
|
117
|
+
if File.exists?(path)
|
118
|
+
if not $:.include?(path)
|
119
|
+
$:.push(path)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# add [lib/, msg_gen/ruby, srv_gen/ruby] dirs of all depend packages
|
127
|
+
# to RUBYLIB, if the directory exists
|
128
|
+
# @param [String] package name of package
|
129
|
+
def self.add_path_with_depend_packages(package)
|
130
|
+
add_path_of_package(package)
|
131
|
+
Package::depends(package).each do |pack|
|
132
|
+
add_path_of_package(pack)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
##
|
139
|
+
# load manifest and add all dependencies
|
140
|
+
# @param [String] package name of package
|
141
|
+
def self.load_manifest(package)
|
142
|
+
ROS::Package.add_path_with_depend_packages(package)
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# ros/parameter_manager.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
# == Control Parameter Server Interface
|
8
|
+
#
|
9
|
+
# ROS parameter sever inteface.
|
10
|
+
# API document is here http://ros.org/wiki/ROS/Parameter%20Server%20API
|
11
|
+
#
|
12
|
+
require "xmlrpc/client"
|
13
|
+
|
14
|
+
module ROS
|
15
|
+
|
16
|
+
# ROS parameter sever inteface.
|
17
|
+
# API document is here http://ros.org/wiki/ROS/Parameter%20Server%20API
|
18
|
+
class ParameterManager
|
19
|
+
|
20
|
+
# @param [String] master_uri URI of ROS Master (parameter server)
|
21
|
+
# @param [String] caller_id caller_id of this node
|
22
|
+
# @param [Array] remappings remapps to use for local remappings
|
23
|
+
def initialize(master_uri, caller_id, remappings)
|
24
|
+
@caller_id = caller_id
|
25
|
+
@master_uri = master_uri
|
26
|
+
@remappings = remappings
|
27
|
+
@server = XMLRPC::Client.new2(@master_uri)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# get parameter named 'key'
|
32
|
+
# @param [String] key name of parameter
|
33
|
+
# @return [String] parameter value
|
34
|
+
def get_param(key)
|
35
|
+
if @remappings[key]
|
36
|
+
return @remappings[key]
|
37
|
+
end
|
38
|
+
code, message, value = @server.call("getParam", @caller_id, key)
|
39
|
+
case code
|
40
|
+
when 1
|
41
|
+
return value
|
42
|
+
else
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# set parameter for 'key'
|
49
|
+
# @param [String] key key of parameter
|
50
|
+
# @param [String, Integer, Float, Boolean] value value of parameter
|
51
|
+
# @return [Boolean] true if succeed
|
52
|
+
# @raise
|
53
|
+
def set_param(key, value)
|
54
|
+
code, message, value = @server.call("setParam", @caller_id, key, value)
|
55
|
+
case code
|
56
|
+
when 1
|
57
|
+
return true
|
58
|
+
when -1
|
59
|
+
raise message
|
60
|
+
else
|
61
|
+
return false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# delete parameter 'key'
|
67
|
+
# @param [String] key key for remove
|
68
|
+
# @return [Boolean] return true if success, false if it is not exist
|
69
|
+
def delete_param(key)
|
70
|
+
code, message, value = @server.call("deleteParam", @caller_id, key)
|
71
|
+
case code
|
72
|
+
when 1
|
73
|
+
return true
|
74
|
+
else
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# search the all namespace for key
|
81
|
+
# @param [String] key key for search
|
82
|
+
# @return [Array] values
|
83
|
+
def search_param(key)
|
84
|
+
code, message, value = @server.call("searchParam", @caller_id, key)
|
85
|
+
case code
|
86
|
+
when 1
|
87
|
+
return value
|
88
|
+
when -1
|
89
|
+
raise message
|
90
|
+
else
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# check if the master has the key
|
97
|
+
# @param [String] key key for check
|
98
|
+
# @return [String, Integer, Float, Boolean] value of key
|
99
|
+
def has_param(key)
|
100
|
+
code, message, value = @server.call("hasParam", @caller_id, key)
|
101
|
+
case code
|
102
|
+
when 1
|
103
|
+
return value
|
104
|
+
when -1
|
105
|
+
raise message
|
106
|
+
else
|
107
|
+
return false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# get the all keys of parameters
|
113
|
+
# @return [Array] all keys
|
114
|
+
#
|
115
|
+
def get_param_names
|
116
|
+
code, message, value = @server.call("getParamNames", @caller_id)
|
117
|
+
case code
|
118
|
+
when 1
|
119
|
+
return value
|
120
|
+
when -1
|
121
|
+
raise message
|
122
|
+
else
|
123
|
+
return false
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# ros/parameter_subscriber.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# == Parameter Subscriber
|
9
|
+
# callback object for paramUpdate
|
10
|
+
#
|
11
|
+
#
|
12
|
+
|
13
|
+
module ROS
|
14
|
+
|
15
|
+
# callback object for paramUpdate
|
16
|
+
#
|
17
|
+
class ParameterSubscriber
|
18
|
+
# do not make instance directory. Plese use Node#subscribe_parameter.
|
19
|
+
# @param [String] key param key to subscribe
|
20
|
+
# @param [Proc] callback callback when parameter updated
|
21
|
+
def initialize(key, callback)
|
22
|
+
@key = key
|
23
|
+
@callback = callback
|
24
|
+
end
|
25
|
+
|
26
|
+
# callback with param value
|
27
|
+
# @param [String] value value of updated parameter
|
28
|
+
def call(value)
|
29
|
+
@callback.call(value)
|
30
|
+
end
|
31
|
+
|
32
|
+
# set GraphManager for management
|
33
|
+
# @param [GraphManager] manager GraphManager
|
34
|
+
def set_manager(manager) #:nodoc
|
35
|
+
@manager = manager
|
36
|
+
end
|
37
|
+
|
38
|
+
# shutdown this subscription
|
39
|
+
def shutdown
|
40
|
+
@manager.shutdown_parameter_subscriber(self)
|
41
|
+
end
|
42
|
+
|
43
|
+
# key of parameter for subscription
|
44
|
+
attr_accessor :key
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# ros/publisher.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'ros/topic'
|
9
|
+
require 'ros/tcpros/server'
|
10
|
+
|
11
|
+
module ROS
|
12
|
+
# Publisher interface of ROS.
|
13
|
+
# A publisher contains multi connection with subscribers.
|
14
|
+
# TCPROS protocol implementation is in ROS::TCPROS::Server.
|
15
|
+
# Here is sample code. You can shutdown publisher by using this
|
16
|
+
# instance (ROS::Publisher#shutdown)
|
17
|
+
# node = ROS::Node.new('/rosruby/sample_publisher')
|
18
|
+
# publisher = node.advertise('/chatter', Std_msgs::String)
|
19
|
+
# sleep(1)
|
20
|
+
# msg = Std_msgs::String.new
|
21
|
+
# i = 0
|
22
|
+
# while node.ok?
|
23
|
+
# msg.data = "Hello, rosruby!: #{i}"
|
24
|
+
# publisher.publish(msg)
|
25
|
+
# i += 1
|
26
|
+
# end
|
27
|
+
class Publisher < Topic
|
28
|
+
|
29
|
+
# @param [String] caller_id caller_id of this node
|
30
|
+
# @param [String] topic_name name of topic to publish (String)
|
31
|
+
# @param [Class] topic_type class of topic
|
32
|
+
# @param [Boolean] is_latched latched topic?
|
33
|
+
# @param [String] host host name of this node
|
34
|
+
def initialize(caller_id, topic_name, topic_type, is_latched, host)
|
35
|
+
super(caller_id, topic_name, topic_type)
|
36
|
+
@host = host
|
37
|
+
@is_latched = is_latched
|
38
|
+
@seq = 0
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# publish msg object
|
43
|
+
# @param [Class] message instance of topic_type class
|
44
|
+
# @return [Publisher] self
|
45
|
+
def publish(message)
|
46
|
+
@seq += 1
|
47
|
+
@last_published_msg = message
|
48
|
+
if message.has_header?
|
49
|
+
message.header.seq = @seq
|
50
|
+
end
|
51
|
+
@connections.each do |connection|
|
52
|
+
connection.msg_queue.push(message)
|
53
|
+
end
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# add tcpros connection as server
|
59
|
+
# @param [String] caller_id caller_id of subscriber
|
60
|
+
# @return [TCPROS::Server] connection object
|
61
|
+
def add_connection(caller_id) #:nodoc:
|
62
|
+
connection = TCPROS::Server.new(@caller_id, @topic_name, @topic_type,
|
63
|
+
:host=>@host,
|
64
|
+
:latched=>@is_latched,
|
65
|
+
:last_published_msg=>@last_published_msg)
|
66
|
+
connection.start
|
67
|
+
connection.id = "#{@topic_name}_out_#{@connection_id_number}"
|
68
|
+
@connection_id_number += 1
|
69
|
+
@connections.push(connection)
|
70
|
+
return connection
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Array] connection data for slave api
|
74
|
+
def get_connection_data
|
75
|
+
@connections.map do |connection|
|
76
|
+
[connection.id, connection.byte_sent, connection.num_sent, 1]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [array] connection info for slave api
|
81
|
+
def get_connection_info
|
82
|
+
info = []
|
83
|
+
@connections.each do |connection|
|
84
|
+
info.push([connection.id, connection.caller_id, 'o', connection.protocol, @topic_name])
|
85
|
+
end
|
86
|
+
info
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# user interface of shutdown this publisher
|
91
|
+
# @return [nil] nil
|
92
|
+
def shutdown
|
93
|
+
@manager.shutdown_publisher(self)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/ros/rate.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# ros/rate.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
#
|
8
|
+
|
9
|
+
module ROS
|
10
|
+
|
11
|
+
##
|
12
|
+
# sleep in a Hz timing.
|
13
|
+
# @example
|
14
|
+
# r = ROS::Rate.new(10)
|
15
|
+
# r.sleep
|
16
|
+
#
|
17
|
+
class Rate
|
18
|
+
|
19
|
+
# @param [Float] hz Hz
|
20
|
+
def initialize(hz)
|
21
|
+
@sleep_duration = 1.0 / hz
|
22
|
+
@last_time = ::Time.now
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# sleep for preset rate [Hz]
|
27
|
+
#
|
28
|
+
def sleep
|
29
|
+
current_time = ::Time.now
|
30
|
+
elapsed = current_time - @last_time
|
31
|
+
Kernel.sleep(@sleep_duration - elapsed)
|
32
|
+
@last_time = @last_time + @sleep_duration
|
33
|
+
|
34
|
+
# detect time jumping forwards, as well as loops that are
|
35
|
+
# inherently too slow
|
36
|
+
if current_time - @last_time > @sleep_duration * 2
|
37
|
+
@last_time = current_time
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|