$search
00001 /* 00002 * Copyright (c) 2008, Willow Garage, Inc. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the Willow Garage, Inc. nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "interactive_marker_display.h" 00031 #include "rviz/visualization_manager.h" 00032 #include "rviz/properties/property_manager.h" 00033 #include "rviz/properties/property.h" 00034 #include "rviz/selection/selection_manager.h" 00035 #include "rviz/frame_manager.h" 00036 #include "rviz/validate_floats.h" 00037 00038 00039 #include <tf/transform_listener.h> 00040 00041 #include <OGRE/OgreSceneNode.h> 00042 #include <OGRE/OgreSceneManager.h> 00043 00044 namespace rviz 00045 { 00046 00048 bool validateFloats(const visualization_msgs::InteractiveMarker& msg) 00049 { 00050 bool valid = true; 00051 valid = valid && validateFloats(msg.pose); 00052 valid = valid && validateFloats(msg.scale); 00053 for ( unsigned c=0; c<msg.controls.size(); c++) 00054 { 00055 valid = valid && validateFloats( msg.controls[c].orientation ); 00056 for ( unsigned m=0; m<msg.controls[c].markers.size(); m++ ) 00057 { 00058 valid = valid && validateFloats(msg.controls[c].markers[m].pose); 00059 valid = valid && validateFloats(msg.controls[c].markers[m].scale); 00060 valid = valid && validateFloats(msg.controls[c].markers[m].color); 00061 valid = valid && validateFloats(msg.controls[c].markers[m].points); 00062 } 00063 } 00064 return valid; 00065 } 00067 00068 00069 00070 InteractiveMarkerDisplay::InteractiveMarkerDisplay() 00071 : Display() 00072 , im_client_( this ) 00073 , show_descriptions_(true) 00074 , show_tool_tips_(true) 00075 , show_axes_(false) 00076 { 00077 } 00078 00079 void InteractiveMarkerDisplay::onInitialize() 00080 { 00081 tf_filter_ = new tf::MessageFilter<visualization_msgs::InteractiveMarker>(*vis_manager_->getTFClient(), "", 100, update_nh_); 00082 tf_pose_filter_ = new tf::MessageFilter<visualization_msgs::InteractiveMarkerPose>(*vis_manager_->getTFClient(), "", 100, update_nh_); 00083 scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode(); 00084 00085 //message flow: incomingMarkerUpdate(..) -> tf_filter_ -> tfMarkerSuccess(..) -> message_queue_ -> update(..) 00086 00087 tf_filter_->registerCallback(boost::bind(&InteractiveMarkerDisplay::tfMarkerSuccess, this, _1)); 00088 tf_filter_->registerFailureCallback(boost::bind(&InteractiveMarkerDisplay::tfMarkerFail, this, _1, _2)); 00089 tf_pose_filter_->registerCallback(boost::bind(&InteractiveMarkerDisplay::tfPoseSuccess, this, _1)); 00090 tf_pose_filter_->registerFailureCallback(boost::bind(&InteractiveMarkerDisplay::tfPoseFail, this, _1, _2)); 00091 00092 client_id_ = ros::this_node::getName() + "/" + name_; 00093 } 00094 00095 InteractiveMarkerDisplay::~InteractiveMarkerDisplay() 00096 { 00097 unsubscribe(); 00098 scene_manager_->destroySceneNode( scene_node_ ); 00099 delete tf_filter_; 00100 delete tf_pose_filter_; 00101 } 00102 00103 void InteractiveMarkerDisplay::onEnable() 00104 { 00105 subscribe(); 00106 scene_node_->setVisible( true ); 00107 } 00108 00109 void InteractiveMarkerDisplay::onDisable() 00110 { 00111 unsubscribe(); 00112 tf_filter_->clear(); 00113 tf_pose_filter_->clear(); 00114 scene_node_->setVisible( false ); 00115 } 00116 00117 void InteractiveMarkerDisplay::setMarkerUpdateTopic(const std::string& topic) 00118 { 00119 if ( marker_update_topic_.empty() && topic.empty() ) 00120 { 00121 return; 00122 } 00123 unsubscribe(); 00124 marker_update_topic_ = topic; 00125 subscribe(); 00126 propertyChanged(marker_update_topic_property_); 00127 } 00128 00129 void InteractiveMarkerDisplay::subscribe() 00130 { 00131 if ( !isEnabled() ) 00132 { 00133 return; 00134 } 00135 00136 marker_update_sub_.shutdown(); 00137 num_publishers_ = 0; 00138 00139 try 00140 { 00141 if ( !marker_update_topic_.empty() ) 00142 { 00143 ROS_DEBUG( "Subscribing to %s", marker_update_topic_.c_str() ); 00144 marker_update_sub_ = update_nh_.subscribe(marker_update_topic_, 100, &InteractiveMarkerClient::processMarkerUpdate, &im_client_); 00145 } 00146 00147 setStatus(status_levels::Ok, "Topic", "OK"); 00148 } 00149 catch (ros::Exception& e) 00150 { 00151 setStatus(status_levels::Error, "Topic", std::string("Error subscribing: ") + e.what()); 00152 } 00153 00154 im_client_.clear(); 00155 } 00156 00157 bool InteractiveMarkerDisplay::subscribeToInit() 00158 { 00159 bool result = false; 00160 00161 ROS_DEBUG( "subscribeToInit()" ); 00162 try 00163 { 00164 if ( !marker_update_topic_.empty() ) 00165 { 00166 std::string init_topic = marker_update_topic_ + "_full"; 00167 ROS_DEBUG( "Subscribing to %s", init_topic.c_str() ); 00168 marker_init_sub_ = update_nh_.subscribe(init_topic, 100, &InteractiveMarkerClient::processMarkerInit, &im_client_); 00169 result = true; 00170 } 00171 00172 setStatus(status_levels::Ok, "InitTopic", "OK"); 00173 } 00174 catch (ros::Exception& e) 00175 { 00176 setStatus(status_levels::Error, "InitTopic", std::string("Error subscribing: ") + e.what()); 00177 } 00178 return result; 00179 } 00180 00181 void InteractiveMarkerDisplay::clearMarkers() 00182 { 00183 interactive_markers_.clear(); 00184 tf_filter_->clear(); 00185 tf_pose_filter_->clear(); 00186 } 00187 00188 void InteractiveMarkerDisplay::unsubscribe() 00189 { 00190 marker_update_sub_.shutdown(); 00191 marker_init_sub_.shutdown(); 00192 clearMarkers(); 00193 im_client_.unsubscribedFromInit(); 00194 } 00195 00196 void InteractiveMarkerDisplay::unsubscribeFromInit() 00197 { 00198 marker_init_sub_.shutdown(); 00199 } 00200 00201 void InteractiveMarkerDisplay::processMarkerChanges( const std::vector<visualization_msgs::InteractiveMarker>* markers, 00202 const std::vector<visualization_msgs::InteractiveMarkerPose>* poses, 00203 const std::vector<std::string>* erases ) 00204 { 00205 std::set<std::string> names; 00206 00207 if( markers != NULL ) 00208 { 00209 std::vector<visualization_msgs::InteractiveMarker>::const_iterator marker_it = markers->begin(); 00210 std::vector<visualization_msgs::InteractiveMarker>::const_iterator marker_end = markers->end(); 00211 for (; marker_it != marker_end; ++marker_it) 00212 { 00213 if ( !names.insert( marker_it->name ).second ) 00214 { 00215 setStatus(status_levels::Error, "Marker array", "The name '" + marker_it->name + "' was used multiple times."); 00216 } 00217 00218 visualization_msgs::InteractiveMarker::ConstPtr marker_ptr(new visualization_msgs::InteractiveMarker(*marker_it)); 00219 00220 if ( marker_it->header.stamp == ros::Time(0) ) 00221 { 00222 // bypass tf filter 00223 updateMarker( marker_ptr ); 00224 vis_manager_->queueRender(); 00225 } 00226 else 00227 { 00228 ROS_DEBUG("Forwarding %s to tf filter.", marker_it->name.c_str()); 00229 tf_filter_->add( marker_ptr ); 00230 } 00231 } 00232 } 00233 00234 if( poses != NULL ) 00235 { 00236 // pipe all pose updates into tf filter 00237 std::vector<visualization_msgs::InteractiveMarkerPose>::const_iterator pose_it = poses->begin(); 00238 std::vector<visualization_msgs::InteractiveMarkerPose>::const_iterator pose_end = poses->end(); 00239 00240 for (; pose_it != pose_end; ++pose_it) 00241 { 00242 if ( !names.insert( pose_it->name ).second ) 00243 { 00244 setStatus(status_levels::Error, "Marker array", "The name '" + pose_it->name + "' was used multiple times."); 00245 } 00246 00247 visualization_msgs::InteractiveMarkerPose::ConstPtr pose_ptr(new visualization_msgs::InteractiveMarkerPose(*pose_it)); 00248 00249 if ( pose_it->header.stamp == ros::Time(0) ) 00250 { 00251 updatePose( pose_ptr ); 00252 vis_manager_->queueRender(); 00253 } 00254 else 00255 { 00256 ROS_DEBUG("Forwarding pose for %s to tf filter.", pose_it->name.c_str()); 00257 tf_pose_filter_->add( pose_ptr ); 00258 } 00259 } 00260 } 00261 00262 if( erases != NULL ) 00263 { 00264 // erase markers 00265 std::vector<std::string>::const_iterator erase_it = erases->begin(); 00266 std::vector<std::string>::const_iterator erase_end = erases->end(); 00267 00268 for (; erase_it != erase_end; ++erase_it) 00269 { 00270 interactive_markers_.erase( *erase_it ); 00271 } 00272 } 00273 } 00274 00275 void InteractiveMarkerDisplay::tfMarkerSuccess( const visualization_msgs::InteractiveMarker::ConstPtr& marker ) 00276 { 00277 ROS_DEBUG("Queueing %s", marker->name.c_str()); 00278 boost::mutex::scoped_lock lock(queue_mutex_); 00279 marker_queue_.push_back(marker); 00280 vis_manager_->queueRender(); 00281 } 00282 00283 void InteractiveMarkerDisplay::tfMarkerFail(const visualization_msgs::InteractiveMarker::ConstPtr& marker, tf::FilterFailureReason reason) 00284 { 00285 std::string error = FrameManager::instance()->discoverFailureReason(marker->header.frame_id, marker->header.stamp, marker->__connection_header ? (*marker->__connection_header)["callerid"] : "unknown", reason); 00286 setStatus( status_levels::Error, marker->name, error); 00287 } 00288 00289 void InteractiveMarkerDisplay::tfPoseSuccess(const visualization_msgs::InteractiveMarkerPose::ConstPtr& marker_pose) 00290 { 00291 ROS_DEBUG("Queueing pose for %s", marker_pose->name.c_str()); 00292 boost::mutex::scoped_lock lock(queue_mutex_); 00293 pose_queue_.push_back(marker_pose); 00294 vis_manager_->queueRender(); 00295 } 00296 00297 void InteractiveMarkerDisplay::tfPoseFail(const visualization_msgs::InteractiveMarkerPose::ConstPtr& marker_pose, tf::FilterFailureReason reason) 00298 { 00299 std::string error = FrameManager::instance()->discoverFailureReason( 00300 marker_pose->header.frame_id, marker_pose->header.stamp, 00301 marker_pose->__connection_header ? (*marker_pose->__connection_header)["callerid"] : "unknown", reason); 00302 setStatus( status_levels::Error, marker_pose->name, error); 00303 } 00304 00305 00306 void InteractiveMarkerDisplay::update(float wall_dt, float ros_dt) 00307 { 00308 //detect if all servers have shut down 00309 if ( !im_client_.isPublisherListEmpty() ) 00310 { 00311 // weak detection of server shutdown 00312 unsigned num_pub = marker_update_sub_.getNumPublishers(); 00313 if ( num_pub < num_publishers_ ) 00314 { 00315 reset(); 00316 } 00317 else 00318 { 00319 num_publishers_ = num_pub; 00320 } 00321 00322 im_client_.flagLateConnections(); 00323 } 00324 00325 V_InteractiveMarkerMessage local_marker_queue; 00326 V_InteractiveMarkerPoseMessage local_pose_queue; 00327 00328 // the queue is accessed from another thread, so we need to lock it 00329 // and swap it's contents to a copy 00330 { 00331 boost::mutex::scoped_lock lock(queue_mutex_); 00332 local_marker_queue.swap( marker_queue_ ); 00333 local_pose_queue.swap( pose_queue_ ); 00334 } 00335 00336 if ( !local_marker_queue.empty() ) 00337 { 00338 V_InteractiveMarkerMessage::iterator message_it = local_marker_queue.begin(); 00339 V_InteractiveMarkerMessage::iterator message_end = local_marker_queue.end(); 00340 for ( ; message_it != message_end; ++message_it ) 00341 { 00342 updateMarker( *message_it ); 00343 } 00344 } 00345 00346 if ( !local_pose_queue.empty() ) 00347 { 00348 V_InteractiveMarkerPoseMessage::iterator message_it = local_pose_queue.begin(); 00349 V_InteractiveMarkerPoseMessage::iterator message_end = local_pose_queue.end(); 00350 for ( ; message_it != message_end; ++message_it ) 00351 { 00352 updatePose( *message_it ); 00353 } 00354 } 00355 00356 M_StringToInteractiveMarkerPtr::iterator it; 00357 for ( it = interactive_markers_.begin(); it != interactive_markers_.end(); it++ ) 00358 { 00359 it->second->update( wall_dt ); 00360 } 00361 } 00362 00363 void InteractiveMarkerDisplay::updateMarker( visualization_msgs::InteractiveMarker::ConstPtr& marker ) 00364 { 00365 if ( !validateFloats( *marker ) ) 00366 { 00367 setStatus( status_levels::Error, marker->name, "Message contains invalid floats!" ); 00368 return; 00369 } 00370 ROS_DEBUG("Processing interactive marker '%s'. %d", marker->name.c_str(), (int)marker->controls.size() ); 00371 00372 std::map< std::string, InteractiveMarkerPtr >::iterator int_marker_entry = interactive_markers_.find( marker->name ); 00373 00374 std::string topic = marker_update_topic_; 00375 00376 topic = ros::names::clean( topic ); 00377 topic = topic.substr( 0, topic.find_last_of( '/' ) ); 00378 00379 if ( int_marker_entry == interactive_markers_.end() ) 00380 { 00381 int_marker_entry = interactive_markers_.insert( std::make_pair(marker->name, InteractiveMarkerPtr ( new InteractiveMarker(this, vis_manager_, topic, client_id_) ) ) ).first; 00382 } 00383 00384 if ( int_marker_entry->second->processMessage( marker ) ) 00385 { 00386 int_marker_entry->second->setShowAxes(show_axes_); 00387 int_marker_entry->second->setShowDescription(show_descriptions_); 00388 } 00389 } 00390 00391 void InteractiveMarkerDisplay::updatePose( visualization_msgs::InteractiveMarkerPose::ConstPtr& marker_pose ) 00392 { 00393 if ( !validateFloats( marker_pose->pose ) ) 00394 { 00395 setStatus( status_levels::Error, marker_pose->name, "Pose message contains invalid floats!" ); 00396 return; 00397 } 00398 00399 std::map< std::string, InteractiveMarkerPtr >::iterator int_marker_entry = interactive_markers_.find( marker_pose->name ); 00400 00401 if ( int_marker_entry != interactive_markers_.end() ) 00402 { 00403 int_marker_entry->second->processMessage( marker_pose ); 00404 } 00405 } 00406 00407 void InteractiveMarkerDisplay::targetFrameChanged() 00408 { 00409 } 00410 00411 void InteractiveMarkerDisplay::fixedFrameChanged() 00412 { 00413 tf_filter_->setTargetFrame( fixed_frame_ ); 00414 tf_pose_filter_->setTargetFrame( fixed_frame_ ); 00415 reset(); 00416 } 00417 00418 void InteractiveMarkerDisplay::reset() 00419 { 00420 ROS_DEBUG("reset"); 00421 Display::reset(); 00422 unsubscribe(); 00423 subscribe(); 00424 } 00425 00426 void InteractiveMarkerDisplay::createProperties() 00427 { 00428 // interactive marker update topic 00429 marker_update_topic_property_ = property_manager_->createProperty<ROSTopicStringProperty>( 00430 "Update Topic", property_prefix_, boost::bind( &InteractiveMarkerDisplay::getMarkerUpdateTopic, this ), 00431 boost::bind( &InteractiveMarkerDisplay::setMarkerUpdateTopic, this, _1 ), parent_category_, this ); 00432 00433 setPropertyHelpText(marker_update_topic_property_, "visualization_msgs::InteractiveMarkerUpdate topic to subscribe to."); 00434 ROSTopicStringPropertyPtr marker_update_topic_property_locked = marker_update_topic_property_.lock(); 00435 marker_update_topic_property_locked->setMessageType(ros::message_traits::datatype<visualization_msgs::InteractiveMarkerUpdate>()); 00436 00437 // display options 00438 show_descriptions_property_ = property_manager_->createProperty<BoolProperty>( 00439 "Show Descriptions", property_prefix_, boost::bind( &InteractiveMarkerDisplay::getShowDescriptions, this ), 00440 boost::bind( &InteractiveMarkerDisplay::setShowDescriptions, this, _1 ), parent_category_, this ); 00441 00442 setPropertyHelpText(show_descriptions_property_, "Whether or not to show the descriptions of each Interactive Marker."); 00443 00444 show_tool_tips_property_ = property_manager_->createProperty<BoolProperty>( 00445 "Show Tool Tips", property_prefix_, boost::bind( &InteractiveMarkerDisplay::getShowToolTips, this ), 00446 boost::bind( &InteractiveMarkerDisplay::setShowToolTips, this, _1 ), parent_category_, this ); 00447 00448 setPropertyHelpText(show_tool_tips_property_, "Whether or not to show tool tips for the Interactive Marker Controls."); 00449 00450 show_axes_property_ = property_manager_->createProperty<BoolProperty>( 00451 "Show Axes", property_prefix_, boost::bind( &InteractiveMarkerDisplay::getShowAxes, this ), 00452 boost::bind( &InteractiveMarkerDisplay::setShowAxes, this, _1 ), parent_category_, this ); 00453 00454 setPropertyHelpText(show_axes_property_, "Whether or not to show the axes of each Interactive Marker."); 00455 } 00456 00457 00458 void InteractiveMarkerDisplay::setShowDescriptions( bool show ) 00459 { 00460 show_descriptions_ = show; 00461 00462 M_StringToInteractiveMarkerPtr::iterator it; 00463 for ( it = interactive_markers_.begin(); it != interactive_markers_.end(); it++ ) 00464 { 00465 it->second->setShowDescription(show); 00466 } 00467 00468 propertyChanged(show_descriptions_property_); 00469 } 00470 00471 00472 void InteractiveMarkerDisplay::setShowToolTips( bool show ) 00473 { 00474 show_tool_tips_ = show; 00475 00476 propertyChanged(show_descriptions_property_); 00477 } 00478 00479 00480 void InteractiveMarkerDisplay::setShowAxes( bool show ) 00481 { 00482 show_axes_ = show; 00483 00484 M_StringToInteractiveMarkerPtr::iterator it; 00485 for ( it = interactive_markers_.begin(); it != interactive_markers_.end(); it++ ) 00486 { 00487 it->second->setShowAxes(show); 00488 } 00489 00490 propertyChanged(show_axes_property_); 00491 } 00492 00493 void InteractiveMarkerDisplay::setStatusOk(const std::string& name, const std::string& text) 00494 { 00495 setStatus( status_levels::Ok, name, text ); 00496 } 00497 00498 void InteractiveMarkerDisplay::setStatusWarn(const std::string& name, const std::string& text) 00499 { 00500 setStatus( status_levels::Warn, name, text ); 00501 } 00502 00503 void InteractiveMarkerDisplay::setStatusError(const std::string& name, const std::string& text) 00504 { 00505 setStatus( status_levels::Error, name, text ); 00506 } 00507 00508 } // namespace rviz