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,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
@@ -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
@@ -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
@@ -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