robot.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2016 SoftBank Robotics Europe
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  *
00016 */
00017 
00018 #include <sensor_msgs/JointState.h>
00019 
00020 #include <diagnostic_msgs/DiagnosticArray.h>
00021 
00022 #include <XmlRpcValue.h>
00023 
00024 #include "naoqi_dcm_driver/robot.hpp"
00025 #include "naoqi_dcm_driver/tools.hpp"
00026 
00027 QI_REGISTER_OBJECT( Robot,
00028                     isConnected,
00029                     connect,
00030                     stopService);
00031 
00032 Robot::Robot(qi::SessionPtr session):
00033                _session(session),
00034                session_name_("naoqi_dcm_driver"),
00035                is_connected_(false),
00036                nhPtr_(new ros::NodeHandle("")),
00037                body_type_(""),
00038                topic_queue_(10),
00039                prefix_("naoqi_dcm"),
00040                high_freq_(50.0),
00041                controller_freq_(15.0),
00042                joint_precision_(0.1),
00043                odom_frame_("odom"),
00044                use_dcm_(false),
00045                stiffness_value_(0.9f)
00046 {
00047 }
00048 
00049 Robot::~Robot()
00050 {
00051   stopService();
00052 }
00053 
00054 void Robot::stopService() {
00055   ROS_INFO_STREAM(session_name_ << " stopping the service...");
00056 
00057   if (motion_)
00058   {
00059     /* reset stiffness for arms if using DCM
00060      * to prevent its concurrence with ALMotion */
00061     if(use_dcm_)
00062       motion_->setStiffnessArms(0.0f, 2.0f);
00063 
00064     //going to rest
00065     if (motor_groups_.size() == 1)
00066       if (motor_groups_[0] == "Body")
00067         motion_->rest();
00068 
00069     //set stiffness for the whole body
00070     //setStiffness(0.0f);
00071     motion_->setStiffnessArms(0.0f, 2.0f);
00072   }
00073 
00074   is_connected_ = false;
00075 
00076   if(nhPtr_)
00077   {
00078     nhPtr_->shutdown();
00079     ros::shutdown();
00080   }
00081 }
00082 
00083 bool Robot::initializeControllers(const std::vector <std::string> &joints)
00084 {
00085   int joints_nbr = joints.size();
00086 
00087   // Initialize Controllers' Interfaces
00088   hw_angles_.reserve(joints_nbr);
00089   hw_velocities_.reserve(joints_nbr);
00090   hw_efforts_.reserve(joints_nbr);
00091   hw_commands_.reserve(joints_nbr);
00092 
00093   hw_angles_.resize(joints_nbr);
00094   hw_velocities_.resize(joints_nbr);
00095   hw_efforts_.resize(joints_nbr);
00096   hw_commands_.resize(joints_nbr);
00097 
00098   try
00099   {
00100     for(int i=0; i<joints_nbr; ++i)
00101     {
00102       hardware_interface::JointStateHandle state_handle(joints.at(i),
00103                                                         &hw_angles_[i],
00104                                                         &hw_velocities_[i],
00105                                                         &hw_efforts_[i]);
00106       jnt_state_interface_.registerHandle(state_handle);
00107 
00108       hardware_interface::JointHandle pos_handle(jnt_state_interface_.getHandle(joints.at(i)),
00109                                                  &hw_commands_[i]);
00110       jnt_pos_interface_.registerHandle(pos_handle);
00111     }
00112 
00113     registerInterface(&jnt_state_interface_);
00114     registerInterface(&jnt_pos_interface_);
00115   }
00116   catch(const ros::Exception& e)
00117   {
00118     ROS_ERROR("Could not initialize hardware interfaces!\n\tTrace: %s", e.what());
00119     return false;
00120   }
00121 
00122   return true;
00123 }
00124 
00125 // The entry point from outside
00126 bool Robot::connect()
00127 {
00128   is_connected_ = false;
00129 
00130   // Load ROS Parameters
00131   if (!loadParams())
00132     return false;
00133 
00134   // Initialize DCM Wrapper
00135   if (use_dcm_)
00136     dcm_ = boost::shared_ptr<DCM>(new DCM(_session, controller_freq_));
00137 
00138   // Initialize Memory Wrapper
00139   memory_ = boost::shared_ptr<Memory>(new Memory(_session));
00140 
00141   //get the robot's name
00142   std::string robot = memory_->getData("RobotConfig/Body/Type");
00143   std::transform(robot.begin(), robot.end(), robot.begin(), ::tolower);
00144 
00145   // Initialize Motion Wrapper
00146   motion_ = boost::shared_ptr<Motion>(new Motion(_session));
00147 
00148   // check if the robot is waked up
00149   if (motor_groups_.size() == 1)
00150   {
00151     if (motor_groups_[0] == "Body")
00152       motion_->wakeUp();
00153   }
00154   else if (!use_dcm_)
00155     motion_->wakeUp();
00156   if (!motion_->robotIsWakeUp())
00157   {
00158     ROS_ERROR("Please, wakeUp the robot to be able to set stiffness");
00159     stopService();
00160     return false;
00161   }
00162 
00163   if (use_dcm_)
00164     motion_->manageConcurrence();
00165 
00166   //read Naoqi joints names that will be controlled
00167   qi_joints_ = motion_->getBodyNamesFromGroup(motor_groups_);
00168   if (qi_joints_.empty())
00169     ROS_ERROR("Controlled joints are not known.");
00170   //define HW joints if empty
00171   if (hw_joints_.empty())
00172   {
00173     ROS_INFO_STREAM("Initializing the HW controlled joints with Naoqi joints.");
00174     hw_joints_.reserve(qi_joints_.size());
00175     copy(qi_joints_.begin(), qi_joints_.end(), back_inserter(hw_joints_));
00176   }
00177   ROS_INFO_STREAM("HW controlled joints are : " << print(hw_joints_));
00178 
00179   ignoreMimicJoints(&qi_joints_);
00180   ROS_INFO_STREAM("Naoqi controlled joints are : " << print(qi_joints_));
00181   qi_commands_.reserve(qi_joints_.size());
00182   qi_commands_.resize(qi_joints_.size(), 0.0);
00183 
00184   //initialise Memory, Motion, and DCM classes with controlled joints
00185   memory_->init(qi_joints_);
00186   motion_->init(qi_joints_);
00187   if (use_dcm_)
00188     dcm_->init(qi_joints_);
00189 
00190   hw_enabled_ = checkJoints();
00191 
00192   //read joints names to initialize the joint_states topic
00193   joint_states_topic_.header.frame_id = "base_link";
00194   joint_states_topic_.name = motion_->getBodyNames("Body"); //Body=JointActuators+Wheels
00195   joint_states_topic_.position.resize(joint_states_topic_.name.size());
00196 
00197   //read joints names to initialize the diagnostics
00198   std::vector<std::string> joints_all_names = motion_->getBodyNames("JointActuators");
00199   diagnostics_ = boost::shared_ptr<Diagnostics>(
00200         new Diagnostics(_session, &diag_pub_, joints_all_names, robot));
00201 
00202   is_connected_ = true;
00203 
00204   // Subscribe/Publish ROS Topics/Services
00205   subscribe();
00206 
00207   // Turn Stiffness On
00208   if (!setStiffness(stiffness_value_))
00209     return false;
00210 
00211   // Initialize Controller Manager and Controllers
00212   try
00213   {
00214     manager_ = new controller_manager::ControllerManager( this, *nhPtr_);
00215   }
00216   catch(const ros::Exception& e)
00217   {
00218     ROS_ERROR("Could not initialize controller manager!\n\tTrace: %s", e.what());
00219     return false;
00220   }
00221 
00222   if(!initializeControllers(hw_joints_))
00223     return false;
00224 
00225   ROS_INFO_STREAM(session_name_ << " module initialized!");
00226   return true;
00227 }
00228 
00229 void Robot::subscribe()
00230 {
00231   // Subscribe/Publish ROS Topics/Services
00232   cmd_moveto_sub_ = nhPtr_->subscribe(prefix_+"cmd_moveto", 1, &Robot::commandVelocity, this);
00233 
00234   diag_pub_ = nhPtr_->advertise<diagnostic_msgs::DiagnosticArray>(prefix_+"diagnostics", topic_queue_);
00235 
00236   stiffness_pub_ = nhPtr_->advertise<std_msgs::Float32>(prefix_+"stiffnesses", topic_queue_);
00237   stiffness_.data = 1.0f;
00238 
00239   joint_states_pub_ = nhPtr_->advertise<sensor_msgs::JointState>("/joint_states", topic_queue_);
00240 }
00241 
00242 bool Robot::loadParams()
00243 {
00244   ros::NodeHandle nh("~");
00245   // Load Server Parameters
00246   nh.getParam("BodyType", body_type_);
00247   nh.getParam("TopicQueue", topic_queue_);
00248   nh.getParam("HighCommunicationFrequency", high_freq_);
00249   nh.getParam("ControllerFrequency", controller_freq_);
00250   nh.getParam("JointPrecision", joint_precision_);
00251   nh.getParam("OdomFrame", odom_frame_);
00252   nh.getParam("use_dcm", use_dcm_);
00253 
00254   if (nh.hasParam("max_stiffness"))
00255     nh.getParam("max_stiffness", stiffness_value_);
00256 
00257   if (use_dcm_)
00258     ROS_WARN_STREAM("Please, be carefull! "
00259                     << "You have chosen to control the robot based on DCM. "
00260                     << "It leads to concurrence between DCM and ALMotion, and "
00261                     << "it can cause shaking the robot. "
00262                     << "If the robot starts shaking, stop the node (Ctrl+C). "
00263                     << "Use either ALMotion or stop ALMotion and use DCM only.");
00264 
00265   //set the prefix for topics
00266   nh.getParam("Prefix", prefix_);
00267   if (prefix_.length() > 0)
00268     if (prefix_.at(prefix_.length()-1) != '/')
00269       prefix_ += "/";
00270 
00271   //read HW controllers names
00272   XmlRpc::XmlRpcValue params_pepper_dcm;
00273   nh.getParam("pepper_dcm", params_pepper_dcm);
00274   if (params_pepper_dcm.getType() != XmlRpc::XmlRpcValue::TypeStruct)
00275     ROS_ERROR("Please ensure that the list of controllers is TypeStruct");
00276 
00277   XmlRpc::XmlRpcValue::ValueStruct::const_iterator it=params_pepper_dcm.begin();
00278   for (; it != params_pepper_dcm.end(); ++it)
00279   {
00280     XmlRpc::XmlRpcValue::ValueStruct::const_iterator it2 = params_pepper_dcm[it->first].begin();
00281     for (; it2 != params_pepper_dcm[it->first].end(); ++it2)
00282     {
00283       std::string param = (std::string)(it2->first);
00284       if (param.compare("joints") == 0)
00285       {
00286         XmlRpc::XmlRpcValue params_joints = params_pepper_dcm[it->first][it2->first];
00287         if (params_joints.getType() == XmlRpc::XmlRpcValue::TypeArray)
00288         {
00289           xmlToVector(params_joints, &hw_joints_);
00290           continue;
00291         }
00292       }
00293     }
00294   }
00295 
00296   //define the motors groups to control
00297   std::string motor_groups_temp = "";
00298   nh.getParam("motor_groups", motor_groups_temp);
00299   motor_groups_ = toVector(motor_groups_temp);
00300   if (motor_groups_.empty())
00301   {
00302     motor_groups_.push_back("LArm");
00303     motor_groups_.push_back("RArm");
00304   }
00305   return true;
00306 }
00307 
00308 void Robot::run()
00309 {
00310   controllerLoop();
00311 }
00312 
00313 void Robot::controllerLoop()
00314 {
00315   static ros::Rate rate(controller_freq_);
00316   while(ros::ok())
00317   {
00318     ros::Time time = ros::Time::now();
00319 
00320     if(!is_connected_)
00321       break;
00322 
00323     //publishBaseFootprint(time);
00324 
00325     stiffness_pub_.publish(stiffness_);
00326 
00327     if (!diagnostics_->publish())
00328       stopService();
00329 
00330     readJoints();
00331 
00332     //motion_->stiffnessInterpolation(diagnostics_->getForcedJoints(), 0.3f, 2.0f);
00333 
00334     try
00335     {
00336       manager_->update(time, ros::Duration(1.0f/controller_freq_));
00337     }
00338     catch(ros::Exception& e)
00339     {
00340       ROS_ERROR("%s", e.what());
00341       return;
00342     }
00343 
00344     writeJoints();
00345 
00346     //no need if Naoqi Driver is running
00347     //publishJointStateFromAlMotion();
00348 
00349     rate.sleep();
00350   }
00351   ROS_INFO_STREAM("Shutting down the main loop");
00352 }
00353 
00354 bool Robot::isConnected()
00355 {
00356   return is_connected_;
00357 }
00358 
00359 void Robot::commandVelocity(const geometry_msgs::TwistConstPtr &msg)
00360 {
00361   //reset stiffness for arms if using DCM to prevent its concurrence with ALMotion
00362   if(use_dcm_)
00363     motion_->setStiffnessArms(0.0f, 1.0f);
00364 
00365   motion_->moveTo(msg->linear.x, msg->linear.y, msg->angular.z);
00366   sleep(1.0);
00367 
00368   //set stiffness for arms if using DCM
00369   if(use_dcm_)
00370     motion_->setStiffnessArms(1.0f, 1.0f);
00371 }
00372 
00373 void Robot::publishBaseFootprint(const ros::Time &ts)
00374 {
00375   std::string odom_frame, base_link_frame;
00376   try 
00377   {
00378     odom_frame = base_footprint_listener_.resolve(odom_frame_);
00379     base_link_frame = base_footprint_listener_.resolve("base_link");
00380   }
00381   catch(ros::Exception& e)
00382   {
00383     ROS_ERROR("%s", e.what());
00384     return;
00385   }
00386 
00387   tf::StampedTransform tf_odom_to_base, tf_odom_to_left_foot, tf_odom_to_right_foot;
00388   double temp_freq = 1.0f/(10.0*high_freq_);
00389   if(!base_footprint_listener_.waitForTransform(odom_frame, base_link_frame, ros::Time(0), ros::Duration(temp_freq)))
00390     return;
00391   try 
00392   {
00393     base_footprint_listener_.lookupTransform(odom_frame, base_link_frame,  ros::Time(0), tf_odom_to_base);
00394   }
00395   catch (const tf::TransformException& ex)
00396   {
00397     ROS_ERROR("%s",ex.what());
00398     return ;
00399   }
00400 
00401   tf::Vector3 new_origin = (tf_odom_to_right_foot.getOrigin() + tf_odom_to_left_foot.getOrigin())/2.0;
00402   double height = std::min(tf_odom_to_left_foot.getOrigin().getZ(), tf_odom_to_right_foot.getOrigin().getZ());
00403   new_origin.setZ(height);
00404 
00405   double roll, pitch, yaw;
00406   tf_odom_to_base.getBasis().getRPY(roll, pitch, yaw);
00407 
00408   tf::Transform tf_odom_to_footprint(tf::createQuaternionFromYaw(yaw), new_origin);
00409   tf::Transform tf_base_to_footprint = tf_odom_to_base.inverse() * tf_odom_to_footprint;
00410 
00411   base_footprint_broadcaster_.sendTransform(tf::StampedTransform(tf_base_to_footprint, ts,
00412                                                                  base_link_frame, "base_footprint"));
00413 }
00414 
00415 std::vector <bool> Robot::checkJoints()
00416 {
00417   std::vector <bool> hw_enabled;
00418   hw_enabled.reserve(hw_joints_.size());
00419   hw_enabled.resize(hw_joints_.size(), false);
00420 
00421   //store joints angles
00422   std::vector<std::string>::iterator hw_j = hw_joints_.begin();
00423   std::vector<std::string>::iterator qi_j = qi_joints_.begin();
00424   std::vector<bool>::iterator hw_enabled_j = hw_enabled.begin();
00425 
00426   for(; hw_j != hw_joints_.end(); ++hw_j, ++hw_enabled_j)
00427   {
00428     if (*hw_j == *qi_j)
00429     {
00430       *hw_enabled_j = true;
00431       ++qi_j;
00432     }
00433   }
00434   return hw_enabled;
00435 }
00436 
00437 void Robot::readJoints()
00438 {
00439   //read memory keys for joint/position/sensor
00440   std::vector<float> qi_joints_positions = memory_->getListData();
00441 
00442   //store joints angles
00443   std::vector<double>::iterator hw_command_j = hw_commands_.begin();
00444   std::vector<double>::iterator hw_angle_j = hw_angles_.begin();
00445   std::vector<float>::iterator qi_position_j = qi_joints_positions.begin();
00446   std::vector<bool>::iterator hw_enabled_j = hw_enabled_.begin();
00447 
00448   for(; hw_command_j != hw_commands_.end(); ++hw_command_j, ++hw_angle_j, ++hw_enabled_j)
00449   {
00450     if (!*hw_enabled_j)
00451       continue;
00452 
00453     *hw_angle_j = *qi_position_j;
00454     // Set commands to the read angles for when no command specified
00455     *hw_command_j = *qi_position_j;
00456 
00457     //increment qi iterators
00458     ++qi_position_j;
00459   }
00460 }
00461 
00462 void Robot::publishJointStateFromAlMotion(){
00463   joint_states_topic_.header.stamp = ros::Time::now();
00464 
00465   std::vector<double> position_data = motion_->getAngles("Body");
00466   for(int i = 0; i<position_data.size(); ++i)
00467     joint_states_topic_.position[i] = position_data[i];
00468 
00469   joint_states_pub_.publish(joint_states_topic_);
00470 }
00471 
00472 void Robot::writeJoints()
00473 {
00474   // Check if there is some change in joints values
00475   bool changed(false);
00476   std::vector<double>::iterator hw_angle_j = hw_angles_.begin();
00477   std::vector<double>::iterator hw_command_j = hw_commands_.begin();
00478   std::vector<double>::iterator qi_command_j = qi_commands_.begin();
00479   std::vector<bool>::iterator hw_enabled_j = hw_enabled_.begin();
00480   for(int i=0; hw_command_j != hw_commands_.end(); ++i, ++hw_command_j, ++hw_angle_j, ++hw_enabled_j)
00481   {
00482     if (!*hw_enabled_j)
00483       continue;
00484 
00485     *qi_command_j = *hw_command_j;
00486     ++qi_command_j;
00487 
00488     double diff = std::fabs(*hw_command_j - *hw_angle_j);
00489     if(diff > joint_precision_)
00490     {
00491       //ROS_INFO_STREAM(" joint " << i << " : diff=" << diff);
00492       changed = true;
00493       break;
00494     }
00495   }
00496 
00497   // Update joints values if there are some changes
00498   if(!changed)
00499     return;
00500 
00501   if (use_dcm_)
00502     dcm_->writeJoints(qi_commands_);
00503   else
00504     motion_->writeJoints(qi_commands_);
00505 }
00506 
00507 void Robot::ignoreMimicJoints(std::vector <std::string> *joints)
00508 {
00509   //ignore mimic joints
00510   for(std::vector<std::string>::iterator it=joints->begin(); it!=joints->end(); ++it)
00511   {
00512     if( (it->find("Wheel") != std::string::npos)
00513          || (*it=="RHand" || *it=="LHand" || *it == "RWristYaw" || *it == "LWristYaw") && (body_type_ == "H21"))
00514     {
00515       joints->erase(it);
00516       it--;
00517     }
00518   }
00519 }
00520 
00521 //  rewrite by calling DCM rather than ALMotion
00522 bool Robot::setStiffness(const float &stiffness)
00523 {
00524   stiffness_.data = stiffness;
00525 
00526   if (!motion_->stiffnessInterpolation(motor_groups_, stiffness, 2.0f))
00527     return false;
00528 
00529   return true;
00530 }


naoqi_dcm_driver
Author(s): Konstantinos Chatzilygeroudis , Mikael Arguedas , Karsten Knese , Natalia Lyubova
autogenerated on Thu Jun 6 2019 20:50:50