Next

Prev

Prev-tail

Tail

Up

Chapter 21
Communication with ROS

This chapter is not an introduction to using ROS from Urbi, see Listing 13 for a tutorial.

Urbi provides a set of tools to communicate with ROS (Robot Operating System). For more information about ROS, please refer to http://www.ros.org. Urbi, acting as a ROS node, is able to interact with the ROS world.

 21.1 Ros
  21.1.1 Construction
  21.1.2 Slots
 21.2 Ros.Topic
  21.2.1 Construction
  21.2.2 Slots
  21.2.3 Example
 21.3 Ros.Service
  21.3.1 Construction
  21.3.2 Slots

Requirements You need to have installed ROS (possibly a recent version), and compiled all of the common ROS tools (rxconsole, roscore, roscpp, …).

You also need to have a few environment variables set, normally provided with ROS installation: ROS_ROOT, ROS_MASTER_URI and ROS_PACKAGE_PATH.

Usage The classes are implemented as uobjects (see Listing I): Ros.Service (Section 21.3), Ros.Topic (Section 21.2), and Ros (Section 21.1).

This module is loaded automatically if ROS_ROOT is set in your environment. If roscore is not launched, you will be noticed by a warning and Urbi will check regularly for roscore.

If for any reason you need to load this module manually, use:

 
loadModule("urbi/ros");  

21.1 Ros

This object provides some handy tools to know the status of roscore, to list the different nodes, topics, services, …. It also serves as a namespace entry point for ROS entities, such as Ros.Topic (Section 21.2) and so forth.

21.1.1 Construction

There is no construction, since this class only provides a set of tools related to ROS in general, or the current node (which is unique per instance of Urbi).

21.1.2 Slots

21.2 Ros.Topic

This UObject provides a handy way to communicate through ROS topics, by subscribing to existent topics or advertising to them.

21.2.1 Construction

To create a new topic, call Ros.topic.new with a string (the name of the topic you want to subscribe to / advertise on).

The topic name can only contain alphanumerical characters, ‘/’ and ‘_’, and cannot be empty. If the topic name is invalid, an exception is thrown and the topic is not created.

Until you decide what you want to do with your topic (subscribe or advertise), you are free to call init to change its name.

21.2.2 Slots

Some slots on this UObject have no interest once the type of instance is determined. For example, you cannot call unsubscribe if you advertise, and in the same way you cannot call publish if you subscribed to a topic.

21.2.2.1 Common

21.2.2.2 Subscription

21.2.2.3 Advertising

21.2.3 Example

This is a typical example of the creation of a publisher, a subscriber, and message transmission between both of them.

First we need to declare our Publisher, the topic name is ‘/example’, and the type of message that will be sent on this topic is ‘std_msgs/String’. This type contains a single field called ‘data’, holding a string. We also set up handlers for onConnect and onDisconnect to be noticed when someone subscribes to us.

 
var publisher = Ros.Topic.new("/example")| 
con: at (publisher.onConnect?(var name)) 
  echo(name[0,5] + " is now listening on " + publisher.name); 
dcon: at (publisher.onDisconnect?(var name)) 
  echo(name[0,5] + " is no longer listening on " + publisher.name); 
publisher.advertise("std_msgs/String");  

Then we subscribe to the freshly created topic, and for each message, we display the ‘data’ section (which is the content of the message). Thanks to the previous at above, a message is displayed at subscription time.

 
var subscriber = Ros.Topic.new("/example")| 
msg: at (subscriber.onMessage?(var m)) 
  echo(m["data"]); 
subscriber.subscribe; 
[00026580] *** /urbi is now listening on /example 
 
// The types should be the same, ensure that. 
assert { subscriber.structure == publisher.structure };  

Now we can send a message, and get it back through the at in the section above. To do this we first copy the template structure and then fill the field ‘data’ with our message.

 
var message = publisher.structure.new; 
[00098963] ["data" => ""] 
message["data"] = "Hello world!"|; 
 
// publish the message. 
publisher << message; 
// Leave some time to asynchronous communications before shutting down. 
sleep(200ms); 
[00098964] *** Hello world! 
 
subscriber.unsubscribe; 
[00252566] *** /urbi is no longer listening on /example  

21.3 Ros.Service

This UObject provides a handy way to call services provided by other ROS nodes.

21.3.1 Construction

To create a new instance of this object, call Ros.Service.new with a string representing which service you want to use, and a Boolean stating whether the connection between you and the service provider should be kept opened (pass true for better performances on multiple requests).

The service name can only contain alphanumerical characters, ‘/’, ‘_’, and cannot be empty. If the service name is invalid, an exception is thrown, and the object is not created.

Then if the service does not exist, an other exception is thrown. Since the initialization is asynchronous internally, you need to wait for service.initialized to be true to be able to call request.

21.3.2 Slots