[Documentation] [TitleIndex] [WordIndex

Note: This tutorial assumes that you have completed the previous tutorials: 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.

Interactive Markers: Basic Controls

Description: This tutorial explains how the basic_controls tutorial code works.

Tutorial Level: BEGINNER

Next Tutorial: Plugins: New Display Type

The basic_controls tutorial explained

The basic_controls tutorial showing in RViz

This tutorial shows you most of the common options you have for designing interactive markers. The node providing will print all feedback it gets from RViz on the command line.

All interactive markers contain a grey box, which in most cases will do nothing more than move together with the rest of the controls. It will show you how the coordinate frame of the Interactive Marker moves.

Simple 6-DOF control

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

This shows how to control all 6 degrees of freedom using 6 separate controls. Use the rings to rotate and the arrows to move the structure.

Simple 6-DOF control (fixed orientation)

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

Identical to the 6-DOF control, with the exception that the orientation of the controls will stay fixed, independent of the orientation of the frame being controlled.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

  48 Marker makeBox( InteractiveMarker &msg )
  49 {
  50   Marker marker;
  51 
  52   marker.type = Marker::CUBE;
  53   marker.scale.x = msg.scale * 0.45;
  54   marker.scale.y = msg.scale * 0.45;
  55   marker.scale.z = msg.scale * 0.45;
  56   marker.color.r = 0.5;
  57   marker.color.g = 0.5;
  58   marker.color.b = 0.5;
  59   marker.color.a = 1.0;
  60 
  61   return marker;
  62 }
  63 
  64 InteractiveMarkerControl& makeBoxControl( InteractiveMarker &msg )
  65 {
  66   InteractiveMarkerControl control;
  67   control.always_visible = true;
  68   control.markers.push_back( makeBox(msg) );
  69   msg.controls.push_back( control );
  70 
  71   return msg.controls.back();
  72 }

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 183 void make6DofMarker( bool fixed, unsigned int interaction_mode, const tf::Vector3& position, bool show_6dof )
 184 {
 185   InteractiveMarker int_marker;
 186   int_marker.header.frame_id = "base_link";
 187   tf::pointTFToMsg(position, int_marker.pose.position);
 188   int_marker.scale = 1;
 189 
 190   int_marker.name = "simple_6dof";
 191   int_marker.description = "Simple 6-DOF Control";
 192 
 193   // insert a box
 194   makeBoxControl(int_marker);
 195   int_marker.controls[0].interaction_mode = interaction_mode;
 196 
 197   InteractiveMarkerControl control;
 198 
 199   if ( fixed )
 200   {
 201     int_marker.name += "_fixed";
 202     int_marker.description += "\n(fixed orientation)";
 203     control.orientation_mode = InteractiveMarkerControl::FIXED;
 204   }
 205 
 206   if (interaction_mode != visualization_msgs::InteractiveMarkerControl::NONE)
 207   {
 208       std::string mode_text;
 209       if( interaction_mode == visualization_msgs::InteractiveMarkerControl::MOVE_3D )         mode_text = "MOVE_3D";
 210       if( interaction_mode == visualization_msgs::InteractiveMarkerControl::ROTATE_3D )       mode_text = "ROTATE_3D";
 211       if( interaction_mode == visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D )  mode_text = "MOVE_ROTATE_3D";
 212       int_marker.name += "_" + mode_text;
 213       int_marker.description = std::string("3D Control") + (show_6dof ? " + 6-DOF controls" : "") + "\n" + mode_text;
 214   }
 215 
 216   if(show_6dof)
 217   {
 218     control.orientation.w = 1;
 219     control.orientation.x = 1;
 220     control.orientation.y = 0;
 221     control.orientation.z = 0;
 222     control.name = "rotate_x";
 223     control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 224     int_marker.controls.push_back(control);
 225     control.name = "move_x";
 226     control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
 227     int_marker.controls.push_back(control);
 228 
 229     control.orientation.w = 1;
 230     control.orientation.x = 0;
 231     control.orientation.y = 1;
 232     control.orientation.z = 0;
 233     control.name = "rotate_z";
 234     control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 235     int_marker.controls.push_back(control);
 236     control.name = "move_z";
 237     control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
 238     int_marker.controls.push_back(control);
 239 
 240     control.orientation.w = 1;
 241     control.orientation.x = 0;
 242     control.orientation.y = 0;
 243     control.orientation.z = 1;
 244     control.name = "rotate_y";
 245     control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 246     int_marker.controls.push_back(control);
 247     control.name = "move_y";
 248     control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
 249     int_marker.controls.push_back(control);
 250   }
 251 
 252   server->insert(int_marker);
 253   server->setCallback(int_marker.name, &processFeedback);
 254   if (interaction_mode != visualization_msgs::InteractiveMarkerControl::NONE)
 255     menu_handler.apply( *server, int_marker.name );
 256 }

The code section above shows how to construct the first two interactive markers. After adding the grey box, 6 controls for each degree of freedom are added. No markers are added to these controls, which will result in RViz creating a set of colored rings and arrows as a default visualization.

The only difference between the two is that in the second case, the orientation mode is set to InteractiveMarkerControl::FIXED, while in the first it is left at its default value, which is InteractiveMarkerControl::INHERIT.

Note that the 3D controls (shown lower in this list) are constructed using this function as well. For the simple 6-DOF controls shown above, the block under if(interaction_mode != InteractiveMarkerControl::NONE) is ignored.

NOTE: The orientations in the above code snippet can be confusing. If you compute the rotation matrices corresponding to each of the quaternions, you can verify that the specified orientation is correct.

3D Controls

New in Groovy

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

These new marker types support various kinds of 3D motion with a mouse.

It is possible to write an Rviz plugin that allows 3D grabbing of these markers using a 6D input device such as a Phantom Omni or Razer Hydra. See http://wiki/interaction_cursor_rviz.

6-DOF (Arbitrary Axes)

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

Shows that controls are not limited to the unit axes but can work on any arbitrary orientation.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 258 void makeRandomDofMarker( const tf::Vector3& position )
 259 {
 260   InteractiveMarker int_marker;
 261   int_marker.header.frame_id = "base_link";
 262   tf::pointTFToMsg(position, int_marker.pose.position);
 263   int_marker.scale = 1;
 264 
 265   int_marker.name = "6dof_random_axes";
 266   int_marker.description = "6-DOF\n(Arbitrary Axes)";
 267 
 268   makeBoxControl(int_marker);
 269 
 270   InteractiveMarkerControl control;
 271 
 272   for ( int i=0; i<3; i++ )
 273   {
 274     control.orientation.w = rand(-1,1);
 275     control.orientation.x = rand(-1,1);
 276     control.orientation.y = rand(-1,1);
 277     control.orientation.z = rand(-1,1);
 278     control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 279     int_marker.controls.push_back(control);
 280     control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
 281     int_marker.controls.push_back(control);
 282   }
 283 
 284   server->insert(int_marker);
 285   server->setCallback(int_marker.name, &processFeedback);
 286 }

The controls in this example are created by assigning random values to the quaternions which determine the orientation of each control. RViz will normalize these quaternions, so you don't have to worry about it when creating an interactive marker.

View-Facing 6-DOF

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

This interactive marker can move and rotate in all directions. In contrast to the previous examples, it does that using only two controls. The outer ring rotates along the view axis of the camera in RViz. The box moves in the camera plane, although it is not visually aligned with the camera coordinate frame.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 289 void makeViewFacingMarker( const tf::Vector3& position )
 290 {
 291   InteractiveMarker int_marker;
 292   int_marker.header.frame_id = "base_link";
 293   tf::pointTFToMsg(position, int_marker.pose.position);
 294   int_marker.scale = 1;
 295 
 296   int_marker.name = "view_facing";
 297   int_marker.description = "View Facing 6-DOF";
 298 
 299   InteractiveMarkerControl control;
 300 
 301   // make a control that rotates around the view axis
 302   control.orientation_mode = InteractiveMarkerControl::VIEW_FACING;
 303   control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 304   control.orientation.w = 1;
 305   control.name = "rotate";
 306 
 307   int_marker.controls.push_back(control);
 308 
 309   // create a box in the center which should not be view facing,
 310   // but move in the camera plane.
 311   control.orientation_mode = InteractiveMarkerControl::VIEW_FACING;
 312   control.interaction_mode = InteractiveMarkerControl::MOVE_PLANE;
 313   control.independent_marker_orientation = true;
 314   control.name = "move";
 315 
 316   control.markers.push_back( makeBox(int_marker) );
 317   control.always_visible = true;
 318 
 319   int_marker.controls.push_back(control);
 320 
 321   server->insert(int_marker);
 322   server->setCallback(int_marker.name, &processFeedback);
 323 }

Quadrocopter

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

This interactive marker has a constrained set of 4 degrees of freedom. It can rotate around the z axis and move in all 3 dimensions. It it realized using two controls: the green ring moves in the y-z plane and rotates around the z-axis, while the two additional arrows move along z.

Click and drag the green ring to see how the combined movement and rotation works: If the mouse cursor stays close to the ring, it will only rotate. Once you move it further away, it will start following the mouse.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 326 void makeQuadrocopterMarker( const tf::Vector3& position )
 327 {
 328   InteractiveMarker int_marker;
 329   int_marker.header.frame_id = "base_link";
 330   tf::pointTFToMsg(position, int_marker.pose.position);
 331   int_marker.scale = 1;
 332 
 333   int_marker.name = "quadrocopter";
 334   int_marker.description = "Quadrocopter";
 335 
 336   makeBoxControl(int_marker);
 337 
 338   InteractiveMarkerControl control;
 339 
 340   control.orientation.w = 1;
 341   control.orientation.x = 0;
 342   control.orientation.y = 1;
 343   control.orientation.z = 0;
 344   control.interaction_mode = InteractiveMarkerControl::MOVE_ROTATE;
 345   int_marker.controls.push_back(control);
 346   control.interaction_mode = InteractiveMarkerControl::MOVE_AXIS;
 347   int_marker.controls.push_back(control);
 348 
 349   server->insert(int_marker);
 350   server->setCallback(int_marker.name, &processFeedback);
 351 }

The creation of the interactive marker is analogous to the previous examples, just that the interaction mode for one of the controls is set to MOVE_ROTATE.

Chess Piece

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

Click and drag the box or the surrounding Ring to move it in the x-y plane. Once you let go of the mouse button, it will snap to one of the grid fields. The way this works is that the basic_controls server running outside of RViz will set the pose of the Interactive Marker to a new value when it receives the pose from RViz. RViz will apply the update once you stop dragging it.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 353 void makeChessPieceMarker( const tf::Vector3& position )
 354 {
 355   InteractiveMarker int_marker;
 356   int_marker.header.frame_id = "base_link";
 357   tf::pointTFToMsg(position, int_marker.pose.position);
 358   int_marker.scale = 1;
 359 
 360   int_marker.name = "chess_piece";
 361   int_marker.description = "Chess Piece\n(2D Move + Alignment)";
 362 
 363   InteractiveMarkerControl control;
 364 
 365   control.orientation.w = 1;
 366   control.orientation.x = 0;
 367   control.orientation.y = 1;
 368   control.orientation.z = 0;
 369   control.interaction_mode = InteractiveMarkerControl::MOVE_PLANE;
 370   int_marker.controls.push_back(control);
 371 
 372   // make a box which also moves in the plane
 373   control.markers.push_back( makeBox(int_marker) );
 374   control.always_visible = true;
 375   int_marker.controls.push_back(control);
 376 
 377   // we want to use our special callback function
 378   server->insert(int_marker);
 379   server->setCallback(int_marker.name, &processFeedback);
 380 
 381   // set different callback for POSE_UPDATE feedback
 382   server->setCallback(int_marker.name, &alignMarker, visualization_msgs::InteractiveMarkerFeedback::POSE_UPDATE );
 383 }

The major difference to the previous example is that an additional feedback function is specified, which will be called instead of processFeedback() when the pose of the marker gets updated. This function modifies the pose of the marker and sends it back to RViz:

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 148 void alignMarker( const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback )
 149 {
 150   geometry_msgs::Pose pose = feedback->pose;
 151 
 152   pose.position.x = round(pose.position.x-0.5)+0.5;
 153   pose.position.y = round(pose.position.y-0.5)+0.5;
 154 
 155   ROS_INFO_STREAM( feedback->marker_name << ":"
 156       << " aligning position = "
 157       << feedback->pose.position.x
 158       << ", " << feedback->pose.position.y
 159       << ", " << feedback->pose.position.z
 160       << " to "
 161       << pose.position.x
 162       << ", " << pose.position.y
 163       << ", " << pose.position.z );
 164 
 165   server->setPose( feedback->marker_name, pose );
 166   server->applyChanges();
 167 }

Pan / Tilt

The structure of an <<MsgLink(visualization_msgs/InteractiveMarker)>> message

This example shows that you can combine frame aligned and fixed-orientation controls in one Interactive Marker. The Pan control will always stay in place, while the tilt control will rotate.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 385 void makePanTiltMarker( const tf::Vector3& position )
 386 {
 387   InteractiveMarker int_marker;
 388   int_marker.header.frame_id = "base_link";
 389   tf::pointTFToMsg(position, int_marker.pose.position);
 390   int_marker.scale = 1;
 391 
 392   int_marker.name = "pan_tilt";
 393   int_marker.description = "Pan / Tilt";
 394 
 395   makeBoxControl(int_marker);
 396 
 397   InteractiveMarkerControl control;
 398 
 399   control.orientation.w = 1;
 400   control.orientation.x = 0;
 401   control.orientation.y = 1;
 402   control.orientation.z = 0;
 403   control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 404   control.orientation_mode = InteractiveMarkerControl::FIXED;
 405   int_marker.controls.push_back(control);
 406 
 407   control.orientation.w = 1;
 408   control.orientation.x = 0;
 409   control.orientation.y = 0;
 410   control.orientation.z = 1;
 411   control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 412   control.orientation_mode = InteractiveMarkerControl::INHERIT;
 413   int_marker.controls.push_back(control);
 414 
 415   server->insert(int_marker);
 416   server->setCallback(int_marker.name, &processFeedback);
 417 }

Context Menu

This example shows how to attach a simple-static menu to an interactive marker. If you do not specify a custom marker for visualization (as in the case of the grey box), RViz will create a text marker floating above the Interactive Marker, which will enables you to open the context menu.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 419 void makeMenuMarker( const tf::Vector3& position )
 420 {
 421   InteractiveMarker int_marker;
 422   int_marker.header.frame_id = "base_link";
 423   tf::pointTFToMsg(position, int_marker.pose.position);
 424   int_marker.scale = 1;
 425 
 426   int_marker.name = "context_menu";
 427   int_marker.description = "Context Menu\n(Right Click)";
 428 
 429   InteractiveMarkerControl control;
 430 
 431   control.interaction_mode = InteractiveMarkerControl::MENU;
 432   control.name = "menu_only_control";
 433 
 434   Marker marker = makeBox( int_marker );
 435   control.markers.push_back( marker );
 436   control.always_visible = true;
 437   int_marker.controls.push_back(control);
 438 
 439   server->insert(int_marker);
 440   server->setCallback(int_marker.name, &processFeedback);
 441   menu_handler.apply( *server, int_marker.name );
 442 }

Button

Button controls behave almost exactly like the Menu control in the previous example. You can use this type to indicate to the user that a left-click is the desired mode of interaction. RViz will use a different mouse cursor for this type of control (ROS Groovy and above).

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 444 void makeButtonMarker( const tf::Vector3& position )
 445 {
 446   InteractiveMarker int_marker;
 447   int_marker.header.frame_id = "base_link";
 448   tf::pointTFToMsg(position, int_marker.pose.position);
 449   int_marker.scale = 1;
 450 
 451   int_marker.name = "button";
 452   int_marker.description = "Button\n(Left Click)";
 453 
 454   InteractiveMarkerControl control;
 455 
 456   control.interaction_mode = InteractiveMarkerControl::BUTTON;
 457   control.name = "button_control";
 458 
 459   Marker marker = makeBox( int_marker );
 460   control.markers.push_back( marker );
 461   control.always_visible = true;
 462   int_marker.controls.push_back(control);
 463 
 464   server->insert(int_marker);
 465   server->setCallback(int_marker.name, &processFeedback);
 466 }

Marker attached to a moving frame

This example shows what happens if you click on a marker that is attached to a frame which moves relative to the fixed frame specified in RViz. Click on the box to move and on the ring to rotate. As the containing frame moves, the marker will continue moving relative to your mouse even if you are holding it. The interactive marker header's stamp must be ros::Time(0) (as it is by default if not set), so that rviz will take the most recent tf frames to transform it.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 468 void makeMovingMarker( const tf::Vector3& position )
 469 {
 470   InteractiveMarker int_marker;
 471   int_marker.header.frame_id = "moving_frame";
 472   tf::pointTFToMsg(position, int_marker.pose.position);
 473   int_marker.scale = 1;
 474 
 475   int_marker.name = "moving";
 476   int_marker.description = "Marker Attached to a\nMoving Frame";
 477 
 478   InteractiveMarkerControl control;
 479 
 480   control.orientation.w = 1;
 481   control.orientation.x = 1;
 482   control.orientation.y = 0;
 483   control.orientation.z = 0;
 484   control.interaction_mode = InteractiveMarkerControl::ROTATE_AXIS;
 485   int_marker.controls.push_back(control);
 486 
 487   control.interaction_mode = InteractiveMarkerControl::MOVE_PLANE;
 488   control.always_visible = true;
 489   control.markers.push_back( makeBox(int_marker) );
 490   int_marker.controls.push_back(control);
 491 
 492   server->insert(int_marker);
 493   server->setCallback(int_marker.name, &processFeedback);
 494 }

The surrounding code

To setup the server node, all that is needed is to create an instance of InteractiveMarkerServer and pass all InteractiveMarker messages to that object.

Note that you have to call applyChanges() after you have added, updated or removed interactive markers, their pose, menus or feedback functions. This will cause the InteractiveMarkerServer to apply all scheduled changes to its internal state and send an update message to all connected clients. This is done to make it possible to maintain a coherent state and minimize data traffic between the server and its clients.

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

  44 boost::shared_ptr<interactive_markers::InteractiveMarkerServer> server;
  45 interactive_markers::MenuHandler menu_handler;

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

 496 int main(int argc, char** argv)
 497 {
 498   ros::init(argc, argv, "basic_controls");
 499   ros::NodeHandle n;
 500 
 501   // create a timer to update the published transforms
 502   ros::Timer frame_timer = n.createTimer(ros::Duration(0.01), frameCallback);
 503 
 504   server.reset( new interactive_markers::InteractiveMarkerServer("basic_controls","",false) );
 505 
 506   ros::Duration(0.1).sleep();
 507 
 508   menu_handler.insert( "First Entry", &processFeedback );
 509   menu_handler.insert( "Second Entry", &processFeedback );
 510   interactive_markers::MenuHandler::EntryHandle sub_menu_handle = menu_handler.insert( "Submenu" );
 511   menu_handler.insert( sub_menu_handle, "First Entry", &processFeedback );
 512   menu_handler.insert( sub_menu_handle, "Second Entry", &processFeedback );
 513 
 514   tf::Vector3 position;
 515   position = tf::Vector3(-3, 3, 0);
 516   make6DofMarker( false, visualization_msgs::InteractiveMarkerControl::NONE, position, true );
 517   position = tf::Vector3( 0, 3, 0);
 518   make6DofMarker( true, visualization_msgs::InteractiveMarkerControl::NONE, position, true );
 519   position = tf::Vector3( 3, 3, 0);
 520   makeRandomDofMarker( position );
 521   position = tf::Vector3(-3, 0, 0);
 522   make6DofMarker( false, visualization_msgs::InteractiveMarkerControl::ROTATE_3D, position, false );
 523   position = tf::Vector3( 0, 0, 0);
 524   make6DofMarker( false, visualization_msgs::InteractiveMarkerControl::MOVE_ROTATE_3D, position, true );
 525   position = tf::Vector3( 3, 0, 0);
 526   make6DofMarker( false, visualization_msgs::InteractiveMarkerControl::MOVE_3D, position, false );
 527   position = tf::Vector3(-3,-3, 0);
 528   makeViewFacingMarker( position );
 529   position = tf::Vector3( 0,-3, 0);
 530   makeQuadrocopterMarker( position );
 531   position = tf::Vector3( 3,-3, 0);
 532   makeChessPieceMarker( position );
 533   position = tf::Vector3(-3,-6, 0);
 534   makePanTiltMarker( position );
 535   position = tf::Vector3( 0,-6, 0);
 536   makeMovingMarker( position );
 537   position = tf::Vector3( 3,-6, 0);
 538   makeMenuMarker( position );
 539   position = tf::Vector3( 0,-9, 0);
 540   makeButtonMarker( position );
 541 
 542   server->applyChanges();
 543 
 544   ros::spin();
 545 
 546   server.reset();
 547 }

A timer is set up to update the tf transformation between base_link and moving_frame, which is done in frameCallback():

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

  74 void frameCallback(const ros::TimerEvent&)
  75 {
  76   static uint32_t counter = 0;
  77 
  78   static tf::TransformBroadcaster br;
  79 
  80   tf::Transform t;
  81 
  82   ros::Time time = ros::Time::now();
  83 
  84   t.setOrigin(tf::Vector3(0.0, 0.0, sin(float(counter)/140.0) * 2.0));
  85   t.setRotation(tf::Quaternion(0.0, 0.0, 0.0, 1.0));
  86   br.sendTransform(tf::StampedTransform(t, time, "base_link", "moving_frame"));
  87 
  88   t.setOrigin(tf::Vector3(0.0, 0.0, 0.0));
  89   t.setRotation(tf::createQuaternionFromRPY(0.0, float(counter)/140.0, 0.0));
  90   br.sendTransform(tf::StampedTransform(t, time, "base_link", "rotating_frame"));
  91 
  92   counter++;
  93 }

Finally, processFeedback() is used to print output to rosconsole when feedback arrives:

https://raw.github.com/ros-visualization/visualization_tutorials/groovy-devel/interactive_marker_tutorials/src/basic_controls.cpp

  95 void processFeedback( const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback )
  96 {
  97   std::ostringstream s;
  98   s << "Feedback from marker '" << feedback->marker_name << "' "
  99       << " / control '" << feedback->control_name << "'";
 100 
 101   std::ostringstream mouse_point_ss;
 102   if( feedback->mouse_point_valid )
 103   {
 104     mouse_point_ss << " at " << feedback->mouse_point.x
 105                    << ", " << feedback->mouse_point.y
 106                    << ", " << feedback->mouse_point.z
 107                    << " in frame " << feedback->header.frame_id;
 108   }
 109 
 110   switch ( feedback->event_type )
 111   {
 112     case visualization_msgs::InteractiveMarkerFeedback::BUTTON_CLICK:
 113       ROS_INFO_STREAM( s.str() << ": button click" << mouse_point_ss.str() << "." );
 114       break;
 115 
 116     case visualization_msgs::InteractiveMarkerFeedback::MENU_SELECT:
 117       ROS_INFO_STREAM( s.str() << ": menu item " << feedback->menu_entry_id << " clicked" << mouse_point_ss.str() << "." );
 118       break;
 119 
 120     case visualization_msgs::InteractiveMarkerFeedback::POSE_UPDATE:
 121       ROS_INFO_STREAM( s.str() << ": pose changed"
 122           << "\nposition = "
 123           << feedback->pose.position.x
 124           << ", " << feedback->pose.position.y
 125           << ", " << feedback->pose.position.z
 126           << "\norientation = "
 127           << feedback->pose.orientation.w
 128           << ", " << feedback->pose.orientation.x
 129           << ", " << feedback->pose.orientation.y
 130           << ", " << feedback->pose.orientation.z
 131           << "\nframe: " << feedback->header.frame_id
 132           << " time: " << feedback->header.stamp.sec << "sec, "
 133           << feedback->header.stamp.nsec << " nsec" );
 134       break;
 135 
 136     case visualization_msgs::InteractiveMarkerFeedback::MOUSE_DOWN:
 137       ROS_INFO_STREAM( s.str() << ": mouse down" << mouse_point_ss.str() << "." );
 138       break;
 139 
 140     case visualization_msgs::InteractiveMarkerFeedback::MOUSE_UP:
 141       ROS_INFO_STREAM( s.str() << ": mouse up" << mouse_point_ss.str() << "." );
 142       break;
 143   }
 144 
 145   server->applyChanges();
 146 }


2019-06-15 13:10