Note: This tutorial assumes you are comfortable with using roscpp, and have gone through the ROS Tutorials.
(!) Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags.

Markers: Sending Basic Shapes (C++)

Description: Shows how to use visualization_msgs/Marker messages to send basic shapes (cube, sphere, cylinder, arrow) to rviz.

Tutorial Level: BEGINNER

Next Tutorial: Markers: Points and Lines

  Show EOL distros: 

Intro

Unlike other displays, the Marker Display lets you visualize data in rviz without rviz knowing anything about interpreting that data. Instead, primitive objects are sent to the display through visualization_msgs/Marker messages, which let you show things like arrows, boxes, spheres and lines.

This tutorial will show you how to send the four basic shapes (boxes, spheres, cylinders, and arrows). We'll create a program that sends out a new marker every second, replacing the last one with a different shape.

Create a Package

Before getting started, let's create a package called using_markers, somewhere in your package path:

catkin_create_pkg using_markers roscpp visualization_msgs

roscreate-pkg using_markers roscpp visualization_msgs

Sending Markers

The Code

Paste the following into src/basic_shapes.cpp:

https://raw.github.com/ros-visualization/visualization_tutorials/indigo-devel/visualization_marker_tutorials/src/basic_shapes.cpp

  30 #include <ros/ros.h>
  31 #include <visualization_msgs/Marker.h>
  32 
  33 int main( int argc, char** argv )
  34 {
  35   ros::init(argc, argv, "basic_shapes");
  36   ros::NodeHandle n;
  37   ros::Rate r(1);
  38   ros::Publisher marker_pub = n.advertise<visualization_msgs::Marker>("visualization_marker", 1);
  39 
  40   // Set our initial shape type to be a cube
  41   uint32_t shape = visualization_msgs::Marker::CUBE;
  42 
  43   while (ros::ok())
  44   {
  45     visualization_msgs::Marker marker;
  46     // Set the frame ID and timestamp.  See the TF tutorials for information on these.
  47     marker.header.frame_id = "/my_frame";
  48     marker.header.stamp = ros::Time::now();
  49 
  50     // Set the namespace and id for this marker.  This serves to create a unique ID
  51     // Any marker sent with the same namespace and id will overwrite the old one
  52     marker.ns = "basic_shapes";
  53     marker.id = 0;
  54 
  55     // Set the marker type.  Initially this is CUBE, and cycles between that and SPHERE, ARROW, and CYLINDER
  56     marker.type = shape;
  57 
  58     // Set the marker action.  Options are ADD, DELETE, and new in ROS Indigo: 3 (DELETEALL)
  59     marker.action = visualization_msgs::Marker::ADD;
  60 
  61     // Set the pose of the marker.  This is a full 6DOF pose relative to the frame/time specified in the header
  62     marker.pose.position.x = 0;
  63     marker.pose.position.y = 0;
  64     marker.pose.position.z = 0;
  65     marker.pose.orientation.x = 0.0;
  66     marker.pose.orientation.y = 0.0;
  67     marker.pose.orientation.z = 0.0;
  68     marker.pose.orientation.w = 1.0;
  69 
  70     // Set the scale of the marker -- 1x1x1 here means 1m on a side
  71     marker.scale.x = 1.0;
  72     marker.scale.y = 1.0;
  73     marker.scale.z = 1.0;
  74 
  75     // Set the color -- be sure to set alpha to something non-zero!
  76     marker.color.r = 0.0f;
  77     marker.color.g = 1.0f;
  78     marker.color.b = 0.0f;
  79     marker.color.a = 1.0;
  80 
  81     marker.lifetime = ros::Duration();
  82 
  83     // Publish the marker
  84     while (marker_pub.getNumSubscribers() < 1)
  85     {
  86       if (!ros::ok())
  87       {
  88         return 0;
  89       }
  90       ROS_WARN_ONCE("Please create a subscriber to the marker");
  91       sleep(1);
  92     }
  93     marker_pub.publish(marker);
  94 
  95     // Cycle between different shapes
  96     switch (shape)
  97     {
  98     case visualization_msgs::Marker::CUBE:
  99       shape = visualization_msgs::Marker::SPHERE;
 100       break;
 101     case visualization_msgs::Marker::SPHERE:
 102       shape = visualization_msgs::Marker::ARROW;
 103       break;
 104     case visualization_msgs::Marker::ARROW:
 105       shape = visualization_msgs::Marker::CYLINDER;
 106       break;
 107     case visualization_msgs::Marker::CYLINDER:
 108       shape = visualization_msgs::Marker::CUBE;
 109       break;
 110     }
 111 
 112     r.sleep();
 113   }
 114 }

Now edit the CMakeLists.txt file in your using_markers package, and add:

rosbuild_add_executable(basic_shapes src/basic_shapes.cpp)

add_executable(basic_shapes src/basic_shapes.cpp)
target_link_libraries(basic_shapes ${catkin_LIBRARIES})

to the bottom.

The Code Explained

Ok, let's break down the code piece by piece:

  30 #include <ros/ros.h>
  31 #include <visualization_msgs/Marker.h>
  32 

You should have seen the ROS include by now. We also include the visualization_msgs/Marker message definition.

  33 int main( int argc, char** argv )
  34 {
  35   ros::init(argc, argv, "basic_shapes");
  36   ros::NodeHandle n;
  37   ros::Rate r(1);
  38   ros::Publisher marker_pub = n.advertise<visualization_msgs::Marker>("visualization_marker", 1);

This should look familiar. We initialize ROS, and create a ros::Publisher on the visualization_marker topic.

  41   uint32_t shape = visualization_msgs::Marker::CUBE;

Here we create an integer to keep track of what shape we're going to publish. The four types we'll be using here all use the visualization_msgs/Marker message in the same way, so we can simply switch out the shape type to demonstrate the four different shapes.

  43   while (ros::ok())
  44   {
  45     visualization_msgs::Marker marker;
  46     // Set the frame ID and timestamp.  See the TF tutorials for information on these.
  47     marker.header.frame_id = "/my_frame";
  48     marker.header.stamp = ros::Time::now();

This begins the meat of the program. First we create a visualization_msgs/Marker, and begin filling it out. The header here is a roslib/Header, which should be familiar if you've done the tf tutorials. We set the frame_id member to /my_frame as an example. In a running system this should be the frame relative to which you want the marker's pose to be interpreted.

  52     marker.ns = "basic_shapes";
  53     marker.id = 0;

The namespace (ns) and id are used to create a unique name for this marker. If a marker message is received with the same ns and id, the new marker will replace the old one.

  56     marker.type = shape;

This type field is what specifies the kind of marker we're sending. The available types are enumerated in the visualization_msgs/Marker message. Here we set the type to our shape variable, which will change every time through the loop.

  59     marker.action = visualization_msgs::Marker::ADD;

The action field is what specifies what to do with the marker. The options are visualization_msgs::Marker::ADD and visualization_msgs::Marker::DELETE. ADD is something of a misnomer, it really means "create or modify".

New in Indigo A new action has been added to delete all markers in the particular Rviz display, regardless of ID or namespace. The value is 3 and in future ROS version the message will change to have value visualization_msgs::Marker::DELETEALL.

  62     marker.pose.position.x = 0;
  63     marker.pose.position.y = 0;
  64     marker.pose.position.z = 0;
  65     marker.pose.orientation.x = 0.0;
  66     marker.pose.orientation.y = 0.0;
  67     marker.pose.orientation.z = 0.0;
  68     marker.pose.orientation.w = 1.0;

Here we set the pose of the marker. The geometry_msgs/Pose message consists of a geometry_msgs/Vector3 to specify the position and a geometry_msgs/Quaternion to specify the orientation. Here we set the position to the origin, and the orientation to the identity orientation (note the 1.0 for w).

  71     marker.scale.x = 1.0;
  72     marker.scale.y = 1.0;
  73     marker.scale.z = 1.0;

Now we specify the scale of the marker. For the basic shapes, a scale of 1 in all directions means 1 meter on a side.

  76     marker.color.r = 0.0f;
  77     marker.color.g = 1.0f;
  78     marker.color.b = 0.0f;
  79     marker.color.a = 1.0;

The color of the marker is specified as a std_msgs/ColorRGBA. Each member should be between 0 and 1. An alpha (a) value of 0 means completely transparent (invisible), and 1 is completely opaque.

  81     marker.lifetime = ros::Duration();

The lifetime field specifies how long this marker should stick around before being automatically deleted. A value of ros::Duration() means never to auto-delete.

If a new marker message is received before the lifetime has been reached, the lifetime will be reset to the value in the new marker message.

  84     while (marker_pub.getNumSubscribers() < 1)
  85     {
  86       if (!ros::ok())
  87       {
  88         return 0;
  89       }
  90       ROS_WARN_ONCE("Please create a subscriber to the marker");
  91       sleep(1);
  92     }
  93     marker_pub.publish(marker);

We wait for the marker to have a subscriber and we then publish the marker. Note that you can also use a latched publisher as an alternative to this code.

  96     switch (shape)
  97     {
  98     case visualization_msgs::Marker::CUBE:
  99       shape = visualization_msgs::Marker::SPHERE;
 100       break;
 101     case visualization_msgs::Marker::SPHERE:
 102       shape = visualization_msgs::Marker::ARROW;
 103       break;
 104     case visualization_msgs::Marker::ARROW:
 105       shape = visualization_msgs::Marker::CYLINDER;
 106       break;
 107     case visualization_msgs::Marker::CYLINDER:
 108       shape = visualization_msgs::Marker::CUBE;
 109       break;
 110     }

This code lets us show all four shapes while just publishing the one marker message. Based on the current shape, we set what the next shape to publish will be.

 112     r.sleep();
 113   }

Sleep and loop back to the top.

Building the Code

You should be able to build the code with:

$ cd %TOP_DIR_YOUR_CATKIN_WORKSPACE%
$ catkin_make

rosmake using_markers

Running the Code

You should be able to run the code with:

rosrun using_markers basic_shapes

Viewing the Markers

Now that you're publishing markers, you need to set rviz up to view them. First, make sure rviz is built:

rosmake rviz

Now, run rviz:

rosrun using_markers basic_shapes
rosrun rviz rviz

If you've never used rviz before, please see the User's Guide to get you started.

The first thing to do, because we don't have any tf transforms setup, is to set the Fixed Frames to the frame we set the marker to above, /my_frame. In order to do so, set the Fixed Frame field to "/my_frame".

The first thing to do, because we don't have any tf transforms setup, is to set the Fixed Frames to the frame we set the marker to above, /my_frame. In order to do so, expand ".Global Options" in "Displays" area so that you'll see Fixed Frame fields. Then type in "/my_frame" into it.

The first thing to do, because we don't have any tf transforms setup, is to set both the Fixed and Target Frames to the frame we set the marker to above, /my_frame. In order to do so, first expand ".Global Options" in "Displays" area so that you'll see both "{ Fixed, Target } Frame" fields. Then type in "/my_frame" into each field.

The first thing to do, because we don't have any tf transforms setup, is to set both the Fixed and Target Frames to the frame we set the marker to above, /my_frame. In order to do so, first expand ".Global Options" in "Displays" area so that you'll see both "{ Fixed, Target } Frame" fields. Then type in "/my_frame" into each field.

Next add a Markers display. Notice that the default topic specified, visualization_marker, is the same as the one being published.

You should now see a marker at the origin that changes shape every second: Basic Shapes

More Information

For more information on the different types of markers beyond the ones shown here, please see the Markers Display Page

Wiki: rviz/Tutorials/Markers: Basic Shapes (last edited 2016-05-24 00:34:23 by DHood)