effort_display.h
Go to the documentation of this file.
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 // MessageFilter to support message with out frame_id
00030 // https://code.ros.org/trac/ros-pkg/ticket/5467
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         // If you hit this assert your message does not have a header, or does not have the HasHeader trait defined for it
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                     // If this message is about to push us past our queue size, erase the oldest message
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                     // Add the message to our list
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();//message->__connection_header ? (*message->__connection_header)["callerid"] : "unknown";
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                 // FIXED
00278                 if (frame_id.empty()) frame_id = * (target_frames_.begin());
00279                 //Throw out messages which have an empty frame_id
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                 //Throw out messages which are too old
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 // No Q_OBJECT macro here, moc does not support Q_OBJECT in a templated class.
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 } // rviz
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         // Constructor.  pluginlib::ClassLoader creates instances by calling
00666         // the default constructor, so make sure you have one.
00667         EffortDisplay();
00668         virtual ~EffortDisplay();
00669 
00670         // Overrides of public virtual functions from the Display class.
00671         virtual void onInitialize();
00672         virtual void reset();
00673 
00674     private Q_SLOTS:
00675         // Helper function to apply color and alpha to all visuals.
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         // overrides from Display
00685         virtual void onEnable();
00686         virtual void onDisable();
00687 
00688         // load
00689         void load();
00690         void clear();
00691 
00692         // The object for urdf model
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         // Storage for the list of visuals.  It is a circular buffer where
00702         // data gets popped from the front (oldest) and pushed to the back (newest)
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         // Property objects for user-editable properties.
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 } // end namespace rviz_plugin_tutorials
00717 
00718 #endif // EFFORT_DISPLAY_H


rviz
Author(s): Dave Hershberger, David Gossow, Josh Faust
autogenerated on Mon Oct 6 2014 07:26:35