Clone wiki

ariac / 2019 / tutorials / hello_world


This tutorial covers creating a ROS Package and Node to interface with the competition.

If you're new to ROS then follow the ROS Tutorials first. The ROS tutorial on Creating a Package will be especially helpful. Afterwards, it is recommended to complete the GEAR Interface Tutorial before trying this one.

Creating a Competition Package

Teams will need at least a ROS package and Node to compete. This is where you will put code to start the competition, receive orders, receive sensor data, and control the arms.

See this ROS package template for example of a package and node that interacts with ARIAC. This tutorial will use it as an example.

Setting up a Catkin Workspace

First set up a Catkin workspace in which to build your package. A workspace is just a set of folders with a conventional structure. To make one, create a folder with a subfolder named src.

mkdir -p ~/helloworld_ws/src
cd ~/helloworld_ws/src

Now we'll make the workspace ready to build ROS packages

source /opt/ros/melodic/setup.bash

The workspace is now ready to build packages.

Creating a New Package Using the Template

This ROS package template comes with build system files, a sample configuration, an example C++ node, and an example python node.

This tutorial will limit itself to the C++ example.

To use the template, you need to pick a name for your package. The name must only have lower case characters and underscores. This tutorial uses the name ariac_example. Anywhere you see ariac_example, replace it with your desired package name.

Now that you have the name, create a folder in the src folder of the workspace with it.

mkdir ~/helloworld_ws/src/ariac_example
cd ~/helloworld_ws/src/ariac_example

All the files in your package need to go into this folder.

Writing the package.xml

Create a file called package.xml in the package folder

touch ~/helloworld_ws/src/ariac_example/package.xml

This is called the package manifest. Its job is to describe what is needed to build and run your package in a machine readable format. Additionally, it marks the root folder of your package.

Many of the entries in the package manifest are used for packagng and releasing your package. Since you're probably not going to release your package, many fields can be neglected or filled with placeholders.

<?xml version="1.0"?>
<package format="2">
  <description>An example of an ARIAC competitor's package.</description>
  <maintainer email="">William Woodall</maintainer>

  <license>Apache 2.0</license>




You should change a few things:

  • Replace ariac_example with your package name
  • Change the description
  • Change the maintainer name and email to your name and email
  • You can have multiple <maintainer> tags
  • Change the license
  • add any additional dependencies your code will need

Writing the CMakeLists.txt

ROS packages use CMake, so next create a CMake build file.

touch ~/helloworld_ws/src/ariac_example/CMakeLists.txt

This must be in the same folder as your package manifest. Copy the content from the example CMakeLists.txt. If you want to create more executables or libraries, you'll need to add them here to tell CMake how to build them.

Important, If you have been following the tutorial instructions then comment out the call to catkin_python_setup(). You do not need to comment it out if you copied the whole ariac_example folder.

You should change the project name from ariac_example to your package name. For more information, see the ROS documentation on CMakeLists.txt.

ARIAC Competition Configuration

You will need a competition config file to tell ARIAC what sensors you will be using.

Create a directory to store the configuration Then create a file in the config folder called sample_gear_conf.yaml

mkdir -p ~/helloworld_ws/src/ariac_example/config
touch ~/helloworld_ws/src/ariac_example/config/sample_gear_conf.yaml

For the example tutorial, copy the content of this file into it. This is just an example. When you write your own config file, you will want more sensors to see all of the bins. After this tutorial, see this page for more information about writing your config file.

Creating a C++ Node to Interface with the Competition

You will need a ROS node to interface with the competition. Popular languages for ROS nodes are C++ and Python. This tutorial will cover creating a C++ ROS node.

Create a folder called src in the package and create a file for the C++ code.

mkdir -p ~/helloworld_ws/src/ariac_example/src/
touch ~/helloworld_ws/src/ariac_example/src/ariac_example_node.cpp

Copy the content of this file into it.

C++ Includes

The first couple lines are including standard C++ libraries. These allow using some built in functions and types like std::count_if and std::vector.

#include <algorithm>
#include <vector>

The next include is for ROS. This lets you use types like ros::NodeHandle and call functions like ros::init().

#include <ros/ros.h>

The last block of include statements is for all the ROS message types used.

#include <osrf_gear/LogicalCameraImage.h>
#include <osrf_gear/Order.h>
#include <osrf_gear/Proximity.h>
#include <sensor_msgs/JointState.h>
#include <sensor_msgs/LaserScan.h>
#include <sensor_msgs/Range.h>
#include <std_msgs/Float32.h>
#include <std_msgs/String.h>
#include <std_srvs/Trigger.h>
#include <trajectory_msgs/JointTrajectory.h>

You must include a file for each ROS message or service type you use in your program. For example, to use the ROS message sensor_msgs/LaserScan you must include the file called sensor_msgs/LaserScan.h. That gives you access to a C++ type sensor_msgs::LaserScan which you use in your code.

C++ Main Function

The main() function is the entry point for your program. It has the following structure:

int main(int argc, char ** argv) {
  // Last argument is the default name of the node.
  ros::init(argc, argv, "ariac_example_node");

  ros::NodeHandle node;

  // Instance of custom class from above.
  MyCompetitionClass comp_class(node);

  // ... Creation of subscriptions omitted for brevity

  ROS_INFO("Setup complete.");
  ros::spin();  // This executes callbacks on new data until ctrl-c.

  return 0;

First, the call to ros::init() sets the node's name. This name must be unique when the node is run (but don't worry, it can be changed at runtime if it isn't).

Next a ros::NodeHandle is created. This gives access to most of the ROS APIs.

An instance of the example class MyCompetitionClass is created and set up. The largest section is the creation of a bunch of subscribers and callbacks; they will be covered in the next section.

Finally, the competition is started and control is given to ROS using ros::spin(). Inside this function ROS will wait for ROS messages and call callbacks.

C++ Creating Publishers and Subscribers

The largest section of the main function is where publishers and subscribers are created. See the tutorial about C++ ROS publishers and subscribers for more information.

Lets look at one example.

  // Subscribe to the '/ariac/orders' topic.
  ros::Subscriber orders_subscriber = node.subscribe(
    "/ariac/orders", 10,
    &MyCompetitionClass::order_callback, &comp_class);

The first argument is the name of the topic, /ariac/orders. The second argument is the queue size, which is how many messages to save if your callback is slow to handle them. The last two arguments say a function order_callback() on an instance of MyCompetitionClass stored in comp_class should be called every time a new order is received.

Starting the Competition

You may have noticed the main function called start_competition().

/// Start the competition by waiting for and then calling the start ROS Service.
void start_competition(ros::NodeHandle & node) {
  // Create a Service client for the correct service, i.e. '/ariac/start_competition'.
  ros::ServiceClient start_client =
  // If it's not already ready, wait for it to be ready.
  // Calling the Service using the client before the server is ready would fail.
  if (!start_client.exists()) {
    ROS_INFO("Waiting for the competition to be ready...");
    ROS_INFO("Competition is now ready.");
  ROS_INFO("Requesting competition start...");
  std_srvs::Trigger srv;  // Combination of the "request" and the "response".;  // Call the start Service.
  if (!srv.response.success) {  // If not successful, print out why.
    ROS_ERROR_STREAM("Failed to start the competition: " << srv.response.message);
  } else {
    ROS_INFO("Competition started!");

This function starts the competition by calling the service /ariac/start_competition. This is part of the ARIAC competition interface, and it must be called when your code is ready to begin a trial. This function waits for the service to become available first. It's important to do this because the service server is in another process, and may not be ready yet. Next, call() blocks until a response is received. The rest of the code checks if the competition was successfully started.

Trying the Example

Before you can run the example, you need to build it.

cd ~/helloworld_ws

Once that succeeds, open a new terminal. We'll need to source setup.bash in the workspace to make our terminal aware of it.

source ~/helloworld_ws/devel/setup.bash

Now we can launch the competition with our configuration.

rosrun osrf_gear -f `catkin_find --first-only --share osrf_gear`/config/sample.yaml ~/helloworld_ws/src/ariac_example/config/sample_gear_conf.yaml

The first config file sample.yaml specifies what trial will be run. The second config file is the one you created that describes where the sensors should go.

Open a third terminal and source your workspace again. Then run this command to run your example C++ node.

rosrun ariac_example ariac_example_node

The example prints information about the competition to the console, like sensor data being received. It also commands the arms to move to the zero position. Be sure to read through all the example code to make sure you understand it.