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