effort_display.cpp
Go to the documentation of this file.
00001 #include <OGRE/OgreSceneNode.h>
00002 #include <OGRE/OgreSceneManager.h>
00003 
00004 #include <tf/transform_listener.h>
00005 #include <tf/message_filter.h>
00006 
00007 #include <rviz/visualization_manager.h>
00008 #include <rviz/properties/property.h>
00009 #include <rviz/properties/property_manager.h>
00010 #include <rviz/frame_manager.h>
00011 
00012 #include <boost/foreach.hpp>
00013 
00014 #include "effort_visual.h"
00015 
00016 #include "effort_display.h"
00017 
00018 #include <urdf/model.h>
00019 
00020 // MessageFilter to support message with out frame_id
00021 // https://code.ros.org/trac/ros-pkg/ticket/5467
00022 namespace tf {
00023 
00024 #define TF_MESSAGEFILTER_DEBUG(fmt, ...) \
00025   ROS_DEBUG_NAMED("message_filter", "MessageFilter [target=%s]: "fmt, getTargetFramesString().c_str(), __VA_ARGS__)
00026 
00027 #define TF_MESSAGEFILTER_WARN(fmt, ...) \
00028   ROS_WARN_NAMED("message_filter", "MessageFilter [target=%s]: "fmt, getTargetFramesString().c_str(), __VA_ARGS__)
00029 
00030     class MessageFilterJointState : public MessageFilter<sensor_msgs::JointState>
00031     {
00032         typedef sensor_msgs::JointState M;
00033 public:
00034         typedef boost::shared_ptr<M const> MConstPtr;
00035         typedef ros::MessageEvent<M const> MEvent;
00036         typedef boost::function<void(const MConstPtr&, FilterFailureReason)> FailureCallback;
00037         typedef boost::signal<void(const MConstPtr&, FilterFailureReason)> FailureSignal;
00038 
00039         // If you hit this assert your message does not have a header, or does not have the HasHeader trait defined for it
00040         ROS_STATIC_ASSERT(ros::message_traits::HasHeader<M>::value);
00041 
00051         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))
00052             : MessageFilter<sensor_msgs::JointState>(tf, target_frame, queue_size, nh, max_rate)
00053             , tf_(tf)
00054             , nh_(nh)
00055             , max_rate_(max_rate)
00056             , queue_size_(queue_size)
00057             {
00058                 init();
00059 
00060                 setTargetFrame(target_frame);
00061             }
00062 
00073         template<class F>
00074         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))
00075             : tf_(tf)
00076             , nh_(nh)
00077             , max_rate_(max_rate)
00078             , queue_size_(queue_size)
00079             , MessageFilter<sensor_msgs::JointState>(f, tf, target_frame, queue_size, nh, max_rate)
00080             {
00081                 init();
00082 
00083                 setTargetFrame(target_frame);
00084 
00085                 connectInput(f);
00086             }
00087 
00091         template<class F>
00092         void connectInput(F& f)
00093             {
00094                 message_connection_.disconnect();
00095                 message_connection_ = f.registerCallback(&MessageFilterJointState::incomingMessage, this);
00096             }
00097 
00101         ~MessageFilterJointState()
00102             {
00103                 message_connection_.disconnect();
00104                 tf_.removeTransformsChangedListener(tf_connection_);
00105 
00106                 clear();
00107 
00108                 TF_MESSAGEFILTER_DEBUG("Successful Transforms: %llu, Failed Transforms: %llu, Discarded due to age: %llu, Transform messages received: %llu, Messages received: %llu, Total dropped: %llu",
00109                                        (long long unsigned int)successful_transform_count_, (long long unsigned int)failed_transform_count_, 
00110                                        (long long unsigned int)failed_out_the_back_count_, (long long unsigned int)transform_message_count_, 
00111                                        (long long unsigned int)incoming_message_count_, (long long unsigned int)dropped_message_count_);
00112 
00113             }
00114 
00118         void setTargetFrame(const std::string& target_frame)
00119             {
00120                 std::vector<std::string> frames;
00121                 frames.push_back(target_frame);
00122                 setTargetFrames(frames);
00123             }
00124 
00128         void setTargetFrames(const std::vector<std::string>& target_frames)
00129             {
00130                 boost::mutex::scoped_lock list_lock(messages_mutex_);
00131                 boost::mutex::scoped_lock string_lock(target_frames_string_mutex_);
00132 
00133                 target_frames_ = target_frames;
00134 
00135                 std::stringstream ss;
00136                 for (std::vector<std::string>::iterator it = target_frames_.begin(); it != target_frames_.end(); ++it)
00137                 {
00138                     *it = tf::resolve(tf_.getTFPrefix(), *it);
00139                     ss << *it << " ";
00140                 }
00141                 target_frames_string_ = ss.str();
00142             }
00146         std::string getTargetFramesString()
00147             {
00148                 boost::mutex::scoped_lock lock(target_frames_string_mutex_);
00149                 return target_frames_string_;
00150             };
00151 
00155         void setTolerance(const ros::Duration& tolerance)
00156             {
00157                 time_tolerance_ = tolerance;
00158             }
00159 
00163         void clear()
00164             {
00165                 boost::mutex::scoped_lock lock(messages_mutex_);
00166 
00167                 TF_MESSAGEFILTER_DEBUG("%s", "Cleared");
00168 
00169                 messages_.clear();
00170                 message_count_ = 0;
00171 
00172                 warned_about_unresolved_name_ = false;
00173                 warned_about_empty_frame_id_ = false;
00174             }
00175 
00176         void add(const MEvent& evt)
00177             {
00178                 boost::mutex::scoped_lock lock(messages_mutex_);
00179 
00180                 testMessages();
00181 
00182                 if (!testMessage(evt))
00183                 {
00184                     // If this message is about to push us past our queue size, erase the oldest message
00185                     if (queue_size_ != 0 && message_count_ + 1 > queue_size_)
00186                     {
00187                         ++dropped_message_count_;
00188                         const MEvent& front = messages_.front();
00189                         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());
00190                         signalFailure(messages_.front(), filter_failure_reasons::Unknown);
00191 
00192                         messages_.pop_front();
00193                         --message_count_;
00194                     }
00195 
00196                     // Add the message to our list
00197                     messages_.push_back(evt);
00198                     ++message_count_;
00199                 }
00200 
00201                 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_);
00202 
00203                 ++incoming_message_count_;
00204             }
00205 
00211         void add(const MConstPtr& message)
00212             {
00213                 boost::shared_ptr<std::map<std::string, std::string> > header(new std::map<std::string, std::string>);
00214                 (*header)["callerid"] = "unknown";
00215                 add(MEvent(message, header, ros::Time::now()));
00216             }
00217 
00222         message_filters::Connection registerFailureCallback(const FailureCallback& callback)
00223             {
00224                 boost::mutex::scoped_lock lock(failure_signal_mutex_);
00225                 return message_filters::Connection(boost::bind(&MessageFilterJointState::disconnectFailure, this, _1), failure_signal_.connect(callback));
00226             }
00227 
00228         virtual void setQueueSize( uint32_t new_queue_size )
00229             {
00230                 queue_size_ = new_queue_size;
00231             }
00232 
00233         virtual uint32_t getQueueSize()
00234             {
00235                 return queue_size_;
00236             }
00237 
00238     private:
00239 
00240         void init()
00241             {
00242                 message_count_ = 0;
00243                 new_transforms_ = false;
00244                 successful_transform_count_ = 0;
00245                 failed_transform_count_ = 0;
00246                 failed_out_the_back_count_ = 0;
00247                 transform_message_count_ = 0;
00248                 incoming_message_count_ = 0;
00249                 dropped_message_count_ = 0;
00250                 time_tolerance_ = ros::Duration(0.0);
00251                 warned_about_unresolved_name_ = false;
00252                 warned_about_empty_frame_id_ = false;
00253 
00254                 tf_connection_ = tf_.addTransformsChangedListener(boost::bind(&MessageFilterJointState::transformsChanged, this));
00255 
00256                 max_rate_timer_ = nh_.createTimer(max_rate_, &MessageFilterJointState::maxRateTimerCallback, this);
00257             }
00258 
00259         typedef std::list<MEvent> L_Event;
00260 
00261         bool testMessage(const MEvent& evt)
00262             {
00263                 const MConstPtr& message = evt.getMessage();
00264                 std::string callerid = evt.getPublisherName();//message->__connection_header ? (*message->__connection_header)["callerid"] : "unknown";
00265                 std::string frame_id = ros::message_traits::FrameId<M>::value(*message);
00266                 ros::Time stamp = ros::message_traits::TimeStamp<M>::value(*message);
00267 
00268                 // FIXED
00269                 if (frame_id.empty()) frame_id = * (target_frames_.begin());
00270                 //Throw out messages which have an empty frame_id
00271                 if (frame_id.empty())
00272                 {
00273                     if (!warned_about_empty_frame_id_)
00274                     {
00275                         warned_about_empty_frame_id_ = true;
00276                         TF_MESSAGEFILTER_WARN("Discarding message from [%s] due to empty frame_id.  This message will only print once.", callerid.c_str());
00277                     }
00278                     signalFailure(evt, filter_failure_reasons::EmptyFrameID);
00279                     return true;
00280                 }
00281 
00282                 if (frame_id[0] != '/')
00283                 {
00284                     std::string unresolved = frame_id;
00285                     frame_id = tf::resolve(tf_.getTFPrefix(), frame_id);
00286 
00287                     if (!warned_about_unresolved_name_)
00288                     {
00289                         warned_about_unresolved_name_ = true;
00290                         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());
00291                     }
00292                 }
00293 
00294                 //Throw out messages which are too old
00296                 for (std::vector<std::string>::iterator target_it = target_frames_.begin(); target_it != target_frames_.end(); ++target_it)
00297                 {
00298                     const std::string& target_frame = *target_it;
00299 
00300                     if (target_frame != frame_id && stamp != ros::Time(0))
00301                     {
00302                         ros::Time latest_transform_time ;
00303 
00304                         tf_.getLatestCommonTime(frame_id, target_frame, latest_transform_time, 0) ;
00305                         if (stamp + tf_.getCacheLength() < latest_transform_time)
00306                         {
00307                             ++failed_out_the_back_count_;
00308                             ++dropped_message_count_;
00309                             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_);
00310 
00311                             last_out_the_back_stamp_ = stamp;
00312                             last_out_the_back_frame_ = frame_id;
00313 
00314                             signalFailure(evt, filter_failure_reasons::OutTheBack);
00315                             return true;
00316                         }
00317                     }
00318 
00319                 }
00320 
00321                 bool ready = !target_frames_.empty();
00322                 for (std::vector<std::string>::iterator target_it = target_frames_.begin(); ready && target_it != target_frames_.end(); ++target_it)
00323                 {
00324                     std::string& target_frame = *target_it;
00325                     if (time_tolerance_ != ros::Duration(0.0))
00326                     {
00327                         ready = ready && (tf_.canTransform(target_frame, frame_id, stamp) &&
00328                                           tf_.canTransform(target_frame, frame_id, stamp + time_tolerance_) );
00329                     }
00330                     else
00331                     {
00332                         ready = ready && tf_.canTransform(target_frame, frame_id, stamp);
00333                     }
00334                 }
00335 
00336                 if (ready)
00337                 {
00338                     TF_MESSAGEFILTER_DEBUG("Message ready in frame %s at time %.3f, count now %d", frame_id.c_str(), stamp.toSec(), message_count_);
00339 
00340                     ++successful_transform_count_;
00341 
00342                     signalMessage(evt);
00343                 }
00344                 else
00345                 {
00346                     ++failed_transform_count_;
00347                 }
00348 
00349                 return ready;
00350             }
00351 
00352         void testMessages()
00353             {
00354                 if (!messages_.empty() && getTargetFramesString() == " ")
00355                 {
00356                     ROS_WARN_NAMED("message_notifier", "MessageFilter [target=%s]: empty target frame", getTargetFramesString().c_str());
00357                 }
00358 
00359                 int i = 0;
00360 
00361                 L_Event::iterator it = messages_.begin();
00362                 for (; it != messages_.end(); ++i)
00363                 {
00364                     MEvent& evt = *it;
00365 
00366                     if (testMessage(evt))
00367                     {
00368                         --message_count_;
00369                         it = messages_.erase(it);
00370                     }
00371                     else
00372                     {
00373                         ++it;
00374                     }
00375                 }
00376             }
00377 
00378         void maxRateTimerCallback(const ros::TimerEvent&)
00379             {
00380                 boost::mutex::scoped_lock list_lock(messages_mutex_);
00381                 if (new_transforms_)
00382                 {
00383                     testMessages();
00384                     new_transforms_ = false;
00385                 }
00386 
00387                 checkFailures();
00388             }
00389 
00393         void incomingMessage(const ros::MessageEvent<M const>& evt)
00394             {
00395                 add(evt);
00396             }
00397 
00398         void transformsChanged()
00399             {
00400                 new_transforms_ = true;
00401 
00402                 ++transform_message_count_;
00403             }
00404 
00405         void checkFailures()
00406             {
00407                 if (next_failure_warning_.isZero())
00408                 {
00409                     next_failure_warning_ = ros::Time::now() + ros::Duration(15);
00410                 }
00411 
00412                 if (ros::Time::now() >= next_failure_warning_)
00413                 {
00414                     if (incoming_message_count_ - message_count_ == 0)
00415                     {
00416                         return;
00417                     }
00418 
00419                     double dropped_pct = (double)dropped_message_count_ / (double)(incoming_message_count_ - message_count_);
00420                     if (dropped_pct > 0.95)
00421                     {
00422                         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);
00423                         next_failure_warning_ = ros::Time::now() + ros::Duration(60);
00424 
00425                         if ((double)failed_out_the_back_count_ / (double)dropped_message_count_ > 0.5)
00426                         {
00427                             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());
00428                         }
00429                     }
00430                 }
00431             }
00432 
00433         void disconnectFailure(const message_filters::Connection& c)
00434             {
00435                 boost::mutex::scoped_lock lock(failure_signal_mutex_);
00436                 c.getBoostConnection().disconnect();
00437             }
00438 
00439         void signalFailure(const MEvent& evt, FilterFailureReason reason)
00440             {
00441                 boost::mutex::scoped_lock lock(failure_signal_mutex_);
00442                 failure_signal_(evt.getMessage(), reason);
00443             }
00444 
00445         Transformer& tf_; 
00446         ros::NodeHandle nh_; 
00447         ros::Duration max_rate_;
00448         ros::Timer max_rate_timer_;
00449         std::vector<std::string> target_frames_; 
00450         std::string target_frames_string_;
00451         boost::mutex target_frames_string_mutex_;
00452         uint32_t queue_size_; 
00453 
00454         L_Event messages_; 
00455         uint32_t message_count_; 
00456         boost::mutex messages_mutex_; 
00457 
00458         bool new_messages_; 
00459         volatile bool new_transforms_; 
00460 
00461         bool warned_about_unresolved_name_;
00462         bool warned_about_empty_frame_id_;
00463 
00464         uint64_t successful_transform_count_;
00465         uint64_t failed_transform_count_;
00466         uint64_t failed_out_the_back_count_;
00467         uint64_t transform_message_count_;
00468         uint64_t incoming_message_count_;
00469         uint64_t dropped_message_count_;
00470 
00471         ros::Time last_out_the_back_stamp_;
00472         std::string last_out_the_back_frame_;
00473 
00474         ros::Time next_failure_warning_;
00475 
00476         ros::Duration time_tolerance_; 
00477 
00478         boost::signals::connection tf_connection_;
00479         message_filters::Connection message_connection_;
00480 
00481         FailureSignal failure_signal_;
00482         boost::mutex failure_signal_mutex_;
00483     };
00484 }
00485 
00486 namespace jsk_rviz_plugin
00487 {
00488 
00489     struct JointInfo {
00490         JointInfo();
00491 
00492         bool isEnabled() { return enabled_; }
00493         void setEffort(double e) { effort_ = e; }
00494         double getEffort() { return effort_; }
00495         void setMaxEffort(double m) { max_effort_ = m; }
00496         double getMaxEffort() { return max_effort_; }
00497 
00498         std::string name_;
00499         bool enabled_;
00500         double effort_, max_effort_;
00501 
00502         ros::Time last_update_;
00503 
00504         rviz::CategoryPropertyWPtr category_;
00505         rviz::BoolPropertyWPtr enabled_property_;
00506         rviz::FloatPropertyWPtr effort_property_;
00507         rviz::FloatPropertyWPtr max_effort_property_;
00508     };
00509 
00510     JointInfo::JointInfo()
00511         : enabled_(true)
00512     {
00513     }
00514 
00515     JointInfo* EffortDisplay::getJointInfo( const std::string& joint)
00516     {
00517         M_JointInfo::iterator it = joints_.find( joint );
00518         if ( it == joints_.end() )
00519             {
00520                 return NULL;
00521             }
00522 
00523         return it->second;
00524     }
00525 
00526     void EffortDisplay::setJointEnabled(JointInfo* joint, bool enabled)
00527     {
00528         joint->enabled_ = enabled;
00529         propertyChanged(joint->enabled_property_);
00530     }
00531 
00532     JointInfo* EffortDisplay::createJoint(const std::string &joint)
00533     {
00534         JointInfo *info = new JointInfo;
00535         joints_.insert( std::make_pair( joint, info ) );
00536 
00537         info->name_ = joint;
00538         info->enabled_ = true;
00539         info->effort_ = 0;
00540         info->max_effort_ = 0;
00541         info->last_update_ = ros::Time::now();
00542 
00543         std::string prefix = "Joints.";
00544         info->category_ = property_manager_->createCategory( info->name_, "", joints_category_, this);
00545 
00546         prefix += info->name_ + ".";
00547 
00548         info->enabled_property_ = property_manager_->createProperty<rviz::BoolProperty>( "Enabled", prefix, boost::bind( &JointInfo::isEnabled, info), boost::bind(&EffortDisplay::setJointEnabled, this, info, _1), info->category_, this);
00549         setPropertyHelpText(info->enabled_property_, "Enable or disable this individual joint.");
00550 
00551         info->effort_property_ = property_manager_->createProperty<rviz::FloatProperty>( "Effort", prefix, boost::bind( &JointInfo::getEffort, info), boost::bind( &JointInfo::setEffort, info, _1), info->category_, this);
00552         setPropertyHelpText(info->effort_property_, "Effort value of this joint.");
00553 
00554         info->max_effort_property_ = property_manager_->createProperty<rviz::FloatProperty>( "Max Effort", prefix, boost::bind( &JointInfo::getMaxEffort, info), boost::bind( &JointInfo::setMaxEffort, info, _1), info->category_, this);
00555         setPropertyHelpText(info->max_effort_property_, "Max Effort value of this joint.");
00556         updateJoint(info);
00557 
00558         return info;
00559     }
00560 
00561     void EffortDisplay::updateJoint(JointInfo* joint)
00562     {
00563     }
00564 
00565     void EffortDisplay::deleteJoint(JointInfo* joint, bool delete_properties)
00566     {
00567     }
00568 
00569     EffortDisplay::EffortDisplay()
00570         : Display()
00571         , scene_node_( NULL )
00572         , messages_received_( 0 )
00573         , alpha_( 1.0 )              // Default alpha is completely opaque.
00574         , width_( 0.02 )              // Default width
00575         , scale_( 1.0 )              // Default scale
00576         , all_enabled_( true )
00577     {
00578     }
00579 
00580     void EffortDisplay::onInitialize()
00581     {
00582         // Make an Ogre::SceneNode to contain all our visuals.
00583         scene_node_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
00584 
00585         // Set the default history length and resize the ``visuals_`` array.
00586         setHistoryLength( 1 );
00587 
00588         // A tf::MessageFilter listens to ROS messages and calls our
00589         // callback with them when they can be matched up with valid tf
00590         // transform data.
00591         tf_filter_ =
00592             //new tf::MessageFilter<sensor_msgs::JointState>( *vis_manager_->getTFClient(),
00593             new tf::MessageFilterJointState( *vis_manager_->getTFClient(),
00594                                              "", 100, update_nh_, ros::Duration(0.1) );
00595         tf_filter_->connectInput( sub_ );
00596         tf_filter_->registerCallback( boost::bind( &EffortDisplay::incomingMessage,
00597                                                    this, _1 ));
00598 
00599         // FrameManager has some built-in functions to set the status of a
00600         // Display based on callbacks from a tf::MessageFilter.  These work
00601         // fine for this simple display.
00602         vis_manager_->getFrameManager()
00603             ->registerFilterForTransformStatusCheck( tf_filter_, this );
00604 
00605     }
00606 
00607     EffortDisplay::~EffortDisplay()
00608     {
00609         unsubscribe();
00610         clear();
00611         visuals_.clear();
00612 
00613         delete tf_filter_;
00614     }
00615 
00616     // Clear the visuals by deleting their objects.
00617     void EffortDisplay::clear()
00618     {
00619         for( size_t i = 0; i < visuals_.size(); i++ ) {
00620             delete visuals_[ i ];
00621             visuals_[ i ] = NULL;
00622         }
00623         tf_filter_->clear();
00624         messages_received_ = 0;
00625         setStatus( rviz::status_levels::Warn, "Topic", "No messages received" );
00626     }
00627 
00628     void EffortDisplay::setTopic( const std::string& topic )
00629     {
00630         unsubscribe();
00631         clear();
00632         topic_ = topic;
00633         subscribe();
00634 
00635         // Broadcast the fact that the variable has changed.
00636         propertyChanged( topic_property_ );
00637 
00638         // Make sure rviz renders the next time it gets a chance.
00639         causeRender();
00640     }
00641 
00642     void EffortDisplay::setAlpha( float alpha )
00643     {
00644         alpha_ = alpha;
00645 
00646         propertyChanged( alpha_property_ );
00647         updateColorAndAlpha();
00648         causeRender();
00649     }
00650 
00651     void EffortDisplay::setWidth( float width )
00652     {
00653         width_ = width;
00654 
00655         propertyChanged( width_property_ );
00656         updateColorAndAlpha();
00657         causeRender();
00658     }
00659 
00660     void EffortDisplay::setScale( float scale )
00661     {
00662         scale_ = scale;
00663 
00664         propertyChanged( scale_property_ );
00665         updateColorAndAlpha();
00666         causeRender();
00667     }
00668 
00669     // Set the current color and alpha values for each visual.
00670     void EffortDisplay::updateColorAndAlpha()
00671     {
00672         BOOST_FOREACH(MapEffortVisual::value_type visual, visuals_)
00673         {
00674             if ( visual ) {
00675                 visual->setWidth( width_ );
00676                 visual->setScale( scale_ );
00677             }
00678         }
00679     }
00680 
00681     // Set the number of past visuals to show.
00682     void EffortDisplay::setHistoryLength( int length )
00683     {
00684         // Don't let people enter invalid values.
00685         if( length < 1 )
00686         {
00687             length = 1;
00688         }
00689         // If the length is not changing, we don't need to do anything.
00690         if( history_length_ == length )
00691         {
00692             return;
00693         }
00694 
00695         // Set the actual variable.
00696         history_length_ = length;
00697         propertyChanged( history_length_property_ );
00698 
00699         // Create a new array of visual pointers, all NULL.
00700         std::vector<EffortVisual*> new_visuals( history_length_, (EffortVisual*)0 );
00701 
00702         // Copy the contents from the old array to the new.
00703         // (Number to copy is the minimum of the 2 vector lengths).
00704         size_t copy_len =
00705             (new_visuals.size() > visuals_.size()) ?
00706             visuals_.size() : new_visuals.size();
00707         for( size_t i = 0; i < copy_len; i++ )
00708         {
00709             int new_index = (messages_received_ - i) % new_visuals.size();
00710             int old_index = (messages_received_ - i) % visuals_.size();
00711             new_visuals[ new_index ] = visuals_[ old_index ];
00712             visuals_[ old_index ] = NULL;
00713         }
00714 
00715         // Delete any remaining old visuals
00716         for( size_t i = 0; i < visuals_.size(); i++ ) {
00717             delete visuals_[ i ];
00718         }
00719 
00720         // We don't need to create any new visuals here, they are created as
00721         // needed when messages are received.
00722 
00723         // Put the new vector into the member variable version and let the
00724         // old one go out of scope.
00725         visuals_.swap( new_visuals );
00726     }
00727 
00728     void EffortDisplay::load()
00729     {
00730         // get robot_description
00731         std::string urdf_string;
00732         update_nh_.getParam(description_param_, urdf_string);
00733         urdfModel = boost::shared_ptr<urdf::Model>(new urdf::Model());
00734         if (!urdfModel->initString(urdf_string))
00735         {
00736             ROS_ERROR("Unable to parse URDF description!");
00737             setStatus(rviz::status_levels::Error, "URDF", "Unable to parse robot model description!");
00738             return;
00739         }
00740         setStatus(rviz::status_levels::Ok, "URDF", "Ok");
00741 
00742         for (std::map<std::string, boost::shared_ptr<urdf::Joint> >::iterator it = urdfModel->joints_.begin(); it != urdfModel->joints_.end(); it ++ ) {
00743             boost::shared_ptr<urdf::Joint> joint = it->second;
00744             if ( joint->type == urdf::Joint::REVOLUTE ) {
00745                 std::string joint_name = it->first;
00746                 boost::shared_ptr<urdf::JointLimits> limit = joint->limits;
00747                 joints_[joint_name] = createJoint(joint_name);
00748                 joints_[joint_name]->setMaxEffort(limit->effort);
00749             }
00750         }
00751     }
00752 
00753     void EffortDisplay::setRobotDescription( const std::string& description_param )
00754     {
00755         description_param_ = description_param;
00756 
00757         propertyChanged(robot_description_property_);
00758 
00759         if ( isEnabled() )
00760             {
00761                 load();
00762                 unsubscribe();
00763                 subscribe();
00764                 causeRender();
00765             }
00766     }
00767 
00768     void EffortDisplay::setAllEnabled(bool enabled)
00769     {
00770         all_enabled_ = enabled;
00771 
00772         M_JointInfo::iterator it = joints_.begin();
00773         M_JointInfo::iterator end = joints_.end();
00774         for (; it != end; ++it)
00775             {
00776                 JointInfo* joint = it->second;
00777 
00778                 setJointEnabled(joint, enabled);
00779             }
00780 
00781         propertyChanged(all_enabled_property_);
00782     }
00783 
00784 
00785     void EffortDisplay::subscribe()
00786     {
00787         // If we are not actually enabled, don't do it.
00788         if ( !isEnabled() )
00789         {
00790             return;
00791         }
00792 
00793         // if urdf model is not loaded, return
00794         if ( ! urdfModel ) {
00795             setStatus( rviz::status_levels::Warn, "URDF", "Valid robot model is not loaded" );
00796             return;
00797         }
00798 
00799         // Try to subscribe to the current topic name (in ``topic_``).  Make
00800         // sure to catch exceptions and set the status to a descriptive
00801         // error message.
00802         try
00803         {
00804             sub_.subscribe( update_nh_, topic_, 10 );
00805             setStatus( rviz::status_levels::Ok, "Topic", "OK" );
00806         }
00807         catch( ros::Exception& e )
00808         {
00809             setStatus( rviz::status_levels::Error, "Topic",
00810                        std::string( "Error subscribing: " ) + e.what() );
00811         }
00812     }
00813 
00814     void EffortDisplay::unsubscribe()
00815     {
00816         sub_.unsubscribe();
00817     }
00818 
00819     void EffortDisplay::onEnable()
00820     {
00821         subscribe();
00822     }
00823 
00824     void EffortDisplay::onDisable()
00825     {
00826         unsubscribe();
00827         clear();
00828     }
00829 
00830     // When the "Fixed Frame" changes, we need to update our
00831     // tf::MessageFilter and erase existing visuals.
00832     void EffortDisplay::fixedFrameChanged()
00833     {
00834         tf_filter_->setTargetFrame( fixed_frame_ );
00835         clear();
00836     }
00837 
00838     // This is our callback to handle an incoming message.
00839     void EffortDisplay::incomingMessage( const sensor_msgs::JointState::ConstPtr& msg )
00840     {
00841         ++messages_received_;
00842 
00843         // Each display can have multiple status lines.  This one is called
00844         // "Topic" and says how many messages have been received in this case.
00845         std::stringstream ss;
00846         ss << messages_received_ << " messages received";
00847         setStatus( rviz::status_levels::Ok, "Topic", ss.str() );
00848 
00849         // We are keeping a circular buffer of visual pointers.  This gets
00850         // the next one, or creates and stores it if it was missing.
00851         EffortVisual* visual = visuals_[ messages_received_ % history_length_ ];
00852         if( visual == NULL )
00853           {
00854             visual = new EffortVisual( vis_manager_->getSceneManager(), scene_node_ , urdfModel );
00855             visuals_[ messages_received_ % history_length_ ] = visual;
00856           }
00857 
00858         V_string joints;
00859         int joint_num = msg->name.size();
00860         for (int i = 0; i < joint_num; i++ )
00861         {
00862             std::string joint_name = msg->name[i];
00863             JointInfo* joint_info = getJointInfo(joint_name);
00864             if ( !joint_info ) continue; // skip joints..
00865 
00866             // set effort
00867             joint_info->setEffort(msg->effort[i]);
00868 
00869             // update effort property
00870             if ( ros::Time::now() - joint_info->last_update_ > ros::Duration(0.2) ) {
00871                 propertyChanged(joint_info->effort_property_);
00872                 joint_info->last_update_ = ros::Time::now();
00873             }
00874 
00875             const urdf::Joint* joint = urdfModel->getJoint(joint_name).get();
00876             int joint_type = joint->type;
00877             if ( joint_type == urdf::Joint::REVOLUTE )
00878             {
00879                 // we expects that parent_link_name equals to frame_id.
00880                 std::string parent_link_name = joint->child_link_name;
00881                 Ogre::Quaternion orientation;
00882                 Ogre::Vector3 position;
00883 
00884                 // Here we call the rviz::FrameManager to get the transform from the
00885                 // fixed frame to the frame in the header of this Effort message.  If
00886                 // it fails, we can't do anything else so we return.
00887                 if( !vis_manager_->getFrameManager()->getTransform( parent_link_name,
00888                                                                     ros::Time(),
00889                                                                     //msg->header.stamp, // ???
00890                                                                     position, orientation ))
00891                 {
00892                     ROS_DEBUG( "Error transforming from frame '%s' to frame '%s'",
00893                                parent_link_name.c_str(), fixed_frame_.c_str() );
00894                     continue;
00895                 }
00896 ;
00897                 tf::Vector3 axis_joint(joint->axis.x, joint->axis.y, joint->axis.z);
00898                 tf::Vector3 axis_z(0,0,1);
00899                 tf::Quaternion axis_rotation(tf::tfCross(axis_joint, axis_z), tf::tfAngle(axis_joint, axis_z));
00900                 if ( std::isnan(axis_rotation.x()) ||
00901                      std::isnan(axis_rotation.y()) ||
00902                      std::isnan(axis_rotation.z()) ) axis_rotation = tf::Quaternion::getIdentity();
00903 
00904                 tf::Quaternion axis_orientation(orientation.x, orientation.y, orientation.z, orientation.w);
00905                 tf::Quaternion axis_rot = axis_orientation * axis_rotation;
00906                 Ogre::Quaternion joint_orientation(Ogre::Real(axis_rot.w()), Ogre::Real(axis_rot.x()), Ogre::Real(axis_rot.y()), Ogre::Real(axis_rot.z()));
00907                 visual->setFramePosition( joint_name, position );
00908                 visual->setFrameOrientation( joint_name, joint_orientation );
00909                 visual->setFrameEnabled( joint_name, joint_info->isEnabled() );
00910             }
00911         }
00912 
00913 
00914         // Now set or update the contents of the chosen visual.
00915         visual->setWidth( width_ );
00916         visual->setScale( scale_ );
00917         visual->setMessage( msg );
00918     }
00919 
00920     // Override rviz::Display's reset() function to add a call to clear().
00921     void EffortDisplay::reset()
00922     {
00923         Display::reset();
00924         clear();
00925     }
00926 
00927     void EffortDisplay::createProperties()
00928     {
00929         topic_property_ =
00930             property_manager_->createProperty<rviz::ROSTopicStringProperty>( "Topic",
00931                                                                              property_prefix_,
00932                                                                              boost::bind( &EffortDisplay::getTopic, this ),
00933                                                                              boost::bind( &EffortDisplay::setTopic, this, _1 ),
00934                                                                              parent_category_,
00935                                                                              this );
00936         setPropertyHelpText( topic_property_, "sensor_msgs::Effort topic to subscribe to." );
00937         rviz::ROSTopicStringPropertyPtr topic_prop = topic_property_.lock();
00938         topic_prop->setMessageType( ros::message_traits::datatype<sensor_msgs::JointState>() );
00939 
00940         alpha_property_ =
00941             property_manager_->createProperty<rviz::FloatProperty>( "Alpha",
00942                                                                     property_prefix_,
00943                                                                     boost::bind( &EffortDisplay::getAlpha, this ),
00944                                                                     boost::bind( &EffortDisplay::setAlpha, this, _1 ),
00945                                                                     parent_category_,
00946                                                                     this );
00947         setPropertyHelpText( alpha_property_, "0 is fully transparent, 1.0 is fully opaque." );
00948 
00949         width_property_ =
00950             property_manager_->createProperty<rviz::FloatProperty>( "Width",
00951                                                                     property_prefix_,
00952                                                                     boost::bind( &EffortDisplay::getWidth, this ),
00953                                                                     boost::bind( &EffortDisplay::setWidth, this, _1 ),
00954                                                                     parent_category_,
00955                                                                     this );
00956         setPropertyHelpText( width_property_, "Width to drow effort circle" );
00957 
00958         scale_property_ =
00959             property_manager_->createProperty<rviz::FloatProperty>( "Scale",
00960                                                                     property_prefix_,
00961                                                                     boost::bind( &EffortDisplay::getScale, this ),
00962                                                                     boost::bind( &EffortDisplay::setScale, this, _1 ),
00963                                                                     parent_category_,
00964                                                                     this );
00965         setPropertyHelpText( scale_property_, "Scale to drow effort circle" );
00966 
00967         history_length_property_ =
00968             property_manager_->createProperty<rviz::IntProperty>( "History Length",
00969                                                                   property_prefix_,
00970                                                                   boost::bind( &EffortDisplay::getHistoryLength, this ),
00971                                                                   boost::bind( &EffortDisplay::setHistoryLength, this, _1 ),
00972                                                                   parent_category_,
00973                                                             this );
00974         setPropertyHelpText( history_length_property_, "Number of prior measurements to display." );
00975 
00976         robot_description_property_ = property_manager_->createProperty<rviz::StringProperty>( "Robot Description", property_prefix_, boost::bind( &EffortDisplay::getRobotDescription, this ), boost::bind( &EffortDisplay::setRobotDescription, this, _1 ), parent_category_, this );
00977         rviz::setPropertyHelpText(robot_description_property_, "Name of the parameter to search for to load the robot description.");
00978 
00979 
00980         joints_category_ =
00981             property_manager_->createCategory( "Joints",
00982                                                property_prefix_,
00983                                                parent_category_,
00984                                                this );
00985         setPropertyHelpText( joints_category_, "The list of all joints." );
00986         rviz::CategoryPropertyPtr cat_prop = joints_category_.lock();
00987         cat_prop->collapse();
00988         all_enabled_property_ = property_manager_->createProperty<rviz::BoolProperty>( "All Enabled", property_prefix_, boost::bind( &EffortDisplay::getAllEnabled, this ),
00989                                                                                        boost::bind( &EffortDisplay::setAllEnabled, this, _1 ), joints_category_, this );
00990         setPropertyHelpText(all_enabled_property_, "Whether all the joints should be enabled or not.");
00991 
00992     }
00993 } // end namespace jsk_rviz_plugin
00994 
00995 // Tell pluginlib about this class.  It is important to do this in
00996 // global scope, outside our package's namespace.
00997 #include <pluginlib/class_list_macros.h>
00998 PLUGINLIB_DECLARE_CLASS( jsk_rviz_plugin, Effort, jsk_rviz_plugin::EffortDisplay, rviz::Display )
00999 
01000 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


jsk_rviz_plugins
Author(s): Kei Okada
autogenerated on Sat Mar 23 2013 20:30:29