transmission_check.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 
00036 #include "pr2_transmission_check/transmission_check.h"
00037 #include <limits>
00038 #include "angles/angles.h"
00039 
00040 #include <boost/accumulators/statistics/max.hpp>
00041 #include <boost/accumulators/statistics/min.hpp>
00042 
00043 using namespace pr2_transmission_check;
00044 using namespace std;
00045 
00046 /*** TODO
00047  * Set deadband properly for each joint
00048  * Figure out max/min
00049  * Track state with accumulators
00050  * Only halt motors if we've had >3 consecutive hits, etc
00051  * Add tests for warnings
00052  * Publish status topic (bool) at 1 Hz
00053  * 
00054  *****/
00055 
00056 #define GRACE_HITS 5
00057 
00058 // Transmission Listener
00059 TransmissionListener::TransmissionListener() :
00060   joint_name_(""),
00061   actuator_name_(""),
00062   deadband_(0.1),
00063   has_wrap_(false),
00064   has_up_(false),
00065   has_down_(false),
00066   status_(true),
00067   last_trans_status_(true),
00068   error_cnt_(0),
00069   num_errors_(0),
00070   num_hits_(0),
00071   num_errors_since_reset_(0),
00072   rx_cnt_(0),
00073   last_rising_(0.0),
00074   last_falling_(0.0),
00075   last_bad_reading_(0.0),
00076   last_position_(0.0),
00077   is_calibrated_(false),
00078   has_updated_(false)
00079 { }
00080 
00081 bool TransmissionListener::initUrdf(const boost::shared_ptr<urdf::Joint> jnt, const string &actuator_name)
00082 {
00083   joint_name_ = jnt->name;
00084   actuator_name_ = actuator_name;
00085   
00086   if (!jnt->calibration)
00087   {
00088     ROS_DEBUG("Joint \"%s\" does not support calibration.", joint_name_.c_str());
00089     return false;
00090   }
00091 
00092   has_up_ = (bool) jnt->calibration->rising;
00093   has_down_ = (bool) jnt->calibration->falling;
00094 
00095   if (has_up_)
00096     up_ref_ = *(jnt->calibration->rising);
00097 
00098   if (has_down_)
00099     down_ref_ = *(jnt->calibration->falling);
00100   
00101   if (jnt->type == urdf::Joint::CONTINUOUS)
00102   {
00103     has_wrap_ = true;
00104 
00105     if (has_up_ && !has_down_)
00106       down_ref_ = up_ref_ + M_PI;
00107     if (!has_up_ && has_down_)
00108       up_ref_ = down_ref_ + M_PI;
00109 
00110     up_ref_ = angles::normalize_angle(up_ref_);
00111     down_ref_ = angles::normalize_angle(down_ref_);
00112 
00113     has_up_ = true;
00114     has_down_ = true;
00115   }
00116 
00117   return true;
00118 }
00119 
00120 // Look for joint, actuator
00121 // Check bounds
00122 bool TransmissionListener::update(const pr2_mechanism_msgs::MechanismStatistics::ConstPtr& mechMsg)
00123 {
00124   const pr2_mechanism_msgs::JointStatistics *js = NULL;
00125   const pr2_mechanism_msgs::ActuatorStatistics *as = NULL;
00126 
00127   for (uint i = 0; i < mechMsg->joint_statistics.size(); ++i)
00128   {
00129     if (mechMsg->joint_statistics[i].name == joint_name_)
00130       js = &mechMsg->joint_statistics[i];
00131   }
00132 
00133   if (!js)
00134   {
00135     ROS_ERROR_ONCE("Unable to find joint state for joint \"%s\".", joint_name_.c_str());
00136     return false;
00137   }
00138 
00139   if (!js->is_calibrated)
00140     return true; // Ignore until we're calibrated
00141 
00142   // Same for actuators
00143   for (uint i = 0; i < mechMsg->actuator_statistics.size(); ++i)
00144   {
00145     if (mechMsg->actuator_statistics[i].name == actuator_name_)
00146       as = &mechMsg->actuator_statistics[i];
00147   }
00148 
00149   if (!as)
00150   {
00151     ROS_ERROR_ONCE("Unable to find actuator state for actuator \"%s\".", actuator_name_.c_str());
00152     return false;
00153   }
00154 
00155   rx_cnt_++;
00156   last_rising_ = as->last_calibration_rising_edge;
00157   last_falling_ = as->last_calibration_falling_edge;
00158   last_cal_reading_ = as->calibration_reading;
00159   last_position_ = js->position;
00160   is_calibrated_ = js->is_calibrated;
00161   position_obs_(last_position_);
00162 
00163   /* Don't check bounds because we have no max/min
00164   if (!checkBounds(js))
00165   {
00166     last_trans_status_ = false;
00167     status_ = false;
00168     return false;
00169   }
00170   */
00171 
00172   bool rv = checkFlag(js, as);
00173 
00174   last_trans_status_ = rv;
00175   if (!rv)
00176   {
00177     num_hits_++;
00178     last_bad_reading_ = last_position_;
00179     error_cnt_++;
00180   }
00181   else
00182     error_cnt_ = 0;
00183   
00184   if (error_cnt_ > GRACE_HITS)
00185   {
00186     num_errors_++;
00187     num_errors_since_reset_++;
00188     status_ = false;
00189   }
00190 
00191   has_updated_ = true;
00192   return true;
00193 }
00194 
00195 bool TransmissionListener::checkBounds(const pr2_mechanism_msgs::JointStatistics *js) const
00196 {
00197   ROS_ASSERT_MSG(js->name == joint_name_, "Joint name didn't match!");
00198 
00199   // We should only see calibrated joints
00200   if (!js->is_calibrated)
00201   {
00202     ROS_ERROR_ONCE("Joint \"%s\" isn't calibrated. Unable to check bounds for joint.", joint_name_.c_str());
00203     return false; 
00204   }
00205 
00206   return js->position < max_ && js->position > min_;
00207 }
00208 
00209 bool TransmissionListener::checkFlag(const pr2_mechanism_msgs::JointStatistics *js,
00210                                      const pr2_mechanism_msgs::ActuatorStatistics *as) const
00211 {
00212   ROS_ASSERT_MSG(js->name == joint_name_, "Joint name didn't match!");
00213   ROS_ASSERT_MSG(as->name == actuator_name_, "Actuator name didn't match!");
00214 
00215   float jnt_position = js->position;
00216 
00217   if (!has_up_ && !has_down_)
00218   {
00219     ROS_ERROR("Neither up or down reference specified for joint \"%s\". Unable to check transmission.",
00220               joint_name_.c_str());
00221     return false;
00222   }
00223 
00224   // Check if we need to wrap position
00225   if (has_wrap_)
00226     jnt_position = angles::normalize_angle(jnt_position);
00227 
00228   // Check deadband for up reference
00229   if (has_up_)
00230   {
00231     if (abs(jnt_position - up_ref_) < deadband_)
00232       return true; // Too close to deadband
00233   }
00234   if (has_down_)
00235   {
00236     if (abs(jnt_position - down_ref_) < deadband_)
00237       return true; // Too close to deadband
00238   }
00239 
00240   // Check that we're OK on other side of normalized angle
00241   if (has_up_ && has_down_ && has_wrap_)
00242   {
00243     if (abs((  2 * M_PI - jnt_position) - up_ref_)   < deadband_)
00244       return true;
00245     if (abs((- 2 * M_PI + jnt_position) - up_ref_)   < deadband_)
00246       return true;
00247     if (abs((  2 * M_PI - jnt_position) - down_ref_) < deadband_)
00248       return true;
00249     if (abs((- 2 * M_PI + jnt_position) - down_ref_) < deadband_)
00250       return true;
00251   }
00252   
00253   if (has_up_ && has_down_)
00254   {
00255     if (up_ref_ > down_ref_)
00256     {
00257       if (jnt_position < down_ref_ && as->calibration_reading)
00258         return true;
00259       else if (jnt_position > down_ref_ && jnt_position < up_ref_ && !as->calibration_reading)
00260         return true;
00261       else if (jnt_position > up_ref_ && as->calibration_reading)
00262         return true;
00263       else 
00264       {
00265         ROS_WARN_THROTTLE(1, "Broken transmission reading for \"%s\". Position: %f (wrapped), cal reading: %d. Up ref: %f, Down ref: %f", joint_name_.c_str(), jnt_position, as->calibration_reading, up_ref_, down_ref_);
00266         return false;
00267       }
00268     }
00269     else // down_ref_ > up_ref_
00270     {
00271       if (jnt_position < up_ref_ && !as->calibration_reading)
00272         return true;
00273       else if (jnt_position > up_ref_ && jnt_position < down_ref_ && as->calibration_reading)
00274         return true;
00275       else if (jnt_position > down_ref_ && !as->calibration_reading)
00276         return true;
00277       else 
00278       {
00279         ROS_WARN_THROTTLE(1, "Broken transmission reading for \"%s\". Position: %f (wrapped), cal reading: %d. Up ref: %f, Down ref: %f", joint_name_.c_str(), jnt_position, as->calibration_reading, up_ref_, down_ref_);
00280         return false;
00281       }
00282     }
00283   }
00284   else if (has_up_)
00285   {
00286     if (jnt_position > up_ref_ && as->calibration_reading)
00287       return true;
00288     else if (jnt_position < up_ref_ && !as->calibration_reading)
00289       return true;
00290     else
00291     {
00292       ROS_WARN_THROTTLE(1, "Broken transmission reading for \"%s\". Position: %f (wrapped), cal reading: %d. Up ref: %f, Down ref: %f", joint_name_.c_str(), jnt_position, as->calibration_reading, up_ref_, down_ref_);
00293         return false;
00294     }
00295   }
00296 
00297   else // has_down_
00298   {
00299     if (jnt_position > down_ref_ && !as->calibration_reading)
00300       return true;
00301     else if (jnt_position < down_ref_ && as->calibration_reading)
00302       return true;
00303     else
00304     {
00305       ROS_WARN_THROTTLE(1, "Broken transmission reading for \"%s\". Position: %f (wrapped), cal reading: %d. Up ref: %f, Down ref: %f", joint_name_.c_str(), jnt_position, as->calibration_reading, up_ref_, down_ref_);
00306         return false;
00307     }
00308   }
00309     
00310   ROS_ASSERT_MSG(false, "No case handled for transmission checker!");
00311   return false;
00312 }
00313 
00314 boost::shared_ptr<diagnostic_updater::DiagnosticStatusWrapper> TransmissionListener::toDiagStat() const
00315 {
00316   boost::shared_ptr<diagnostic_updater::DiagnosticStatusWrapper> stat(new diagnostic_updater::DiagnosticStatusWrapper);
00317   
00318   stat->name = "Transmission (" + joint_name_ + ")";
00319       
00320   if (!has_updated_)
00321     stat->mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "No Updates");
00322 
00323   if (!status_)
00324     stat->mergeSummary(diagnostic_msgs::DiagnosticStatus::ERROR, "Broken Transmission");
00325 
00326   stat->add("Transmission Status", status_ ? "OK" : "Broken");
00327   stat->add("Current Reading", last_trans_status_ ? "OK" : "Broken");
00328   
00329   stat->add("Joint", joint_name_);
00330   stat->add("Actuator", actuator_name_);
00331   if (has_up_)
00332     stat->add("Up Position", up_ref_);
00333   else
00334     stat->add("Up Position", "N/A");
00335 
00336   if (has_down_)
00337     stat->add("Down Position", down_ref_);
00338   else
00339     stat->add("Down Position", "N/A");
00340 
00341   stat->add("Wrapped", has_wrap_ ? "True" : "False");
00342   //stat->add("Max Limit", max_);
00343   //stat->add("Min Limit", min_);
00344  
00345   // Todo: Start tracking state....
00346   stat->add("Mech State RX Count", rx_cnt_);
00347   stat->add("Is Calibrated", is_calibrated_ ? "True" : "False");
00348   stat->add("Calibration Reading", last_cal_reading_);
00349   stat->add("Joint Position", last_position_);
00350   stat->add("Total Errors", num_errors_);
00351   stat->add("Errors Since Reset", num_errors_since_reset_);
00352   stat->add("Total Bad Readings", num_hits_);
00353   float max_obs_val = boost::accumulators::max( position_obs_ );
00354   float min_obs_val = boost::accumulators::min( position_obs_ );
00355   stat->add("Max Obs. Position", max_obs_val );
00356   stat->add("Min Obs. Position", min_obs_val );
00357   
00358   stat->add("Last Rising Edge", last_rising_);
00359   stat->add("Last Falling Edge", last_falling_);
00360   stat->add("Last Bad Reading", last_bad_reading_);
00361   
00362 
00363   return stat;
00364 }
00365 


pr2_transmission_check
Author(s): Kevin Watts
autogenerated on Sat Dec 28 2013 17:53:50