Difference between revisions of "ROS HOWTO"

From AIRWiki
Jump to: navigation, search
m (TF)
m (tf)
Line 91: Line 91:
  
 
== tf ==
 
== tf ==
From [http://www.ros.org/wiki/tf ROS TF documentation]: "''tf is a package that lets the user keep track of multiple coordinate frames over time. tf maintains the relationship between coordinate frames in a tree structure buffered in time, and lets the user transform points, vectors, etc between any two coordinate frames at any desired point in time''" (from ROS documentation). It is a key element of ROS and, if you work on mobile robotics, there's not much that you can do with ROS without using tf.
+
From [http://www.ros.org/wiki/tf ROS documentation]: "''tf is a package that lets the user keep track of multiple coordinate frames over time. tf maintains the relationship between coordinate frames in a tree structure buffered in time, and lets the user transform points, vectors, etc between any two coordinate frames at any desired point in time''" (from ROS documentation). It is a key element of ROS and, if you work on mobile robotics, there's not much that you can do with ROS without using tf.
  
 
One problem of the ROS documentation about tf is that there are countless references to a frame called ''/world'' but... /world is not defined anywhere! The solution is that (see [http://answers.ros.org/question/27668/frame-problem-when-using-with-a-third-party-node/ this help page]) "By convention, the /world frame is never defined. The frame /world is simply the default."
 
One problem of the ROS documentation about tf is that there are countless references to a frame called ''/world'' but... /world is not defined anywhere! The solution is that (see [http://answers.ros.org/question/27668/frame-problem-when-using-with-a-third-party-node/ this help page]) "By convention, the /world frame is never defined. The frame /world is simply the default."
  
 
Actually, it seems that the "default" reference frame does not need to be called /world. tf manages a tree of reference frames, where each frame has one (and only one) parent. The only exception to this rule is the frame that constitutes the root of the tree, which has no parent. This is OK, as long as there is a single root frame: i.e., as long as every other frame in the tree has a parent. Which frame is the root, i.e. which is the "default" frame, seems to be defined implicitly. In fact, any frame F in the tree is there because a transform between another frame (its parent) and F has been defined. So, the one frame that has been used as a parent while defining at least one transform, but has ''not'' been defined itself through a transform from another frame, is the root of the tree. The name of such root, or "default", frame seems to be arbitrary; frequently it is called "/map" or "/world".
 
Actually, it seems that the "default" reference frame does not need to be called /world. tf manages a tree of reference frames, where each frame has one (and only one) parent. The only exception to this rule is the frame that constitutes the root of the tree, which has no parent. This is OK, as long as there is a single root frame: i.e., as long as every other frame in the tree has a parent. Which frame is the root, i.e. which is the "default" frame, seems to be defined implicitly. In fact, any frame F in the tree is there because a transform between another frame (its parent) and F has been defined. So, the one frame that has been used as a parent while defining at least one transform, but has ''not'' been defined itself through a transform from another frame, is the root of the tree. The name of such root, or "default", frame seems to be arbitrary; frequently it is called "/map" or "/world".

Revision as of 12:21, 14 June 2012

About ROS in general

ROS (Robot Operating System) is an open-source framework for the creation of software for robots. It is a very interesting tool, since it promises to take care of many of the lower-level issues that make realizing the software for autonomous robots so difficult and time-consuming. By leaving such issues (e.g., communication among modules) to ROS, a researcher can focus on the more interesting high-level issues (e.g., perception). In the words of its creators:

"ROS provides libraries and tools to help software developers create robot applications. It provides hardware abstraction, device drivers, libraries, visualizers, message-passing, package management, and more."

ROS includes a large collection of packages that you can incorporate into your own system. A ROS package is a bundle of software dedicated to a single functionality (e.g., data acquisition from a laser scanner). Your own ROS-based applications will take the form of one or more ROS packages. If they can be useful to other people as well, once they are completed and tested such packages could become part of ROS: much of ROS was born in this way.

Though striving to be as easy-to-use as possible, ROS is a complex tool. This is unavoidable, as autonomous robots themselves are very complex systems. Before you can start writing your own ROS-based software, you have to devote a fair amount of time to studying how it works and how to use it. This part of AIRWiki will help you to start using ROS as quickly as possible.

How to get ROS

This is probably the single aspect where the ROS team succeeded best in removing all the difficulties, even for beginners. Installing ROS is very simple: this webpage tells you how. At the moment ROS is only available for the Linux operating system, and support for other OSs is still experimental.

Resources

The ROS website itself includes a good deal of information, and you are invited to use it heavily. However, not always the information it provides is very clear for someone who is not an expert in ROS, nor all topics are equally covered. Here we'll try to complement what's provided by ROS with additional information, instead of saying the same things in another way.

Arguably, the most useful tools to learn how to use ROS are the basic tutorials. Be sure to go through them before writing a single line of code (except those that you will write for the tutorial, of course!). Once you have worked your way through the tutorials, the next thing to do is to write your own ROS package and apply what you have learned. The "Nodes" section below is the suggested starting point for that. Maybe you should start experimenting with a "test" package, before passing to a real application: in this way you can experiment without worrying if the end result is a mess :-) You are strongly invited to experiment: as usually happens in computer programming, that's the best way to understand and check if you have correctly understood, all at the same time.

Before you start with the tutorials, please read this introduction to the concepts behind ROS: you will not necessarily understand how things are done in practice until you will have completed the tutorials, but reading it before passing to these will provide you with useful background.

Programming languages

ROS, per se, does not force the developer to use a specific programming language. In practice, while there are expansion plans for the future, at present only two languages are supported: C++ and Python. That is to say, only for these two languages ROS provides client libraries that enable non-ROS software to interface with ROS. Such libraries are called roscpp (for C++) and rospy (for Python).

You can choose what language to use on a module-per-module basis, choosing C++ or Python (or whatever other language will be supported in the future) separately for each software module of your ROS system. As we will explain shortly, ROS software modules are called nodes.

Tutorials for roscpp and rospy are available: see here and here respectively.

Nodes and communications

The basic element, or module, of a ROS-based software system is the node. A node executes one or more tasks and communicates with other nodes using the ROS infrastructure. Such communication takes the form of an exchange of messages. For instance, messages can be used to pass sensor data to a processing node, or to issue commands to a motor-controlling node. Many predefined types of ROS messages are available; if none of them suits your requirements, you can define new message types. A message can include a timestamp, which tells to the recipient when it has been generated: this is especially useful when dealing with sensor data. ROS usually calls "Stamped" a message type that includes a timestamp; this is useful to keep in mind while choosing among available message types.

Communications among modules of a ROS system should always be performed using ROS messages. In fact, the many powerful tools provided by ROS to collect, analyze and debug such communications are all targeted to the processing of messages, and become useless if your system does not use these.

Of course, there are real-world situations when communicating data through messages is not feasible because it would require too many resources. For instance, this happens when a large set of data (such as a complex map) has to be processed by different modules. Using messages to provide the map to each module would require the frequent generation of copies of it (thus wasting both CPU time, for creation, and RAM space, for storage). The typical solution to such problems is to let all the modules involved access the RAM area where the data are stored, thus exchanging only pointers; however, ROS provides its own solutions, which you should investigate first. One of these is the use of nodelets.

A key aspect of the communications among ROS nodes is that, as they are based on the exchange of ROS messages, they are asynchronous. Outgoing messages are delivered as soon as the ROS system manages to free the necessary resources, are stored in a queue by the receiving node(s), and the node(s) processes them as soon as it is able to (i.e., as soon as it "awakens" if it is executed periodically). An important consequence of this is that you must never count on correct message timing, or even on correct ordering, for critical aspects of your system's functioning. Your ROS system must be tolerant of alterations in the message flow such as delays, misordering, or loss.

Messages that deal with the same aspect of the functioning of the robot can be grouped by publishing them on the same topic. A topic identifies a "communication channel", shared by nodes that deal with the same aspect of the robot. Each node can subscribe to the topics it is interested in (thus receiving all the messages that are published on them, without being bothered by messages published on other topics) and/or publish messages on them (thus ensuring that its messages reach all interested nodes).

A node can perform several types of activities, including:

  • publishing messages on a ROS topic;
  • requesting a service from ROS servers, i.e. acting as a ROS client;
  • acting as a ROS server, i.e. providing services to ROS clients;
  • executing a task whenever a message is published on a ROS topic;
  • managing a timeout and executing a task if it expires;
  • execute a task periodically.

In practice, a node is implemented as a single executable file. This is produced from a source code file written in one of the programming languages supported by ROS. For instance, if you use C++ you will have to write a .cpp file comprising a main block (and anything else your program needs to work, such as additional functions, data types, #include directives and so on).

AIRLab's basic ROS node template provides all the elements that you need to set up the structure of the .cpp file of a basic ROS node, including the elements that are required for the types of activities listed above. The template includes a single C++ class comprehending a suitable set of member variables and member functions, plus a very simple main block. By uncommenting the parts of the template that you require for your ROS node, you can quickly set up the structure of the node. Moreover, the template includes notes and comments that explain how a ROS node is built and works in practice: so take a look at it.

Tools

ROS comes with a wide set of tools that you will need while building your own ROS-based application. Among them, those listed below are especially useful:

  • roscore must be run before anything else every time you run a ROS application, and should be kept running: it sets up the ROS infrastructure that all other elements of ROS connect to;
  • rosmake is necessary to compile your code as part of the ROS system;
  • rosrun lets you run a single node;
  • roslaunch lets you run a set of nodes at the same time (a .launch text file specifies the nodes to run, using a special syntax);
  • rxgraph graphically shows how the nodes of your system interact through ROS messages;
  • rxconsole is an interface to the (very comprehensive) logging system built-in in ROS: it's very useful to understand what's happening within your running ROS system;
  • rosbag records or plays back ROS messages: in particular, it can be used to simulate the presence of some parts of a robot system (e.g., those dealing with hardware) even if they are not available at the moment, by playing back their output;
  • rviz is a powerful (but not so straightforward to use...) visualizer for data published as ROS messages.

To get information on the usage of each of the above listed tools, refer to the ROS wiki. For quick help, if you enter (through the command line) the tool's name without arguments you usually get a short list of options, similar to the man pages of Linux.

Starting and stopping ROS components

One powerful feature of ROS is that (provided that roscore is running) you can start or stop any element of ROS (such as nodes or debugging tools like rxconsole or rviz) whenever you like: the ROS system will automatically react to the changes and reconfigure itself. In some cases ROS or one of its elements can take a few seconds to react to the change; and sometimes something just gets stuck and has to be stopped and started again (rxgraph, notably)... but this does not happen too often.

Node names

When a ROS node is run using rosrun, it takes the name specified by its associated .cpp file (precisely, by the call to ros::init). When roslaunch is used, for each of the nodes specified by the .launch file you can choose a name: such name overrides the one specified in the .cpp file (so you don't have to change it). This is especially useful when you need to run more than one instance of a node.

Actually, it would be more precise to say that the name specified by the call to ros::init in the .cpp file associated to a node is that of a type of node. If a single instance of such type of node is run with rosrun, it will take as its own name the name of its type; when, instead, one or more instances of such type of node are run with roslaunch, each of them can be given an arbitrary individual name.

About specific ROS packages

tf

From ROS documentation: "tf is a package that lets the user keep track of multiple coordinate frames over time. tf maintains the relationship between coordinate frames in a tree structure buffered in time, and lets the user transform points, vectors, etc between any two coordinate frames at any desired point in time" (from ROS documentation). It is a key element of ROS and, if you work on mobile robotics, there's not much that you can do with ROS without using tf.

One problem of the ROS documentation about tf is that there are countless references to a frame called /world but... /world is not defined anywhere! The solution is that (see this help page) "By convention, the /world frame is never defined. The frame /world is simply the default."

Actually, it seems that the "default" reference frame does not need to be called /world. tf manages a tree of reference frames, where each frame has one (and only one) parent. The only exception to this rule is the frame that constitutes the root of the tree, which has no parent. This is OK, as long as there is a single root frame: i.e., as long as every other frame in the tree has a parent. Which frame is the root, i.e. which is the "default" frame, seems to be defined implicitly. In fact, any frame F in the tree is there because a transform between another frame (its parent) and F has been defined. So, the one frame that has been used as a parent while defining at least one transform, but has not been defined itself through a transform from another frame, is the root of the tree. The name of such root, or "default", frame seems to be arbitrary; frequently it is called "/map" or "/world".