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