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
@@ -0,0 +1,132 @@
|
|
1
|
+
# ros/tcpros/service_server.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
require 'ros/tcpros/message'
|
8
|
+
require 'gserver'
|
9
|
+
|
10
|
+
module ROS::TCPROS
|
11
|
+
|
12
|
+
##
|
13
|
+
# TCPROS protocol Service Server
|
14
|
+
#
|
15
|
+
class ServiceServer < ::GServer
|
16
|
+
|
17
|
+
##
|
18
|
+
# max number of connection with clients
|
19
|
+
#
|
20
|
+
MAX_CONNECTION = 100
|
21
|
+
|
22
|
+
include ::ROS::TCPROS::Message
|
23
|
+
|
24
|
+
##
|
25
|
+
# @param [String] caller_id caller_id of this node
|
26
|
+
# @param [String] service_name name of this service
|
27
|
+
# @param [Class] service_type class of this service message
|
28
|
+
# @param [Proc] callback of this service
|
29
|
+
# @param [Integer] port port number
|
30
|
+
# @param [host] host host name
|
31
|
+
def initialize(caller_id, service_name, service_type, callback,
|
32
|
+
port=0, host=::GServer::DEFAULT_HOST)
|
33
|
+
super(port, host, MAX_CONNECTION)
|
34
|
+
@caller_id = caller_id
|
35
|
+
@service_name = service_name
|
36
|
+
@service_type = service_type
|
37
|
+
@callback = callback
|
38
|
+
@byte_received = 0
|
39
|
+
@byte_sent = 0
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# message must send 1 byte for service call result (success)
|
44
|
+
# @param [IO] socket
|
45
|
+
def send_ok_byte(socket)
|
46
|
+
socket.write([1].pack('c'))
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# message must send 1 byte for service call result (fail)
|
51
|
+
# @param [IO] socket
|
52
|
+
def send_ng_byte(socket)
|
53
|
+
socket.write([0].pack('c'))
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# main loop of this connection.
|
58
|
+
# read data and do callback.
|
59
|
+
# @param [IO] socket
|
60
|
+
# @return [Boolean] result of callback
|
61
|
+
def read_and_callback(socket)
|
62
|
+
request = @service_type.request_class.new
|
63
|
+
response = @service_type.response_class.new
|
64
|
+
data = read_all(socket)
|
65
|
+
@byte_received += data.length
|
66
|
+
request.deserialize(data)
|
67
|
+
result = @callback.call(request, response)
|
68
|
+
if result
|
69
|
+
send_ok_byte(socket)
|
70
|
+
data = write_msg(socket, response)
|
71
|
+
@byte_sent += data.length
|
72
|
+
else
|
73
|
+
send_ng_byte(socket)
|
74
|
+
write_header(socket, build_header)
|
75
|
+
# write some message
|
76
|
+
end
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# this is called by socket accept
|
82
|
+
# @param [IO] socket given socket
|
83
|
+
def serve(socket)
|
84
|
+
header = read_header(socket)
|
85
|
+
# not documented protocol?
|
86
|
+
if header['probe'] == '1'
|
87
|
+
write_header(socket, build_header)
|
88
|
+
elsif check_header(header)
|
89
|
+
write_header(socket, build_header)
|
90
|
+
read_and_callback(socket)
|
91
|
+
if header['persistent'] == '1'
|
92
|
+
loop do
|
93
|
+
read_and_callback(socket)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
else
|
97
|
+
socket.close
|
98
|
+
raise 'header check error'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# check header.
|
104
|
+
# check md5sum only.
|
105
|
+
# @param [Header] header header for checking
|
106
|
+
# @return [Boolean] check result (true means ok)
|
107
|
+
def check_header(header)
|
108
|
+
header.valid?('md5sum', @service_type.md5sum)
|
109
|
+
end
|
110
|
+
|
111
|
+
##
|
112
|
+
# build header message for service server.
|
113
|
+
# It contains callerid, type, md5sum.
|
114
|
+
# @return [Header] built header
|
115
|
+
def build_header
|
116
|
+
header = Header.new
|
117
|
+
header["callerid"] = @caller_id
|
118
|
+
header['type'] = @service_type.type
|
119
|
+
header['md5sum'] = @service_type.md5sum
|
120
|
+
header
|
121
|
+
end
|
122
|
+
|
123
|
+
# received data amout for slave api
|
124
|
+
# @return [Integer] byte received
|
125
|
+
attr_reader :byte_received
|
126
|
+
|
127
|
+
# sent data amout for slave api
|
128
|
+
# @return [Integer] byte sent
|
129
|
+
attr_reader :byte_sent
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
data/lib/ros/time.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# ros/time.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
# Time object for ROS.
|
8
|
+
#
|
9
|
+
module ROS
|
10
|
+
|
11
|
+
##
|
12
|
+
# super class of times
|
13
|
+
class TimeValue
|
14
|
+
|
15
|
+
include Comparable
|
16
|
+
|
17
|
+
# @return [Integer] seconds
|
18
|
+
attr_accessor :secs
|
19
|
+
|
20
|
+
# @return [Integer] nano seconds
|
21
|
+
attr_accessor :nsecs
|
22
|
+
|
23
|
+
# canonicalize secs and nsecs
|
24
|
+
# @return [TimeValue] self
|
25
|
+
def canonicalize
|
26
|
+
while @nsecs >= 1e9.to_i
|
27
|
+
@secs += 1
|
28
|
+
@nsecs -= 1e9.to_i
|
29
|
+
end
|
30
|
+
while @nsecs < 0
|
31
|
+
@secs -= 1
|
32
|
+
@nsecs += 1e9.to_i
|
33
|
+
end
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
# convert to seconds
|
38
|
+
# @return [Float] seconds
|
39
|
+
def to_sec
|
40
|
+
@secs + (@nsecs / 1e9)
|
41
|
+
end
|
42
|
+
|
43
|
+
# convert to nano seconds
|
44
|
+
# @return [Float] nano seconds
|
45
|
+
def to_nsec
|
46
|
+
@nsecs + (@secs * 1e9)
|
47
|
+
end
|
48
|
+
|
49
|
+
# compare time value
|
50
|
+
# @param [TimeValue] other compare target
|
51
|
+
# @return [Integer] result
|
52
|
+
def <=>(other)
|
53
|
+
diff = self.to_nsec - other.to_nsec
|
54
|
+
if diff > 0
|
55
|
+
1
|
56
|
+
elsif diff < 0
|
57
|
+
-1
|
58
|
+
else
|
59
|
+
0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# ROS Time object. This is used as msg object for time
|
67
|
+
#
|
68
|
+
class Time < TimeValue
|
69
|
+
|
70
|
+
# initialize with current time
|
71
|
+
def self.now
|
72
|
+
self.new(::Time::now)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @overload initialize(time)
|
76
|
+
# @param [::Time] initialize with this time
|
77
|
+
# @overload initialize
|
78
|
+
def initialize(time=nil)
|
79
|
+
if time
|
80
|
+
@secs = time.to_i
|
81
|
+
@nsecs = ((time.to_f - @secs) * 1e9.to_i).to_i
|
82
|
+
else
|
83
|
+
@secs = 0
|
84
|
+
@nsecs = 0
|
85
|
+
end
|
86
|
+
canonicalize
|
87
|
+
end
|
88
|
+
|
89
|
+
# add time value
|
90
|
+
# @param [Duration] duration duration for adding
|
91
|
+
# @return [Time] new time
|
92
|
+
def +(duration)
|
93
|
+
tm = ::ROS::Time.new
|
94
|
+
tm.secs = @secs + duration.secs
|
95
|
+
tm.nsecs = @nsecs + duration.nsecs
|
96
|
+
tm.canonicalize
|
97
|
+
end
|
98
|
+
|
99
|
+
# subtract time value
|
100
|
+
# @param [Time] other
|
101
|
+
# @return [Duration] duration
|
102
|
+
def -(other)
|
103
|
+
d = ::ROS::Duration.new
|
104
|
+
d.secs = @secs - other.secs
|
105
|
+
d.nsecs = @nsecs - other.nsecs
|
106
|
+
d.canonicalize
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/ros/topic.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# ros/topic.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
# Super class of Publisher/Subscriber
|
8
|
+
#
|
9
|
+
module ROS
|
10
|
+
|
11
|
+
##
|
12
|
+
# Base class of {Publisher} and {Subscriber}
|
13
|
+
class Topic
|
14
|
+
|
15
|
+
# initialize member variables
|
16
|
+
# @param [String] caller_id caller id of this node
|
17
|
+
# @param [String] topic_name name of this topic
|
18
|
+
# @param [Class] topic_type class of msg
|
19
|
+
def initialize(caller_id, topic_name, topic_type)
|
20
|
+
@caller_id = caller_id
|
21
|
+
@topic_name = topic_name
|
22
|
+
@topic_type = topic_type
|
23
|
+
@connections = []
|
24
|
+
@connection_id_number = 0
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String] caller id
|
28
|
+
attr_reader :caller_id
|
29
|
+
|
30
|
+
# @return [String] name of this topic
|
31
|
+
attr_reader :topic_name
|
32
|
+
|
33
|
+
# @return [Class] class of msg
|
34
|
+
attr_reader :topic_type
|
35
|
+
|
36
|
+
# shutdown all connections
|
37
|
+
def close #:nodoc:
|
38
|
+
@connections.each {|connection| connection.shutdown}
|
39
|
+
end
|
40
|
+
|
41
|
+
# set manager for shutdown
|
42
|
+
# @param [GraphManager] manager
|
43
|
+
def set_manager(manager) #:nodoc:
|
44
|
+
@manager = manager
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# ros/xmlrpcserver.rb
|
2
|
+
#
|
3
|
+
# License: BSD
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012 Takashi Ogura <t.ogura@gmail.com>
|
6
|
+
#
|
7
|
+
#
|
8
|
+
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'xmlrpc/server'
|
12
|
+
|
13
|
+
module ROS
|
14
|
+
|
15
|
+
# original XMLRPC Server (remove access log)
|
16
|
+
class XMLRPCServer < XMLRPC::WEBrickServlet
|
17
|
+
def initialize(port=8080,
|
18
|
+
host="127.0.0.1",
|
19
|
+
maxConnections=100,
|
20
|
+
stdlog="#{ENV['HOME']}/.ros/log/rosruby.log")
|
21
|
+
super({})
|
22
|
+
require 'webrick'
|
23
|
+
@server = WEBrick::HTTPServer.new(:Port => port,
|
24
|
+
:BindAddress => host,
|
25
|
+
:MaxClients => maxConnections,
|
26
|
+
:Logger => WEBrick::Log.new(stdlog),
|
27
|
+
:AccessLog => [])
|
28
|
+
@server.mount("/", self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def serve
|
32
|
+
@server.start
|
33
|
+
end
|
34
|
+
|
35
|
+
def shutdown
|
36
|
+
@server.shutdown
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ros'
|
4
|
+
|
5
|
+
require 'roscpp_tutorials/TwoInts'
|
6
|
+
|
7
|
+
def main
|
8
|
+
if ARGV.length < 2
|
9
|
+
puts "usage: #{$0} X Y"
|
10
|
+
return
|
11
|
+
end
|
12
|
+
node = ROS::Node.new('/rosruby/sample_service_client')
|
13
|
+
if node.wait_for_service('/add_two_ints', 1)
|
14
|
+
service = node.service('/add_two_ints', Roscpp_tutorials::TwoInts)
|
15
|
+
req = Roscpp_tutorials::TwoInts.request_class.new
|
16
|
+
res = Roscpp_tutorials::TwoInts.response_class.new
|
17
|
+
req.a = ARGV[0].to_i
|
18
|
+
req.b = ARGV[1].to_i
|
19
|
+
if service.call(req, res)
|
20
|
+
p res.sum
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
main
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ros'
|
4
|
+
require 'roscpp_tutorials/TwoInts'
|
5
|
+
|
6
|
+
def main
|
7
|
+
node = ROS::Node.new('/rosruby/sample_service_server')
|
8
|
+
server = node.advertise_service('/add_two_ints', Roscpp_tutorials::TwoInts) do |req, res|
|
9
|
+
res.sum = req.a + req.b
|
10
|
+
node.loginfo("a=#{req.a}, b=#{req.b}")
|
11
|
+
node.loginfo(" sum = #{res.sum}")
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
while node.ok?
|
16
|
+
sleep (1.0)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
main
|
data/samples/gui.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# = sample of gui (Ruby/Tk)
|
5
|
+
# this sample needs geometry_msgs/Twist.
|
6
|
+
# The GUI publishes velocity as Twist.
|
7
|
+
#
|
8
|
+
# if you don't have the message files, try
|
9
|
+
#
|
10
|
+
# $ rosrun rosruby rosruby_genmsg.py geometry_msgs
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'tk'
|
14
|
+
require 'ros'
|
15
|
+
require 'geometry_msgs/Twist'
|
16
|
+
|
17
|
+
topic_name = '/cmd_vel'
|
18
|
+
node = ROS::Node.new('/gui_test')
|
19
|
+
pub = node.advertise(topic_name, Geometry_msgs::Twist)
|
20
|
+
|
21
|
+
linear_vel = 0.5
|
22
|
+
angular_vel = 1.0
|
23
|
+
|
24
|
+
TkButton.new {
|
25
|
+
text "FORWARD"
|
26
|
+
command do
|
27
|
+
msg = Geometry_msgs::Twist.new
|
28
|
+
msg.linear.x = linear_vel
|
29
|
+
pub.publish(msg)
|
30
|
+
end
|
31
|
+
width 10
|
32
|
+
grid("row"=>0, "column"=>1)
|
33
|
+
}
|
34
|
+
|
35
|
+
TkButton.new {
|
36
|
+
text "LEFT"
|
37
|
+
command do
|
38
|
+
msg = Geometry_msgs::Twist.new
|
39
|
+
msg.angular.z = angular_vel
|
40
|
+
pub.publish(msg)
|
41
|
+
end
|
42
|
+
width 10
|
43
|
+
grid("row"=>1, "column"=>0)
|
44
|
+
}
|
45
|
+
|
46
|
+
TkButton.new {
|
47
|
+
text "STOP"
|
48
|
+
command do
|
49
|
+
msg = Geometry_msgs::Twist.new
|
50
|
+
pub.publish(msg)
|
51
|
+
end
|
52
|
+
width 10
|
53
|
+
grid("row"=>1, "column"=>1)
|
54
|
+
}
|
55
|
+
|
56
|
+
TkButton.new {
|
57
|
+
text "RIGHT"
|
58
|
+
command do
|
59
|
+
msg = Geometry_msgs::Twist.new
|
60
|
+
msg.angular.z = -angular_vel
|
61
|
+
pub.publish(msg)
|
62
|
+
end
|
63
|
+
width 10
|
64
|
+
grid("row"=>1, "column"=>2)
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
TkButton.new {
|
69
|
+
text "BACKWARD"
|
70
|
+
command do
|
71
|
+
msg = Geometry_msgs::Twist.new
|
72
|
+
msg.linear.x = -linear_vel
|
73
|
+
pub.publish(msg)
|
74
|
+
end
|
75
|
+
width 10
|
76
|
+
grid("row"=>2, "column"=>1)
|
77
|
+
}
|
78
|
+
|
79
|
+
TkScale.new {
|
80
|
+
label 'linear vel(%)'
|
81
|
+
from 0
|
82
|
+
to 100
|
83
|
+
orient 'horizontal'
|
84
|
+
command do |val|
|
85
|
+
linear_vel = val.to_f * 0.005
|
86
|
+
end
|
87
|
+
grid("row"=>3, "column"=>0)
|
88
|
+
}.set(50)
|
89
|
+
|
90
|
+
TkScale.new {
|
91
|
+
label 'angular vel(%)'
|
92
|
+
from 0
|
93
|
+
to 100
|
94
|
+
orient 'horizontal'
|
95
|
+
command do |val|
|
96
|
+
angular_vel = val.to_f * 0.01
|
97
|
+
end
|
98
|
+
grid("row"=>3, "column"=>1)
|
99
|
+
}.set(50)
|
100
|
+
|
101
|
+
TkButton.new {
|
102
|
+
text "exit"
|
103
|
+
command do
|
104
|
+
node.shutdown
|
105
|
+
exit
|
106
|
+
end
|
107
|
+
width 5
|
108
|
+
grid("row"=>3, "column"=>2)
|
109
|
+
}
|
110
|
+
|
111
|
+
TkLabel.new {
|
112
|
+
text 'topic'
|
113
|
+
grid("row"=>4, "column"=>0)
|
114
|
+
}
|
115
|
+
|
116
|
+
TkEntry.new {
|
117
|
+
self.value = topic_name
|
118
|
+
bind 'Return', proc {
|
119
|
+
topic_name = self.value
|
120
|
+
pub.shutdown
|
121
|
+
pub = node.advertise(topic_name, Geometry_msgs::Twist)
|
122
|
+
}
|
123
|
+
grid("row"=>4, "column"=>1, "columnspan"=>2, "sticky"=>"news")
|
124
|
+
}
|
125
|
+
|
126
|
+
Tk.mainloop
|