00001
00023 #include <iostream>
00024 #include "nao_dcm_driver/nao.h"
00025 #include <alerror/alerror.h>
00026 #include <alcommon/albroker.h>
00027 #include <algorithm>
00028
00029 Nao::Nao(boost::shared_ptr<AL::ALBroker> broker, const string &name)
00030 : AL::ALModule(broker,name),is_connected_(false)
00031 {
00032 setModuleDescription("Nao Robot Module");
00033
00034 functionName("brokerDisconnected", getName(), "Callback when broker disconnects!");
00035 BIND_METHOD(Nao::brokerDisconnected);
00036 }
00037
00038 Nao::~Nao()
00039 {
00040 if(is_connected_)
00041 disconnect();
00042 }
00043
00044 bool Nao::initialize()
00045 {
00046
00047 const char* joint[] = {"HeadYaw",
00048 "HeadPitch",
00049 "LShoulderPitch",
00050 "LShoulderRoll",
00051 "LElbowYaw",
00052 "LElbowRoll",
00053 "LWristYaw",
00054 "LHand",
00055 "RShoulderPitch",
00056 "RShoulderRoll",
00057 "RElbowYaw",
00058 "RElbowRoll",
00059 "RWristYaw",
00060 "RHand",
00061 "LHipYawPitch",
00062 "RHipYawPitch",
00063 "LHipRoll",
00064 "LHipPitch",
00065 "LKneePitch",
00066 "LAnklePitch",
00067 "LAnkleRoll",
00068 "RHipRoll",
00069 "RHipPitch",
00070 "RKneePitch",
00071 "RAnklePitch",
00072 "RAnkleRoll"};
00073 joint_names_ = vector<string>(joint, end(joint));
00074
00075 for(vector<string>::iterator it=joint_names_.begin();it!=joint_names_.end();it++)
00076 {
00077 if((*it=="RHand" || *it=="LHand" || *it == "RWristYaw" || *it == "LWristYaw") && (body_type_ == "H21"))
00078 {
00079 joint_names_.erase(it);
00080 it--;
00081 continue;
00082 }
00083 joints_names_.push_back("Device/SubDeviceList/"+(*it)+"/Position/Sensor/Value");
00084 if(*it!="RHipYawPitch")
00085 {
00086 joint_temperature_names_.push_back("Device/SubDeviceList/"+(*it)+"/Temperature/Sensor/Value");
00087 }
00088 }
00089 number_of_joints_ = joint_names_.size();
00090
00091
00092 try
00093 {
00094
00095 commands_.arraySetSize(4);
00096 commands_[0] = string("Joints");
00097 commands_[1] = string("ClearAll");
00098 commands_[2] = string("time-mixed");
00099 commands_[3].arraySetSize(number_of_joints_);
00100
00101
00102 AL::ALValue commandAlias;
00103 commandAlias.arraySetSize(2);
00104 commandAlias[0] = string("Joints");
00105 commandAlias[1].arraySetSize(number_of_joints_);
00106 for(int i=0;i<number_of_joints_;i++)
00107 {
00108 commandAlias[1][i] = string("Device/SubDeviceList/"+joint_names_[i]+"/Position/Actuator/Value");
00109 commands_[3][i].arraySetSize(1);
00110 commands_[3][i][0].arraySetSize(2);
00111 }
00112 dcm_proxy_.createAlias(commandAlias);
00113
00114
00115 commandAlias[0] = string("JointsHardness");
00116 commandAlias[1].arraySetSize(number_of_joints_-1);
00117 int k = 0;
00118 for(int i=0;i<number_of_joints_;i++)
00119 {
00120 if(joint_names_[i] == "RHipYawPitch")
00121 {
00122 k = -1;
00123 i++;
00124 }
00125 commandAlias[1][i+k] = string("Device/SubDeviceList/"+joint_names_[i]+"/Hardness/Actuator/Value");
00126 }
00127 dcm_proxy_.createAlias(commandAlias);
00128
00129 }
00130 catch(const AL::ALError& e)
00131 {
00132 ROS_ERROR("Could not initialize dcm aliases!\n\tTrace: %s",e.what());
00133 return false;
00134 }
00135
00136
00137 vector<float> stiff = vector<float>(number_of_joints_-1,1.0f);
00138 vector<int> times = vector<int>(number_of_joints_-1,0);
00139 DCMAliasTimedCommand("JointsHardness",stiff, times);
00140 stiffnesses_enabled_ = true;
00141
00142 return true;
00143 }
00144
00145 bool Nao::initializeControllers(controller_manager::ControllerManager& cm)
00146 {
00147 if(!initialize())
00148 {
00149 ROS_ERROR("Initialization method failed!");
00150 return false;
00151 }
00152
00153
00154 joint_angles_.resize(number_of_joints_);
00155 joint_velocities_.resize(number_of_joints_);
00156 joint_efforts_.resize(number_of_joints_);
00157 joint_commands_.resize(number_of_joints_);
00158
00159 try
00160 {
00161 for(int i=0;i<number_of_joints_;i++)
00162 {
00163 hardware_interface::JointStateHandle state_handle(joint_names_[i], &joint_angles_[i],
00164 &joint_velocities_[i], &joint_efforts_[i]);
00165 jnt_state_interface_.registerHandle(state_handle);
00166
00167 hardware_interface::JointHandle pos_handle(jnt_state_interface_.getHandle(joint_names_[i]),
00168 &joint_commands_[i]);
00169 jnt_pos_interface_.registerHandle(pos_handle);
00170 }
00171
00172 registerInterface(&jnt_state_interface_);
00173 registerInterface(&jnt_pos_interface_);
00174 }
00175 catch(const ros::Exception& e)
00176 {
00177 ROS_ERROR("Could not initialize hardware interfaces!\n\tTrace: %s",e.what());
00178 return false;
00179 }
00180 ROS_INFO("Nao Module initialized!");
00181 return true;
00182 }
00183
00184 bool Nao::connect(const ros::NodeHandle nh)
00185 {
00186
00187 node_handle_ = nh;
00188
00189 is_connected_ = false;
00190
00191
00192 loadParams();
00193
00194
00195 try
00196 {
00197 subscribeToMicroEvent("ClientDisconnected", "Nao", "brokerDisconnected");
00198 }
00199 catch (const AL::ALError& e)
00200 {
00201 ROS_ERROR("Could not subscribe to brokerDisconnected!\n\tTrace: %s",e.what());
00202 }
00203
00204
00205 try
00206 {
00207 dcm_proxy_ = AL::DCMProxy(getParentBroker());
00208 }
00209 catch (const AL::ALError& e)
00210 {
00211 ROS_ERROR("Failed to connect to DCM Proxy!\n\tTrace: %s",e.what());
00212 return false;
00213 }
00214
00215
00216 try
00217 {
00218 memory_proxy_ = AL::ALMemoryProxy(getParentBroker());
00219 }
00220 catch (const AL::ALError& e)
00221 {
00222 ROS_ERROR("Failed to connect to Memory Proxy!\n\tTrace: %s",e.what());
00223 return false;
00224 }
00225
00226 is_connected_ = true;
00227
00228
00229 subscribe();
00230
00231
00232 manager_ = new controller_manager::ControllerManager(this,node_handle_);
00233 if(!initializeControllers(*manager_))
00234 {
00235 ROS_ERROR("Could not load controllers!");
00236 return false;
00237 }
00238 ROS_INFO("Controllers successfully loaded!");
00239 return true;
00240 }
00241
00242 void Nao::disconnect()
00243 {
00244 if(!is_connected_)
00245 return;
00246 try
00247 {
00248 unsubscribeFromMicroEvent("ClientDisconnected", "Nao");
00249 }
00250 catch (const AL::ALError& e)
00251 {
00252 ROS_ERROR("Failed to unsubscribe from subscribed events!\n\tTrace: %s",e.what());
00253 }
00254 is_connected_ = false;
00255 }
00256
00257 void Nao::subscribe()
00258 {
00259
00260
00261 stiffness_pub_ = node_handle_.advertise<std_msgs::Float32>(prefix_+"stiffnesses", topic_queue_);
00262 stiffness_.data = 1.0f;
00263
00264 stiffness_switch_ = node_handle_.advertiseService<Nao, nao_dcm_msgs::BoolService::Request,
00265 nao_dcm_msgs::BoolService::Response>(prefix_+"Stiffnesses/Enable", &Nao::switchStiffnesses, this);
00266 }
00267
00268 void Nao::loadParams()
00269 {
00270 ros::NodeHandle n_p("~");
00271
00272 n_p.param("Version", version_, string("V4"));
00273 n_p.param("BodyType", body_type_, string("H21"));
00274 n_p.param("TopicQueue", topic_queue_, 50);
00275
00276 n_p.param("Prefix", prefix_, string("nao_dcm"));
00277 prefix_ = prefix_+"/";
00278
00279 n_p.param("LowCommunicationFrequency", low_freq_, 10.0);
00280 n_p.param("HighCommunicationFrequency", high_freq_, 100.0);
00281 n_p.param("ControllerFrequency", controller_freq_, 15.0);
00282 n_p.param("JointPrecision", joint_precision_, 0.00174532925);
00283 n_p.param("OdomFrame", odom_frame_, string("odom"));
00284 }
00285
00286 void Nao::brokerDisconnected(const string& event_name, const string &broker_name, const string& subscriber_identifier)
00287 {
00288 if(broker_name == "Nao Driver Broker")
00289 is_connected_ = false;
00290 }
00291
00292 void Nao::DCMTimedCommand(const string &key, const AL::ALValue &value, const int &timeOffset, const string &type)
00293 {
00294 try
00295 {
00296
00297 AL::ALValue command;
00298 command.arraySetSize(3);
00299 command[0] = key;
00300 command[1] = type;
00301 command[2].arraySetSize(1);
00302 command[2][0].arraySetSize(2);
00303 command[2][0][0] = value;
00304 command[2][0][1] = dcm_proxy_.getTime(timeOffset);
00305
00306
00307 dcm_proxy_.set(command);
00308 }
00309 catch(const AL::ALError& e)
00310 {
00311 ROS_ERROR("Could not execute DCM timed-command!\n\t%s\n\n\tTrace: %s", key.c_str(), e.what());
00312 }
00313 }
00314
00315 void Nao::DCMAliasTimedCommand(const string &alias, const vector<float> &values, const vector<int> &timeOffsets,
00316 const string &type, const string &type2)
00317 {
00318 try
00319 {
00320
00321 AL::ALValue command;
00322 command.arraySetSize(4);
00323 command[0] = alias;
00324 command[1] = type;
00325 command[2] = type2;
00326 command[3].arraySetSize(values.size());
00327 int T = dcm_proxy_.getTime(0);
00328 for(int i=0;i<values.size();i++)
00329 {
00330 command[3][i].arraySetSize(1);
00331 command[3][i][0].arraySetSize(2);
00332 command[3][i][0][0] = values[i];
00333 command[3][i][0][1] = T+timeOffsets[i];
00334 }
00335
00336
00337 dcm_proxy_.setAlias(command);
00338 }
00339 catch(const AL::ALError& e)
00340 {
00341 ROS_ERROR("Could not execute DCM timed-command!\n\t%s\n\n\tTrace: %s", alias.c_str(), e.what());
00342 }
00343 }
00344
00345 void Nao::insertDataToMemory(const string &key, const AL::ALValue &value)
00346 {
00347 memory_proxy_.insertData(key,value);
00348 }
00349
00350 AL::ALValue Nao::getDataFromMemory(const string &key)
00351 {
00352 return memory_proxy_.getData(key);
00353 }
00354
00355 void Nao::subscribeToEvent(const string &name, const string &callback_module, const string &callback_method)
00356 {
00357 try
00358 {
00359 memory_proxy_.subscribeToEvent(name,callback_module,"",callback_method);
00360 }
00361 catch(const AL::ALError& e)
00362 {
00363 ROS_ERROR("Could not subscribe to event '%s'.\n\tTrace: %s",name.c_str(),e.what());
00364 }
00365 }
00366
00367 void Nao::subscribeToMicroEvent(const string &name, const string &callback_module,
00368 const string &callback_method, const string &callback_message)
00369 {
00370 try
00371 {
00372 memory_proxy_.subscribeToMicroEvent(name,callback_module,callback_message,callback_method);
00373 }
00374 catch(const AL::ALError& e)
00375 {
00376 ROS_ERROR("Could not subscribe to micro-event '%s'.\n\tTrace: %s",name.c_str(),e.what());
00377 }
00378 }
00379
00380 void Nao::unsubscribeFromEvent(const string &name, const string &callback_module)
00381 {
00382 try
00383 {
00384 memory_proxy_.unsubscribeToEvent(name,callback_module);
00385 }
00386 catch(const AL::ALError& e)
00387 {
00388 ROS_ERROR("Could not unsubscribe from event '%s'.\n\tTrace: %s",name.c_str(),e.what());
00389 }
00390 }
00391
00392 void Nao::unsubscribeFromMicroEvent(const string &name, const string &callback_module)
00393 {
00394 try
00395 {
00396 memory_proxy_.unsubscribeToMicroEvent(name,callback_module);
00397 }
00398 catch(const AL::ALError& e)
00399 {
00400 ROS_ERROR("Could not unsubscribe from micro-event '%s'.\n\tTrace: %s",name.c_str(),e.what());
00401 }
00402 }
00403
00404 void Nao::raiseEvent(const string &name, const AL::ALValue &value)
00405 {
00406 try
00407 {
00408 memory_proxy_.raiseEvent(name,value);
00409 }
00410 catch(const AL::ALError& e)
00411 {
00412 ROS_ERROR("Could not raise event '%s'.\n\tTrace: %s",name.c_str(),e.what());
00413 }
00414 }
00415
00416 void Nao::raiseMicroEvent(const string &name, const AL::ALValue &value)
00417 {
00418 try
00419 {
00420 memory_proxy_.raiseMicroEvent(name,value);
00421 }
00422 catch(const AL::ALError& e)
00423 {
00424 ROS_ERROR("Could not raise micro-event '%s'.\n\tTrace: %s",name.c_str(),e.what());
00425 }
00426 }
00427
00428 void Nao::declareEvent(const string &name)
00429 {
00430 try
00431 {
00432 memory_proxy_.declareEvent(name);
00433 }
00434 catch(AL::ALError& e)
00435 {
00436 ROS_ERROR("Could not declare event '%s'.\n\tTrace: %s",name.c_str(),e.what());
00437 }
00438 }
00439
00440 void Nao::run()
00441 {
00442
00443
00444
00445
00446
00447
00448 controllerLoop();
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500 void Nao::controllerLoop()
00501 {
00502 static ros::Rate rate(controller_freq_+10.0);
00503 while(ros::ok())
00504 {
00505 ros::Time time = ros::Time::now();
00506
00507 if(!is_connected_)
00508 break;
00509 try
00510 {
00511 dcm_proxy_.ping();
00512 }
00513 catch(const AL::ALError& e)
00514 {
00515 ROS_ERROR("Could not ping DCM proxy.\n\tTrace: %s",e.what());
00516 is_connected_ = false;
00517 }
00518
00519 publishBaseFootprint(time);
00520 if(stiffnesses_enabled_)
00521 {
00522 stiffness_.data = 1.0f;
00523 }
00524 else
00525 {
00526 stiffness_.data = 0.0f;
00527 }
00528
00529 stiffness_pub_.publish(stiffness_);
00530
00531 readJoints();
00532
00533 manager_->update(time,ros::Duration(1.0f/controller_freq_));
00534
00535 writeJoints();
00536
00537 rate.sleep();
00538 }
00539 }
00540
00541 bool Nao::connected()
00542 {
00543 return is_connected_;
00544 }
00545
00546 void Nao::commandVelocity(const geometry_msgs::TwistConstPtr &msg)
00547 {
00548 ROS_WARN("This function does nothing at the moment..");
00549 }
00550
00551
00552 void Nao::publishBaseFootprint(const ros::Time &ts)
00553 {
00554 string odom_frame, l_sole_frame, r_sole_frame, base_link_frame;
00555 try {
00556 odom_frame = base_footprint_listener_.resolve(odom_frame_);
00557 l_sole_frame = base_footprint_listener_.resolve("l_sole");
00558 r_sole_frame = base_footprint_listener_.resolve("r_sole");
00559 base_link_frame = base_footprint_listener_.resolve("base_link");
00560 }
00561 catch(ros::Exception& e)
00562 {
00563 ROS_ERROR("%s",e.what());
00564 return;
00565 }
00566
00567 tf::StampedTransform tf_odom_to_base, tf_odom_to_left_foot, tf_odom_to_right_foot;
00568 double temp_freq = 1.0f/(10.0*high_freq_);
00569 if(!base_footprint_listener_.waitForTransform(odom_frame, l_sole_frame, ros::Time(0), ros::Duration(temp_freq)))
00570 return;
00571 try {
00572 base_footprint_listener_.lookupTransform(odom_frame, l_sole_frame, ros::Time(0), tf_odom_to_left_foot);
00573 base_footprint_listener_.lookupTransform(odom_frame, r_sole_frame, ros::Time(0), tf_odom_to_right_foot);
00574 base_footprint_listener_.lookupTransform(odom_frame, base_link_frame, ros::Time(0), tf_odom_to_base);
00575 }
00576 catch (const tf::TransformException& ex){
00577 ROS_ERROR("%s",ex.what());
00578 return ;
00579 }
00580
00581 tf::Vector3 new_origin = (tf_odom_to_right_foot.getOrigin() + tf_odom_to_left_foot.getOrigin())/2.0;
00582 double height = std::min(tf_odom_to_left_foot.getOrigin().getZ(), tf_odom_to_right_foot.getOrigin().getZ());
00583 new_origin.setZ(height);
00584
00585 double roll, pitch, yaw;
00586 tf_odom_to_base.getBasis().getRPY(roll, pitch, yaw);
00587
00588 tf::Transform tf_odom_to_footprint(tf::createQuaternionFromYaw(yaw), new_origin);
00589 tf::Transform tf_base_to_footprint = tf_odom_to_base.inverse() * tf_odom_to_footprint;
00590
00591 base_footprint_broadcaster_.sendTransform(tf::StampedTransform(tf_base_to_footprint, ts,
00592 base_link_frame, "base_footprint"));
00593 }
00594
00595 void Nao::readJoints()
00596 {
00597 vector<float> jointData;
00598 try
00599 {
00600 jointData = memory_proxy_.getListData(joints_names_);
00601 }
00602 catch(const AL::ALError& e)
00603 {
00604 ROS_ERROR("Could not get joint data from Nao.\n\tTrace: %s",e.what());
00605 return;
00606 }
00607
00608 for(short i = 0; i<jointData.size(); i++)
00609 {
00610 joint_angles_[i] = jointData[i];
00611
00612 joint_commands_[i] = jointData[i];
00613 }
00614 }
00615
00616 void Nao::writeJoints()
00617 {
00618
00619 bool changed = false;
00620 for(int i=0;i<number_of_joints_;i++)
00621 {
00622 if(fabs(joint_commands_[i]-joint_angles_[i])>joint_precision_)
00623 {
00624 changed = true;
00625 break;
00626 }
00627 }
00628
00629 if(!changed)
00630 {
00631 return;
00632 }
00633
00634 try
00635 {
00636 int T = dcm_proxy_.getTime(0);
00637 for(int i=0;i<number_of_joints_;i++)
00638 {
00639 commands_[3][i][0][0] = float(joint_commands_[i]);
00640 commands_[3][i][0][1] = T+(int)(800.0f/controller_freq_);
00641 }
00642
00643 dcm_proxy_.setAlias(commands_);
00644 }
00645 catch(const AL::ALError& e)
00646 {
00647 ROS_ERROR("Could not send joint commands to Nao.\n\tTrace: %s",e.what());
00648 return;
00649 }
00650 }
00651
00652 bool Nao::switchStiffnesses(nao_dcm_msgs::BoolService::Request &req, nao_dcm_msgs::BoolService::Response &res)
00653 {
00654 if(stiffnesses_enabled_!=req.enable && req.enable)
00655 {
00656 DCMAliasTimedCommand("JointsHardness",vector<float>(number_of_joints_,1.0f), vector<int>(number_of_joints_,0));
00657 }
00658 else if(stiffnesses_enabled_!=req.enable)
00659 {
00660 DCMAliasTimedCommand("JointsHardness",vector<float>(number_of_joints_,0.0f), vector<int>(number_of_joints_,0));
00661 }
00662 stiffnesses_enabled_ = req.enable;
00663 }
00664