pmb2_hardware_gazebo.cpp
Go to the documentation of this file.
00001 
00002 // Copyright (C) 2013, 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 
00035 #include <joint_limits_interface/joint_limits_urdf.h>
00036 #include <joint_limits_interface/joint_limits_rosparam.h>
00037 
00038 #include <pmb2_hardware_gazebo/pmb2_hardware_gazebo.h>
00039 
00040 using std::string;
00041 using std::vector;
00042 
00043 namespace pmb2_hardware_gazebo
00044 {
00045   using namespace hardware_interface;
00046 
00047   Pmb2HardwareGazebo::Pmb2HardwareGazebo()
00048     : gazebo_ros_control::RobotHWSim()
00049   {}
00050 
00051 
00052   bool Pmb2HardwareGazebo::initSim(const std::string& robot_namespace,
00053       ros::NodeHandle nh,
00054       gazebo::physics::ModelPtr model,
00055       const urdf::Model* const urdf_model,
00056       std::vector<transmission_interface::TransmissionInfo> transmissions)
00057   {
00058     using gazebo::physics::JointPtr;
00059 
00060     // Cleanup
00061     pos_sim_joints_.clear();
00062     vel_sim_joints_.clear();
00063     sim_joints_.clear();
00064     jnt_pos_.clear();
00065     jnt_vel_.clear();
00066     jnt_eff_.clear();
00067     jnt_pos_cmd_.clear();
00068     jnt_pos_cmd_curr_.clear();
00069     jnt_vel_cmd_.clear();
00070 
00071     // Simulation joints
00072     std::vector<gazebo::physics::JointPtr> sim_joints_tmp = model->GetJoints();
00073 
00074     std::vector<std::string> pos_jnt_names;
00075     std::vector<std::string> vel_jnt_names;
00076     std::vector<std::string> jnt_names;
00077     for (size_t i = 0; i < sim_joints_tmp.size(); ++i)
00078     {
00079 
00080       // NOTE: This loop has a bunch of tricks that will get removed once automatic transmission parsing is implemented
00081       const std::string unscoped_name = sim_joints_tmp[i]->GetName();//.substr(7); // NOTE: Removing extra scoping, TODO: Fix!
00082       if ( !(unscoped_name.size() >= 6 && 0 == unscoped_name.compare(0, 6, "caster")) )
00083       {
00084         if(0 == unscoped_name.compare(0, 5, "wheel"))
00085         {
00086           boost::shared_ptr<const urdf::Joint> joint(urdf_model->getJoint(unscoped_name));
00087           if(!joint)
00088           {
00089             ROS_ERROR_STREAM(unscoped_name
00090                              << " couldn't be retrieved from model description");
00091             return false;
00092           }
00093 
00094           sim_joints_tmp[i]->SetMaxForce(0u, joint->limits->effort);
00095           vel_sim_joints_.push_back(sim_joints_tmp[i]);
00096           vel_jnt_names.push_back(unscoped_name);
00097         }
00098         else
00099         {
00100           pos_sim_joints_.push_back(sim_joints_tmp[i]);
00101           pos_jnt_names.push_back(unscoped_name);
00102         }
00103       }
00104 
00105       sim_joints_.push_back(sim_joints_tmp[i]);
00106       jnt_names.push_back(unscoped_name);
00107     }
00108 
00109     pos_n_dof_ = pos_sim_joints_.size();
00110     vel_n_dof_ = vel_sim_joints_.size();
00111     n_dof_ = sim_joints_.size();
00112 
00113     // Raw data
00114     jnt_pos_.resize(n_dof_);
00115     jnt_vel_.resize(n_dof_);
00116     jnt_eff_.resize(n_dof_);
00117     jnt_pos_cmd_.resize(pos_n_dof_);
00118     jnt_pos_cmd_curr_.resize(pos_n_dof_);
00119     jnt_vel_cmd_.resize(vel_n_dof_);
00120 
00121     // Hardware interfaces
00122     for (size_t i = 0; i < n_dof_; ++i)
00123     {
00124 
00125       jnt_state_interface_.registerHandle(JointStateHandle(jnt_names[i],
00126                                                            &jnt_pos_[i],
00127                                                            &jnt_vel_[i],
00128                                                            &jnt_eff_[i]));
00129     }
00130     for (size_t i = 0; i < pos_n_dof_; ++i)
00131     {
00132 
00133       jnt_pos_cmd_interface_.registerHandle(JointHandle(jnt_state_interface_.getHandle(pos_jnt_names[i]),
00134                                                         &jnt_pos_cmd_[i]));
00135       ROS_DEBUG_STREAM("Registered joint '" << pos_jnt_names[i] << "' in the PositionJointInterface.");
00136     }
00137     for (size_t i = 0; i < vel_n_dof_; ++i)
00138     {
00139 
00140       jnt_vel_cmd_interface_.registerHandle(JointHandle(jnt_state_interface_.getHandle(vel_jnt_names[i]),
00141                                                         &jnt_vel_cmd_[i]));
00142       ROS_DEBUG_STREAM("Registered joint '" << pos_jnt_names[i] << "' in the VelocityJointInterface.");
00143     }
00144     registerInterface(&jnt_state_interface_);
00145     registerInterface(&jnt_pos_cmd_interface_);
00146     registerInterface(&jnt_vel_cmd_interface_);
00147 
00148     // Position joint limits interface
00149     vector<string> pos_joints_with_limits, pos_joints_without_limits;
00150     for (size_t i = 0; i < pos_n_dof_; ++i)
00151     {
00152       JointHandle cmd_handle = jnt_pos_cmd_interface_.getHandle(pos_sim_joints_[i]->GetName());
00153       const string name = cmd_handle.getName();
00154 
00155       using namespace joint_limits_interface;
00156       boost::shared_ptr<const urdf::Joint> urdf_joint = urdf_model->getJoint(name);
00157       JointLimits limits;
00158       SoftJointLimits soft_limits;
00159       if (!getJointLimits(urdf_joint, limits) || !getSoftJointLimits(urdf_joint, soft_limits))
00160       {
00161         pos_joints_without_limits.push_back(name);
00162         continue;
00163       }
00164       pos_jnt_limits_interface_.registerHandle(PositionJointSoftLimitsHandle(cmd_handle, limits, soft_limits));
00165       pos_joints_with_limits.push_back(name);
00166     }
00167     if (!pos_joints_with_limits.empty())
00168     {
00169       ROS_DEBUG_STREAM("Joint limits will be enforced for position-controlled joints:" <<
00170                         containerToString(pos_joints_with_limits, "\n - "));
00171     }
00172     if (!pos_joints_without_limits.empty())
00173     {
00174       ROS_WARN_STREAM("Joint limits will not be enforced for position-controlled joints:" <<
00175                       containerToString(pos_joints_without_limits, "\n - "));
00176     }
00177 
00178     // Velocity joint limits interface
00179     vector<string> vel_joints_with_limits, vel_joints_without_limits;
00180     for (unsigned int i = 0; i < vel_n_dof_; ++i)
00181     {
00182       JointHandle cmd_handle = jnt_vel_cmd_interface_.getHandle(vel_sim_joints_[i]->GetName());
00183       const string name = cmd_handle.getName();
00184 
00185       using namespace joint_limits_interface;
00186       boost::shared_ptr<const urdf::Joint> urdf_joint = urdf_model->getJoint(name);
00187       JointLimits limits;
00188       if (!getJointLimits(urdf_joint, limits) || !getJointLimits(name, nh, limits))
00189       {
00190         vel_joints_without_limits.push_back(name);
00191         continue;
00192       }
00193       vel_jnt_limits_interface_.registerHandle(VelocityJointSaturationHandle(cmd_handle, limits));
00194       vel_joints_with_limits.push_back(name);
00195     }
00196     if (!vel_joints_with_limits.empty())
00197     {
00198       ROS_DEBUG_STREAM("Joint limits will be enforced for velocity-controlled joints:" <<
00199                         containerToString(vel_joints_with_limits, "\n - "));
00200     }
00201     if (!vel_joints_without_limits.empty())
00202     {
00203       ROS_WARN_STREAM("Joint limits will not be enforced for velocity-controlled joints:" <<
00204                       containerToString(vel_joints_without_limits, "\n - "));
00205     }
00206 
00207     // Hardware interfaces: Base IMU sensors
00208     const string imu_name = "base_imu";
00209     imu_sensor_  = (gazebo::sensors::ImuSensor*)gazebo::sensors::SensorManager::Instance()->GetSensor(imu_name+"_sensor").get(); // TODO: Fetch from URDF?
00210     if (!this->imu_sensor_)
00211     {
00212       ROS_ERROR_STREAM("Could not find base IMU sensor.");
00213       return false;
00214     }
00215 
00216     ImuSensorHandle::Data data;
00217     data.name     = imu_name;           // TODO: Fetch from elsewhere?
00218     data.frame_id = imu_name + "_link"; // TODO: Fetch from URDF?
00219     data.orientation = &base_orientation_[0];
00220     imu_sensor_interface_.registerHandle(ImuSensorHandle(data));
00221     registerInterface(&imu_sensor_interface_);
00222     ROS_DEBUG_STREAM("Registered IMU sensor.");
00223 
00224     // PID controllers
00225     pids_.resize(pos_n_dof_);
00226     for (size_t i = 0; i < pos_n_dof_; ++i)
00227     {
00228       ros::NodeHandle joint_nh(nh, "gains/" + pos_jnt_names[i]);
00229       if (!pids_[i].init(joint_nh)) {return false;}
00230     }
00231 
00232     return true;
00233   }
00234 
00235   void Pmb2HardwareGazebo::readSim(ros::Time time, ros::Duration period)
00236   {
00237     for(unsigned int j = 0; j < n_dof_; ++j)
00238     {
00239       // Gazebo has an interesting API...
00240       jnt_pos_[j] += angles::shortest_angular_distance
00241           (jnt_pos_[j], sim_joints_[j]->GetAngle(0u).Radian());
00242       jnt_vel_[j] = sim_joints_[j]->GetVelocity(0u);
00243       jnt_eff_[j] = sim_joints_[j]->GetForce(0u);
00244     }
00245 
00246     // TODO: Implement ina cleaner way
00247     for(unsigned int j = 0; j < pos_n_dof_; ++j)
00248     {
00249       jnt_pos_cmd_curr_[j] += angles::shortest_angular_distance
00250           (jnt_pos_cmd_curr_[j], pos_sim_joints_[j]->GetAngle(0u).Radian());
00251     }
00252 
00253     // Read IMU sensor
00254     gazebo::math::Quaternion imu_quat = imu_sensor_->GetOrientation();
00255     base_orientation_[0] = imu_quat.x;
00256     base_orientation_[1] = imu_quat.y;
00257     base_orientation_[2] = imu_quat.z;
00258     base_orientation_[3] = imu_quat.w;
00259 
00260     gazebo::math::Vector3 imu_ang_vel = imu_sensor_->GetAngularVelocity();
00261     base_ang_vel_[0] = imu_ang_vel.x;
00262     base_ang_vel_[1] = imu_ang_vel.y;
00263     base_ang_vel_[2] = imu_ang_vel.z;
00264 
00265     gazebo::math::Vector3 imu_lin_acc = imu_sensor_->GetLinearAcceleration();
00266     base_lin_acc_[0] =  imu_lin_acc.x;
00267     base_lin_acc_[1] =  imu_lin_acc.y;
00268     base_lin_acc_[2] =  imu_lin_acc.z;
00269   }
00270 
00271   void Pmb2HardwareGazebo::writeSim(ros::Time time, ros::Duration period)
00272   {
00273     // Enforce joint limits
00274     pos_jnt_limits_interface_.enforceLimits(period);
00275     vel_jnt_limits_interface_.enforceLimits(period);
00276 
00277     // Compute and send commands
00278     for(unsigned int j = 0; j < pos_n_dof_; ++j)
00279     {
00280       const double error = jnt_pos_cmd_[j] - jnt_pos_cmd_curr_[j];
00281       const double effort = pids_[j].computeCommand(error, period);
00282 
00283       // Gazebo has an interesting API...
00284       pos_sim_joints_[j]->SetForce(0u, effort);
00285     }
00286     for(unsigned int j = 0; j < vel_n_dof_; ++j)
00287     {
00288       // Gazebo has an interesting API...
00289       vel_sim_joints_[j]->SetVelocity(0u, jnt_vel_cmd_[j]);
00290     }
00291   }
00292 
00293 } // pmb2_hardware_gazebo
00294 
00295 PLUGINLIB_EXPORT_CLASS( pmb2_hardware_gazebo::Pmb2HardwareGazebo, gazebo_ros_control::RobotHWSim)


pmb2_hardware_gazebo
Author(s): Enrique Fernandez
autogenerated on Wed Aug 26 2015 15:32:19