Rviz教程(六):Interactive Markers: Basic Controls

本文介绍交互标记的基本控制教程,展示了如何使用ROS中的交互标记来实现不同类型的自由度控制,包括简单的6-DOF控制、固定方向控制、3D控制等,并解释了如何创建自定义控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.

  • MOVE_3D: Drawn as a box-marker in the tutorial, this interaction mode allows 3D translation of the marker (in the camera plane by default, and into/out-of the camera while holding shift).
  • ROTATE_3D: Drawn as a box marker in this tutorial, this interacton mode allows 3D rotation of the marker (about the camera plane's vertical and horizontal axes by default, and about the axis perpendicular to the camera plane while holding shift).
  • MOVE_ROTATE_3D: This interaction mode is the union of MOVE_3D (default) and ROTATE_3D (while holding ctrl). An interactive marker can have multiple redundant control types; in this tutorial, the box is a 3D control yet the marker also has a simple set of 6-DOF rings-and-arrows.

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://www.ros.org/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 }
<think>嗯,用户问的是关于在ROS Rviz中配置锚点形态。之前他们刚问过base_link,现在可能是在继续深入ROS和Rviz的配置问题。我需要先理解“锚点形态”指的是什么。在ROS和Rviz中,通常没有直接称为“锚点”的概念,可能用户指的是坐标系中的参考点或者固定的标记物,比如用于可视化的标记或者TF中的固定点。 首先,用户可能想设置一些固定的参考点,方便在Rviz中观察机器人的位置或者路径。比如,设置一个起始点或者目标点作为锚点,或者可能是指向某个固定的坐标系,比如map或odom。也有可能是使用Rviz中的Marker来显示特定的标记,作为视觉参考。 我需要回顾Rviz中的相关功能,比如Marker、TF坐标系、或者Interactive MarkersInteractive Markers允许用户与Rviz中的对象交互,比如拖拽标记点,这可能就是用户所说的“锚点形态”。另外,Rviz中的Axes或Arrow等显示类型可能被用来表示锚点。 用户可能的需求场景包括:在导航中设置目标点,调试时标记特定位置,或者需要可视化某些关键点。他们可能需要步骤指导如何在Rviz中添加和配置这些标记,可能涉及发布Marker消息或者使用Interactive Markers。 需要检查用户的问题是否有拼写错误,比如“锚点形态”是否正确,或者是否指其他术语。确认后,应该分步骤解释如何在Rviz中配置这些锚点,包括使用哪些工具和ROS包,如何发布消息,以及如何在Rviz界面中进行设置。 另外,用户之前询问过base_link,可能现在的问题是在同一个项目中进行更复杂的可视化配置,需要确保回答与之前的base_link配置相关联,比如如何将锚点与base_link坐标系结合使用。 需要提供具体的配置方法,例如使用rviz中的Marker显示类型,或者使用Interactive Markers,给出代码示例和配置步骤。同时,可能需要解释不同的锚点类型,如固定位置、可交互的标记等,以及它们在导航或调试中的应用。 还要考虑用户可能的错误,比如无法显示锚点,或者坐标不正确,提供调试技巧,比如检查TF树,确认坐标系是否正确发布,或者消息是否正常发送。 最后,总结应用场景,帮助用户理解何时以及如何使用这些锚点配置,比如路径规划中的目标点设置,或者多机器人系统中的位置标记。</think>以下是在 ROS Rviz 中配置**锚点形态**的完整技术指南(包含实现方法和应用场景): --- ### 一、锚点形态核心概念 在 Rviz 中,锚点(Anchor Point)通常指**可视化参考标记**,用于: ✅ 定位基准点可视化 ✅ 交互式目标点设置 ✅ 坐标系关系验证 ✅ 路径规划目标标记 --- ### 二、基础配置方法 #### 方法1:使用 **Marker** 显示类型 ```bash # 启动可视化节点 rosrun visualization_tutorials basic_shapes ``` **Rviz 配置步骤**: 1. 添加 `Marker` 显示插件 2. 设置 `Marker Topic` 为 `/visualization_marker` 3. 配置形状属性: ```yaml Shape: Cube/Sphere/Arrow # 几何形态 Scale: (0.5,0.5,0.5) # 尺寸比例 Color: RGBA(0,1,0,0.8) # 颜色与透明度 ``` #### 方法2:通过 **InteractiveMarkers** 实现 ```python # 创建交互式标记(Python示例) from interactive_markers import InteractiveMarkerServer server = InteractiveMarkerServer("anchor_markers") int_marker = InteractiveMarker() int_marker.header.frame_id = "map" int_marker.name = "waypoint_anchor" int_marker.description = "Goal Position" # 添加控制手柄 control = InteractiveMarkerControl() control.orientation.w = 1 control.interaction_mode = InteractiveMarkerControl.MOVE_PLANE int_marker.controls.append(control) server.insert(int_marker, feedback_callback) server.applyChanges() ``` --- ### 三、高级形态配置 #### 1. 坐标系锚点 (TF Anchor) ```xml <!-- 在 URDF 中定义静态锚点 --> <link name="anchor_point_1"/> <joint name="anchor_joint" type="fixed"> <parent link="map"/> <child link="anchor_point_1"/> <origin xyz="2.0 3.5 0" rpy="0 0 0"/> <!-- 绝对坐标位置 --> </joint> ``` #### 2. 多形态组合锚点 ```python # 组合多种几何形状的 MarkerArray from visualization_msgs.msg import MarkerArray, Marker marker_array = MarkerArray() # 主体圆柱 cylinder = Marker() cylinder.type = Marker.CYLINDER cylinder.scale.z = 2.0 # 高度 # 顶部箭头 arrow = Marker() arrow.type = Marker.ARROW arrow.scale.x = 0.5 # 箭头长度 arrow.color.r = 1.0 # 红色 ``` --- ### 四、关键参数配置表 | 参数项 | 典型值 | 作用说明 | |------------------|-------------------------|----------------------------| | `frame_id` | `map/base_link` | 锚点参考坐标系 | | `lifetime` | `ros::Duration(0)` | 持续显示时间(0=永久) | | `ns` | `navigation_anchors` | 命名空间分类 | | `pose.position` | `(x,y,z)` | 三维空间位置 | | `pose.orientation`| `(qx,qy,qz,qw)` | 四元数方向 | --- ### 五、调试与优化技巧 1. **坐标对齐验证** ```bash rosrun tf tf_echo map anchor_point_1 # 检查锚点实际坐标 ``` 2. **显示异常处理** - **锚点不可见**:检查 `frame_id` 是否在 TF 树中存在 - **位置偏移**:确认坐标系变换方向是否正确(使用 `rqt_tf_tree`) - **交互延迟**:确保 `InteractiveMarkerServer` 更新频率 > 10Hz 3. **性能优化** ```python # 控制 Marker 更新频率 rate = rospy.Rate(5) # 5Hz 更新 while not rospy.is_shutdown(): marker_pub.publish(marker_array) rate.sleep() ``` --- ### 、典型应用场景 1. **导航目标点预设** ```python # 通过点击设置目标点 def click_callback(msg): goal = PoseStamped() goal.header.frame_id = "map" goal.pose = msg.pose # 发送到 move_base 目标话题 rospy.Subscriber("/clicked_point", PointStamped, click_callback) ``` 2. **多机器人协同标记** ```xml <!-- 定义不同颜色锚点 --> <Marker> <ns>robot1_anchors</ns> <color>R=1.0 G=0.0 B=0.0</color> </Marker> <Marker> <ns>robot2_anchors</ns> <color>R=0.0 G=1.0 B=0.0</color> </Marker> ``` --- 通过合理配置锚点形态,可实现: 🔧 增强空间位置感知 🎯 提升人机交互效率 📊 优化多坐标系统调试过程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值