Anda di halaman 1dari 51

CSCE574 Robotics Spring 2013 Notes on ROS

This document is intended to provide an introduction to ROS, acting as a supplement to the online tutorials. It will be edited and expanded throughout the semester. 2013-01-14 First version, based on notes from Spring 2012. 2013-01-16 Added Section 8 and Appendix B. 2013-01-16 Added Section 9 and Appendix C. 2013-02-06 Added Section 10. 2013-02-08 Added Section 12. 2013-02-09 Added Section 11 and Appendix D. 2013-02-09 Small but important expansion to Section 7. 2013-03-02 Added Sections 1316. 2013-04-03 Revised Section 16.4 and added Section 16.3. 2013-04-15 Added Appendix E.

Contents
I ROS Basics
1 Getting Information About ROS 2 Conguring ROS, Exploring Packages, and Creating Your Workspace 2.1 Conguring Your Account . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Finding and Visiting Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Creating a workspace and a package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Masters, Nodes, Topics, Publishers, Subscribers 3.1 Starting roscore . . . . . . . . . . . . . . . . 3.2 Starting nodes . . . . . . . . . . . . . . . . . . 3.3 Inspecting the graph . . . . . . . . . . . . . . 3.4 Inspecting a topic and observing its messages

4
4 5 5 5 6 7 7 7 7 9 11 11 11 13 15 16 Notes on ROS 1 of 51

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

4 Writing Simple ROS Programs in C++ 4.1 Hello, ROS! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Compiling Your Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Publishing messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Writing a ROS main loop 6 Subscribing CSCE574 Spring 2013

7 Launch Files 7.1 A basic launch le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Launch arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Calling services 8.1 Finding services . . . . . . . . . . . . . . 8.2 Service data types . . . . . . . . . . . . . 8.3 Calling services from the command line 8.4 Calling services from C++ . . . . . . . .

17 17 17 18 18 18 19 19 21 21 21 22 22 22 23 24 24 24 25 25 25 26 26 26 28

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

9 Setting and querying parameters 9.1 Accessing parameters from the command line . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2 Accessing parameters from C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Bags 10.1 Recording and playing bags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 Bag example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.3 Other bag tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Visualizing data with RViz 11.1 Setting the xed frame . . . . . . . . 11.2 Working with RViz displays . . . . . 11.3 RViz display congurations . . . . . 11.4 Setting the RViz view . . . . . . . . . 11.5 Segfaults and Bad Drawable errors

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

12 Using Frames and Transforms 12.1 TF overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2 Looking up transforms in within your code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3 Frames from the command line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

II Turtlebots
13 About the Turtlebot 13.1 Turtlebot is not turtlesim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.2 Turtlebot has two computers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.3 Getting your Turtlebot kit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Netbook setup 14.1 Installing the operating system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14.2 Installing basic software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14.3 Installing ROS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Running ROS over a network 15.1 Physical setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29
29 29 29 30 31 31 32 32 33 33

CSCE574 Spring 2013

Notes on ROS

2 of 51

15.2 15.3 15.4 15.5 15.6 15.7 15.8

Wireless access point conguration . . . . . . . . . . Connecting to the netbook via SSH . . . . . . . . . . Sharing les between the workstation and netbook How to compile on workstation and run on netbook Netbook and workstation conguration . . . . . . . Testing the network conguration . . . . . . . . . . Where should nodes run? . . . . . . . . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

33 33 34 34 34 35 35 36 36 36 36 37 38 38 38 38 39 39

16 Turtlebot operation 16.1 Physical connections . . . . . . . . . . . 16.2 Basic Turtlebot Nodes . . . . . . . . . . 16.2.1 Driver for the Create Base . . . . 16.2.2 Velocity Command Multiplexer . 16.2.3 Teleoperation Node . . . . . . . 16.2.4 Robot State Publisher . . . . . . 16.2.5 Diagnostic Aggregator . . . . . . 16.2.6 Extended Kalman Filter . . . . . 16.3 Kinect power supply . . . . . . . . . . . 16.4 Kinect-related nodelets . . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

. . . . . . . . . .

III Appendices
A How to publish messages B How to call a service C How to set parameters D Laser Scan Messages E Images in ROS E.1 Viewing images . . . . . . . . . . . . . . E.2 Image Transport . . . . . . . . . . . . . . E.3 OpenCV . . . . . . . . . . . . . . . . . . E.3.1 Compiling for OpenCV . . . . . E.3.2 Converting images to cv::Mat . E.4 Examining the images . . . . . . . . . . E.5 Viewing images . . . . . . . . . . . . . .

40
40 42 45 46 47 47 47 49 49 49 49 50

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

CSCE574 Spring 2013

Notes on ROS

3 of 51

Part I

ROS Basics
1 Getting Information About ROS
In this course, well make extensive use of a platform called Robot Operating System. This software is usually just called ROS, which rhymes with moss. In this document, Ill attempt to give you an overview of what youll need to know about ROS, but I cant hope to provide a complete picture in one short set of notes. Fortunately, there are a number of good online resources that can ll in the gaps. Most importantly, the developers of ROS maintain extensive documentation, including a set of tutorials, at http://www.ros.org You are likely to make many visits to ros.org throughout the semester. Here are two important details that will help you make sense of some of that documentation, but are not always fully explained in context there: 1. Versions of ROS are named using an adjectives that happen to start with successive letters of the alphabet. (This is, for comparison, very similar to the naming schemes use for Ubuntu and Android.) The current version, which well use for this course, is groovy. Older versions include fuerte, electric, diamondback, C Turtle, and box turtle. You may occasionally see references to these version names in the documentation. 2. The groovy version that were using, which was released just a few weeks ago, contains some major changes to the way ROS software is compiled. Specically, the older build system called rosbuild has been replaced by a new build system called catkin. This is important to know because a few of the tutorials have separate versions, depending on whether youre using rosbuild or catkin. These separate versions are selected using a pair of buttons near the top of the tutorial. If you see such buttons, always be sure to use the catkin version.

CSCE574 Spring 2013

Notes on ROS

4 of 51

2 Conguring ROS, Exploring Packages, and Creating Your Workspace


2.1 Conguring Your Account
Before you can use ROS, there is one important conguration step that must be done. ROS relies on a couple of environment variables to locate the les it needs. To set these variables, youll need to execute the setup script that ROS provides, using this command:
source /opt/ros/groovy/setup.bash

You can then conrm that the environment variables are set correctly using a command like this:
export | grep ROS

If everything is working correctly, you should see a handful values as output from this command. Note, however, that the steps listed above apply only to the current shell, and that you would need to repeat them each time you start to work with ROS in a new terminal. Because ROS often requires you to use several separate terminals, youll want to congure your account to run the setup.bash script automatically, each time you start a new shell. To do this, put the source command above into your .bashrc le. Hint 1: If you get command not found errors from the standard ROS commands, the most likely reason is that setup.bash has not been run in your current shell. Hint 2: If phrases like environment variable or .bashrc sound strange to you, I suggest reviewing the Notes on the Linux Command Line on the course website, along with the links youll nd there.

2.2

Finding and Visiting Packages

Software thats part of the ROS system is organized into packages. Each package is a self-contained unit of software that provides some functionality. To learn where a particular package is stored, use the rospack command:
rospack find <package name>

Importantly, this command also supports tab-completion of the package name. So, for example, you could type rospack find and then press the tab key twice to see a list of all of the installed ROS packages. 1 On my system, this produces a list of 222 packages. To view the les in a package, use a command like this:
rosls <package name>

To change the current directory to the directory containing a particular package, use a command like this:
roscd <package name>

References http://www.ros.org/wiki/ROS/Tutorials/NavigatingTheFilesystem
1 In fact, you are likely to nd tab completion extremely helpful throughout ROS. For example, in the command above, you could use tabs to complete both the command name rospack and the sub-command find. Try pressing tab frequently as you are typing ROS command. You might be surprised at how well it works.

CSCE574 Spring 2013

Notes on ROS

5 of 51

2.3

Creating a workspace and a package

Of course, our goal will be for you to create your own ROS packages. Those packages that you create should all live together in a directory called your ROS workspace. For example, my ROS workspace is a directory called /teaching/574/ros, but you can name your workspace whatever you like, and store the directory anywhere in your account that you wish. Just use the normal mkdir command to create a directory. Well refer to this new directory as your workspace directory. Your workspace can contain one or more packages. Use mkdir to create a src subdirectory in your workspace. The source code for each package should live inside a subdirectory, with the same name as the package, of this src directory. The command to create a new ROS package, which should be run from your src directory, looks like this:
catkin_create_pkg <package name> roscpp

The roscpp parameter there indicates a dependency on the roscpp package, which provides a C++ library of ROS functions. All of the packages we create for this course will depend on roscpp. Actually, this package creation command doesnt do much: It creates a directory to hold the package, and creates two les called package.xml and CMakeLists.txt in that folder. Having a directory that contains those two les, in a place that ROS can nd, is enough to make your directory a package. Well discuss, in Section 4.2, how to you can edit both of these les to congure your new package. References http://www.ros.org/wiki/ROS/Tutorials/CreatingPackage

CSCE574 Spring 2013

Notes on ROS

6 of 51

3 Masters, Nodes, Topics, Publishers, Subscribers


So far weve talked primarily about les, and how they are organized into packages and stored within your workspace. Lets shift gears and talk now about how to actually execute some ROS software.

3.1

Starting roscore

One of the basic goals of ROS is to enable roboticists to design software as a collection of small, mostly independent programs that all run in parallel. For this to work, those programs must be able to communicate with one another. The part of ROS that facilitates this communication is called the ROS master. To start the master, use this command:
roscore

Some comments: You must keep the master running for the entire time that youre using ROS. Generally, youll start it in one terminal, then open another terminal for your real work. You cannot have more than one master running at a time. If you try to start a second roscore, you should expect an error message. When youre done using ROS, you can stop the master by typing a Ctrl-C in its terminal. This will, of course, irreparably munge up any ROS programs that are running at the time. In Section 7, well examine a tool called roslaunch that handles starting roscorealong with other programs that you specifyautomatically.

3.2

Starting nodes

Once youve started roscore, you can run programs that use ROS. A running instance of a ROS program is called a node. The basic command to create a node (also known as running a ROS program) is
rosrun <package name> <node name>

You probably recognize the concept of package names from before. The node name part is simply the name of an executable le within that package. Heres an example that starts a very simple simulator of a turtle-shaped robot:
rosrun turtlesim turtlesim node

Once the turtlesim is running, you can drive the turtle around using your keyboard by starting this node in a separate terminal:
rosrun turtlesim turtle teleop key

Here teleop is short for teleoperation, a term that refers to human control of a robot. Dont forget to make sure that the turtle teleop key program has input focus before you try to press any arrow keys.

3.3

Inspecting the graph

ROS provides a few ways to get information about the nodes that are running at any particular time. To get a list of running nodes, try this:
rosnode list

If you try this after executing the rosrun commands above, youll see something like this: CSCE574 Spring 2013 Notes on ROS 7 of 51

/rosout /teleop_turtle /turtlesim

So there are actually three nodes running: The /rosout node is a special node that is started automatically by roscore. Its purpose is similar to the standard output (i.e. cout) that you might use in a console program. We see how to use rosout in Section 4.1. The other two nodes should be fairly clear: Theyre the simulator (turtlesim) and the teleoperation program (teleop_turtle) we started in the previous section. It seems clear that the teleoperation program and the simulator must be talking to each other somehow. Otherwise, how would the turtle know when to move in response to your key presses? This works by the teleoperation program sending messages that represent velocity commands to the turtle simulator. The primary mechanism that ROS nodes use to communicate is the concept of messages.2 Messages in ROS are organized into named topics. The idea is that a node that wants to share information will publish messages under the appropriate topic; a node that wants to receive information will subscribe to the topic or topics that its interested in. The ROS master takes care of ensuring that messages are delivered from publishers to subscribers. This idea is probably easiest to see graphically, and the easiest way to visualize the relationships between ROS nodes is to use this command3 :
rxgraph

If those same two nodes that we started above are running, youll see something like this:
/turtle1/command_velocity /teleop_turtle /turtlesim /rosout /rosout /rosout

In this graph, the ovals represent ROS nodes, and the directed edges represent publisher-subscriber relationships. So the node named /teleop turtle publishes messages on a topic called /turtle1/command velocity, and the node named turtlesim subscribes to those messages. Both of those nodes publish messages on a topic called /rosout, to which the node named /rosout subscribes. If you click, in the rxgraph window, the All topics check box, youll see a bit more:
/turtle1/color_sensor

/turtle1/command_velocity /teleop_turtle

/turtlesim

/turtle1/pose

/rosout

/rosout

/rosout_agg

This view expands the graph to include the topics themselves as rectangular boxes. This gives us the all of the same information, but also shows three new topics called /turtle1/color sensor, /turtle1/pose, and rosout_agg that we couldnt see before. These topics didnt show up in the original view because they dont have any subscribers. This is actually fairly common, because ROS nodes are usually designed to publish the useful information that they have, without worrying about whether anyone is subscribing
discuss a secondary technique based on services in Section 8. documentation suggests using a newer tool called rqt graph instead of rxgraph. At the moment, rqt graph seems not to be working.
3 The 2 Well

CSCE574 Spring 2013

Notes on ROS

8 of 51

to those messages. When youre exploring a new ROS system, the All topics option is a useful way to discover what topics are available for your programs to use to communicate with the existing nodes. Now we can understand at least part of how the teleoperation system works. When you press a key, the /teleop turtle node publishes messages with those movement commands on /turtle1/command velocity, and the turtlesim node receives those messages, and simulates the turtle moving with the requested velocity. The important points here are that The simulator doesnt care (or even know) which program publishes those command velocity messages. Any program that publishes on that topic can control the turtle. The teleoperation program doesnt care (or even know) which program subscribes to the command velocity messages it publishes. Any program that subscribes to that topic is free to respond to those commands.

3.4

Inspecting a topic and observing its messages

You can see the actual messages that are being published using the rostopic command:
rostopic echo /turtle1/command velocity

This command will dump any messages published on the given topic to the terminal. Heres some example output:
linear: 2.0 angular: 0.0 --linear: 0.0 angular: -2.0 --linear: 2.0 angular: 0.0 ---

Each --- line shows the end of one message and the start of another; in this case there were three messages. You can learn more about a topic using a command like this:
rostopic info /turtle1/command velocity

The output might look like this:


Type: turtlesim/Velocity

Publishers: * /teleop turtle (http://donatello:58531/) Subscribers: * /turtlesim (http://donatello:53925/) * /rostopic 17170 1358263206987 (http://donatello:38130/)

First, youll notice also that rostopic is listed as a subscriber to this topic. This is because rostopic echowhich was still running when I did this rostopic infois a node itself, and it works just like any other node: It subscribes to the topic you ask about, and prints out any messages that are published that topic. However, the important part about the output above is the rst line, which shows the data type of the messages on this topic. In this case, the data type is turtlesim/Velocity. To see details about a ROS data type, use a command like this: CSCE574 Spring 2013 Notes on ROS 9 of 51

rosmsg show turtlesim/Velocity

The output you should see is:


float32 linear float32 angular

So a turtlesim/Velocity is a thing that contains two 32-bit oating point numbers called linear and angular. Well see a moment that these message types become structs in C++. The rostopic program also has a few other subcommands that we wont cover here. The tutorial on Understanding Topics linked below has a few worthwhile examples, including how to use rostopic to publish messages by hand. References http://www.ros.org/wiki/ROS/Tutorials/UnderstandingNodes http://www.ros.org/wiki/ROS/Tutorials/UnderstandingTopics

CSCE574 Spring 2013

Notes on ROS

10 of 51

4 Writing Simple ROS Programs in C++


Now that you know how to congure your account for ROS, and how to work with nodes and topics, its time to write your rst ROS programs. You should rst make sure to have a correctly congured ROS workspace, and a package within that workspaceI called my package simple_examples, but any name is nefor testing.

4.1

Hello, ROS!
#include <ros/ros.h> int main(int argc, char **argv) { ros::init(argc, argv, "hello ros"); ros::NodeHandle n; ROS INFO("Hello, ROS!"); ros::spinOnce(); }

Heres a ROS version of the standard Hello, world! program.

Comments: This source le, named hello.cpp, belongs in your package folder, right next to your package.xml and CMakeLists.txt. (The tutorials suggest creating a src directory within your package directory, but this is not really necessary.) The include le ros/ros.h includes most of the standard ROS classes. Youll want to include it in every ROS program that you write. The ros::init function initializes the ROS library. Call this once at the beginning of your program to set things up. The last parameter is a string containing the name of your node. The ros::NodeHandle object is the main mechanism that your program will use to interact with the ROS system. Creating this object registers your program as a node with the ROS master. When the object is destroyed, your program de-registers itself from the master. The ROS_INFO line is a shorthand for publishing a message to the topic rosout. Youll see these on your terminal screen, and you can also use rostopic echo /rosout to see the details. Those rosout messages actually contain a bit more information that just the string message; after you compile and run this program, you can use the tools from Section 3.4 to explore the details for yourself. The ros::spinOnce() function gives the ROS library control of your program for a short time. This is when messages are actually sent and received.

4.2

Compiling Your Package

How can you compile and run this program? This is handled by ROSs build system, called catkin. There are three steps: 1. First, you need to edit the packages CMakeLists.txt le. The purpose of this le is to enable catkin to know where to nd include les and libraries for your executable. Heres a minimal version of this le that should work for our Hello, ROS example.
cmake_minimum_required(VERSION 2.8.3) project(simple_examples) find_package(catkin REQUIRED COMPONENTS roscpp) catkin_package() include_directories(include $catkin_INCLUDE_DIRS) add_executable(hello hello.cpp) target_link_libraries(hello ${catkin_LIBRARIES})

CSCE574 Spring 2013

Notes on ROS

11 of 51

The details of this le, which is actually a script for an industrial-strength cross-platform build system called CMake, are not important for us. There are three parts that deserve your attention: (a) The project line should contain the name of your package. In this example, my package is called simple_examples. (b) The find_package line should list the other packages on which your package depends. In this case, its just roscpp, but youll need to add others later. These are used to locate include les and libraries, so if you miss some dependencies, then you will likely see compiler or linker errors. (c) The last two lines dene the executable itself, which is named hello, and compiled from a source le named hello.cpp. If you have more than one source le, you can list them all here. If you have more than one executable, you can copy and modify these two lines for each executable you have. 2. Once your CMakeLists.txt is set up, you can compile your package using this command:
catkin_make

This command must be run from your workspace directory. It will perform several conguration steps (especially the rst time you run it) and create subdirectories called devel and build within your workspace. These two new directories contain build-related les like automatically-generated makeles, object code, and the executables themselves. They can safely be deleted when youve nished working on your package. If there are compile errors, youll see them here. After correcting them, you can catkin_make again to complete the build process. 3. The nal step is to source the setup.bash le created by catkin:
source devel/setup.bash

This automatically-generated script sets several environment variables that enable ROS to nd your package and its newly-generated executables. In most cases, its sufcient to do this only once in each terminal (. . . but doing this multiple times is harmless). When all of these steps are complete, your new ROS program is ready to execute just like any other ROS program:
rosrun simple_examples hello

This should produce output that looks something like this:


[ INFO] [1358276894.657872120]: Hello, ROS!

Woot! Note that, in the INFO line, the numbers represent the current time when our ROS_INFO was executed. References http://www.ros.org/wiki/ROS/Tutorials/WritingPublisherSubscriber(c++) http://www.ros.org/wiki/ROS/Tutorials/BuildingPackages

CSCE574 Spring 2013

Notes on ROS

12 of 51

4.3

Publishing messages

The hello program from the previous section showed how to compile and run a simple ROS program, but that program didnt do anything useful. In this section, well examine a slightly more complex program that publishes a message. Specically, lets send a randomly-generated velocity command to the turtlesim robot. Heres the source code, a le called pub_one.cpp:
#include <ros/ros.h> #include <turtlesim/Velocity.h> #include <stdlib.h> int main(int argc, char **argv) { ros::init(argc, argv, "pub_one"); ros::NodeHandle n; ros::Publisher pub = n.advertise<turtlesim::Velocity>( "/turtle1/command_velocity", 1000); srand(time(0)); while(pub.getNumSubscribers() == 0) ros::Duration(0.1).sleep(); turtlesim::Velocity msg; msg.linear = float(rand())/float(RAND_MAX); msg.angular = 2*float(rand())/float(RAND_MAX) - 1; pub.publish(msg); ROS_INFO("Sending random velocity command: msg.linear, msg.angular); ros::spinOnce(); } linear=%f angular=%f",

Comments: The turtlesim/Velocity.h header contains the denition of the Velocity data type, within the turtlesim package. Recall from Section 3.4 that this is the data type used on the /turtle1/command_velocity topic. We must create a Publisher object. 1. The part inside the angle brackets (turtlesim::Velocity) is the data type we would like to publish. 2. The string is the topic name, which should match one of the topic names we found using rostopic list or rxgraph. 3. The integer is the buffer size. ROS uses a buffer to store messages temporarily until they are actually sent. The buffer size determines the number of messages that can be queued in this way at a time. Any extra messages beyond the queue size will be discarded. The value here, 1000, is likely to be adequate for anything we do. If you want to publish messages on multiple topics from the same node, youll need to create multiple Publisher objects. The srand function seeds the random number generator, to ensure that we get different results each time we run the program. This should be done once; if youre calling srand more than once in a program, youre probably doing something wrong. CSCE574 Spring 2013 Notes on ROS 13 of 51

The while loop waits for at least one subscriber to be listening on our topic. Note: This loop is weird. Its necessary because the connection between a publisher and a subscriber takes some time to initialize. Without this loop, our message would very likely be published before the connections between our publisher and the subscribers on its topic were nalized. The subscribers would, therefore, likely never see our message. Since, in this example program, were sending exactly one message, we need to wait until the subscribers have had time to connect before we send that message. The loop is unusual because most ROS programs publish new messages repeatedly, in a loop (see Section 5). In that case, subscribers might miss the rst message or two that a publisher publishes, but theyll quickly start to receive the messages normally. We create a turtlesim::Velocity object and assign values to its members. Remember Section 3.4, where we use rosmsg show to nd out about this data type? This is the place in the code where those linear and angular elds come into play. Notice that ROS_INFO works just like printf to send formatted strings to rosout. This part is, of course, not strictly necessary for the message publishing to work correctly, but it can be a helpful way to keep track of what your program is up to. Finally, we call ros::spinOnce to give ROS an opportunity to actually send the message. If you never call ros::spinOnce, then ROS will never be able to send or receive and messages.4 If you want to compile and run this example, dont forget to insert lines in your CMakeLists.txt to declare a new executable in your package. Youll also want to make sure to have a turtlesim node running, so that you can see the turtle respond to the motion command you publish.

4 This is a slight b, because ROS does seem to empty its outgoing message queues when the NodeHandle is destroyed. I dont recommend relying on this.

CSCE574 Spring 2013

Notes on ROS

14 of 51

5 Writing a ROS main loop


What if we want to publish message periodically, instead of just once? As you might expect, you can wrap the publishing code in a loop. Heres an example, called loop.cpp:
... ros::Rate rate(2); while(ros::ok()) { turtlesim::Velocity msg; msg.linear = float(rand())/float(RAND_MAX); msg.angular = 2*float(rand())/float(RAND_MAX) - 1; pub.publish(msg); ros::spinOnce(); rate.sleep(); } ...

Comments: Weve omitted all of the setup code, which is the same is in pub_one.cpp. The ros::Rate object is used to control how rapidly the loop runs. The parameter in its constructor is in units of Hertz, that is, in cycles per second. The rate.sleep() call at the end of the loop allows the rate object to control the speed of the loop, to iterate no faster than the given speed. Its better than using a xed delay in each loop iteration, because it accounts for the time consumed by anything else that happens in the loop. We use ros::ok() to test whether our ROS node is functioning correctly. This enables us to use Ctrl-C to shutdown our node gracefully. Notice the ros::spinOnce here. This must be inside the loop; without it, none of the messages will be ever be published. References http://www.ros.org/wiki/roscpp/Overview/Callbacks%20and%20Spinning

CSCE574 Spring 2013

Notes on ROS

15 of 51

6 Subscribing
So far, weve covered the basics of publishing messages. Thus, our programs so far are the ROS equivalent to an annoying toddler that talks incessantly, but never listens to anyone else. Lets take a look at a program that subscribes to messages published by other nodes. Specically, lets look at the /turtle1/pose topic. Heres a short program that subscribes to those messages and summarizes them on rosout.
#include <ros/ros.h> #include <turtlesim/Pose.h> void poseCallback(const turtlesim::Pose::ConstPtr& msg) { ROS_INFO("The turtle is currently at x=%f y=%f", msg->x, msg->y); } int main(int argc, char **argv) { ros::init(argc, argv, "sub"); ros::NodeHandle n; ros::Subscriber sub = n.subscribe("/turtle1/pose", 1000, poseCallback); ros::spin(); }

Comments: Were using the turtlesim/Pose data type this time. How did we know that we the right one? We used rostopic info to get the details about what the turtlesim node is publishing. We need to create a Subscriber object, using the name of topic and a buffer size. This uses the same buffer idea that we saw for publishing messages: If the buffer lls up, messages will be discarded. Since we dont know when message will be published, we use a callback function that ROS calls each time a message arrives. A pointer to the message itself is passed to this callback function. In this case, our callback simply prints out some of the data from the message; a real program would perform some meaningful computation on the message. Just as with message publishing, we need to make give control to ROS to allow messages to be sent and received. In this case, everything we want to do happens in the callback function, so instead of ros::spinOnce, we use ros::spin(), which is roughly equivalent to:
while(ros::ok()) ros::spinOnce();

CSCE574 Spring 2013

Notes on ROS

16 of 51

7 Launch Files
If youve worked through all of the examples so far, by now you might be getting frustrated by the need to start so many different nodes, not to mention roscore, by hand in so many different terminals.

7.1

A basic launch le

Fortunately, ROS provides a mechanism for starting the master and many nodes all at once, using a le called a launch le. Heres an example launch le that starts a turtle simulator, along with the publisher and subscriber nodes we wrote in Section 4.
<launch> <node pkg="turtlesim" name="turtlesim" type="turtlesim_node" output="screen" /> <node pkg="simple_examples" name="loop" type="loop" output="screen" /> <node pkg="simple_examples" name="sub" type="sub" output="screen" /> </launch>

As you can see, a launch le is an XML le which, in its simplest form, contains a collection of <node> tags. To use a launch le, use the roslaunch command:
roslaunch <package name> <launch file name>

For example, assuming that I have saved the XML code above as a le named random.launch in my simple_examples package, I could say
roslaunch simple_examples random.launch

to start roscore, the turtle simulator, our random velocity command simulator, and our turtle pose subscriber all at once. One important thing to keep in mind is that all of the nodes you specic are all started simultaneously, so you cannot be sure about the order in which theyll be initialized. This can cause problems if you test your system using individual rosrun commands. For example, services needed by one node might be needed before the server is up. Be careful. ;

7.2

Launch arguments

There is also a mechanism supported by roslaunch to modify the behavior of a launch le using commandline parameters. The advantage is that you can avoid code duplication by writing launch les that use arguments for the small number of details that might change from run to run. To do this, use the arg directive in your launch le. Heres an example that allows you to choose the name of a turtlesim node at run time:
<node pkg="turtlesim" name="$(arg turtle_name)" type="turtlesim_node" />

Then add turtle_name:=Leo to the command line when you use ROS launch. This technique works by a simple text substitution, so it can be used anywhere in your launch le. References http://www.ros.org/wiki/ROS/Tutorials/UsingRqtconsoleRoslaunch

CSCE574 Spring 2013

Notes on ROS

17 of 51

8 Calling services
So far weve seen one basic mechanism for communication between nodes: publishing on and subscribing to topics. That is, in fact, the primary method for communication in ROS. It is characterized by being unidirectional (so that the publisher does not need to wait for a response from the subscribers, if there even are any) and many-to-many (many different nodes can publish and subscribe on the same topic). This section introduces an alternative method of communication called services that can be useful in some instances. Services differ from topics in a couple of ways. 1. First, services are bi-directional. A client node sends a request. A server node receives that request and sends a response. Information ows in both directions. 2. Second, services represent one-to-one communication. Only one node can offer a given service at a time. Each request comes from one node, and the response goes back to that same node. Aside from those differences, services work similarly to topics. In this section well focus on writing clients for services. The online tutorials have additional information about writing the server side.

8.1

Finding services

You can get a list of services that are currently active using this command:
rosservice list

On my system, with just a turtlesim running, heres the list I get:


/clear /kill /reset /rosout/get_loggers /rosout/set_logger_level /spawn /turtle1/set_pen /turtle1/teleport_absolute /turtle1/teleport_relative /turtlesim/get_loggers /turtlesim/set_logger_level

Each line represents one service that some node is offering. You can also get information about the services offered by a particular node using rxgraph (by hovering your mouse pointer over each node) or using rosnode info.

8.2

Service data types

Like topics, each service has a data type. You can determine that data type of a service using a command like this:
rosservice info <service name>

For example, when I type


rosservice info /spawn

the output is

CSCE574 Spring 2013

Notes on ROS

18 of 51

Node: /turtlesim URI: rosrpc://donatello:47441 Type: turtlesim/Spawn Args: x y theta name

Here we see that the data type of the /spawn service is turtlesim/Spawn. We can get some details about service data types using the rossrv command. For example,
rossrv show turtlesim/Spawn

produces this output:


float32 x float32 y float32 theta string name --string name

In this case, the data before the --- are the elements of the request. This is the information that the client node sends to the server node. Everything after the --- are elements of the response, or information that the server sends back from the client when the server has nished acting on the request. Note that either or both of these groups can be empty. For example, in the /reset service offered by turtlesim_node, both the request and response parts are empty. This is roughly equivalent to a C++ function that accepts no arguments and returns void: No information goes in or out, but useful things still may happen.

8.3

Calling services from the command line

To get a feel for how services work, you can call them from the command line using this command:
rosservice <service name> <request data>

The request data part should simply be a list of values for each of the request data members returned by rosmsg show. Heres an example:
rosservice /spawn 3 3 0 Tim

The effect of this service call is to create a new turtle called Tim, at position (3, 3), facing at angle = 0, within the existing simulator. This is just one example. You might have some fun experimenting with the other services offered by turtlesim_node.

8.4

Calling services from C++

Calling services from the command line is handy in a pinch, but its much more useful to be able to call services from your code. Heres a short example that shows how to do that.

CSCE574 Spring 2013

Notes on ROS

19 of 51

#include <ros/ros.h> #include <turtlesim/Spawn.h> #include <stdlib.h> int main(int argc, char **argv) { ros::init(argc, argv, "service"); ros::NodeHandle n; ros::ServiceClient spawnClient = n.serviceClient<turtlesim::Spawn>("/spawn"); turtlesim::Spawn srv; srv.request.x = 10 * float(rand())/float(RAND_MAX); srv.request.y = 10 * float(rand())/float(RAND_MAX); srv.request.theta = 2 * 3.14159 * float(rand())/float(RAND_MAX); srv.request.name = "Tim"; bool success = spawnClient.call(srv); if(success) { ROS_INFO("Spawned a turtle named %s at (%f,%f).", srv.response.name.c_str(), srv.request.x, srv.request.y); } else { ROS_INFO("Spawn failed."); } }

The basic steps shown in the example are: Include the corresponding header le for the data type of our service. Create a ServiceClient object, using this data type and the name of the service. Create an object (usually called a srv) for that data type. Fill in the members (if any) of its request portion. Use the ServiceClient and the srv to call the service. Check the boolean return value for success or failure. Use the members (if any) of the response portion of the srv, which should be lled in by the service call. Thats all there is to it. We wont use services as frequently as topics in this course, but there are a few places where service calls will be necessary.

CSCE574 Spring 2013

Notes on ROS

20 of 51

9 Setting and querying parameters


In addition to topics and services, ROS provides one more basic mechanism to get information from one node to another called the parameter server. The basic idea is that the ROS master keeps track of a collection of values, each identied by a short string name. Any node can set or query these values.

9.1

Accessing parameters from the command line

Just as with other things in ROS, we can access parameters from either the command line or from code. Lets start with a few command line examples. To see a list of all existing parameters, use this command:
rosparam list

On my system, with no nodes running, the output is:


/rosdistro /roslaunch/uris/host_donatello__56935 /rosversion /run_id

Each of these strings is a parameter name that the master has associated with some value. To nd out what that value is, use a command like this:
rosparam get <parameter name>

For example, running


rosparam get /rosdistro

returns the string


groovy

This ts, since we already knew that were using the groovy version of ROS. Other parameters are likely to be of more interest. For example, turtlesim_node creates parameters called /background_b, /background_g, and /background_r that control the background color of the simulated world.5 If you want to modify the values of parameters from the command line, you can use rosparam set. The details of this command are left as an exercise.

9.2

Accessing parameters from C++

Reading and setting parameters from your C++ couldnt be easier. There are just two (overloaded) functions that youll need:
n.setParam(<parameter name>, <input value>); n.getParam(<parameter name>, <output value>);

In both cases, the parameter name is a string. The input value for setParam can be a string, boolean value, integer, or oating point number; the output value for getParam should be a variable (which is passed by reference) of one of those types. Thats it! References http://www.ros.org/wiki/roscpp/Overview/Parameter%20Server http://www.ros.org/wiki/Parameter%20Server
5 Note, however, that turtlesim node sets its own values for these parameters when it starts (clobbering any values that might exist there already), and it only reads their values from the parameter server when its reset or clear services are called. If you want to change the background color, youll need to account for these quirks.

CSCE574 Spring 2013

Notes on ROS

21 of 51

10

Bags

Because it takes so much effort to carry out experiments with robots, its often helpful to record the sensor data that our robots collect. The mechanism that ROS uses to enable this functionality is called a bag le. Roughly speaking, a bag le stores timestamped ROS messages. Bag les may be recorded as a ROS system runs, storing the messages published on a set of topics that you choose, and they may be replayed, republishing those messages at the same rate. The advantage of this technique is that you can run the robot just once, and try many different techniques for processing the data that it collects.

10.1

Recording and playing bags

To create a bag le, use the rosbag command:


rosbag record [-O filename.bag ] [topic names]

If you dont give a le name, rosbag will choose one for you based on the current date and time. There are a few other options for rosbag record that might be useful: 1. Instead of listing specic topics, you can use rosbag record -a to include every topic that is currently being published. 2. You can enable compression in the bag le using -j. This has the usually tradeoffs of compression: Generally smaller le sizes, in exchange for slightly more computation to read and write. Compression generally seems to be a good idea for bag les. Note that rosbag play (introduced below) detects this compression automatically. To replay a bag le, use a command like this:
rosbag play filename.bag

The messages stored in the bag le are then replayed, with the same time intervals as when they were originally published.

10.2

Bag example

If you want to get a feeling for how this works, try out these steps: 1. Start roscore. 2. Start turtlesim_node and draw_square, both of which live in the turtlesim package. 3. While the turtle is drawing squares, run
rosbag record -O square.bag /turtle1/command_velocity

Unfortunately, rosbag record seems to be one of the few places in which tab completion does not work correctly, so youll need to type out the entire topic name. 4. At this point, rxgraph will show something like this:
/rosout_agg

/rosout

/turtle1/color_sensor

/turtlesim

/turtle1/pose

/draw_square /turtle1/command_velocity /record_1360185935425446685

CSCE574 Spring 2013

Notes on ROS

22 of 51

The new and interesting part here is that rosbag has created a new node, called /record_... that subscribes to /turtle1/command_velocity. (The number in that nodes name serves to make the node name unique, so that we can run multiple rosbag record instances at once, if we choose to.) We can infer from this that rosbag records messages by subscribing to the topics you ask for just like any other node, using the same mechanism that we learned in Section 6. 5. Kill rosbag to stop the recording. 6. Kill draw_square to stop the turtles drawing. 7. Inspect your new bag le using this command:
rosbag info square.bag

On my system, this provides a number of interesting snippets of information:


path: square.bag version: 2.0 duration: 7.3s start: Feb 06 2013 16:23:00.47 (1360185780.47) end: Feb 06 2013 16:23:07.81 (1360185787.81) size: 34.1 KB messages: 457 compression: none [1/1 chunks] types: turtlesim/Velocity [9d5c2dcd348ac8f76ce2a4307bd63a13] topics: /turtle1/command_velocity 457 msgs : turtlesim/Velocity

8. Replay the bag using this command:


rosbag play square.bag

Notice that the turtle will resume moving. This happens because rosbag, has created a node named play_... that is now publishing on /turtle1/command_velocity:
/rosout /play_1360186878362623199 /clock /turtlesim /turtle1/command_velocity /turtle1/pose /turtle1/color_sensor /rosout /rosout_agg

The messages that it publishes are the same ones that draw_square originally published.

10.3

Other bag tricks

There are a few more sub-commands for rosbag that are potentially helpful, including a command to get a human-readable summary of a bags contents, and commands to compress, decompress, and repair bag les. See the documentation le linked below for details. References http://www.ros.org/wiki/rosbag

CSCE574 Spring 2013

Notes on ROS

23 of 51

11

Visualizing data with RViz

So far weve seen some rudimentary ways to see whats going on in a running ROS system. However, none of these techniques are really suitable for viewing and understanding the complex data thats produced by a real robot. To ll this gap, ROS provides a tool called RViz that can display a wide variety of information about how the robot itself is operating. To start RViz, use the command
rosrun rviz rviz

or include the corresponding line in your launch le. Thats it. The rest of this section has some details on how to use RViz.

11.1

Setting the xed frame

Well display some data shortly, but rst we need to tell RViz what coordinate system to use. In ROS terms, we need to choose a frame_id (see Section 12) for a frame to act as a xed frame. To choose the xed frame, use the drop-down box on the left under Global Options. You are free to choose any frame you like, but there are generally two types of reasonable choices: We can choose a body frame of the robot. For many robots supported by ROS (including our TurtleBots), theres a body frame called /base_footprint, whose origin is on the ground below the center of the robot, that is a particularly good choice. Choosing a body frame as the xed frame will put the robot at the origin. Then as the robot moves, well see everything else in the world move around it. We can choose an odometric frame, whose origin is at the robots starting position. A moving robot will generally publish transforms between the odometric frame and its body frames that change based on the robots (estimated) movements. The odometric frame is often called /odom or odom_combined. Choosing this for the xed frame provides more of a global view in which we can see the robot moving through the world.

11.2

Working with RViz displays

When you start RViz for the rst time, most of its window will be taken up with a black rectangle. This is the 3D view of the world; nothing is displayed there yet because we havent asked RViz to display any data. RViz refers to the different kinds of data that we might want to show as displays. To add a new display, use the Add button near the bottom left of the window, then select the type of display that you want. After adding the display in this way, it will show up in the Displays panel on the left, and generally will need to be congured there. There are several different displays that you may want to add when youre working with the TurtleBot. A Grid display as a reference point for where the ground is. A Robot Model display to show the robot itself. You might be curious about how RViz knows what our robot looks like. It reads the robots physical description as a (lengthy) string from a ROS parameter called robot_description. This robot description is in a format called Unied Robot Description Format (URDF). The usual way to do this is to include a tag like this in your launch le:
<param name="robot_description" command="$(find xacro)/xacro.py $(find turtlebot_description)/robots/create_circles_kinect.urdf.xacro"/>

CSCE574 Spring 2013

Notes on ROS

24 of 51

A Laser Scan display to show messages of type sensor_msgs/LaserScan, which represents a reading from a laser range scanner, or from another sensor that provides similar data. Youll need to choose a specic topic of this type to display (but there will not generally be many choices). Some details about these messages are in Appendix D. A Map display to show messages of type nav_msgs/OccupancyGrid, which represents the robots idea of which places area free to move through and which are obstacles. Dont forget to set the specic topic to display. A TF display to show all of the coordinate frames in the system. All of these together provide a wealth of information. A reasonable practice is to include all of them in your RViz conguration, but to use the check boxes next to each displays name to hide the information that you are not interested at a particular time. Note that some of these displays can be resource hogs, so you may be able to improve performance by selective disabling.

11.3

RViz display congurations

If youve started RViz several times, you might have noticed that it remembers your displays and their conguration from the previous run. RViz stores this kind of information in a .rviz le. There are several things you can do with this kind of le to force RViz to behave nicely. To save (or load) the RViz conguration to (or from) a .rviz le, you can use the appropriate commands in the File menu of RViz. To force RViz to use a specic, existing .rviz le when it starts up, you can pass it a -d followed by the le name on its command line. In a launch le, you can put the -d and lename in the args attribute. When RViz starts without a -d, it automatically loads conguration from a le in your home directory called .rviz/default.rviz. If you would like to return to the default, empty conguration, you should close RViz, delete this le, then reopen RViz.

11.4

Setting the RViz view

In the top right of the RViz window, youll nd drop-down to select a view type, which controls the camera placement for your RViz view. The details of how these views work is best learned by experimenting. However, you will likely nd the TopDownOrtho view type to be particularly useful, especially when youre dealing with two dimensional data like maps.

11.5

Segfaults and Bad Drawable errors

Some versions of RViz experience segmentation fault of Bad Drawable errors on certain hardware. In both cases, the error is fatal but intermittent. This is more likely to occur if you use a computer with an integrated video card. Let me know if you experience this issue.

CSCE574 Spring 2013

Notes on ROS

25 of 51

12

Using Frames and Transforms

As we discussed in class, the ideas of coordinate frames and transforms between them can be important for understanding a robots operation in the world. Youll be glad to know that ROS provides a package called tf that can make these issues relatively painless, as long as we are careful.

12.1

TF overview

Every time you are working with coordinates, you should know which frame those coordinates are expressed in. (Otherwise, the likelihood of making a mistake is quite high.) In tf, each coordinate frame is identied by short string called a frame_id. The tf system works by using a topic called /tf to publish transforms that describe how to convert coordinates in one frame to another. Each message on this topic contains one or more transforms that look like this:
Header header uint32 seq time stamp string frame_id string child_frame_id geometry_msgs/Transform transform geometry_msgs/Vector3 translation float64 x float64 y float64 z geometry_msgs/Quaternion rotation float64 x float64 y float64 z float64 w

This data type contains two frame_id strings: One in the header, called simply frame_id, and another called child_frame_id. This transform tells us how to convert coordinates expressed in the frame named by frame_id into the frame named by child_frame_id. Notice that this setup forms a directed graph, in which the nodes are coordinate frames, and the directed edges are transforms between those frames. In tf, each frame can have only one parent frame, so we actually get a tree structure. For example, heres a portion of the tf tree that is used with the Turtlebot robots well use in this course:
/odom_combined

/base_footprint

/base_link

/left_wheel_link

/right_wheel_link

/wall_sensor_link

/front_wheel_link

/gyro_link

/laser

/rear_wheel_link

The ovals show the frames with their frame_id, and the directed edges show transforms between pairs of frames. By applying these transforms or their inverses in the correct sequence, tf can convert coordinates between any pair of frames we want.

12.2

Looking up transforms in within your code

In principle, you now know enough to convert between coordinate frames. You could subscribe to tf, remember the transforms that are published on that topic, and compose them carefully (probably by expressing them as homogeneous transformation matrices) to compute the correct transform to move points CSCE574 Spring 2013 Notes on ROS 26 of 51

from one frame to another. The good news is that there is no need to explicitly subscribe to /tf, because the ROS client library has C++ classes that handle all of the dirty work for us. To do this, there are a few steps. 1. Make sure your package depends on the tf package. 2. Create a transform listener. Include <tf/transform_listener.h>. Create an object of class tf::TransformListener. This object will, behind the scenes, subscribe to tf and cache the transforms that are broadcast after it is created. Therefore, its is important to: (a) create this object after the node is initialized (that is, after the NodeHandle is created), and (b) destroy it only after you are completely nished using the tf system (that is, when your program ends). For example, if you create a new TransformListener each time you need to change coordinate frames, then its cache will be empty, and it wont be able to return the transformations you need. Ask your transform listener for the transform between the two frames you care about. Create an object of type tf::StampedTransform:
tf::StampedTransform transform;

Inside a try/catch block, ask the transform listener for the appropriate transform:
try { listener.lookupTransform( "targetFrameID ", "sourceFrameID ", ros::Time(0), transform ); } catch (tf::TransformException ex) { ROS_ERROR("%s",ex.what()); }

The method lookupTransform method takes care of the details of nding a path through the transform tree and composing all of the transforms along the way. For example, in the tree shown above, it would be just ne to ask for the transform between /left_wheel_link and /right_wheel_link, because tf will automatically nd a path between these two via /base_link and perform the appropriate inversion and composition, to return a transform directly between the body frames of the left and right wheels. The ros::Time(0) in the code above means that we want to know the most recent transform between those two frames. Time 0 is a special case. A more likely situation is that youll want to give a specic time stamp to ask for the transform that was correct at some specic point in the past. These timestamps are particularly important when you are processing sensor data. By the time you are processing a sensor data message, the corresponding transforms may already have changed. Fortunately, most messages containing sensor data contain a timestamp eld. You should use the timestamp of message containing the sensor data instead of ros::Time(0). The try/catch block is important here, because lookupTransform can generate exceptions even if youve done everything right. The most common reason for this to occur is that the transform listener has not yet received enough messages on topic /tf to construct the transform you need. These things often resolve themselves within a second or so. CSCE574 Spring 2013 Notes on ROS 27 of 51

3. Use the transform to change coordinates between your two frames. Store the point you care about in a tf::Point.
tf::Point pointInSourceFrame pointInFromFrame.setX(yourX ); pointInFromFrame.setY(yourY ); pointInFromFrame.setZ(yourZ);

Multiply that point by the transform object and store the resulting tf::Point.
tf:Point pointInTargetFrame = transform * pointInFromFrame;

Access the coordinates of the transformed point:


ROS_INFO("Transformed point is (%f, %f, %f).", pointInTargetFrame.x(), pointInTargetFrame.y(), pointInTargetFrame.z() );

12.3

Frames from the command line

In addition to the client library functions described above, tf also includes a couple of command line tools that can help you gure out whats going on. First, to see the current tf tree, use the command view_frames. This will subscribe to /tf for a few seconds, and then create a le called frames.pdf that illustrates all of the frames for which transforms are currently being being published. (This is the technique I used to create the transform tree image a few pages back.) Second, you can see specic the transforms between a pair of frames using the tf_echo command. Heres an example:
rosrun tf tf_echo /kinect_depth_frame /base_link

References http://www.ros.org/wiki/tf/Tutorials/Introductiontotf http://www.ros.org/wiki/tf/Tutorials/Writingatflistener(C++) http://www.ros.org/wiki/tf/Overview/DataTypes http://ros.org/doc/groovy/api/tf/html/c++/

CSCE574 Spring 2013

Notes on ROS

28 of 51

Part II

Turtlebots
13 About the Turtlebot
Through the remainder of this class, we use ROS to work with a robot platform called the Turtlebot. The next few sections describe how to obtain your Turtlebot kit, how to set up these robots, and how to operate them. The Turtlebot built from several off-the-shelf components: 1. An iRobot Create mobile base. 2. A small laptop. 3. A Kinect sensor that collects Red-Green-Blue-Depth (RGBD) images. 4. A custom circuit board with both single-axis gyroscope and a power supply for the Kinect. For this course, we are using the original Turtlebot, which might also be called Turtlebot 1 in the documentation. The newer Turtlebot 2 version (which, coincidentally, was the robot I used to collect the bag le we used in Project 2) is very similar, but has a redesigned mobile base.

13.1

Turtlebot is not turtlesim

Note that the rst project and many of the tutorials used a very simple robot simulator called turtlesim, which is designed to help people learn about ROS without worrying too much about the details of real robots. We will not use turtlesim again this semester. The fact that both of these names contain the word turtle is an unfortunate coincidence.

13.2

Turtlebot has two computers

As you are working with the Turtlebot, there are actually two computers youll use. A netbook computer that rides atop the robot. Throughout these notes, Ill refer to this computer as the robots computer or the netbook. Once this computer is set up correctly, it should be very rare for you to remove it from the robot, except to power it on or off. If you nd yourself typing on the netbook keyboard regularly after youve got the robot working, youre probably doing something wrong. A desktop or laptop computer that youll use to operate the robot. Ill refer to this computer as the workstation in these notes. Most all of the typing and clicking you do will be on this computer. It will be important to keep careful track of the differences between these two computers. Each will have its own commands for you to give and ROS nodes to execute. References http://www.willowgarage.com/turtlebot http://www.irobot.com/create http://www.xbox.com/kinect

CSCE574 Spring 2013

Notes on ROS

29 of 51

13.3

Getting your Turtlebot kit

We have access to six Turtlebot robot bases for this class. (Note that there are seven groups, so it will not be possible for everyone to work on the project simultaneously. Please plan accordingly and be considerate to your classmates.) These robots will be stored in the 3D22 lab and should remain there, connected to their chargers, when theyre not in use. In addition to the robot bases, I will distribute to each group a kit of additional hardware to use throughout the rest of the semester. Each kit will include: 1. A netbook, to ride on and control the robot base . 2. A USB stick, to install an operating system on the netbook. 3. A wireless access point, to enable communication between the netbook and a workstation. 4. A spare battery for the robot bases. 5. Cables for all of these devices. 6. An information sheet with certain details you should use as you set up your robot. The idea is that the parts of the robot that need to be congured or charged will be checked out to your group individually. Before you can check out a kit, each member of your group must read and sign a Robot Signout Form, acknowledging responsibility for the equipment and promising to return it in good condition at the end of the semester.

CSCE574 Spring 2013

Notes on ROS

30 of 51

14

Netbook setup

The rst step toward getting your Turtlebot up and running is to install and congure ROS on the netbook. You should start from scratch on this, without assuming that any useful les of any kind are stored on that computer.

14.1

Installing the operating system

Before you can install ROS itself, youll need to install an operating system on the netbook. 1. Using another computer of your choice, download the installation image for the Ubuntu GNU/Linux operating system. A link to the download page appears below. (a) I strongly suggest that you download Ubuntu 12.10, which is the latest stable version. (b) I also suggest that you stick to the 32 bit version; so far 64-bit operating systems often seem to create more trouble than theyre worth. You may use other Linux distributions if you prefer, but Ubuntu seems to have the best ROS support. 2. Create a bootable USB ash drive from this image. (a) Your robot kit includes a USB ash drive that you can use for this purpose. (b) The Ubuntu download page has detailed instructions on how to make the drive bootable. (c) If you are using an Ubuntu computer to create the bootable USB, this command will start the program you need:
usb-creator-gtk

3. Boot the netbook from the USB drive. You may need to congure the netbooks boot sequence (that is, the ordered list of hardware devices from which it tries to load an operating system) to force it to start from the USB drive, rather than from the netbooks hard disk. The details of how to do this vary depending on the specic netbook model youre using, but for the ASUS netbooks we have: (a) Pressing F2 to access the BIOS menu when the computer rst starts to boot generally seems to be the rst step. (b) Within the BIOS menu, bootable USB devices (such as your ClearPath USB stick) might show up as hard disks and not, as you might expect, as removable devices. 4. Follow the on-screen prompts to install Ubuntu. (a) You should see a screen that has options to Try Ubuntu or Install Ubuntu. If you get a typical Linux login screen instead, its likely that something when wrong in the previous step. (b) Choose Install Ubuntu. (c) When youre asked, I suggest choosing both Download updates while installing and Install third-party software. (d) If you are asked about operating systems that are already installed, I recommend that you vaporize anything that is already on the netbook, so that you new Ubuntu 12.10 installation uses the entire hard disk. (e) During the installation process, you will also be prompted to provide a name for the computer and to create a user account. Please use the information listed on your Turtlebot Information Sheet for all of the data on this screen. (f) Dont forget to remove the USB drive during the reboot, after the installation is nished. Otherwise, youll nd yourself back at the beginning of the installation process. CSCE574 Spring 2013 Notes on ROS 31 of 51

14.2

Installing basic software

You will likely want to install other software beyond the packages pre-installed with Ubuntu. If you have not administered a Debian-based Linux system before, youll be interested in the link below, which has some instructions on how to use the apt-get command-line tool to install and manage packages. There are two standard (that is, non-ROS) packages that you will denitely want to install: 1. The package openssh-server provides an SSH server, so that you can execute commands on the netbook remotely over the network via ssh. 2. The package chrony package provides a clock synchronization service. This is important because, as you have seen, ROS relies on timestamps in many of its messages.

14.3

Installing ROS

Now that you have a working Ubuntu installation on the robots netbook, the next step is to install ROS itself. 1. First, install the core ROS packages. The link below has the instructions on how to do this. However, those instructions mention a tool called rosinstall, which I recommend that you ignore. All of the software that well need is available as Ubuntu deb packages, which do not require rosinstall. 2. Second, there are a few packages that are specic to the turtlebot that youll need as well. They are: ros-groovy-turtlebot ros-groovy-turtlebot-apps ros-groovy-turtlebot-create ros-groovy-turtlebot-create-desktop ros-groovy-turtlebot-dashboard ros-groovy-turtlebot-simulator ros-groovy-turtlebot-viz ros-groovy-python-orocos-kdl These can be installed with the usual apt-get install command. References http://www.ubuntu.com/download/ubuntu/download/ http://www.basicconfig.com/linux/ubuntu_package_management_system http://www.ros.org/wiki/groovy/Installation/Ubuntu http://www.ros.org/wiki/turtlebot/Tutorials/groovy/Post-Installation%20Setup

CSCE574 Spring 2013

Notes on ROS

32 of 51

netbook

workstation

netbook

workstation

[4] workstation [1] [2] netbook WAP [3] WAP [3]

SWGN network

WAP

SWGN network

SWGN network

(a)

(b)

(c)

Figure 1: Physical network setup. (a) Recommended setup for 3D22 lab computers. (b, c) Alternatives for using a laptop as the workstation. Dashed lines indicate wireless connections. Solid lines indicate wired connections. [1] Workstation primary ethernet; [2] Workstation secondary ethernet; [3] WAP Internet port; [4] WAP ethernet port

15

Running ROS over a network

You might remember that one of the primary reasons that ROS exists is to facilitate distributed operation of robots, in which many different programs running on multiple computers can interact using topics, services, and parameters. In the simulations we used so far, your entire ROS system has been contained on a single computer. In contrast, to operate the Turtlebot correctly, well need to use these distributed features of ROS. The good news for you is that, once you have congured things correctly, network communication should occur seamlessly because the ROS system takes care of the details.

15.1

Physical setup

There are several choices for how to connect things to enable the workstation and the netbook to talk to each other, but the recommended option appears in Figure 1a. Figures 1b and 1c show alternatives that might make sense if your workstation is a laptop.

15.2

Wireless access point conguration

Your robot kit includes a wireless access point (WAP) that you should use to allow the netbook to connect to the outside world. Since WAPs vary, I omit detailed instructions on how to congure this. At a minimum, you should 1. set the WAPs SSID (sometimes called network name) to the name on your Turtlebot Information Sheet, 2. enable some form of password protection on the wireless network, and 3. set the WAPs administrator password to the password listed on your sheet. Some students in the past have also had success changing the wireless channel, to avoid interference with the wireless signals used by other groups. On the netbook side, you can attempt to connect to a wireless network using this icon in the top right of the screen: . Youll know that youve succeeded at this step if the netbook is able to connect correctly to the wireless network provided by your WAP.

15.3

Connecting to the netbook via SSH

By now you should be able to connect to the netbook via SSH from your workstation. The command should be something like: CSCE574 Spring 2013 Notes on ROS 33 of 51

ssh turtlebot1@turtlebot1

If this works correctly, you should get a command prompt on the netbook. This is crucial because the netbook will be mounted on the robotwith its keyboard quite inaccessiblemost of the time.

15.4

Sharing les between the workstation and netbook

Its important to note that ROS does not transfer les between the computers. Therefore, you will want to nd a way to develop software on your workstation and transfer that software the netbook to execute there. One possible option is use scp to copy les; another is to use Dropbox to sync things automatically; still another (my favorite) is to use sshfs to mount the workstations ROS workspace on the netbook. There are other solutions as well.

15.5

How to compile on workstation and run on netbook

So far, weve used the setup.bash script generated by catkin_make to help ROS nd the ROS nodes that we write. However, this method wont work if attempt to compile your code on your workstation and run it on the netbook, because setup.bash hard-codes the path to your ROS workspace, which is unlikely to be the same between the two computers. The easiest solution is to use the ROS_PACKAGE_PATH environment variable instead of setup.bash on the netbook. This variable contains a comma-separated list of directories that contain ROS packages. For example, on my netbook, I used:
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$HOME/ros/src

to append my ROS workspace to the package path, allowing ROS to nd my packages. However, this approach cannot nd compiled executables in the devel folder the way that the setup.bash does. Therefore, you will need to copy the executable to a place the ROS can nd it. For example, to recompile my map executable and copy it to its packages source directory, I used a command like this:
catkin_make && cp devel/lib/laser_map/map src/laser_map/

References http://www.linuxtutorialblog.com/post/ssh-and-scp-howto-tips-tricks http://www.dropbox.com/

15.6

Netbook and workstation conguration

ROS requires three things to be true in order to work correctly over a network: 1. Each computer must advertise itself using a name (or IP address) that can be resolved by each other computer. The easiest way to accomplish this is to edit the le /etc/hosts on both the workstation and the netbook, adding a line listing the IP address and hostname of the other computer. For example, heres the hosts le from my workstation, whose name is raphael and whose IP address is 192.168.1.100:
127.0.0.1 localhost 127.0.1.1 raphael 192.168.1.101 turtlebot1

Heres the hosts le from my netbook, whose name is turtlebot1 and whose IP address is 192.168.1.101: CSCE574 Spring 2013 Notes on ROS 34 of 51

127.0.0.1 localhost 127.0.1.1 turtlebot1 192.168.1.100 raphael

You can determine the specic IP address assigned to a computer using the ifconfig command, or possibly directly from the administration interface of your WAP. Note that these IP addresses are assigned dynamically by the WAP, so you should verify that the hosts les are set up correctly each time you start working with the robot. (The ROS documentation also mentions an alternative method that uses environment variables called ROS_IP and ROS_HOSTNAME. This approach seems less reliable in my experience.) 2. Each computer must be able to contact the same ROS master. Recall that there should be exactly one master, regardless of how many computers you use. The location of the master is controlled by the environment variable ROS_MASTER_URI. For a Turtlebot, it is recommended to run the master on the netbook. For example, heres the command I used:
export ROS_MASTER_URI=http://turtlebot1:11311

The number at the end of this URI is a port number; 11311 is the default port for the ROS master. Dont forget to ensure that this variable is set in every terminal you use. 3. Each computer can initiate a connection to any port on any other computer. This is governed by the conguration of the network hardware. In the setups shown in Figure 1, you should get this for free, but in more complex scenarios, it can become tricky.

15.7

Testing the network conguration

After completing the network conguration, I strongly suggest that you do some testing to make sure ROS works correctly in your setup, before you continue. As a simple example, you should be able to start roscore on the netbook, and then run turtlesim_node and turtlesim_teleop on the two different machinesTry it in both directions!and control the simulated robot on one computer from the other. If you have trouble, one place to start troubleshooting is to start rxgraph. When you hover over a node or topic, the panel on the right shows the hostnames or IP addresses that ROS nodes are attempting to use to talk to each other.

15.8

Where should nodes run?

Now that there are multiple computers in your system, youll need to decide which computer should run each node. There are several factors that can inuence this decision, but a general rule of thumb is that any nodes that have GUI components should run on the workstation, and all others should run on the netbook. References http://www.ros.org/wiki/ROS/NetworkSetup http://www.ros.org/wiki/ROS/Tutorials/MultipleMachines http://ros.org/wiki/ROS/EnvironmentVariables

CSCE574 Spring 2013

Notes on ROS

35 of 51

16

Turtlebot operation

After completing the steps in Sections 14 and 15, youre ready to start operating a Turtlebot. This section has some details on how to do that. As usual ROS has an abundance of documentation, of which much is directly useful to us. Two useful starting places are the Turtlebot tutorial page: http://www.ros.org/wiki/turtlebot/Tutorials and the Turtlebot Care and Feeding page: http://www.ros.org/wiki/turtlebot/Tutorials/TurtleBot%20Care%20and%20Feeding

16.1

Physical connections

There are a two steps to take each time you want to use the robot. 1. Place the powered-on netbook in the robot, oriented so that the side with two USB ports is in the back. Plug in both USB cables. One of these cables connects the robot to the iRobot Create mobile base; the other connects it to the Kinect RGBD sensor. 2. Turn on the iRobot Create base. Theres a button inside the lowest plate that looks a bit like this: . If you hear a four-note sad song, this indicates that the Creates battery is too low to operate correctly, and youll need to recharge or swap out the battery.

16.2

Basic Turtlebot Nodes

This section introduces several several nodes that youll want to use every time you operate the Turtlebot. In the turtlebot_bringup package, you can see an example launch le called minimal.launch that uses most of these nodes. It will be helpful, however, to construct your own launch le, to ensure that you understand whats going on inside your robot. 16.2.1 Driver for the Create Base

The create_node package provides a node called turtlebot_node.py. This node is the program that communicates with the iRobot Create mobile base using the white serial cable. (If youve taken CSCE374 recently, then you might have some idea about how this program works.) Before the usual rosrun command, there are two additional steps on the netbook that are needed to get this node working correctly: 1. First, you need to make sure that you have permission to read from and write to the robots serial connection. This device is called /dev/ttyUSB0, and its ls -l entry looks like this:
crw-rw---- 1 root dialout 188, 0 Mar 1 13:52 /dev/ttyUSB0

The important thing here is that the device is accessible to either root (that is, the systems superuser administrator account) or to members of the group dialout. Since you dont want to run our ROS code as root, you must instead ensure that the account that youll use is in the dialout group. You can get a list of the groups a user is in using this command:
groups

If you dont see dialout in that list, then youll need to add it by editing the le named /etc/group. In that le, nd the dialout line, and add the user name at the end. For example, my /etc/group le has this line:

CSCE574 Spring 2013

Notes on ROS

36 of 51

dialout:x:20:jokane

You may need to log out and back in for this change to take effect. 2. Second, youll need to update two les in the standard ROS distribution to correct small but fatal bugs in them. The two les are:

/opt/ros/groovy/stacks/turtlebot_create/create_node/nodes/turtlebot_node.py /opt/ros/groovy/stacks/turtlebot_create/create_node/src/create_node/create_sensor_handler.

It appears that these les have not been updated yet to work correctly with Groovy. Ive provided replacements on the course website. Youll need to download them at put them in the correct directories on your netbook. Once you have turtlebot_node.py running, youll see that it subscribes to a topic called cmd_vel that works much like turtlesims command_velocity. By publishing messages on this topic, you can move the robot around. This node also publishes on several topics, most of which well discuss below in the context of other nodes that subscribe to them. 16.2.2 Velocity Command Multiplexer

As you control the robot, you may have several different nodes that want to publish cmd_vel messages. Which one should have control of the robot? If everyone publishes directly to cmd_vel, then the robot will always try to execute the command in the most recent message it has received. This is obviously not a good solution if, for example, youd like to take teleoperative control of the robot to override automatically generated commands sent by your software. ROS provides a solution to this problem in the form of a multiplexer node. Each node that wants to send movement commands to the robot, instead of publishing directly to cmd_vel, publishes messages on one of three different topics: /cmd_vel_mux/input/navi /cmd_vel_mux/input/teleop /cmd_vel_mux/input/safety_controller (Note that these specic topic names are determined by a conguration le; theres nothing stopping you from adding others if you like.) When messages arrive on any of these topics, cmd_vel_mux decides which should take the highest priority, and forwards the corresponding messages to the turtlebot_node via cmd_vel. Heres a launch le entry for this node:
<node pkg="nodelet" type="nodelet" name="mobile_base_nodelet_manager" args="manager"/> <node pkg="nodelet" type="nodelet" name="cmd_vel_mux" args="load cmd_vel_mux/CmdVelMuxNodelet mobile_base_nodelet_manager"> <param name="yaml_cfg_file" value="$(find turtlebot_bringup)/param/mux.yaml"/> <remap from="/mobile_base/commands/velocity" to="/cmd_vel"/> <remap from="/cmd_vel_mux/input/teleop" to="turtlebot_teleop/cmd_vel"/> </node>

There are three noteworthy things here. 1. First any most noticeably, the cmd_vel_mux functionality is actually provided by a nodelet rather than a full-edged node. The idea is, when nodes are very small and very simple, to reduce overhead CSCE574 Spring 2013 Notes on ROS 37 of 51

by combining the functionality of several nodes into a single process. For this to work, we rst start a nodelet manager, and then load one or more nodelets into that manager. This can be a bit confusing because in rxgraph, youll see both the manager and the nodelet. In this case, theres only one nodelet, but later well load multiple nodelets into the same manager. 2. Second, we must provide a conguration le, which denes the input and output topics for the multiplexer, along with a priority level and a timeout for each input topic. You might understand the role of cmd_vel_mux better if you examine this conguration le. 3. Finally, we use several remap entries to modify the topic names used by this node, to ensure that the correct connections are made with the other nodes. 16.2.3 Teleoperation Node

Once the turtlebot_node and the cmd_vel_mux nodes are running, you can teleoperate the robot using a command like this on your workstation:
rosrun turtlebot_teleop turtlebot_teleop_key

16.2.4

Robot State Publisher

Next, youll want to start a node called robot_state_publisher, which lives in the robot_state_publisher package. This nodes job is to publish tf transforms between all of the robots parts. To do this, it needs information from both the robot_description parameter and the messages published by the Create driver on /joint_states. 16.2.5 Diagnostic Aggregator

You should also start an aggregator_node node from the diagnostics_aggregator package. This node subscribes to /diagnostics, a topic published by the create driver, organizes that data according to the robots subsystems (power system, sensors, etc) are re-publishes it at a lower rate on /diagnostics_agg. A launch le entry for aggregator_node might look like this:
<node pkg="diagnostic_aggregator" type="aggregator_node" name="diagnostic_aggregator" > <rosparam command="load" file="$(find turtlebot_bringup)/param/create/diagnostics.yaml" /> </node>

Here were using a rosparam le (which is in YAML format) to set several parameters at once. In this case, those parameters describe how the diagnostics messages should be organized. The value of the aggregator is that you can view the output from this process, which can be useful for conrming that your robot is working correctly, by running the robot_monitor GUI tool on your workstation: rosrun robot_monitor robot_monitor 16.2.6 Extended Kalman Filter

Next, youll want to create a node of type robot_pose_ekf, from the package named robot_pose_ekf. The node subscribes to /odom (on which the create driver publishes raw estimates of its movements) and /imu/data (on which the create driver publishes measurements of its rotation, taken from its gyroscope). It combines these measurements, using an algorithm called the Extended Kalman Filter, to form both an estimated pose for the robot and a covariance matrix indicating how certain the robot is about that estimate. The EKF node publishes the result of this estimation process on /robot_pose_ekf/odom, and optionally as a tf frame. This node needs several parameters to work correctly. Heres a reasonable launch le entry: CSCE574 Spring 2013 Notes on ROS 38 of 51

<node pkg="robot_pose_ekf" type="robot_pose_ekf" name="robot_pose_ekf"> <remap from="imu_data" to="imu/data"/> <param name="freq" value="10.0"/> <param name="sensor_timeout" value="1.0"/> <param name="publish_tf" value="true"/> <param name="odom_used" value="true"/> <param name="imu_used" value="true"/> <param name="vo_used" value="false"/> <param name="output_frame" value="odom"/> </node>

Note also the remap tag, which is used to rename the output topic.

16.3

Kinect power supply

For the Kinect sensor to operate correctly, it must draw power from the Creates battery. (The 5V available from the USB connection to the netbook is not sufcient; the Kinect needs at least 8V. Note that seeing blinking lights in the Kinect is, in my experience, not enough to know for sure that the Kinect is receiving the power it needs.) Your Turtlebot has a cable connecting the Kinect to the Create for this purpose, but by default that power supply is disabled. To enable it, use a node like this:
<node pkg="create node" type="kinect_breaker enabler.py" name="kinect_breaker enabler" />

This script will call a service called set operation mode, which is offered by turtlebot node. This service puts the robot into Full mode (as its name suggests) and also enables the breaker that supplies power to the Kinect. After successfully calling that service, this node will terminate.

16.4

Kinect-related nodelets

In addition to the nodes described above, you will also need to launch several nodelets whose job is to publish data from the robots Kinect RGBD sensor. The standard ROS distribution contains a launch le, which you can import into your own launch les, that does what we need. Heres an example:
<include file="$(find turtlebot bringup)/launch/3dsensor.launch"> <arg name="depth registration" value="false" /> <arg name="rgb processing" value="true" /> <arg name="depth processing" value="true" /> <arg name="scan processing" value="true" /> </include>

Notice that this launch le accepts several arguments. The rst, depth registration, disables depth registration (which seems to be buggy in the current version). The nal three arguments are used to enable or disable nodelets that publish various kinds of data from the sensor. The idea is that you can reduce the amount computation by loading only the nodelets that you need. Its not likely that youll need to modify these parameters. If the sensor is working correctly, these nodelets should publish faked laser scan messages, showing the distances to nearby obstacles, on topic /scan.

CSCE574 Spring 2013

Notes on ROS

39 of 51

Part III

Appendices
A How to publish messages
Heres a step-by-step reminder of how to publish messages. Step 1: Determine the name and data type of the correct topic. 1. Start roscore. 2. Start the node that you would like to talk to. 3. Start rxgraph. 4. Click All Topics. 5. Find the topic you want and hover your mouse pointer over its rectangle. 6. The name of the topic is the text that appears in the rectangle. 7. The data type of the topic appears in the column to the right. This data type has a package name and a type name, separated by a slash. 8. Remember the topic name, the package name, and the type name, because youll need them in the next steps. Step 2: Make sure your package depends on the package for the data type you need. 1. In your package directory, open the le CMakeLists.txt. 2. Look for a line that reads:
find_package(catkin REQUIRED COMPONENTS ...)

3. If your topics package name does not appear in this line, add it before the closing paren. This step is needed to ensure that catkin_make makes the correct header les available when you compile your program. Step 3: Include the header le for the data type you need. 1. Near the top of your C++ code, include a line like this:
#include "packageName/typeName.h"

2. Example: If rxgraph showed turtlesim/Velocity, then your code would say:


#include "turtlesim/Velocity.h"

3. Example: If rxgraph showed sensor msgs/LaserScan, then your code would say:
#include "sensor msgs/LaserScan.h"

Step 4: Create a publisher. 1. Shortly after you create your ros::NodeHandle object, use it to create a Publisher object, like this:
ros::Publisher pub = n.advertise<packageName::typeName>( "topicName", 1000);

CSCE574 Spring 2013

Notes on ROS

40 of 51

2. Example: If rxgraph showed a topic named /turtle1/command velocity with type turtlesim/Velocity then your code would say:
ros::Publisher pub = n.advertise<turtlesim::Velocity>( "/turtle1/command velocity", 1000);

3. Example: If rxgraph showed a topic named /ik with type kinematics msgs/PositionIKRequest, then your code would say:
ros::Publisher pub = n.advertise<kinematics msgs::PositionIKRequest>("ik", 1000);

Step 5: Create a message object. 1. Declare a variable of type packageName::typeName. 2. Example:


turtlesim::Velocity velMsg;

3. Example:
sensor msgs::LaserScan scanMsg;

4. Example:
kinematics msgs::PositionIKRequest ikReqMsg;

Step 6: Fill in the data members of your message object. 1. At the command line, use rosmsg show packageName/typeName to get a list of the data members. 2. In your C++ code, assign a value to each of these data members. 3. Example: The output of rosmsg show turtlesim/Velocity is
float32 linear float32 angular

So your C++ code must provide oating point values for the linear and angular members of the message object:
turtlesim::Velocity velMsg; velMsg.linear = 1.0; velMsg.angular = 0.0;

Step 7: Use your Publisher object to publish your message. 1. Use the publish method of your publisher object. 2. Example:
pub.publish(velMsg);

Step 8: Give ROS a chance to send the message. 1. Call ros::spinOnce().

CSCE574 Spring 2013

Notes on ROS

41 of 51

B How to call a service


Step 1: Determine the name of the correct service. 1. Start roscore. 2. Start the node that you think might provide the service you want. 3. Start rxgraph. 4. Find your node and hover your mouse pointer over its oval. 5. Information about this node, include a list of services that it provides, will appear in the column to the right. 6. Remember the service name, because youll need it in the next steps. 7. Example: The standard turtlesim node provides a service called /turtle1/set pen. Step 2: Determine the data type used by your service. 1. At the command line, say rosservice type serviceName. The output is the data type used by the service. This data type has a package name and a type name, separated by a slash. 2. Example: The output of rosservice type /turtle1/set pen is turtlesim/SetPen. The package name is turtlesim and the type name is SetPen. Step 3: Make sure your package depends on the package for the data type you need. 1. In your package directory, open the le CMakeLists.txt. 2. Look for a line that reads:
find_package(catkin REQUIRED COMPONENTS ...)

3. If your topics package name does not appear in this line, add it before the closing paren. This step is needed to ensure that catkin_make makes the correct header les available when you compile your program. Step 4: Include the header le for the data type you need. 1. Near the top of your C++ code, include a line like this:
#include "packageName/typeName.h"

2. Example: If rosservice type showed turtlesim/SetPen, then your code would say:
#include "turtlesim/SetPen.h"

Step 5: Create a client. 1. Shortly after you create your ros::NodeHandle object, use it to create a ServiceClient object, like this:
ros::ServiceClient client = n.serviceClient<packageName::typeName>("serviceName");

2. Example: If rxgraph showed a service named /turtle1/set pen with type turtlesim/SetPen, then your code would say:
ros::ServiceClient client = n.serviceClient<turtlesim::SetPen>("/turtle1/set pen");

CSCE574 Spring 2013

Notes on ROS

42 of 51

Step 6: Create a service request (srv) object. 1. Declare a variable of type packageName::typeName. 2. Example:
turtlesim::SetPen setPenSrv;

Step 7: Fill in the data members of your srv, if any. 1. At the command line, use rossrv show packageName/typeName to get a list of the data members. The output will show data members that are part of the request that you will send, followed by a line, followed by the data members that are part of the response that the server will send back. 2. In your C++ code, assign a value to each of these data members of the request part. 3. Example: The output of rosmsg show turtlesim/SetPen is
uint8 uint8 uint8 uint8 uint8 --r g b width off

So your C++ code must provide integer values for the r, g, b, width, and off members of the angular members of the srv:
turtlesim::SetPen setPenSrv; setPenSrv.request.r = 128; setPenSrv.request.g = 128; setPenSrv.request.b = 128; setPenSrv.request.width = 3; setPenSrv.request.off = 0;

4. Example: The output of rosmsg show std srvs/Empty is:


---

This means that there are no data members to ll in. Just create the std srvs::Empty object, and its ready to go. Step 8: Use your ServiceClient object to call the service. 1. Use the call method of your client object. 2. Example:
bool success = client.call(setPenSrv);

3. This call will wait until the node provide the service has completed our request. Step 9: Inspect the data members in the response part of your srv, if any. 1. Remember that the data members that youll have access to are listed in the output of rossrv show.

CSCE574 Spring 2013

Notes on ROS

43 of 51

2. Example: The set pen service does not have any data members in its response, so we know theres no information coming back from the turtlesim node; theres nothing to do for this step. 3. Example: Some nodes provide a service of type diagnostic msgs/SelfTest. The output of rossrv show diagnostic msgs/SelfTest is:
--string id byte passed diagnostic msgs/DiagnosticStatus[] status byte OK=0 ...

Each line after the --- shows a data member of the response part of your srv, so you could, for example, say something like:
client.call(diagnosticSrv); if(!diagnosticSrv.response.passed) { ROS INFO("Oh no! Diagnostic failed!"); }

CSCE574 Spring 2013

Notes on ROS

44 of 51

How to set parameters


Step 1: Determine the name of the parameter you would like to set. 1. At the command line, say
rosparam list

to get a list of parameters that have been set. 2. Example: After running the turtlesim, youll see a list something like this:
/background b /background g /background r /rosdistro /rosversion

Each of these is a parameter that you can set. Step 2: Use the setParam method of your NodeHandle to change the value of that parameter. 1. Just one line is enough:
n.setParam("paramName", value);

2. The value can be a bool, an int, a double or a string. 3. Example: To set the background color used by turtlesim to white:
n.setParam("background r", 255); n.setParam("background g", 255); n.setParam("background b", 255);

Then call the clear service (See Section 8) to get turtlesim to read the new values.

CSCE574 Spring 2013

Notes on ROS

45 of 51

Laser Scan Messages

One way to access the sensor data from Turtlebots Kinect sensor is to subscribe to the /scan topic, which has data type sensor_msgs/LaserScan. This data type is a bit more complicated than some others, so heres a diagram that might help you sort things out:

angle max

axes for frame named frame id ranges[i]

angle min + i angle increment x angle min

Perhaps the most important thing to catch is that the sensor is at the origin in frame frame_id, facing along the positive x-axis. The given ranges represent the measured distance to the nearest obstacle, in directions spaced evenly between angle_min and angle_max.

CSCE574 Spring 2013

Notes on ROS

46 of 51

E Images in ROS
This appendix has some details about the image data types provided by ROS, which are much like any other data type, but which also have a few unique quirks.

E.1 Viewing images


The basic data type used to represent images in ROS is called sensor_msgs/Image. If you simply want to see the images published on a particular topic of that type, you can use a Camera display in RViz. If RViz seems like overkill, you could also try a much more lightweight program called image_view:
rosrun image_view image_view image:=topic_name

For example, to see the images being captured by the Turtlebots Kinect sensor, you might say
rosrun image_view image_view image:=/camera/rgb/image_color

References http://www.ros.org/wiki/image_view

E.2 Image Transport


As you might imagine, subscribing to image topics, from a computer other than the one that captures and publishes the images, can consume substantial amounts of network bandwidth. For example, on my system, subscribing to the topic /camera/rgb/image_color consumes about 2.5 megabytes per second:
rostopic bw /camera/rgb/image_color

generates output somewhat like this:


rostopic bw /camera/rgb/image_color subscribed to [/camera/rgb/image_color] average: 2.93MB/s mean: 0.92MB min: 0.92MB max: 0.92MB window: average: 2.45MB/s mean: 0.92MB min: 0.92MB max: 0.92MB window: average: 2.54MB/s mean: 0.92MB min: 0.92MB max: 0.92MB window:

4 6 9

The reason this happens is that those topics contain uncompressed video data. Fortunately, ROS provides a means by which we can subscribe to a series of images that are transmitted in a compressed format, and access those messages in an uncompressed format, without worrying about the details of the compression and decompression in our code. The package that provides this feature is called image_transport. Some details and tutorials for this package appear in the links below. For now, lets have a look at a minimal example that illustrates how this works:

CSCE574 Spring 2013

Notes on ROS

47 of 51

#include <ros/ros.h> #include <image_transport/image_transport.h> void callback(const sensor_msgs::ImageConstPtr& msg) { ROS_INFO("Got image."); } int main(int argc, char **argv) { ros::init(argc, argv, "nodeName"); ros::NodeHandle nh; image_transport::ImageTransport it(nh); image_transport::Subscriber sub = it.subscribe( "topicName", queueSize, callback); ros::spin(); }

Note that, to compile correctly, this example requires a dependency on the image_transport package in your package.xml and CMakeLists.txt. Note that there is very little difference between this version and the usual ROS topic subscribing youve been doing all semester. However, the ImageHandler object will, instead of directly subscribing to the topic you request, rst query a string parameter called image_transport to decide whether subscribe to a compressed version of that topics video stream instead. A few comments: In the current version of ROS, there are three valid choices for image_transport: If you leave this parameter unspecied, the ImageTransport will subscribe directly to the uncompressed image topic. This is equivalent to not using image_transport at all, and is usually a bad idea when the publisher and subscriber run on different computers. If you set image_transport to compressed, each image will be compressed to either a JPEG or PNG image before it is transmitted, and decompressed back to a sensor_msgs/Image before your callback is called. If you set image_transport to theora, the video stream will be compressed to a very small size using the Theora codec. (See references below.) This tends to be quite a bit more efcient than compressed, because it is able to exploit similarities between successive frames. The key idea is that you can use run-time parameters to control how the images are transmitted, without writing code that needs to know about the details of the compression that you eventually choose. The tilde at the beginning of the parameter name image_transport indicates that this is a private name specic to one node. Perhaps the easiest way to assign such a parameter is to include it between the node tags in a launch le. Heres an example:
<launch> <node name="view" pkg="J5" type="view" output="screen"> <param name="image_transport" value="theora" /> </node> </launch>

References http://www.ros.org/wiki/image_transport

CSCE574 Spring 2013

Notes on ROS

48 of 51

http://www.ros.org/wiki/image_transport/Tutorials http://www.ros.org/wiki/image_transport/Tutorials/SubscribingToImages http://www.ros.org/wiki/image_transport/Tutorials/ExaminingImagePublisherSubscriber http://en.wikipedia.org/wiki/Theora http://mirror.umd.edu/roswiki/Names.html

E.3 OpenCV
You may see references in the ROS documentation to a library called OpenCV. OpenCV is a free and widely-used library that implements a fairly large collection of machine vision algorithms. Even better, it is already integrated into ROS. We wont try to cover many details about OpenCV in this coursedoing so would likely take just as long as learning ROS itselfbut you are free to use any OpenCV functions that you nd useful. I do suggest, however, using at least a handful of OpenCV functions to access the images that your Turtlebot publishes. E.3.1 Compiling for OpenCV

To write ROS programs that use OpenCV, the process is somewhat different than for other packages, because OpenCV is not treated as a proper catkin package. Instead youll need to have cmake nd it separately, using lines like this in your CMakeLists.txt:
find_package(OpenCV REQUIRED) target_link_libraries(follow ${OpenCV_LIBS})

Youll also need a dependency on a package called cv_bridge, whose job is to convert ROS images into OpenCV images, using the usual catkin technique. E.3.2 Converting images to cv::Mat

The most important interest we have in OpenCV is that it provides a data type for accessing images that is somewhat easier to deal with than sensor_msgs::Image. Fortunately, its very easy to convert to the OpenCV image type, which is called cv::Mat. For example, you might have an ImageTransport callback that contains code something like this:
#include <cv_bridge/cv_bridge.h> ... cv_bridge::CvImagePtr cvImagePtr; try { cvImagePtr = cv_bridge::toCvCopy(msg); } catch (cv_bridge::Exception &e) { ROS_ERROR("cv_bridge exception: %s", e.what()); }

Using the resulting cv_bridge::CvImagePtr, we can say cvImagePtr->image to get an object of type cv::Mat, containing our image data.

E.4 Examining the images


An image is nothing more than a (really big) two dimensional array. If we have a cv::Mat (here Mat is short for matrix), the most basic question we might want to ask is to get the value of one element of that array, say the element at row i and column j . Theres a method in cv::Mat called at that can do this, but there is a important complication: cv::Mat does not, on its own, know the format (or encoding) of the image data. That is, it doesnt know whether CSCE574 Spring 2013 Notes on ROS 49 of 51

each pixel is stored as a single byte (as in a monochrome image) or a sequence of three bytes (as in a fullcolor image) or a oating point number, or something else. As a result, the at method is templated by the data type of the individual pixels. Fortunately, the encodings generated by the Turtlebot are quite predictable, although they do differ for each of the two main image topics. Images from /camera/rgb/image_mono should have the mono8 encoding. Each pixel is an unsigned character:
cv::Mat &mat = cvImagePtr->image; ROS_INFO("image[%d,%d] = %d", i, j, (int) mat.at<unsigned char>(i, j));

The resulting number can range between 0 and 255, with 0 representing black and 255 representing white. Images from /camera/rgb/image_color should have the bgr8 encoding. Each pixel is a collection of three unsigned characters, one for each of red, green, and blue. We can extract all three at once into a cv::Vec3b and then access the individual channels one at a time:
cv::Mat &mat = cvImagePtr->image; cv::Vec3b pixel = mat.at<cv::Vec3b>(i,j); ROS_INFO("image[%d,%d] = (r=%d,g=%d,b=%d)", i, j, pixel[2], pixel[1], pixel[0]);

Note the ordering carefully. In each color channel, the resulting number can range between 0 and 255, with 0 representing no presence of that color at all, and 255 representing full presence of that color. Note that the coordinates here are such that (0, 0) is the top left of the image, increasing as you move down or to the right.

E.5 Viewing images


One other easily-utilized and potentially useful OpenCV feature is its ability to open GUI windows and display images. In fact, the image_transport tutorial on subscribing to images shows an example that does exactly this. Displaying images is easier than you might think. First, you should create a window. This probably belongs in your main function.
cvNamedWindow("windowName", CV_WINDOW_AUTOSIZE);

The string name given here is used as an identier for the window; you should specify the same window name later when you want to display an image. Second, also probably in main, you should start a separate thread to handle any events the window may need to respond to, such as (very importantly), requests to redraw itself:
cvStartWindowThread();

You only need to call this function once, even if you create multiple windows. Third, when you have a cv::Mat image that you want to display (probably in a callback function somewhere), theres a single function call for that: CSCE574 Spring 2013 Notes on ROS 50 of 51

cv::imshow("windowName", mat);

Finally, when you are completely done using a window, you can close it:
cvDestroyWindow("windowName");

It is customary (but not strictly necessary) to include this window close operation near the end of your program, after your main loop or ros::spin(). One very powerful way to use this feature is to modify the images produced by the robot, before displaying them on your workstation. You can do this by assigning a values to the reference returned by cv::Mat::at. For example, you might do something like this to make a pixel black in a bgr8 image:
cv::Vec3b &pixel = mat.at<cv::Vec3b>(i,j); pixel[0] = 0; pixel[1] = 0; pixel[2] = 0;

With some creativity, modifying images can be an extremely powerful technique for gaining insight into what your program is doing. References http://opencv.willowgarage.com/wiki/ http://www.ros.org/wiki/image_transport/Tutorials/SubscribingToImages

http://www.ros.org/wiki/cv_bridge/Tutorials/UsingCvBridgeToConvertBetweenROSImagesAndOp

CSCE574 Spring 2013

Notes on ROS

51 of 51

Anda mungkin juga menyukai