SoftErrorLimiter.cpp
Go to the documentation of this file.
00001 // -*- C++ -*-
00010 #include "SoftErrorLimiter.h"
00011 #include "hrpsys/util/VectorConvert.h"
00012 #include "hrpsys/idl/RobotHardwareService.hh"
00013 #include <rtm/CorbaNaming.h>
00014 #include <hrpModel/ModelLoaderUtil.h>
00015 
00016 #include <math.h>
00017 #include <vector>
00018 #include <limits>
00019 #include <iomanip>
00020 #define deg2rad(x)((x)*M_PI/180)
00021 
00022 // Module specification
00023 // <rtc-template block="module_spec">
00024 static const char* softerrorlimiter_spec[] =
00025   {
00026     "implementation_id", "SoftErrorLimiter",
00027     "type_name",         "SoftErrorLimiter",
00028     "description",       "soft error limiter",
00029     "version",           HRPSYS_PACKAGE_VERSION,
00030     "vendor",            "AIST",
00031     "category",          "example",
00032     "activity_type",     "DataFlowComponent",
00033     "max_instance",      "10",
00034     "language",          "C++",
00035     "lang_type",         "compile",
00036     // Configuration variables
00037     "conf.default.debugLevel", "0",
00038     ""
00039   };
00040 // </rtc-template>
00041 
00042 static std::ostream& operator<<(std::ostream& os, const struct RTC::Time &tm)
00043 {
00044     int pre = os.precision();
00045     os.setf(std::ios::fixed);
00046     os << std::setprecision(6)
00047        << (tm.sec + tm.nsec/1e9)
00048        << std::setprecision(pre);
00049     os.unsetf(std::ios::fixed);
00050     return os;
00051 }
00052 
00053 SoftErrorLimiter::SoftErrorLimiter(RTC::Manager* manager)
00054   : RTC::DataFlowComponentBase(manager),
00055     // <rtc-template block="initializer">
00056     m_qRefIn("qRef", m_qRef),
00057     m_qCurrentIn("qCurrent", m_qCurrent),
00058     m_servoStateIn("servoStateIn", m_servoState),
00059     m_qOut("q", m_qRef),
00060     m_servoStateOut("servoStateOut", m_servoState),
00061     m_beepCommandOut("beepCommand", m_beepCommand),
00062     m_SoftErrorLimiterServicePort("SoftErrorLimiterService"),
00063     // </rtc-template>
00064     m_debugLevel(0),
00065     dummy(0),
00066     is_beep_port_connected(false)
00067 {
00068   init_beep();
00069   start_beep(3136);
00070 }
00071 
00072 SoftErrorLimiter::~SoftErrorLimiter()
00073 {
00074   quit_beep();
00075 }
00076 
00077 
00078 
00079 RTC::ReturnCode_t SoftErrorLimiter::onInitialize()
00080 {
00081   std::cerr << "[" << m_profile.instance_name << "] onInitialize()" << std::endl;
00082   // <rtc-template block="bind_config">
00083   // Bind variables and configuration variable
00084   bindParameter("debugLevel", m_debugLevel, "0");
00085   
00086   // </rtc-template>
00087 
00088   // Registration: InPort/OutPort/Service
00089   // <rtc-template block="registration">
00090   // Set InPort buffers
00091   addInPort("qRef", m_qRefIn);
00092   addInPort("qCurrent", m_qCurrentIn);
00093   addInPort("servoState", m_servoStateIn);
00094   
00095   // Set OutPort buffer
00096   addOutPort("q", m_qOut);
00097   addOutPort("servoState", m_servoStateOut);
00098   addOutPort("beepCommand", m_beepCommandOut);
00099   
00100   // Set service provider to Ports
00101   m_SoftErrorLimiterServicePort.registerProvider("service0", "SoftErrorLimiterService", m_service0);
00102   
00103   // Set service consumers to Ports
00104   
00105   // Set CORBA Service Ports
00106   addPort(m_SoftErrorLimiterServicePort);
00107   
00108   // </rtc-template>
00109 
00110   m_robot = boost::shared_ptr<robot>(new robot());
00111   RTC::Properties& prop = getProperties();
00112 
00113   RTC::Manager& rtcManager = RTC::Manager::instance();
00114   std::string nameServer = rtcManager.getConfig()["corba.nameservers"];
00115   int comPos = nameServer.find(",");
00116   if (comPos < 0){
00117       comPos = nameServer.length();
00118   }
00119   nameServer = nameServer.substr(0, comPos);
00120   RTC::CorbaNaming naming(rtcManager.getORB(), nameServer.c_str());
00121   if (!loadBodyFromModelLoader(m_robot, prop["model"].c_str(), 
00122                                CosNaming::NamingContext::_duplicate(naming.getRootContext())
00123           )){
00124       std::cerr << "[" << m_profile.instance_name << "] failed to load model[" << prop["model"] << "] in "
00125                 << m_profile.instance_name << std::endl;
00126       return RTC::RTC_ERROR;
00127   }
00128 
00129   std::cout << "[" << m_profile.instance_name << "] dof = " << m_robot->numJoints() << std::endl;
00130   if (!m_robot->init()) return RTC::RTC_ERROR;
00131   m_service0.setRobot(m_robot);
00132   m_servoState.data.length(m_robot->numJoints());
00133   for(unsigned int i = 0; i < m_robot->numJoints(); i++) {
00134     m_servoState.data[i].length(1);
00135     int status = 0;
00136     status |= 1<< OpenHRP::RobotHardwareService::CALIB_STATE_SHIFT;
00137     status |= 1<< OpenHRP::RobotHardwareService::POWER_STATE_SHIFT;
00138     status |= 1<< OpenHRP::RobotHardwareService::SERVO_STATE_SHIFT;
00139     status |= 0<< OpenHRP::RobotHardwareService::SERVO_ALARM_SHIFT;
00140     status |= 0<< OpenHRP::RobotHardwareService::DRIVER_TEMP_SHIFT;
00141     m_servoState.data[i][0] = status;
00142   }
00143 
00144   /* Calculate count for beep sound frequency */
00145   coil::stringTo(dt, prop["dt"].c_str());
00146   soft_limit_error_beep_freq = static_cast<int>(1.0/(4.0*dt)); // soft limit error => 4 times / 1[s]
00147   position_limit_error_beep_freq = static_cast<int>(1.0/(2.0*dt)); // position limit error => 2 times / 1[s]
00148   debug_print_freq = static_cast<int>(0.2/dt); // once per 0.2 [s]
00149   /* If you print debug message for all controller loop, please comment in here */
00150   // debug_print_freq = 1;
00151   m_beepCommand.data.length(bc.get_num_beep_info());
00152 
00153   // load joint limit table
00154   hrp::readJointLimitTableFromProperties (joint_limit_tables, m_robot, prop["joint_limit_table"], std::string(m_profile.instance_name));
00155 
00156   return RTC::RTC_OK;
00157 }
00158 
00159 /*
00160 RTC::ReturnCode_t SoftErrorLimiter::onFinalize()
00161 {
00162   return RTC::RTC_OK;
00163 }
00164 */
00165 
00166 /*
00167 RTC::ReturnCode_t SoftErrorLimiter::onStartup(RTC::UniqueId ec_id)
00168 {
00169   return RTC::RTC_OK;
00170 }
00171 */
00172 
00173 /*
00174 RTC::ReturnCode_t SoftErrorLimiter::onShutdown(RTC::UniqueId ec_id)
00175 {
00176   return RTC::RTC_OK;
00177 }
00178 */
00179 
00180 RTC::ReturnCode_t SoftErrorLimiter::onActivated(RTC::UniqueId ec_id)
00181 {
00182   std::cerr << "[" << m_profile.instance_name<< "] onActivated(" << ec_id << ")" << std::endl;
00183   return RTC::RTC_OK;
00184 }
00185 
00186 RTC::ReturnCode_t SoftErrorLimiter::onDeactivated(RTC::UniqueId ec_id)
00187 {
00188   std::cerr << "[" << m_profile.instance_name<< "] onDeactivated(" << ec_id << ")" << std::endl;
00189   return RTC::RTC_OK;
00190 }
00191 
00192 RTC::ReturnCode_t SoftErrorLimiter::onExecute(RTC::UniqueId ec_id)
00193 {
00194   //std::cout << m_profile.instance_name<< ": onExecute(" << ec_id << ")" << std::endl;
00195   static int loop = 0;
00196   static bool debug_print_velocity_first = false;
00197   static bool debug_print_position_first = false;
00198   static bool debug_print_error_first = false;
00199   loop ++;
00200 
00201   // Connection check of m_beepCommand to BeeperRTC
00202   //   If m_beepCommand is not connected to BeeperRTC and sometimes, check connection.
00203   //   If once connection is found, never check connection.
00204   if (!is_beep_port_connected && (loop % 500 == 0) ) {
00205     if ( m_beepCommandOut.connectors().size() > 0 ) {
00206       is_beep_port_connected = true;
00207       quit_beep();
00208       std::cerr << "[" << m_profile.instance_name<< "] beepCommand data port connection found! Use BeeperRTC." << std::endl;
00209     }
00210   }
00211 
00212   if (m_qRefIn.isNew()) {
00213     m_qRefIn.read();
00214   }
00215   if (m_qCurrentIn.isNew()) {
00216     m_qCurrentIn.read();
00217   }
00218   if (m_servoStateIn.isNew()) {
00219     m_servoStateIn.read();
00220   }
00221 
00222   /*
00223     0x001 : 'SS_OVER_VOLTAGE',
00224     0x002 : 'SS_OVER_LOAD',
00225     0x004 : 'SS_OVER_VELOCITY',
00226     0x008 : 'SS_OVER_CURRENT',
00227     0x010 : 'SS_OVER_HEAT',
00228     0x020 : 'SS_TORQUE_LIMIT',
00229     0x040 : 'SS_VELOCITY_LIMIT',
00230     0x080 : 'SS_FORWARD_LIMIT',
00231     0x100 : 'SS_REVERSE_LIMIT',
00232     0x200 : 'SS_POSITION_ERROR',
00233     0x300 : 'SS_ENCODER_ERROR',
00234     0x800 : 'SS_OTHER'
00235   */
00236   bool soft_limit_error = false;
00237   bool velocity_limit_error = false;
00238   bool position_limit_error = false;
00239   if ( m_qRef.data.length() == m_qCurrent.data.length() &&
00240        m_qRef.data.length() == m_servoState.data.length() ) {
00241     // prev_angle is previous output
00242     static std::vector<double> prev_angle;
00243     if ( prev_angle.size() != m_qRef.data.length() ) { // initialize prev_angle
00244       prev_angle.resize(m_qRef.data.length(), 0);
00245       for ( unsigned int i = 0; i < m_qRef.data.length(); i++ ){
00246         prev_angle[i] = m_qCurrent.data[i];
00247       }
00248     }
00249     std::vector<int> servo_state;
00250     servo_state.resize(m_qRef.data.length(), 0);
00251     for ( unsigned int i = 0; i < m_qRef.data.length(); i++ ){
00252         servo_state[i] = (m_servoState.data[i][0] & OpenHRP::RobotHardwareService::SERVO_STATE_MASK) >> OpenHRP::RobotHardwareService::SERVO_STATE_SHIFT; // enum SwitchStatus {SWITCH_ON, SWITCH_OFF};
00253     }
00254 
00255       /*
00256         From hrpModel/Body.h
00257         inline Link* joint(int id) const
00258            This function returns a link that has a given joint ID.
00259            If there is no link that has a given joint ID,
00260            the function returns a dummy link object whose ID is minus one.
00261            The maximum id can be obtained by numJoints().
00262 
00263          inline Link* link(int index) const
00264            This function returns the link of a given index in the whole link sequence.
00265            The order of the sequence corresponds to a link-tree traverse from the root link.
00266            The size of the sequence can be obtained by numLinks().
00267 
00268          So use m_robot->joint(i) for llimit/ulimit, lvlimit/ulimit
00269        */
00270 
00271     // Velocity limitation for reference joint angles
00272     for ( unsigned int i = 0; i < m_qRef.data.length(); i++ ){
00273       // Determin total upper-lower limit considering velocity, position, and error limits.
00274       // e.g.,
00275       //  total lower limit = max (vel, pos, err) <= severest lower limit
00276       //  total upper limit = min (vel, pos, err) <= severest upper limit
00277       double total_upper_limit = std::numeric_limits<double>::max(), total_lower_limit = -std::numeric_limits<double>::max();
00278       {
00279       double qvel = (m_qRef.data[i] - prev_angle[i]) / dt;
00280       double lvlimit = m_robot->joint(i)->lvlimit + 0.000175; // 0.01 deg / sec
00281       double uvlimit = m_robot->joint(i)->uvlimit - 0.000175;
00282       // fixed joint has ulimit = vlimit
00283       if ( servo_state[i] == 1 && (lvlimit < uvlimit) && ((lvlimit > qvel) || (uvlimit < qvel)) ) {
00284         if (loop % debug_print_freq == 0 || debug_print_velocity_first ) {
00285           std::cerr << "[" << m_profile.instance_name<< "] [" << m_qRef.tm
00286                     << "] velocity limit over " << m_robot->joint(i)->name << "(" << i << "), qvel=" << qvel
00287                     << ", lvlimit =" << lvlimit
00288                     << ", uvlimit =" << uvlimit
00289                     << ", servo_state = " <<  ( servo_state[i] ? "ON" : "OFF") << std::endl;
00290         }
00291         // fix joint angle
00292         if ( lvlimit > qvel ) {
00293             total_lower_limit = std::max(prev_angle[i] + lvlimit * dt, total_lower_limit);
00294         }
00295         if ( uvlimit < qvel ) {
00296             total_upper_limit = std::min(prev_angle[i] + uvlimit * dt, total_upper_limit);
00297         }
00298         velocity_limit_error = true;
00299       }
00300       }
00301 
00302       // Position limitation for reference joint angles
00303       {
00304       double llimit = m_robot->joint(i)->llimit;
00305       double ulimit = m_robot->joint(i)->ulimit;
00306       if (joint_limit_tables.find(m_robot->joint(i)->name) != joint_limit_tables.end()) {
00307           std::map<std::string, hrp::JointLimitTable>::iterator it = joint_limit_tables.find(m_robot->joint(i)->name);
00308           llimit = it->second.getLlimit(m_qRef.data[it->second.getTargetJointId()]);
00309           ulimit = it->second.getUlimit(m_qRef.data[it->second.getTargetJointId()]);
00310       }
00311       // fixed joint have vlimit = ulimit
00312       bool servo_limit_state = (llimit < ulimit) && ((llimit > m_qRef.data[i]) || (ulimit < m_qRef.data[i]));
00313       if ( servo_state[i] == 1 && servo_limit_state ) {
00314         if (loop % debug_print_freq == 0 || debug_print_position_first) {
00315           std::cerr << "[" << m_profile.instance_name<< "] [" << m_qRef.tm
00316                     << "] position limit over " << m_robot->joint(i)->name << "(" << i << "), qRef=" << m_qRef.data[i]
00317                     << ", llimit =" << llimit
00318                     << ", ulimit =" << ulimit
00319                     << ", servo_state = " <<  ( servo_state[i] ? "ON" : "OFF")
00320                     << ", prev_angle = " << prev_angle[i] << std::endl;
00321         }
00322         // fix joint angle
00323         if ( llimit > m_qRef.data[i] && prev_angle[i] > m_qRef.data[i] ) { // ref < llimit and prev < ref -> OK
00324             total_lower_limit = std::max(llimit, total_lower_limit);
00325         }
00326         if ( ulimit < m_qRef.data[i] && prev_angle[i] < m_qRef.data[i] ) { // ulimit < ref and ref < prev -> OK
00327             total_upper_limit = std::min(ulimit, total_upper_limit);
00328         }
00329         m_servoState.data[i][0] |= (0x200 << OpenHRP::RobotHardwareService::SERVO_ALARM_SHIFT);
00330         position_limit_error = true;
00331       }
00332       }
00333 
00334       // Servo error limitation between reference joint angles and actual joint angles
00335       //   pos_vel_limited_angle is current output joint angle which arleady finished position limit and velocity limit.
00336       //   Check and limit error between pos_vel_limited_angle and current actual joint angle.
00337       {
00338       double pos_vel_limited_angle = std::min(total_upper_limit, std::max(total_lower_limit, m_qRef.data[i]));
00339       double limit = m_robot->m_servoErrorLimit[i];
00340       double error = pos_vel_limited_angle - m_qCurrent.data[i];
00341       if ( servo_state[i] == 1 && fabs(error) > limit ) {
00342         if (loop % debug_print_freq == 0 || debug_print_error_first ) {
00343           std::cerr << "[" << m_profile.instance_name<< "] [" << m_qRef.tm
00344                     << "] error limit over " << m_robot->joint(i)->name << "(" << i << "), qRef=" << pos_vel_limited_angle
00345                     << ", qCurrent=" << m_qCurrent.data[i] << " "
00346                     << ", Error=" << error << " > " << limit << " (limit)"
00347                     << ", servo_state = " <<  ( 1 ? "ON" : "OFF");
00348         }
00349         if ( error > limit ) {
00350             total_upper_limit = std::min(m_qCurrent.data[i] + limit, total_upper_limit);
00351         } else {
00352             total_lower_limit = std::max(m_qCurrent.data[i] - limit, total_lower_limit);
00353         }
00354         if (loop % debug_print_freq == 0 || debug_print_error_first ) {
00355           std::cerr << ", q=" << m_qRef.data[i] << std::endl;
00356         }
00357         m_servoState.data[i][0] |= (0x040 << OpenHRP::RobotHardwareService::SERVO_ALARM_SHIFT);
00358         soft_limit_error = true;
00359       }
00360       }
00361 
00362       // Limitation of current output considering total upper and lower limits
00363       prev_angle[i] = m_qRef.data[i] = std::min(total_upper_limit, std::max(total_lower_limit, m_qRef.data[i]));
00364     }
00365     // display error info if no error found
00366     debug_print_velocity_first = !velocity_limit_error;
00367     debug_print_position_first = !position_limit_error;
00368     debug_print_error_first = !soft_limit_error;
00369 
00370     // Beep sound
00371     if ( soft_limit_error ) { // play beep
00372       if (is_beep_port_connected) {
00373         if ( loop % soft_limit_error_beep_freq == 0 ) bc.startBeep(3136, soft_limit_error_beep_freq*0.8);
00374         else bc.stopBeep();
00375       } else {
00376         if ( loop % soft_limit_error_beep_freq == 0 ) start_beep(3136, soft_limit_error_beep_freq*0.8);
00377       }
00378     }else if ( position_limit_error || velocity_limit_error ) { // play beep
00379       if (is_beep_port_connected) {
00380         if ( loop % position_limit_error_beep_freq == 0 ) bc.startBeep(3520, position_limit_error_beep_freq*0.8);
00381         else bc.stopBeep();
00382       } else {
00383         if ( loop % position_limit_error_beep_freq == 0 ) start_beep(3520, position_limit_error_beep_freq*0.8);
00384       }
00385     } else {
00386       if (is_beep_port_connected) {
00387         bc.stopBeep();
00388       } else {
00389         stop_beep();
00390       }
00391     }
00392     m_qOut.write();
00393     m_servoStateOut.write();
00394   } else {
00395     if (is_beep_port_connected) {
00396       bc.startBeep(3136);
00397     } else {
00398       start_beep(3136);
00399     }
00400     if ( loop % 100 == 1 ) {
00401         std::cerr << "SoftErrorLimiter is not working..." << std::endl;
00402         std::cerr << "         m_qRef " << m_qRef.data.length() << std::endl;
00403         std::cerr << "     m_qCurrent " << m_qCurrent.data.length() << std::endl;
00404         std::cerr << "   m_servoState " << m_servoState.data.length() << std::endl;
00405     }
00406   }
00407   if (is_beep_port_connected) {
00408     bc.setDataPort(m_beepCommand);
00409     if (bc.isWritable()) m_beepCommandOut.write();
00410   }
00411 
00412   return RTC::RTC_OK;
00413 }
00414 
00415 /*
00416 RTC::ReturnCode_t SoftErrorLimiter::onAborting(RTC::UniqueId ec_id)
00417 {
00418   return RTC::RTC_OK;
00419 }
00420 */
00421 
00422 /*
00423 RTC::ReturnCode_t SoftErrorLimiter::onError(RTC::UniqueId ec_id)
00424 {
00425   return RTC::RTC_OK;
00426 }
00427 */
00428 
00429 /*
00430 RTC::ReturnCode_t SoftErrorLimiter::onReset(RTC::UniqueId ec_id)
00431 {
00432   return RTC::RTC_OK;
00433 }
00434 */
00435 
00436 /*
00437 RTC::ReturnCode_t SoftErrorLimiter::onStateUpdate(RTC::UniqueId ec_id)
00438 {
00439   return RTC::RTC_OK;
00440 }
00441 */
00442 
00443 /*
00444 RTC::ReturnCode_t SoftErrorLimiter::onRateChanged(RTC::UniqueId ec_id)
00445 {
00446   return RTC::RTC_OK;
00447 }
00448 */
00449 
00450 
00451 
00452 extern "C"
00453 {
00454 
00455   void SoftErrorLimiterInit(RTC::Manager* manager)
00456   {
00457     RTC::Properties profile(softerrorlimiter_spec);
00458     manager->registerFactory(profile,
00459                              RTC::Create<SoftErrorLimiter>,
00460                              RTC::Delete<SoftErrorLimiter>);
00461   }
00462 
00463 };
00464 
00465 


hrpsys
Author(s): AIST, Fumio Kanehiro
autogenerated on Wed Sep 6 2017 02:35:56