00001 #ifndef EFFORT_DISPLAY_H
00002 #define EFFORT_DISPLAY_H
00003
00004 #include <boost/circular_buffer.hpp>
00005
00006 #include <sensor_msgs/JointState.h>
00007 #include <rviz/message_filter_display.h>
00008
00009 namespace Ogre
00010 {
00011 class SceneNode;
00012 }
00013
00014 namespace rviz
00015 {
00016 class FloatProperty;
00017 class IntProperty;
00018 class StringProperty;
00019 class CategoryProperty;
00020 class BoolProperty;
00021 class RosTopicProperty;
00022 }
00023
00024 namespace urdf
00025 {
00026 class Model;
00027 }
00028
00029
00030
00031 namespace tf
00032 {
00033 #define TF_MESSAGEFILTER_DEBUG(fmt, ...) \
00034 ROS_DEBUG_NAMED("message_filter", "MessageFilter [target=%s]: "fmt, getTargetFramesString().c_str(), __VA_ARGS__)
00035
00036 #define TF_MESSAGEFILTER_WARN(fmt, ...) \
00037 ROS_WARN_NAMED("message_filter", "MessageFilter [target=%s]: "fmt, getTargetFramesString().c_str(), __VA_ARGS__)
00038
00039 class MessageFilterJointState : public MessageFilter<sensor_msgs::JointState>
00040 {
00041 typedef sensor_msgs::JointState M;
00042 public:
00043 typedef boost::shared_ptr<M const> MConstPtr;
00044 typedef ros::MessageEvent<M const> MEvent;
00045 typedef boost::function<void(const MConstPtr&, FilterFailureReason)> FailureCallback;
00046 typedef boost::signal<void(const MConstPtr&, FilterFailureReason)> FailureSignal;
00047
00048
00049 ROS_STATIC_ASSERT(ros::message_traits::HasHeader<M>::value);
00050
00060 MessageFilterJointState(Transformer& tf, const std::string& target_frame, uint32_t queue_size, ros::NodeHandle nh = ros::NodeHandle(), ros::Duration max_rate = ros::Duration(0.01))
00061 : MessageFilter<sensor_msgs::JointState>(tf, target_frame, queue_size, nh, max_rate)
00062 , tf_(tf)
00063 , nh_(nh)
00064 , max_rate_(max_rate)
00065 , queue_size_(queue_size)
00066 {
00067 init();
00068
00069 setTargetFrame(target_frame);
00070 }
00071
00082 template<class F>
00083 MessageFilterJointState(F& f, Transformer& tf, const std::string& target_frame, uint32_t queue_size, ros::NodeHandle nh = ros::NodeHandle(), ros::Duration max_rate = ros::Duration(0.01))
00084 : tf_(tf)
00085 , nh_(nh)
00086 , max_rate_(max_rate)
00087 , queue_size_(queue_size)
00088 , MessageFilter<sensor_msgs::JointState>(f, tf, target_frame, queue_size, nh, max_rate)
00089 {
00090 init();
00091
00092 setTargetFrame(target_frame);
00093
00094 connectInput(f);
00095 }
00096
00100 template<class F>
00101 void connectInput(F& f)
00102 {
00103 message_connection_.disconnect();
00104 message_connection_ = f.registerCallback(&MessageFilterJointState::incomingMessage, this);
00105 }
00106
00110 ~MessageFilterJointState()
00111 {
00112 message_connection_.disconnect();
00113 tf_.removeTransformsChangedListener(tf_connection_);
00114
00115 clear();
00116
00117 TF_MESSAGEFILTER_DEBUG("Successful Transforms: %llu, Failed Transforms: %llu, Discarded due to age: %llu, Transform messages received: %llu, Messages received: %llu, Total dropped: %llu",
00118 (long long unsigned int)successful_transform_count_, (long long unsigned int)failed_transform_count_,
00119 (long long unsigned int)failed_out_the_back_count_, (long long unsigned int)transform_message_count_,
00120 (long long unsigned int)incoming_message_count_, (long long unsigned int)dropped_message_count_);
00121
00122 }
00123
00127 void setTargetFrame(const std::string& target_frame)
00128 {
00129 std::vector<std::string> frames;
00130 frames.push_back(target_frame);
00131 setTargetFrames(frames);
00132 }
00133
00137 void setTargetFrames(const std::vector<std::string>& target_frames)
00138 {
00139 boost::mutex::scoped_lock list_lock(messages_mutex_);
00140 boost::mutex::scoped_lock string_lock(target_frames_string_mutex_);
00141
00142 target_frames_ = target_frames;
00143
00144 std::stringstream ss;
00145 for (std::vector<std::string>::iterator it = target_frames_.begin(); it != target_frames_.end(); ++it)
00146 {
00147 *it = tf::resolve(tf_.getTFPrefix(), *it);
00148 ss << *it << " ";
00149 }
00150 target_frames_string_ = ss.str();
00151 }
00155 std::string getTargetFramesString()
00156 {
00157 boost::mutex::scoped_lock lock(target_frames_string_mutex_);
00158 return target_frames_string_;
00159 };
00160
00164 void setTolerance(const ros::Duration& tolerance)
00165 {
00166 time_tolerance_ = tolerance;
00167 }
00168
00172 void clear()
00173 {
00174 boost::mutex::scoped_lock lock(messages_mutex_);
00175
00176 TF_MESSAGEFILTER_DEBUG("%s", "Cleared");
00177
00178 messages_.clear();
00179 message_count_ = 0;
00180
00181 warned_about_unresolved_name_ = false;
00182 warned_about_empty_frame_id_ = false;
00183 }
00184
00185 void add(const MEvent& evt)
00186 {
00187 boost::mutex::scoped_lock lock(messages_mutex_);
00188
00189 testMessages();
00190
00191 if (!testMessage(evt))
00192 {
00193
00194 if (queue_size_ != 0 && message_count_ + 1 > queue_size_)
00195 {
00196 ++dropped_message_count_;
00197 const MEvent& front = messages_.front();
00198 TF_MESSAGEFILTER_DEBUG("Removed oldest message because buffer is full, count now %d (frame_id=%s, stamp=%f)", message_count_, front.getMessage()->header.frame_id.c_str(), front.getMessage()->header.stamp.toSec());
00199 signalFailure(messages_.front(), filter_failure_reasons::Unknown);
00200
00201 messages_.pop_front();
00202 --message_count_;
00203 }
00204
00205
00206 messages_.push_back(evt);
00207 ++message_count_;
00208 }
00209
00210 TF_MESSAGEFILTER_DEBUG("Added message in frame %s at time %.3f, count now %d", evt.getMessage()->header.frame_id.c_str(), evt.getMessage()->header.stamp.toSec(), message_count_);
00211
00212 ++incoming_message_count_;
00213 }
00214
00220 void add(const MConstPtr& message)
00221 {
00222 boost::shared_ptr<std::map<std::string, std::string> > header(new std::map<std::string, std::string>);
00223 (*header)["callerid"] = "unknown";
00224 add(MEvent(message, header, ros::Time::now()));
00225 }
00226
00231 message_filters::Connection registerFailureCallback(const FailureCallback& callback)
00232 {
00233 boost::mutex::scoped_lock lock(failure_signal_mutex_);
00234 return message_filters::Connection(boost::bind(&MessageFilterJointState::disconnectFailure, this, _1), failure_signal_.connect(callback));
00235 }
00236
00237 virtual void setQueueSize( uint32_t new_queue_size )
00238 {
00239 queue_size_ = new_queue_size;
00240 }
00241
00242 virtual uint32_t getQueueSize()
00243 {
00244 return queue_size_;
00245 }
00246
00247 private:
00248
00249 void init()
00250 {
00251 message_count_ = 0;
00252 new_transforms_ = false;
00253 successful_transform_count_ = 0;
00254 failed_transform_count_ = 0;
00255 failed_out_the_back_count_ = 0;
00256 transform_message_count_ = 0;
00257 incoming_message_count_ = 0;
00258 dropped_message_count_ = 0;
00259 time_tolerance_ = ros::Duration(0.0);
00260 warned_about_unresolved_name_ = false;
00261 warned_about_empty_frame_id_ = false;
00262
00263 tf_connection_ = tf_.addTransformsChangedListener(boost::bind(&MessageFilterJointState::transformsChanged, this));
00264
00265 max_rate_timer_ = nh_.createTimer(max_rate_, &MessageFilterJointState::maxRateTimerCallback, this);
00266 }
00267
00268 typedef std::list<MEvent> L_Event;
00269
00270 bool testMessage(const MEvent& evt)
00271 {
00272 const MConstPtr& message = evt.getMessage();
00273 std::string callerid = evt.getPublisherName();
00274 std::string frame_id = ros::message_traits::FrameId<M>::value(*message);
00275 ros::Time stamp = ros::message_traits::TimeStamp<M>::value(*message);
00276
00277
00278 if (frame_id.empty()) frame_id = * (target_frames_.begin());
00279
00280 if (frame_id.empty())
00281 {
00282 if (!warned_about_empty_frame_id_)
00283 {
00284 warned_about_empty_frame_id_ = true;
00285 TF_MESSAGEFILTER_WARN("Discarding message from [%s] due to empty frame_id. This message will only print once.", callerid.c_str());
00286 }
00287 signalFailure(evt, filter_failure_reasons::EmptyFrameID);
00288 return true;
00289 }
00290
00291 if (frame_id[0] != '/')
00292 {
00293 std::string unresolved = frame_id;
00294 frame_id = tf::resolve(tf_.getTFPrefix(), frame_id);
00295
00296 if (!warned_about_unresolved_name_)
00297 {
00298 warned_about_unresolved_name_ = true;
00299 ROS_WARN("Message from [%s] has a non-fully-qualified frame_id [%s]. Resolved locally to [%s]. This is will likely not work in multi-robot systems. This message will only print once.", callerid.c_str(), unresolved.c_str(), frame_id.c_str());
00300 }
00301 }
00302
00303
00305 for (std::vector<std::string>::iterator target_it = target_frames_.begin(); target_it != target_frames_.end(); ++target_it)
00306 {
00307 const std::string& target_frame = *target_it;
00308
00309 if (target_frame != frame_id && stamp != ros::Time(0))
00310 {
00311 ros::Time latest_transform_time ;
00312
00313 tf_.getLatestCommonTime(frame_id, target_frame, latest_transform_time, 0) ;
00314 if (stamp + tf_.getCacheLength() < latest_transform_time)
00315 {
00316 ++failed_out_the_back_count_;
00317 ++dropped_message_count_;
00318 TF_MESSAGEFILTER_DEBUG("Discarding Message, in frame %s, Out of the back of Cache Time(stamp: %.3f + cache_length: %.3f < latest_transform_time %.3f. Message Count now: %d", message->header.frame_id.c_str(), message->header.stamp.toSec(), tf_.getCacheLength().toSec(), latest_transform_time.toSec(), message_count_);
00319
00320 last_out_the_back_stamp_ = stamp;
00321 last_out_the_back_frame_ = frame_id;
00322
00323 signalFailure(evt, filter_failure_reasons::OutTheBack);
00324 return true;
00325 }
00326 }
00327
00328 }
00329
00330 bool ready = !target_frames_.empty();
00331 for (std::vector<std::string>::iterator target_it = target_frames_.begin(); ready && target_it != target_frames_.end(); ++target_it)
00332 {
00333 std::string& target_frame = *target_it;
00334 if (time_tolerance_ != ros::Duration(0.0))
00335 {
00336 ready = ready && (tf_.canTransform(target_frame, frame_id, stamp) &&
00337 tf_.canTransform(target_frame, frame_id, stamp + time_tolerance_) );
00338 }
00339 else
00340 {
00341 ready = ready && tf_.canTransform(target_frame, frame_id, stamp);
00342 }
00343 }
00344
00345 if (ready)
00346 {
00347 TF_MESSAGEFILTER_DEBUG("Message ready in frame %s at time %.3f, count now %d", frame_id.c_str(), stamp.toSec(), message_count_);
00348
00349 ++successful_transform_count_;
00350
00351 signalMessage(evt);
00352 }
00353 else
00354 {
00355 ++failed_transform_count_;
00356 }
00357
00358 return ready;
00359 }
00360
00361 void testMessages()
00362 {
00363 if (!messages_.empty() && getTargetFramesString() == " ")
00364 {
00365 ROS_WARN_NAMED("message_notifier", "MessageFilter [target=%s]: empty target frame", getTargetFramesString().c_str());
00366 }
00367
00368 int i = 0;
00369
00370 L_Event::iterator it = messages_.begin();
00371 for (; it != messages_.end(); ++i)
00372 {
00373 MEvent& evt = *it;
00374
00375 if (testMessage(evt))
00376 {
00377 --message_count_;
00378 it = messages_.erase(it);
00379 }
00380 else
00381 {
00382 ++it;
00383 }
00384 }
00385 }
00386
00387 void maxRateTimerCallback(const ros::TimerEvent&)
00388 {
00389 boost::mutex::scoped_lock list_lock(messages_mutex_);
00390 if (new_transforms_)
00391 {
00392 testMessages();
00393 new_transforms_ = false;
00394 }
00395
00396 checkFailures();
00397 }
00398
00402 void incomingMessage(const ros::MessageEvent<M const>& evt)
00403 {
00404 add(evt);
00405 }
00406
00407 void transformsChanged()
00408 {
00409 new_transforms_ = true;
00410
00411 ++transform_message_count_;
00412 }
00413
00414 void checkFailures()
00415 {
00416 if (next_failure_warning_.isZero())
00417 {
00418 next_failure_warning_ = ros::Time::now() + ros::Duration(15);
00419 }
00420
00421 if (ros::Time::now() >= next_failure_warning_)
00422 {
00423 if (incoming_message_count_ - message_count_ == 0)
00424 {
00425 return;
00426 }
00427
00428 double dropped_pct = (double)dropped_message_count_ / (double)(incoming_message_count_ - message_count_);
00429 if (dropped_pct > 0.95)
00430 {
00431 TF_MESSAGEFILTER_WARN("Dropped %.2f%% of messages so far. Please turn the [%s.message_notifier] rosconsole logger to DEBUG for more information.", dropped_pct*100, ROSCONSOLE_DEFAULT_NAME);
00432 next_failure_warning_ = ros::Time::now() + ros::Duration(60);
00433
00434 if ((double)failed_out_the_back_count_ / (double)dropped_message_count_ > 0.5)
00435 {
00436 TF_MESSAGEFILTER_WARN(" The majority of dropped messages were due to messages growing older than the TF cache time. The last message's timestamp was: %f, and the last frame_id was: %s", last_out_the_back_stamp_.toSec(), last_out_the_back_frame_.c_str());
00437 }
00438 }
00439 }
00440 }
00441
00442 void disconnectFailure(const message_filters::Connection& c)
00443 {
00444 boost::mutex::scoped_lock lock(failure_signal_mutex_);
00445 c.getBoostConnection().disconnect();
00446 }
00447
00448 void signalFailure(const MEvent& evt, FilterFailureReason reason)
00449 {
00450 boost::mutex::scoped_lock lock(failure_signal_mutex_);
00451 failure_signal_(evt.getMessage(), reason);
00452 }
00453
00454 Transformer& tf_;
00455 ros::NodeHandle nh_;
00456 ros::Duration max_rate_;
00457 ros::Timer max_rate_timer_;
00458 std::vector<std::string> target_frames_;
00459 std::string target_frames_string_;
00460 boost::mutex target_frames_string_mutex_;
00461 uint32_t queue_size_;
00462
00463 L_Event messages_;
00464 uint32_t message_count_;
00465 boost::mutex messages_mutex_;
00466
00467 bool new_messages_;
00468 volatile bool new_transforms_;
00469
00470 bool warned_about_unresolved_name_;
00471 bool warned_about_empty_frame_id_;
00472
00473 uint64_t successful_transform_count_;
00474 uint64_t failed_transform_count_;
00475 uint64_t failed_out_the_back_count_;
00476 uint64_t transform_message_count_;
00477 uint64_t incoming_message_count_;
00478 uint64_t dropped_message_count_;
00479
00480 ros::Time last_out_the_back_stamp_;
00481 std::string last_out_the_back_frame_;
00482
00483 ros::Time next_failure_warning_;
00484
00485 ros::Duration time_tolerance_;
00486
00487 boost::signals::connection tf_connection_;
00488 message_filters::Connection message_connection_;
00489
00490 FailureSignal failure_signal_;
00491 boost::mutex failure_signal_mutex_;
00492 };
00493 }
00494
00495 #ifndef Q_MOC_RUN
00496 #include <message_filters/subscriber.h>
00497 #include <tf/message_filter.h>
00498 #endif
00499
00500 #include "rviz/display_context.h"
00501 #include "rviz/frame_manager.h"
00502 #include "rviz/properties/ros_topic_property.h"
00503
00504 namespace rviz
00505 {
00512 class MessageFilterJointStateDisplay: public _RosTopicDisplay
00513 {
00514
00515 public:
00518 typedef MessageFilterJointStateDisplay MFDClass;
00519
00520 MessageFilterJointStateDisplay()
00521 : tf_filter_( NULL )
00522 , messages_received_( 0 )
00523 {
00524 QString message_type = QString::fromStdString( ros::message_traits::datatype<sensor_msgs::JointState>() );
00525 topic_property_->setMessageType( message_type );
00526 topic_property_->setDescription( message_type + " topic to subscribe to." );
00527 }
00528
00529 virtual void onInitialize()
00530 {
00531 tf_filter_ = new tf::MessageFilterJointState( *context_->getTFClient(),
00532 fixed_frame_.toStdString(), 10, update_nh_ );
00533
00534 tf_filter_->connectInput( sub_ );
00535 tf_filter_->registerCallback( boost::bind( &MessageFilterJointStateDisplay::incomingMessage, this, _1 ));
00536 context_->getFrameManager()->registerFilterForTransformStatusCheck( tf_filter_, this );
00537 }
00538
00539 virtual ~MessageFilterJointStateDisplay()
00540 {
00541 unsubscribe();
00542 delete tf_filter_;
00543 }
00544
00545 virtual void reset()
00546 {
00547 Display::reset();
00548 tf_filter_->clear();
00549 messages_received_ = 0;
00550 }
00551
00552 protected:
00553 virtual void updateTopic()
00554 {
00555 unsubscribe();
00556 reset();
00557 subscribe();
00558 context_->queueRender();
00559 }
00560
00561 virtual void subscribe()
00562 {
00563 if( !isEnabled() )
00564 {
00565 return;
00566 }
00567
00568 try
00569 {
00570 sub_.subscribe( update_nh_, topic_property_->getTopicStd(), 10 );
00571 setStatus( StatusProperty::Ok, "Topic", "OK" );
00572 }
00573 catch( ros::Exception& e )
00574 {
00575 setStatus( StatusProperty::Error, "Topic", QString( "Error subscribing: " ) + e.what() );
00576 }
00577 }
00578
00579 virtual void unsubscribe()
00580 {
00581 sub_.unsubscribe();
00582 }
00583
00584 virtual void onEnable()
00585 {
00586 subscribe();
00587 }
00588
00589 virtual void onDisable()
00590 {
00591 unsubscribe();
00592 reset();
00593 }
00594
00595 virtual void fixedFrameChanged()
00596 {
00597 tf_filter_->setTargetFrame( fixed_frame_.toStdString() );
00598 reset();
00599 }
00600
00604 void incomingMessage( const typename sensor_msgs::JointState::ConstPtr& msg )
00605 {
00606 if( !msg )
00607 {
00608 return;
00609 }
00610
00611 ++messages_received_;
00612 setStatus( StatusProperty::Ok, "Topic", QString::number( messages_received_ ) + " messages received" );
00613
00614 processMessage( msg );
00615 }
00616
00620 virtual void processMessage( const typename sensor_msgs::JointState::ConstPtr& msg ) = 0;
00621
00622 message_filters::Subscriber<sensor_msgs::JointState> sub_;
00623 tf::MessageFilterJointState* tf_filter_;
00624 uint32_t messages_received_;
00625 };
00626 }
00627
00628 namespace rviz
00629 {
00630 class JointInfo: public QObject {
00631 Q_OBJECT
00632 public:
00633 JointInfo(const std::string name, rviz::Property* parent_category);
00634 ~JointInfo();
00635
00636 void setEffort(double e);
00637 double getEffort();
00638 void setMaxEffort(double m);
00639 double getMaxEffort();
00640 bool getEnabled() const;
00641
00642 ros::Time last_update_;
00643
00644 public Q_SLOTS:
00645 void updateVisibility();
00646
00647 private:
00648 std::string name_;
00649 double effort_, max_effort_;
00650
00651 rviz::Property* category_;
00652 rviz::FloatProperty* effort_property_;
00653 rviz::FloatProperty* max_effort_property_;
00654 };
00655
00656 typedef std::set<JointInfo*> S_JointInfo;
00657 typedef std::vector<std::string> V_string;
00658
00659 class EffortVisual;
00660
00661 class EffortDisplay: public rviz::MessageFilterJointStateDisplay
00662 {
00663 Q_OBJECT
00664 public:
00665
00666
00667 EffortDisplay();
00668 virtual ~EffortDisplay();
00669
00670
00671 virtual void onInitialize();
00672 virtual void reset();
00673
00674 private Q_SLOTS:
00675
00676 void updateColorAndAlpha();
00677 void updateHistoryLength();
00678 void updateRobotDescription();
00679
00680 JointInfo* getJointInfo( const std::string& joint);
00681 JointInfo* createJoint(const std::string &joint);
00682
00683 protected:
00684
00685 virtual void onEnable();
00686 virtual void onDisable();
00687
00688
00689 void load();
00690 void clear();
00691
00692
00693 boost::shared_ptr<urdf::Model> robot_model_;
00694
00695
00696 std::string robot_description_;
00697
00698 private:
00699 void processMessage( const sensor_msgs::JointState::ConstPtr& msg );
00700
00701
00702
00703 boost::circular_buffer<boost::shared_ptr<EffortVisual> > visuals_;
00704
00705 typedef std::map<std::string, JointInfo*> M_JointInfo;
00706 M_JointInfo joints_;
00707
00708
00709 rviz::FloatProperty *alpha_property_,* width_property_,* scale_property_;
00710 rviz::IntProperty *history_length_property_;
00711
00712 rviz::StringProperty *robot_description_property_;
00713 rviz::Property *joints_category_;
00714 rviz::BoolProperty *all_enabled_property_;
00715 };
00716 }
00717
00718 #endif // EFFORT_DISPLAY_H