pal_hardware_gazebo.cpp
Go to the documentation of this file.
00001 
00002 // Copyright (C) 2016, PAL Robotics S.L.
00003 //
00004 // Redistribution and use in source and binary forms, with or without
00005 // modification, are permitted provided that the following conditions are met:
00006 //   * Redistributions of source code must retain the above copyright notice,
00007 //     this list of conditions and the following disclaimer.
00008 //   * Redistributions in binary form must reproduce the above copyright
00009 //     notice, this list of conditions and the following disclaimer in the
00010 //     documentation and/or other materials provided with the distribution.
00011 //   * Neither the name of PAL Robotics S.L. nor the names of its
00012 //     contributors may be used to endorse or promote products derived from
00013 //     this software without specific prior written permission.
00014 //
00015 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00016 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00019 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00020 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00021 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00023 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00024 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00025 // POSSIBILITY OF SUCH DAMAGE.
00027 
00028 #include <cassert>
00029 #include <boost/foreach.hpp>
00030 
00031 #include <gazebo/sensors/SensorManager.hh>
00032 
00033 #include <urdf_parser/urdf_parser.h>
00034 #include <pluginlib/class_list_macros.h>
00035 #include <angles/angles.h>
00036 #include <Eigen/Core>
00037 #include <Eigen/Geometry>
00038 
00039 #include <joint_limits_interface/joint_limits_urdf.h>
00040 #include <transmission_interface/transmission_interface_loader.h>
00041 
00042 #include <pal_hardware_gazebo/pal_hardware_gazebo.h>
00043 
00044 typedef Eigen::Vector3d   eVector3;
00045 typedef Eigen::Isometry3d eMatrixHom;
00046 typedef Eigen::Matrix3d   eMatrixRot;
00047 typedef Eigen::Quaternion<double>   eQuaternion;
00048 
00049 using std::vector;
00050 using std::string;
00051 
00052 namespace xh
00053 {
00054 
00055   class XmlrpcHelperException : public ros::Exception
00056   {
00057   public:
00058     XmlrpcHelperException(const std::string& what)
00059       : ros::Exception(what) {}
00060   };
00061 
00062   typedef XmlRpc::XmlRpcValue Struct;
00063   typedef XmlRpc::XmlRpcValue Array;
00064 
00065   template <class T>
00066   void fetchParam(ros::NodeHandle nh, const std::string& param_name, T& output)
00067   {
00068     XmlRpc::XmlRpcValue val;
00069     bool ok = false;
00070     try
00071     {
00072       ok = nh.getParam(param_name, val);
00073     }
00074     catch(const ros::InvalidNameException& e) {}
00075 
00076     if (!ok)
00077     {
00078       std::ostringstream err_msg;
00079       err_msg << "could not load parameter '" << param_name << "'. (namespace: "
00080               << nh.getNamespace() << ")";
00081       throw XmlrpcHelperException(err_msg.str());
00082     }
00083 
00084     output = static_cast<T>(val);
00085   }
00086 
00087 }
00088 
00089 inline std::vector<std::string> getIds(const ros::NodeHandle &nh, const std::string& key)
00090 {
00091   using std::vector;
00092   using std::string;
00093 
00094   xh::Struct xh_st;
00095   try {xh::fetchParam(nh, key, xh_st);}
00096   catch (const xh::XmlrpcHelperException&)
00097   {
00098     ROS_DEBUG_STREAM("Requested data found in the parameter server (namespace " <<
00099                      nh.getNamespace() + "/" + key << ").");
00100     return vector<string>();
00101   }
00102 
00103   vector<string> out;
00104   for (xh::Struct::iterator it = xh_st.begin(); it != xh_st.end(); ++it)
00105   {
00106     out.push_back(it->first);
00107   }
00108   return out;
00109 }
00110 
00111 
00112 void convert(const urdf::Vector3 &in, eVector3 &out){
00113   out = eVector3(in.x, in.y, in.z);
00114 }
00115 
00116 void convert(const urdf::Rotation &in, eMatrixRot &out){
00117   out = eQuaternion(in.w, in.x, in.y, in.z);
00118 }
00119 
00120 inline eMatrixHom createMatrix( eMatrixRot const& rot, eVector3 const& trans)
00121 {
00122   eMatrixHom temp;
00123   temp.setIdentity();
00124   temp = (rot);
00125   temp.translation() = trans;
00126   return temp;
00127 }
00128 
00129 void convert(const urdf::Pose &in, eMatrixHom &out){
00130   eVector3 r;
00131   convert(in.position, r);
00132   eMatrixRot E;
00133   convert(in.rotation, E);
00134   out = createMatrix(E, r);
00135 }
00136 
00137 template<typename T>
00138 Eigen::Matrix<T, 3, 3> skew(const Eigen::Matrix<T, 3, 1>& vec)
00139 {
00140   return (Eigen::Matrix<T, 3, 3>() << T(0), -vec(2), vec(1),
00141           vec(2), T(0), -vec(0),
00142           -vec(1), vec(0), T(0)).finished();
00143 }
00144 
00145 
00146 namespace gazebo_ros_control
00147 {
00148 
00149   using namespace hardware_interface;
00150 
00151   bool PalHardwareGazebo::parseForceTorqueSensors(ros::NodeHandle &nh,
00152                                                   gazebo::physics::ModelPtr model,
00153                                                   const urdf::Model* const urdf_model){
00154     using std::vector;
00155     using std::string;
00156 
00157     const string ft_ns = "force_torque";
00158     vector<string> ft_ids = getIds(nh, ft_ns);
00159     ros::NodeHandle ft_nh(nh, ft_ns);
00160     typedef vector<string>::const_iterator Iterator;
00161     for (Iterator it = ft_ids.begin(); it != ft_ids.end(); ++it){
00162       std::string sensor_name = *it;
00163       std::string sensor_joint_name;
00164       std::string sensor_frame_id;
00165       ros::NodeHandle ft_sensor_nh(ft_nh, sensor_name);
00166       xh::fetchParam(ft_sensor_nh, "frame", sensor_frame_id);
00167       xh::fetchParam(ft_sensor_nh, "sensor_joint", sensor_joint_name);
00168 
00169       ForceTorqueSensorDefinitionPtr ft(new ForceTorqueSensorDefinition(sensor_name,
00170                                                                         sensor_joint_name,
00171                                                                         sensor_frame_id));
00172 
00173       ft->gazebo_joint  = model->GetJoint(ft->sensorJointName);
00174 
00175       // Get sensor parent transform
00176       boost::shared_ptr<const urdf::Link> urdf_sensor_link;
00177       boost::shared_ptr<const urdf::Joint> urdf_sensor_joint;
00178       urdf_sensor_link = urdf_model->getLink(ft->sensorFrame);
00179       urdf_sensor_joint = urdf_model->getJoint(sensor_joint_name);
00180 
00181       if(!urdf_sensor_link){
00182         ROS_ERROR_STREAM("Problem finding link: "<<ft->sensorFrame<<" to attach FT sensor in robot model");
00183         return false;
00184       }
00185 
00186       if(!urdf_sensor_joint){
00187         ROS_ERROR_STREAM("Problem finding joint: "<<ft->sensorJointName<<" to attach FT sensor in robot model");
00188         return false;
00189       }
00190 
00191       // Recursively follow the transform until the parent
00192       bool parentFound = false;
00193       eMatrixHom sensorTransform;
00194       sensorTransform.setIdentity();
00195 
00196       // Check that is not the actual first link
00197        if(urdf_sensor_link->name == urdf_sensor_joint->child_link_name){
00198            parentFound = true;
00199         }
00200 
00201       while(!parentFound){
00202        std::cerr<<"      "<<urdf_sensor_link->name<<" - "<<urdf_sensor_joint->child_link_name<<std::endl;
00203 
00204        urdf::Pose tf_urdf = urdf_sensor_link->parent_joint->parent_to_joint_origin_transform;
00205        eMatrixHom tf_eigen;
00206        convert(tf_urdf, tf_eigen);
00207        sensorTransform = tf_eigen*sensorTransform;
00208 
00209        urdf_sensor_link = urdf_sensor_link->getParent();
00210 
00211        if(urdf_sensor_joint->child_link_name == urdf_sensor_link->name){
00212          parentFound = true;
00213        }
00214 
00215       }
00216 
00217       if(!parentFound){
00218        ROS_ERROR_STREAM("No frame found for force torque sensor");
00219       }
00220 
00221       //std::cerr<<"Sensor name: "<<sensor_name<<"transform: "<<std::endl<<sensorTransform.matrix()<<std::endl;
00222       //std::cerr<<"Sensor name: "<<sensor_name<<"transform transpose: "<<std::endl<<sensorTransform.matrix().transpose()<<std::endl;
00223 
00224       ft->sensorTransform = sensorTransform;
00225 
00226       if (!ft->gazebo_joint){
00227         ROS_ERROR_STREAM("Could not find joint '" << ft->sensorJointName << "' to which a force-torque sensor is attached.");
00228         return false;
00229       }
00230 
00231       forceTorqueSensorDefinitions_.push_back(ft);
00232       ROS_INFO_STREAM("Parsed fake FT sensor: "<<sensor_name<<" in frame: "<<sensor_frame_id);
00233     }
00234     return true;
00235   }
00236 
00237   bool PalHardwareGazebo::parseIMUSensors(ros::NodeHandle &nh,
00238                                           gazebo::physics::ModelPtr model,
00239                                           const urdf::Model* const urdf_model){
00240     using std::vector;
00241     using std::string;
00242 
00243     const string imu_ns = "imu";
00244     vector<string> imu_ids = getIds(nh, imu_ns);
00245     ros::NodeHandle imu_nh(nh, imu_ns);
00246     typedef vector<string>::const_iterator Iterator;
00247     for (Iterator it = imu_ids.begin(); it != imu_ids.end(); ++it){
00248       std::string sensor_name = *it;
00249       std::string sensor_frame_id;
00250       ros::NodeHandle imu_sensor_nh(imu_nh, sensor_name);
00251       xh::fetchParam(imu_sensor_nh, "frame", sensor_frame_id);
00252 
00253       boost::shared_ptr<gazebo::sensors::ImuSensor> imu_sensor;
00254       imu_sensor =  boost::dynamic_pointer_cast<gazebo::sensors::ImuSensor>
00255           (gazebo::sensors::SensorManager::Instance()->GetSensor("imu_sensor"));
00256       if (!imu_sensor){
00257         ROS_ERROR_STREAM("Could not find base IMU sensor.");
00258         return false;
00259       }
00260 
00261       ImuSensorDefinitionPtr imu(new ImuSensorDefinition(sensor_name, sensor_frame_id));
00262       imu->gazebo_imu_sensor = imu_sensor;
00263       imuSensorDefinitions_.push_back(imu);
00264       ROS_INFO_STREAM("Parsed imu sensor: "<<sensor_name<<" in frame: "<<sensor_frame_id);
00265     }
00266     return true;
00267   }
00268 
00269   PalHardwareGazebo::PalHardwareGazebo()
00270     : DefaultRobotHWSim()
00271   {}
00272 
00273   bool PalHardwareGazebo::initSim(const std::string& robot_ns,
00274                                   ros::NodeHandle nh, gazebo::physics::ModelPtr model,
00275                                   const urdf::Model* const urdf_model,
00276                                   std::vector<transmission_interface::TransmissionInfo> transmissions)
00277   {
00278 
00279     ROS_INFO_STREAM("Loading PAL HARWARE GAZEBO");
00280 
00281     // register hardware interfaces
00282     // TODO: Automate, so generic interfaces can be added
00283     registerInterface(&js_interface_);
00284     registerInterface(&ej_interface_);
00285     registerInterface(&pj_interface_);
00286     registerInterface(&vj_interface_);
00287 
00288     // cache transmisions information
00289     DefaultRobotHWSim::transmission_infos_ = transmissions;
00290 
00291     // populate hardware interfaces, bind them to raw Gazebo data
00292     namespace ti = transmission_interface;
00293     BOOST_FOREACH(const ti::TransmissionInfo& tr_info, transmission_infos_)
00294     {
00295       BOOST_FOREACH(const ti::JointInfo& joint_info, tr_info.joints_)
00296       {
00297         BOOST_FOREACH(const std::string& iface_type, joint_info.hardware_interfaces_)
00298         {
00299           // TODO: Wrap in method for brevity?
00300           RwResPtr res;
00301           // TODO: A plugin-based approach would do better than this 'if-elseif' chain
00302           // To do this, move contructor logic to init method, and unify signature
00303           if (iface_type == "hardware_interface/JointStateInterface")
00304           {
00305             res.reset(new internal::JointState());
00306           }
00307           else if (iface_type == "hardware_interface/PositionJointInterface")
00308           {
00309             res.reset(new internal::PositionJoint());
00310           }
00311           else if (iface_type == "hardware_interface/VelocityJointInterface")
00312           {
00313             res.reset(new internal::VelocityJoint());
00314           }
00315           else if (iface_type == "hardware_interface/EffortJointInterface")
00316           {
00317             res.reset(new internal::EffortJoint());
00318           }
00319 
00320           // initialize and add to list of managed resources
00321           if (res)
00322           {
00323             try
00324             {
00325               res->init(joint_info.name_,
00326                         nh,
00327                         model,
00328                         urdf_model,
00329                         this);
00330               rw_resources_.push_back(res);
00331               ROS_DEBUG_STREAM("Registered joint '" << joint_info.name_ << "' in hardware interface '" <<
00332                                iface_type << "'."); // TODO: Lower severity to debug!
00333             }
00334             catch (const internal::ExistingResourceException&) {} // resource already added, no problem
00335             catch (const std::runtime_error& ex)
00336             {
00337               ROS_ERROR_STREAM("Failed to initialize gazebo_ros_control plugin.\n" <<
00338                                ex.what());
00339               return false;
00340             }
00341             catch(...)
00342             {
00343               ROS_ERROR_STREAM("Failed to initialize gazebo_ros_control plugin.\n" <<
00344                                "Could not add resource '" << joint_info.name_ << "' to hardware interface '" <<
00345                                iface_type << "'.");
00346               return false;
00347             }
00348           }
00349 
00350         }
00351       }
00352     }
00353 
00354     // initialize the emergency stop code
00355     e_stop_active_ = false;
00356 
00357     // joint mode switching
00358     mode_switch_enabled_ = true;
00359     nh.getParam("gazebo_ros_control/enable_joint_mode_switching", mode_switch_enabled_); // TODO: Check namespace
00360     const std::string enabled_str = mode_switch_enabled_ ? "enabled" : "disabled";
00361     ROS_INFO_STREAM("Joint mode switching is " << enabled_str);
00362 
00363     // initialize active writers
00364     initActiveWriteResources();
00365 
00366     parseForceTorqueSensors(nh, model, urdf_model);
00367 
00368     for(size_t i=0; i<forceTorqueSensorDefinitions_.size(); ++i){
00369       ForceTorqueSensorDefinitionPtr &ft = forceTorqueSensorDefinitions_[i];
00370       ft_sensor_interface_.registerHandle(ForceTorqueSensorHandle(ft->sensorName,
00371                                                                   ft->sensorFrame,
00372                                                                   &ft->force[0],
00373                                           &ft->torque[0]));
00374     }
00375 
00376     registerInterface(&ft_sensor_interface_);
00377     ROS_DEBUG_STREAM("Registered force-torque sensors.");
00378 
00379     // Hardware interfaces: Base IMU sensors
00380     parseIMUSensors(nh, model, urdf_model);
00381 
00382     for(size_t i=0; i<imuSensorDefinitions_.size(); ++i){
00383       ImuSensorDefinitionPtr &imu = imuSensorDefinitions_[i];
00384 
00385       ImuSensorHandle::Data data;
00386       data.name = imu->sensorName;
00387       data.frame_id = imu->sensorFrame;
00388       data.orientation = &imu->orientation[0];
00389       data.linear_acceleration = &imu->linear_acceleration[0];
00390       data.angular_velocity = &imu->base_ang_vel[0];
00391       imu_sensor_interface_.registerHandle(ImuSensorHandle(data));
00392     }
00393 
00394     registerInterface(&imu_sensor_interface_);
00395     ROS_DEBUG_STREAM("Registered IMU sensor.");
00396 
00397     return true;
00398   }
00399 
00400   void PalHardwareGazebo::readSim(ros::Time time, ros::Duration period)
00401   {
00402     // read all resources
00403     BOOST_FOREACH(RwResPtr res, rw_resources_)
00404     {
00405       res->read(time, period, e_stop_active_);
00406     }
00407 
00408     // Read force-torque sensors
00409     for(size_t i = 0; i < forceTorqueSensorDefinitions_.size(); ++i){
00410       ForceTorqueSensorDefinitionPtr &ft = forceTorqueSensorDefinitions_[i];
00411       gazebo::physics::JointWrench ft_wrench = ft->gazebo_joint->GetForceTorque(0u);
00412 
00413       ft->force[0]  = ft_wrench.body2Force.x;
00414       ft->force[1]  = ft_wrench.body2Force.y;
00415       ft->force[2]  = ft_wrench.body2Force.z;
00416       ft->torque[0] = ft_wrench.body2Torque.x;
00417       ft->torque[1] = ft_wrench.body2Torque.y;
00418       ft->torque[2] =  ft_wrench.body2Torque.z;
00419 
00420       // Transform to sensor frame
00421       Eigen::MatrixXd transform(6, 6);
00422       transform.setZero();
00423       transform.block(0, 0, 3, 3) = Eigen::Matrix3d::Identity();
00424       transform.block(3, 3, 3, 3) = ft->sensorTransform.rotation().transpose();
00425       eVector3 r = ft->sensorTransform.translation();
00426       transform.block(3, 0, 3, 3) = skew(r)*ft->sensorTransform.rotation().transpose();
00427 
00428       Eigen::VectorXd wrench(6);
00429       wrench<<ft->torque[0], ft->torque[1], ft->torque[2],
00430               ft->force[0], ft->force[1], ft->force[2];
00431       Eigen::VectorXd transformedWrench(6);
00432 
00433       transformedWrench = transform*wrench;
00434 
00435       ft->torque[0] = transformedWrench(0);
00436       ft->torque[1] = transformedWrench(1);
00437       ft->torque[2] = transformedWrench(2);
00438       ft->force[0]  = transformedWrench(3);
00439       ft->force[1]  = transformedWrench(4);
00440       ft->force[2]  = transformedWrench(5);
00441     }
00442 
00443     // Read IMU sensor
00444     for(size_t i = 0; i < imuSensorDefinitions_.size(); ++i){
00445       ImuSensorDefinitionPtr &imu = imuSensorDefinitions_[i];
00446 
00447       gazebo::math::Quaternion imu_quat = imu->gazebo_imu_sensor->GetOrientation();
00448       imu->orientation[0] = imu_quat.x;
00449       imu->orientation[1] = imu_quat.y;
00450       imu->orientation[2] = imu_quat.z;
00451       imu->orientation[3] = imu_quat.w;
00452 
00453       gazebo::math::Vector3 imu_ang_vel = imu->gazebo_imu_sensor->GetAngularVelocity();
00454       imu->base_ang_vel[0] = imu_ang_vel.x;
00455       imu->base_ang_vel[1] = imu_ang_vel.y;
00456       imu->base_ang_vel[2] = imu_ang_vel.z;
00457 
00458       gazebo::math::Vector3 imu_lin_acc = imu->gazebo_imu_sensor->GetLinearAcceleration();
00459       imu->linear_acceleration[0] =  imu_lin_acc.x;
00460       imu->linear_acceleration[1] =  imu_lin_acc.y;
00461       imu->linear_acceleration[2] =  imu_lin_acc.z;
00462     }
00463 
00464   }
00465 
00466   void PalHardwareGazebo::writeSim(ros::Time time, ros::Duration period)
00467   {
00468     boost::unique_lock<boost::mutex> lock(mutex_);
00469     BOOST_FOREACH(RwResPtr res, active_w_resources_rt_)
00470     {
00471       res->write(time, period, e_stop_active_);
00472     }
00473     // PUBLISH_DEBUG_DATA_TOPIC;
00474   }
00475 
00476 }
00477 
00478 PLUGINLIB_EXPORT_CLASS(gazebo_ros_control::PalHardwareGazebo, gazebo_ros_control::RobotHWSim)


pal_hardware_gazebo
Author(s):
autogenerated on Thu Sep 22 2016 03:29:23