This chapter is not an introduction to using ROS from Urbi, see Chapter 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.
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 Chapter I), Ros.Service (??sec:std-Ros.Service), Ros.Topic (??sec:std-Ros.Topic), and Ros (??sec:std-Ros).
This module will be loaded automatically if ROS_ROOT is detected 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:
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 (??sec:std-Ros.Topic) and so forth.
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).
This UObject provides a handy way to communicate through ROS topics, by subscribing to existent topics or advertising to them.
To create a new topic, call Ros.topic.new with a string (for the name of the topic you want to subscribe to / on which you want to advertise).
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.
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.
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). Due 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
This UObject provides a handy way to call services provided by other ROS nodes.
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 yourservice.initialized to be true to be able to call request.
for (var item in logService.request([=>])["loggers"])
echo(item);[00236349] *** ["level" => "INFO", "name" => "ros"][00236349] *** ["level" => "INFO", "name" => "ros.roscpp"][00236350] *** ["level" => "WARN", "name" => "ros.roscpp.superdebug"][00236350] *** ["level" => "DEBUG", "name" => "roscpp_internal"]