00001
00002
00003 #include <joint_limits_interface/joint_limits.h>
00004 #include <joint_limits_interface/joint_limits_urdf.h>
00005 #include <joint_limits_interface/joint_limits_rosparam.h>
00006
00007 #include <controller_manager/controller_manager.h>
00008 #include <controller_manager_msgs/SwitchController.h>
00009
00010 #include <canopen_motor_node/robot_layer.h>
00011
00012 #include <boost/bimap.hpp>
00013 #include <boost/bimap/multiset_of.hpp>
00014 #include <boost/foreach.hpp>
00015
00016 using namespace canopen;
00017
00018 UnitConverter::UnitConverter(const std::string &expression, get_var_func_type var_func)
00019 : var_func_(var_func)
00020 {
00021 parser_.SetVarFactory(UnitConverter::createVariable, this);
00022
00023 parser_.DefineConst("pi", M_PI);
00024 parser_.DefineConst("nan", std::numeric_limits<double>::quiet_NaN());
00025
00026 parser_.DefineFun("rad2deg", UnitConverter::rad2deg);
00027 parser_.DefineFun("deg2rad", UnitConverter::deg2rad);
00028 parser_.DefineFun("norm", UnitConverter::norm);
00029 parser_.DefineFun("smooth", UnitConverter::smooth);
00030 parser_.DefineFun("avg", UnitConverter::avg);
00031
00032 parser_.SetExpr(expression);
00033 }
00034
00035 void UnitConverter::reset(){
00036 for(variable_ptr_list::iterator it = var_list_.begin(); it != var_list_.end(); ++it){
00037 **it = std::numeric_limits<double>::quiet_NaN();
00038 }
00039 }
00040
00041 double* UnitConverter::createVariable(const char *name, void * userdata){
00042 UnitConverter * uc = static_cast<UnitConverter*>(userdata);
00043 double *p = uc->var_func_ ? uc->var_func_(name) : 0;
00044 if(!p){
00045 p = new double(std::numeric_limits<double>::quiet_NaN());
00046 uc->var_list_.push_back(variable_ptr(p));
00047 }
00048 return p;
00049 }
00050
00051
00052 template<typename T > class LimitsHandle {
00053 T limits_handle_;
00054 public:
00055 LimitsHandle(const T &handle) : limits_handle_(handle) {}
00056 virtual void enforce(const ros::Duration &period) { limits_handle_.enforceLimits(period); }
00057 virtual void reset() {}
00058 };
00059
00060 template<> void LimitsHandle<joint_limits_interface::PositionJointSaturationHandle>::reset() { limits_handle_.reset(); }
00061 template<>void LimitsHandle<joint_limits_interface::PositionJointSoftLimitsHandle>::reset() { limits_handle_.reset(); }
00062
00063 bool HandleLayer::select(const MotorBase::OperationMode &m){
00064 CommandMap::iterator it = commands_.find(m);
00065 if(it == commands_.end()) return false;
00066 jh_ = it->second;
00067 return true;
00068 }
00069
00070 HandleLayer::HandleLayer(const std::string &name, const boost::shared_ptr<MotorBase> & motor, const boost::shared_ptr<ObjectStorage> storage, XmlRpc::XmlRpcValue & options)
00071 : Layer(name + " Handle"), motor_(motor), variables_(storage), jsh_(name, &pos_, &vel_, &eff_), jph_(jsh_, &cmd_pos_), jvh_(jsh_, &cmd_vel_), jeh_(jsh_, &cmd_eff_), jh_(0), forward_command_(false),
00072 filter_pos_("double"), filter_vel_("double"), filter_eff_("double"), options_(options), enable_limits_(true)
00073 {
00074 commands_[MotorBase::No_Mode] = 0;
00075
00076 std::string p2d("rint(rad2deg(pos)*1000)"), v2d("rint(rad2deg(vel)*1000)"), e2d("rint(eff)");
00077 std::string p2r("deg2rad(obj6064)/1000"), v2r("deg2rad(obj606C)/1000"), e2r("0");
00078
00079 if(options.hasMember("pos_unit_factor") || options.hasMember("vel_unit_factor") || options.hasMember("eff_unit_factor")){
00080 const std::string reason("*_unit_factor parameters are not supported anymore, please migrate to conversion functions.");
00081 ROS_FATAL_STREAM(reason);
00082 throw std::invalid_argument(reason);
00083 }
00084
00085 if(options.hasMember("pos_to_device")) p2d = (const std::string&) options["pos_to_device"];
00086 if(options.hasMember("pos_from_device")) p2r = (const std::string&) options["pos_from_device"];
00087
00088 if(options.hasMember("vel_to_device")) v2d = (const std::string&) options["vel_to_device"];
00089 if(options.hasMember("vel_from_device")) v2r = (const std::string&) options["vel_from_device"];
00090
00091 if(options.hasMember("eff_to_device")) e2d = (const std::string&) options["eff_to_device"];
00092 if(options.hasMember("eff_from_device")) e2r = (const std::string&) options["eff_from_device"];
00093
00094 conv_target_pos_.reset(new UnitConverter(p2d, boost::bind(assignVariable, "pos", &cmd_pos_, _1)));
00095 conv_target_vel_.reset(new UnitConverter(v2d, boost::bind(assignVariable, "vel", &cmd_vel_, _1)));
00096 conv_target_eff_.reset(new UnitConverter(e2d, boost::bind(assignVariable, "eff", &cmd_eff_, _1)));
00097
00098 conv_pos_.reset(new UnitConverter(p2r, boost::bind(&ObjectVariables::getVariable, &variables_, _1)));
00099 conv_vel_.reset(new UnitConverter(v2r, boost::bind(&ObjectVariables::getVariable, &variables_, _1)));
00100 conv_eff_.reset(new UnitConverter(e2r, boost::bind(&ObjectVariables::getVariable, &variables_, _1)));
00101 }
00102
00103 HandleLayer::CanSwitchResult HandleLayer::canSwitch(const MotorBase::OperationMode &m){
00104 if(!motor_->isModeSupported(m) || commands_.find(m) == commands_.end()){
00105 return NotSupported;
00106 }else if(motor_->getMode() == m){
00107 return NoNeedToSwitch;
00108 }else if(motor_->getLayerState() == Ready){
00109 return ReadyToSwitch;
00110 }else{
00111 return NotReadyToSwitch;
00112 }
00113 }
00114
00115 bool HandleLayer::switchMode(const MotorBase::OperationMode &m){
00116 if(motor_->getMode() != m){
00117 forward_command_ = false;
00118 jh_ = 0;
00119 if(!motor_->enterModeAndWait(m)){
00120 ROS_ERROR_STREAM(jsh_.getName() << "could not enter mode " << (int)m);
00121 LayerStatus s;
00122 motor_->halt(s);
00123 return false;
00124 }
00125 }
00126 return select(m);
00127 }
00128
00129 bool HandleLayer::forwardForMode(const MotorBase::OperationMode &m){
00130 if(motor_->getMode() == m){
00131 forward_command_ = true;
00132 return true;
00133 }
00134 return false;
00135 }
00136
00137 class InterfaceMapping {
00138 typedef boost::bimap<boost::bimaps::multiset_of<std::string>, boost::bimaps::set_of<MotorBase::OperationMode> > bimap_type;
00139 bimap_type mapping_;
00140 public:
00141 InterfaceMapping(){
00142 mapping_.insert(bimap_type::value_type("hardware_interface::PositionJointInterface" ,MotorBase::Profiled_Position));
00143 mapping_.insert(bimap_type::value_type("hardware_interface::PositionJointInterface" ,MotorBase::Interpolated_Position));
00144 mapping_.insert(bimap_type::value_type("hardware_interface::PositionJointInterface" ,MotorBase::Cyclic_Synchronous_Position));
00145
00146 mapping_.insert(bimap_type::value_type("hardware_interface::VelocityJointInterface" ,MotorBase::Velocity));
00147 mapping_.insert(bimap_type::value_type("hardware_interface::VelocityJointInterface" ,MotorBase::Profiled_Velocity));
00148 mapping_.insert(bimap_type::value_type("hardware_interface::VelocityJointInterface" ,MotorBase::Cyclic_Synchronous_Velocity));
00149
00150 mapping_.insert(bimap_type::value_type("hardware_interface::EffortJointInterface" ,MotorBase::Profiled_Torque));
00151 mapping_.insert(bimap_type::value_type("hardware_interface::EffortJointInterface" ,MotorBase::Cyclic_Synchronous_Torque));
00152 }
00153 std::vector<MotorBase::OperationMode> getInterfaceModes(const std::string &interface){
00154 std::vector<MotorBase::OperationMode> modes;
00155 BOOST_FOREACH(bimap_type::left_reference i, mapping_.left.equal_range(interface)){
00156 modes.push_back(i.second);
00157 }
00158 return modes;
00159 }
00160 bool hasConflict(const std::string &interface, MotorBase::OperationMode mode){
00161 bimap_type::right_const_iterator it;
00162 if((it = mapping_.right.find(mode)) != mapping_.right.end()){
00163 return it->second != interface;
00164 }
00165 return false;
00166 }
00167
00168 } g_interface_mapping;
00169
00170
00171 template<typename T> void addLimitsHandle(std::vector<LimitsHandleBase::Ptr> &limits, const T &t) {
00172 limits.push_back(LimitsHandleBase::Ptr( (LimitsHandleBase *) new LimitsHandle<T> (t) ));
00173 }
00174
00175 hardware_interface::JointHandle* HandleLayer::registerHandle(hardware_interface::PositionJointInterface &iface,
00176 const joint_limits_interface::JointLimits &limits,
00177 const joint_limits_interface::SoftJointLimits *soft_limits){
00178 hardware_interface::JointHandle* h = addHandle(iface, &jph_, g_interface_mapping.getInterfaceModes("hardware_interface::PositionJointInterface"));
00179 if(h && limits.has_position_limits){
00180 addLimitsHandle(limits_, joint_limits_interface::PositionJointSaturationHandle(*h, limits));
00181 if(soft_limits){
00182 addLimitsHandle(limits_, joint_limits_interface::PositionJointSoftLimitsHandle(*h, limits, *soft_limits));
00183 }
00184 }
00185 return h;
00186 }
00187
00188 hardware_interface::JointHandle* HandleLayer::registerHandle(hardware_interface::VelocityJointInterface &iface,
00189 const joint_limits_interface::JointLimits&limits,
00190 const joint_limits_interface::SoftJointLimits *soft_limits){
00191 hardware_interface::JointHandle* h = addHandle(iface, &jvh_, g_interface_mapping.getInterfaceModes("hardware_interface::VelocityJointInterface"));
00192 if(h && limits.has_velocity_limits){
00193 addLimitsHandle(limits_, joint_limits_interface::VelocityJointSaturationHandle(*h, limits));
00194 if(soft_limits){
00195 addLimitsHandle(limits_, joint_limits_interface::VelocityJointSoftLimitsHandle(*h, limits, *soft_limits));
00196 }
00197 }
00198 return h;
00199 }
00200
00201 hardware_interface::JointHandle* HandleLayer::registerHandle(hardware_interface::EffortJointInterface &iface,
00202 const joint_limits_interface::JointLimits&limits,
00203 const joint_limits_interface::SoftJointLimits *soft_limits){
00204 hardware_interface::JointHandle* h = addHandle(iface, &jeh_, g_interface_mapping.getInterfaceModes("hardware_interface::EffortJointInterface"));
00205 if(h && limits.has_effort_limits){
00206 addLimitsHandle(limits_, joint_limits_interface::EffortJointSaturationHandle(*h, limits));
00207 if(soft_limits){
00208 addLimitsHandle(limits_, joint_limits_interface::EffortJointSoftLimitsHandle(*h, limits, *soft_limits));
00209 }
00210 }
00211 return h;
00212 }
00213
00214 void HandleLayer::handleRead(LayerStatus &status, const LayerState ¤t_state) {
00215 if(current_state > Shutdown){
00216 variables_.sync();
00217 filter_pos_.update(conv_pos_->evaluate(), pos_);
00218 filter_vel_.update(conv_vel_->evaluate(), vel_);
00219 filter_eff_.update(conv_eff_->evaluate(), eff_);
00220 }
00221 }
00222 void HandleLayer::handleWrite(LayerStatus &status, const LayerState ¤t_state) {
00223 if(current_state == Ready){
00224 hardware_interface::JointHandle* jh = 0;
00225 if(forward_command_) jh = jh_;
00226
00227 if(jh == &jph_){
00228 motor_->setTarget(conv_target_pos_->evaluate());
00229 cmd_vel_ = vel_;
00230 cmd_eff_ = eff_;
00231 }else if(jh == &jvh_){
00232 motor_->setTarget(conv_target_vel_->evaluate());
00233 cmd_pos_ = pos_;
00234 cmd_eff_ = eff_;
00235 }else if(jh == &jeh_){
00236 motor_->setTarget(conv_target_eff_->evaluate());
00237 cmd_pos_ = pos_;
00238 cmd_vel_ = vel_;
00239 }else{
00240 cmd_pos_ = pos_;
00241 cmd_vel_ = vel_;
00242 cmd_eff_ = eff_;
00243 if(jh) status.warn("unsupported mode active");
00244 }
00245 }
00246 }
00247
00248 bool prepareFilter(const std::string& joint_name, const std::string& filter_name, filters::FilterChain<double> &filter, XmlRpc::XmlRpcValue & options, canopen::LayerStatus &status){
00249 filter.clear();
00250 if(options.hasMember(filter_name)){
00251 if(!filter.configure(options[filter_name],joint_name + "/" + filter_name)){
00252 status.error("could not configure " + filter_name+ " for " + joint_name);
00253 return false;
00254 }
00255 }
00256
00257 return true;
00258 }
00259
00260 bool HandleLayer::prepareFilters(canopen::LayerStatus &status){
00261 return prepareFilter(jsh_.getName(), "position_filters", filter_pos_, options_, status) &&
00262 prepareFilter(jsh_.getName(), "velocity_filters", filter_vel_, options_, status) &&
00263 prepareFilter(jsh_.getName(), "effort_filters", filter_eff_, options_, status);
00264 }
00265
00266 void HandleLayer::handleInit(LayerStatus &status){
00267
00268 conv_pos_->reset();
00269 conv_vel_->reset();
00270 conv_eff_->reset();
00271 conv_target_pos_->reset();
00272 conv_target_vel_->reset();
00273 conv_target_eff_->reset();
00274
00275
00276 if(prepareFilters(status))
00277 {
00278 handleRead(status, Layer::Ready);
00279 }
00280 }
00281
00282 void HandleLayer::enforceLimits(const ros::Duration &period, bool reset){
00283 for(std::vector<LimitsHandleBase::Ptr>::iterator it = limits_.begin(); it != limits_.end(); ++it){
00284 if(reset) (*it)->reset();
00285 if(enable_limits_) (*it)->enforce(period);
00286 }
00287 }
00288
00289 void HandleLayer::enableLimits(bool enable){
00290 enable_limits_ = enable;
00291 }
00292
00293
00294 void RobotLayer::stopControllers(const std::vector<std::string> controllers){
00295 controller_manager_msgs::SwitchController srv;
00296 srv.request.stop_controllers = controllers;
00297 srv.request.strictness = srv.request.BEST_EFFORT;
00298 boost::thread call(boost::bind(ros::service::call<controller_manager_msgs::SwitchController>, "controller_manager/switch_controller", srv));
00299 call.detach();
00300 }
00301
00302 void RobotLayer::add(const std::string &name, boost::shared_ptr<HandleLayer> handle){
00303 LayerGroupNoDiag::add(handle);
00304 handles_.insert(std::make_pair(name, handle));
00305 }
00306
00307 RobotLayer::RobotLayer(ros::NodeHandle nh) : LayerGroupNoDiag<HandleLayer>("RobotLayer"), nh_(nh), first_init_(true)
00308 {
00309 registerInterface(&state_interface_);
00310 registerInterface(&pos_interface_);
00311 registerInterface(&vel_interface_);
00312 registerInterface(&eff_interface_);
00313
00314 urdf_.initParam("robot_description");
00315 }
00316
00317 void RobotLayer::handleInit(LayerStatus &status){
00318 if(first_init_){
00319 for(HandleMap::iterator it = handles_.begin(); it != handles_.end(); ++it){
00320 joint_limits_interface::JointLimits limits;
00321 joint_limits_interface::SoftJointLimits soft_limits;
00322
00323 boost::shared_ptr<const urdf::Joint> joint = getJoint(it->first);
00324
00325 if(!joint){
00326 status.error("joint " + it->first + " not found");
00327 return;
00328 }
00329
00330 bool has_joint_limits = joint_limits_interface::getJointLimits(joint, limits);
00331
00332 has_joint_limits = joint_limits_interface::getJointLimits(it->first, nh_, limits) || has_joint_limits;
00333
00334 bool has_soft_limits = has_joint_limits && joint_limits_interface::getSoftJointLimits(joint, soft_limits);
00335
00336 if(!has_joint_limits){
00337 ROS_WARN_STREAM("No limits found for " << it->first);
00338 }
00339
00340 it->second->registerHandle(state_interface_);
00341
00342 const hardware_interface::JointHandle *h = 0;
00343
00344 it->second->registerHandle(pos_interface_, limits, has_soft_limits ? &soft_limits : 0);
00345 it->second->registerHandle(vel_interface_, limits, has_soft_limits ? &soft_limits : 0);
00346 it->second->registerHandle(eff_interface_, limits, has_soft_limits ? &soft_limits : 0);
00347 }
00348 first_init_ = false;
00349 }
00350 LayerGroupNoDiag::handleInit(status);
00351 }
00352
00353 void RobotLayer::enforce(const ros::Duration &period, bool reset){
00354 for(HandleMap::iterator it = handles_.begin(); it != handles_.end(); ++it){
00355 it->second->enforceLimits(period, reset);
00356 }
00357 }
00358
00359 bool RobotLayer::prepareSwitch(const std::list<hardware_interface::ControllerInfo> &start_list, const std::list<hardware_interface::ControllerInfo> &stop_list) {
00360
00361 (void) &hardware_interface::RobotHW::prepareSwitch;
00362
00363
00364 for (std::list<hardware_interface::ControllerInfo>::const_iterator controller_it = stop_list.begin(); controller_it != stop_list.end(); ++controller_it){
00365
00366 if(switch_map_.find(controller_it->name) == switch_map_.end()){
00367 ROS_ERROR_STREAM(controller_it->name << " was not started before");
00368 return false;
00369 }
00370 }
00371
00372
00373 for (std::list<hardware_interface::ControllerInfo>::const_iterator controller_it = start_list.begin(); controller_it != start_list.end(); ++controller_it){
00374 SwitchContainer to_switch;
00375 ros::NodeHandle nh(nh_,controller_it->name);
00376 int mode;
00377 if(nh.getParam("required_drive_mode", mode)){
00378 if(g_interface_mapping.hasConflict(controller_it->hardware_interface,(MotorBase::OperationMode) mode)){
00379 ROS_ERROR_STREAM(controller_it->hardware_interface << " cannot be provided in mode " << mode);
00380 return false;
00381 }
00382 SwitchData sd;
00383 sd.enforce_limits = nh.param("enforce_limits", true);
00384 sd.mode = MotorBase::OperationMode(mode);
00385 for (std::set<std::string>::const_iterator res_it = controller_it->resources.begin(); res_it != controller_it->resources.end(); ++res_it){
00386 boost::unordered_map< std::string, boost::shared_ptr<HandleLayer> >::const_iterator h_it = handles_.find(*res_it);
00387
00388 if(h_it == handles_.end()){
00389 ROS_ERROR_STREAM(*res_it << " not found");
00390 return false;
00391 }
00392 HandleLayer::CanSwitchResult res = h_it->second->canSwitch((MotorBase::OperationMode)mode);
00393
00394 switch(res){
00395 case HandleLayer::NotSupported:
00396 ROS_ERROR_STREAM("Mode " << mode << " is not available for " << *res_it);
00397 return false;
00398 case HandleLayer::NotReadyToSwitch:
00399 ROS_ERROR_STREAM(*res_it << " is not ready to switch mode");
00400 return false;
00401 case HandleLayer::ReadyToSwitch:
00402 case HandleLayer::NoNeedToSwitch:
00403 sd.handle = h_it->second;
00404 to_switch.push_back(sd);
00405 }
00406 }
00407 }
00408 switch_map_.insert(std::make_pair(controller_it->name, to_switch));
00409 }
00410
00411
00412 boost::unordered_set<boost::shared_ptr<HandleLayer> > to_stop;
00413 std::vector<std::string> failed_controllers;
00414 for (std::list<hardware_interface::ControllerInfo>::const_iterator controller_it = stop_list.begin(); controller_it != stop_list.end(); ++controller_it){
00415 SwitchContainer &to_switch = switch_map_.at(controller_it->name);
00416 for(RobotLayer::SwitchContainer::iterator it = to_switch.begin(); it != to_switch.end(); ++it){
00417 to_stop.insert(it->handle);
00418 }
00419 }
00420 for (std::list<hardware_interface::ControllerInfo>::const_iterator controller_it = start_list.begin(); controller_it != start_list.end(); ++controller_it){
00421 SwitchContainer &to_switch = switch_map_.at(controller_it->name);
00422 bool okay = true;
00423 for(RobotLayer::SwitchContainer::iterator it = to_switch.begin(); it != to_switch.end(); ++it){
00424 it->handle->switchMode(MotorBase::No_Mode);
00425 }
00426 for(RobotLayer::SwitchContainer::iterator it = to_switch.begin(); it != to_switch.end(); ++it){
00427 if(!it->handle->switchMode(it->mode)){
00428 failed_controllers.push_back(controller_it->name);
00429 ROS_ERROR_STREAM("Could not switch one joint for " << controller_it->name << ", will stop all related joints and the controller.");
00430 for(RobotLayer::SwitchContainer::iterator stop_it = to_switch.begin(); stop_it != to_switch.end(); ++stop_it){
00431 to_stop.insert(stop_it->handle);
00432 }
00433 okay = false;
00434 break;
00435 }else{
00436 it->handle->enableLimits(it->enforce_limits);
00437 }
00438 to_stop.erase(it->handle);
00439 }
00440 }
00441 for(boost::unordered_set<boost::shared_ptr<HandleLayer> >::iterator it = to_stop.begin(); it != to_stop.end(); ++it){
00442 (*it)->switchMode(MotorBase::No_Mode);
00443 }
00444 if(!failed_controllers.empty()){
00445 stopControllers(failed_controllers);
00446
00447 }
00448
00449 return true;
00450 }
00451
00452 void RobotLayer::doSwitch(const std::list<hardware_interface::ControllerInfo> &start_list, const std::list<hardware_interface::ControllerInfo> &stop_list) {
00453 std::vector<std::string> failed_controllers;
00454 for (std::list<hardware_interface::ControllerInfo>::const_iterator controller_it = start_list.begin(); controller_it != start_list.end(); ++controller_it){
00455 try{
00456 SwitchContainer &to_switch = switch_map_.at(controller_it->name);
00457 for(RobotLayer::SwitchContainer::iterator it = to_switch.begin(); it != to_switch.end(); ++it){
00458 if(!it->handle->forwardForMode(it->mode)){
00459 failed_controllers.push_back(controller_it->name);
00460 ROS_ERROR_STREAM("Could not switch one joint for " << controller_it->name << ", will stop all related joints and the controller.");
00461 for(RobotLayer::SwitchContainer::iterator stop_it = to_switch.begin(); stop_it != to_switch.end(); ++stop_it){
00462 it->handle->switchMode(MotorBase::No_Mode);
00463 }
00464 break;
00465 }
00466 }
00467
00468 }catch(const std::out_of_range&){
00469 ROS_ERROR_STREAM("Conttroller " << controller_it->name << "not found, will stop it");
00470 failed_controllers.push_back(controller_it->name);
00471 }
00472 }
00473 if(!failed_controllers.empty()){
00474 stopControllers(failed_controllers);
00475 }
00476 }
00477
00478
00479 void ControllerManagerLayer::handleRead(canopen::LayerStatus &status, const LayerState ¤t_state) {
00480 if(current_state > Shutdown){
00481 if(!cm_) status.error("controller_manager is not intialized");
00482 }
00483 }
00484
00485 void ControllerManagerLayer::handleWrite(canopen::LayerStatus &status, const LayerState ¤t_state) {
00486 if(current_state > Shutdown){
00487 if(!cm_){
00488 status.error("controller_manager is not intialized");
00489 }else{
00490 canopen::time_point abs_now = canopen::get_abs_time();
00491 ros::Time now = ros::Time::now();
00492
00493 ros::Duration period = fixed_period_;
00494
00495 if(period.isZero()) {
00496 period.fromSec(boost::chrono::duration<double>(abs_now -last_time_).count());
00497 }
00498
00499 last_time_ = abs_now;
00500
00501 bool recover = recover_.exchange(false);
00502 cm_->update(now, period, recover);
00503 robot_->enforce(period, recover);
00504 }
00505 }
00506 }
00507
00508 void ControllerManagerLayer::handleInit(canopen::LayerStatus &status) {
00509 if(cm_){
00510 status.warn("controller_manager is already intialized");
00511 }else{
00512 recover_ = true;
00513 last_time_ = canopen::get_abs_time();
00514 cm_.reset(new controller_manager::ControllerManager(robot_.get(), nh_));
00515 }
00516 }
00517
00518 void ControllerManagerLayer::handleRecover(canopen::LayerStatus &status) {
00519 if(!cm_) status.error("controller_manager is not intialized");
00520 else recover_ = true;
00521 }
00522
00523 void ControllerManagerLayer::handleShutdown(canopen::LayerStatus &status) {
00524 cm_.reset();
00525 }