default_robot_hw_sim.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2013, Open Source Robotics Foundation
00005  *  Copyright (c) 2013, The Johns Hopkins University
00006  *  All rights reserved.
00007  *
00008  *  Redistribution and use in source and binary forms, with or without
00009  *  modification, are permitted provided that the following conditions
00010  *  are met:
00011  *
00012  *   * Redistributions of source code must retain the above copyright
00013  *     notice, this list of conditions and the following disclaimer.
00014  *   * Redistributions in binary form must reproduce the above
00015  *     copyright notice, this list of conditions and the following
00016  *     disclaimer in the documentation and/or other materials provided
00017  *     with the distribution.
00018  *   * Neither the name of the Open Source Robotics Foundation
00019  *     nor the names of its contributors may be
00020  *     used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *********************************************************************/
00036 
00037 /* Author: Dave Coleman, Johnathan Bohren
00038    Desc:   Hardware Interface for any simulated robot in Gazebo
00039 */
00040 
00041 #ifndef _GAZEBO_ROS_CONTROL___DEFAULT_ROBOT_HW_SIM_H_
00042 #define _GAZEBO_ROS_CONTROL___DEFAULT_ROBOT_HW_SIM_H_
00043 
00044 // ros_control
00045 #include <control_toolbox/pid.h>
00046 #include <hardware_interface/joint_command_interface.h>
00047 #include <hardware_interface/robot_hw.h>
00048 #include <joint_limits_interface/joint_limits.h>
00049 #include <joint_limits_interface/joint_limits_interface.h>
00050 #include <joint_limits_interface/joint_limits_rosparam.h>
00051 #include <joint_limits_interface/joint_limits_urdf.h>
00052 
00053 // Gazebo
00054 #include <gazebo/common/common.hh>
00055 #include <gazebo/physics/physics.hh>
00056 #include <gazebo/gazebo.hh>
00057 
00058 // ROS
00059 #include <ros/ros.h>
00060 #include <angles/angles.h>
00061 #include <pluginlib/class_list_macros.h>
00062 
00063 // gazebo_ros_control
00064 #include <gazebo_ros_control/robot_hw_sim.h>
00065 
00066 // URDF
00067 #include <urdf/model.h>
00068 
00069 namespace
00070 {
00071 
00072 double clamp(const double val, const double min_val, const double max_val)
00073 {
00074   return std::min(std::max(val, min_val), max_val);
00075 }
00076 
00077 }
00078 
00079 namespace gazebo_ros_control
00080 {
00081 
00082 class DefaultRobotHWSim : public gazebo_ros_control::RobotHWSim
00083 {
00084 public:
00085 
00086   bool initSim(
00087     const std::string& robot_namespace,
00088     ros::NodeHandle model_nh,
00089     gazebo::physics::ModelPtr parent_model,
00090     const urdf::Model *const urdf_model,
00091     std::vector<transmission_interface::TransmissionInfo> transmissions)
00092   {
00093     // getJointLimits() searches joint_limit_nh for joint limit parameters. The format of each
00094     // parameter's name is "joint_limits/<joint name>". An example is "joint_limits/axle_joint".
00095     const ros::NodeHandle joint_limit_nh(model_nh, robot_namespace);
00096 
00097     // Resize vectors to our DOF
00098     n_dof_ = transmissions.size();
00099     joint_names_.resize(n_dof_);
00100     joint_types_.resize(n_dof_);
00101     joint_lower_limits_.resize(n_dof_);
00102     joint_upper_limits_.resize(n_dof_);
00103     joint_effort_limits_.resize(n_dof_);
00104     joint_control_methods_.resize(n_dof_);
00105     pid_controllers_.resize(n_dof_);
00106     joint_position_.resize(n_dof_);
00107     joint_velocity_.resize(n_dof_);
00108     joint_effort_.resize(n_dof_);
00109     joint_effort_command_.resize(n_dof_);
00110     joint_position_command_.resize(n_dof_);
00111     joint_velocity_command_.resize(n_dof_);
00112 
00113     // Initialize values
00114     for(unsigned int j=0; j < n_dof_; j++)
00115     {
00116       // Check that this transmission has one joint
00117       if(transmissions[j].joints_.size() == 0)
00118       {
00119         ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00120           << " has no associated joints.");
00121         continue;
00122       }
00123       else if(transmissions[j].joints_.size() > 1)
00124       {
00125         ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00126           << " has more than one joint. Currently the default robot hardware simulation "
00127           << " interface only supports one.");
00128         continue;
00129       }
00130 
00131       // Check that this transmission has one actuator
00132       if(transmissions[j].actuators_.size() == 0)
00133       {
00134         ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00135           << " has no associated actuators.");
00136         continue;
00137       }
00138       else if(transmissions[j].actuators_.size() > 1)
00139       {
00140         ROS_WARN_STREAM_NAMED("default_robot_hw_sim","Transmission " << transmissions[j].name_
00141           << " has more than one actuator. Currently the default robot hardware simulation "
00142           << " interface only supports one.");
00143         continue;
00144       }
00145 
00146       // Add data from transmission
00147       joint_names_[j] = transmissions[j].joints_[0].name_;
00148       joint_position_[j] = 1.0;
00149       joint_velocity_[j] = 0.0;
00150       joint_effort_[j] = 1.0;  // N/m for continuous joints
00151       joint_effort_command_[j] = 0.0;
00152       joint_position_command_[j] = 0.0;
00153       joint_velocity_command_[j] = 0.0;
00154 
00155 #if ROS_VERSION_MINOR > 10 || ROS_VERSION_MAJOR > 1
00156       const std::string &hardware_interface =
00157         transmissions[j].actuators_[0].hardware_interfaces_[0];
00158 #else
00159       const std::string &hardware_interface =
00160         transmissions[j].actuators_[0].hardware_interface_;
00161 #endif
00162 
00163       // Debug
00164       ROS_DEBUG_STREAM_NAMED("default_robot_hw_sim","Loading joint '" << joint_names_[j]
00165         << "' of type '" << hardware_interface << "'");
00166 
00167       // Create joint state interface for all joints
00168       js_interface_.registerHandle(hardware_interface::JointStateHandle(
00169           joint_names_[j], &joint_position_[j], &joint_velocity_[j], &joint_effort_[j]));
00170 
00171       // Decide what kind of command interface this actuator/joint has
00172       hardware_interface::JointHandle joint_handle;
00173       if(hardware_interface == "EffortJointInterface")
00174       {
00175         // Create effort joint interface
00176         joint_control_methods_[j] = EFFORT;
00177         joint_handle = hardware_interface::JointHandle(js_interface_.getHandle(joint_names_[j]),
00178                                                        &joint_effort_command_[j]);
00179         ej_interface_.registerHandle(joint_handle);
00180       }
00181       else if(hardware_interface == "PositionJointInterface")
00182       {
00183         // Create position joint interface
00184         joint_control_methods_[j] = POSITION;
00185         joint_handle = hardware_interface::JointHandle(js_interface_.getHandle(joint_names_[j]),
00186                                                        &joint_position_command_[j]);
00187         pj_interface_.registerHandle(joint_handle);
00188       }
00189       else if(hardware_interface == "VelocityJointInterface")
00190       {
00191         // Create velocity joint interface
00192         joint_control_methods_[j] = VELOCITY;
00193         joint_handle = hardware_interface::JointHandle(js_interface_.getHandle(joint_names_[j]),
00194                                                        &joint_velocity_command_[j]);
00195         vj_interface_.registerHandle(joint_handle);
00196       }
00197       else
00198       {
00199         ROS_FATAL_STREAM_NAMED("default_robot_hw_sim","No matching hardware interface found for '"
00200           << hardware_interface );
00201         return false;
00202       }
00203 
00204       // Get the gazebo joint that corresponds to the robot joint.
00205       //ROS_DEBUG_STREAM_NAMED("default_robot_hw_sim", "Getting pointer to gazebo joint: "
00206       //  << joint_names_[j]);
00207       gazebo::physics::JointPtr joint = parent_model->GetJoint(joint_names_[j]);
00208       if (!joint)
00209       {
00210         ROS_ERROR_STREAM("This robot has a joint named \"" << joint_names_[j]
00211           << "\" which is not in the gazebo model.");
00212         return false;
00213       }
00214       sim_joints_.push_back(joint);
00215 
00216       registerJointLimits(joint_names_[j], joint_handle, joint_control_methods_[j],
00217                           joint_limit_nh, urdf_model,
00218                           &joint_types_[j], &joint_lower_limits_[j], &joint_upper_limits_[j],
00219                           &joint_effort_limits_[j]);
00220       if (joint_control_methods_[j] != EFFORT)
00221       {
00222         // Initialize the PID controller. If no PID gain values are found, use joint->SetAngle() or
00223         // joint->SetVelocity() to control the joint.
00224         const ros::NodeHandle nh(model_nh, robot_namespace + "/gazebo_ros_control/pid_gains/" +
00225                                  joint_names_[j]);
00226         if (pid_controllers_[j].init(nh))
00227         {
00228           switch (joint_control_methods_[j])
00229           {
00230             case POSITION:
00231               joint_control_methods_[j] = POSITION_PID;
00232               break;
00233             case VELOCITY:
00234               joint_control_methods_[j] = VELOCITY_PID;
00235               break;
00236           }
00237         }
00238         else
00239         {
00240           // joint->SetMaxForce() must be called if joint->SetAngle() or joint->SetVelocity() are
00241           // going to be called. joint->SetMaxForce() must *not* be called if joint->SetForce() is
00242           // going to be called.
00243           joint->SetMaxForce(0, joint_effort_limits_[j]);
00244         }
00245       }
00246     }
00247 
00248     // Register interfaces
00249     registerInterface(&js_interface_);
00250     registerInterface(&ej_interface_);
00251     registerInterface(&pj_interface_);
00252     registerInterface(&vj_interface_);
00253 
00254     return true;
00255   }
00256 
00257   void readSim(ros::Time time, ros::Duration period)
00258   {
00259     for(unsigned int j=0; j < n_dof_; j++)
00260     {
00261       // Gazebo has an interesting API...
00262       if (joint_types_[j] == urdf::Joint::PRISMATIC)
00263       {
00264         joint_position_[j] = sim_joints_[j]->GetAngle(0).Radian();
00265       }
00266       else
00267       {
00268         joint_position_[j] += angles::shortest_angular_distance(joint_position_[j],
00269                               sim_joints_[j]->GetAngle(0).Radian());
00270       }
00271       joint_velocity_[j] = sim_joints_[j]->GetVelocity(0);
00272       joint_effort_[j] = sim_joints_[j]->GetForce((unsigned int)(0));
00273     }
00274   }
00275 
00276   void writeSim(ros::Time time, ros::Duration period)
00277   {
00278     ej_sat_interface_.enforceLimits(period);
00279     ej_limits_interface_.enforceLimits(period);
00280     pj_sat_interface_.enforceLimits(period);
00281     pj_limits_interface_.enforceLimits(period);
00282     vj_sat_interface_.enforceLimits(period);
00283     vj_limits_interface_.enforceLimits(period);
00284 
00285     for(unsigned int j=0; j < n_dof_; j++)
00286     {
00287       switch (joint_control_methods_[j])
00288       {
00289         case EFFORT:
00290           {
00291             const double effort = joint_effort_command_[j];
00292             sim_joints_[j]->SetForce(0, effort);
00293           }
00294           break;
00295 
00296         case POSITION:
00297 #if GAZEBO_MAJOR_VERSION >= 4
00298           sim_joints_[j]->SetPosition(0, joint_position_command_[j]);
00299 #else
00300           sim_joints_[j]->SetAngle(0, joint_position_command_[j]);
00301 #endif
00302           break;
00303 
00304         case POSITION_PID:
00305           {
00306             double error;
00307             switch (joint_types_[j])
00308             {
00309               case urdf::Joint::REVOLUTE:
00310                 angles::shortest_angular_distance_with_limits(joint_position_[j],
00311                                                               joint_position_command_[j],
00312                                                               joint_lower_limits_[j],
00313                                                               joint_upper_limits_[j],
00314                                                               error);
00315                 break;
00316               case urdf::Joint::CONTINUOUS:
00317                 error = angles::shortest_angular_distance(joint_position_[j],
00318                                                           joint_position_command_[j]);
00319                 break;
00320               default:
00321                 error = joint_position_command_[j] - joint_position_[j];
00322             }
00323 
00324             const double effort_limit = joint_effort_limits_[j];
00325             const double effort = clamp(pid_controllers_[j].computeCommand(error, period),
00326                                         -effort_limit, effort_limit);
00327             sim_joints_[j]->SetForce(0, effort);
00328           }
00329           break;
00330 
00331         case VELOCITY:
00332           sim_joints_[j]->SetVelocity(0, joint_velocity_command_[j]);
00333           break;
00334 
00335         case VELOCITY_PID:
00336           const double error = joint_velocity_command_[j] - joint_velocity_[j];
00337           const double effort_limit = joint_effort_limits_[j];
00338           const double effort = clamp(pid_controllers_[j].computeCommand(error, period),
00339                                       -effort_limit, effort_limit);
00340           sim_joints_[j]->SetForce(0, effort);
00341           break;
00342       }
00343     }
00344   }
00345 
00346 private:
00347   // Methods used to control a joint.
00348   enum ControlMethod {EFFORT, POSITION, POSITION_PID, VELOCITY, VELOCITY_PID};
00349 
00350   // Register the limits of the joint specified by joint_name and joint_handle. The limits are
00351   // retrieved from joint_limit_nh. If urdf_model is not NULL, limits are retrieved from it also.
00352   // Return the joint's type, lower position limit, upper position limit, and effort limit.
00353   void registerJointLimits(const std::string& joint_name,
00354                            const hardware_interface::JointHandle& joint_handle,
00355                            const ControlMethod ctrl_method,
00356                            const ros::NodeHandle& joint_limit_nh,
00357                            const urdf::Model *const urdf_model,
00358                            int *const joint_type, double *const lower_limit,
00359                            double *const upper_limit, double *const effort_limit)
00360   {
00361     *joint_type = urdf::Joint::UNKNOWN;
00362     *lower_limit = -std::numeric_limits<double>::max();
00363     *upper_limit = std::numeric_limits<double>::max();
00364     *effort_limit = std::numeric_limits<double>::max();
00365 
00366     joint_limits_interface::JointLimits limits;
00367     bool has_limits = false;
00368     joint_limits_interface::SoftJointLimits soft_limits;
00369     bool has_soft_limits = false;
00370 
00371     if (urdf_model != NULL)
00372     {
00373       const boost::shared_ptr<const urdf::Joint> urdf_joint = urdf_model->getJoint(joint_name);
00374       if (urdf_joint != NULL)
00375       {
00376         *joint_type = urdf_joint->type;
00377         // Get limits from the URDF file.
00378         if (joint_limits_interface::getJointLimits(urdf_joint, limits))
00379           has_limits = true;
00380         if (joint_limits_interface::getSoftJointLimits(urdf_joint, soft_limits))
00381           has_soft_limits = true;
00382       }
00383     }
00384     // Get limits from the parameter server.
00385     if (joint_limits_interface::getJointLimits(joint_name, joint_limit_nh, limits))
00386       has_limits = true;
00387 
00388     if (!has_limits)
00389       return;
00390 
00391     if (*joint_type == urdf::Joint::UNKNOWN)
00392     {
00393       // Infer the joint type.
00394 
00395       if (limits.has_position_limits)
00396       {
00397         *joint_type = urdf::Joint::REVOLUTE;
00398       }
00399       else
00400       {
00401         if (limits.angle_wraparound)
00402           *joint_type = urdf::Joint::CONTINUOUS;
00403         else
00404           *joint_type = urdf::Joint::PRISMATIC;
00405       }
00406     }
00407 
00408     if (limits.has_position_limits)
00409     {
00410       *lower_limit = limits.min_position;
00411       *upper_limit = limits.max_position;
00412     }
00413     if (limits.has_effort_limits)
00414       *effort_limit = limits.max_effort;
00415 
00416     if (has_soft_limits)
00417     {
00418       switch (ctrl_method)
00419       {
00420         case EFFORT:
00421           {
00422             const joint_limits_interface::EffortJointSoftLimitsHandle
00423               limits_handle(joint_handle, limits, soft_limits);
00424             ej_limits_interface_.registerHandle(limits_handle);
00425           }
00426           break;
00427         case POSITION:
00428           {
00429             const joint_limits_interface::PositionJointSoftLimitsHandle
00430               limits_handle(joint_handle, limits, soft_limits);
00431             pj_limits_interface_.registerHandle(limits_handle);
00432           }
00433           break;
00434         case VELOCITY:
00435           {
00436             const joint_limits_interface::VelocityJointSoftLimitsHandle
00437               limits_handle(joint_handle, limits, soft_limits);
00438             vj_limits_interface_.registerHandle(limits_handle);
00439           }
00440           break;
00441       }
00442     }
00443     else
00444     {
00445       switch (ctrl_method)
00446       {
00447         case EFFORT:
00448           {
00449             const joint_limits_interface::EffortJointSaturationHandle
00450               sat_handle(joint_handle, limits);
00451             ej_sat_interface_.registerHandle(sat_handle);
00452           }
00453           break;
00454         case POSITION:
00455           {
00456             const joint_limits_interface::PositionJointSaturationHandle
00457               sat_handle(joint_handle, limits);
00458             pj_sat_interface_.registerHandle(sat_handle);
00459           }
00460           break;
00461         case VELOCITY:
00462           {
00463             const joint_limits_interface::VelocityJointSaturationHandle
00464               sat_handle(joint_handle, limits);
00465             vj_sat_interface_.registerHandle(sat_handle);
00466           }
00467           break;
00468       }
00469     }
00470   }
00471 
00472   unsigned int n_dof_;
00473 
00474   hardware_interface::JointStateInterface    js_interface_;
00475   hardware_interface::EffortJointInterface   ej_interface_;
00476   hardware_interface::PositionJointInterface pj_interface_;
00477   hardware_interface::VelocityJointInterface vj_interface_;
00478 
00479   joint_limits_interface::EffortJointSaturationInterface   ej_sat_interface_;
00480   joint_limits_interface::EffortJointSoftLimitsInterface   ej_limits_interface_;
00481   joint_limits_interface::PositionJointSaturationInterface pj_sat_interface_;
00482   joint_limits_interface::PositionJointSoftLimitsInterface pj_limits_interface_;
00483   joint_limits_interface::VelocityJointSaturationInterface vj_sat_interface_;
00484   joint_limits_interface::VelocityJointSoftLimitsInterface vj_limits_interface_;
00485 
00486   std::vector<std::string> joint_names_;
00487   std::vector<int> joint_types_;
00488   std::vector<double> joint_lower_limits_;
00489   std::vector<double> joint_upper_limits_;
00490   std::vector<double> joint_effort_limits_;
00491   std::vector<ControlMethod> joint_control_methods_;
00492   std::vector<control_toolbox::Pid> pid_controllers_;
00493   std::vector<double> joint_position_;
00494   std::vector<double> joint_velocity_;
00495   std::vector<double> joint_effort_;
00496   std::vector<double> joint_effort_command_;
00497   std::vector<double> joint_position_command_;
00498   std::vector<double> joint_velocity_command_;
00499 
00500   std::vector<gazebo::physics::JointPtr> sim_joints_;
00501 };
00502 
00503 typedef boost::shared_ptr<DefaultRobotHWSim> DefaultRobotHWSimPtr;
00504 
00505 }
00506 
00507 PLUGINLIB_EXPORT_CLASS(gazebo_ros_control::DefaultRobotHWSim, gazebo_ros_control::RobotHWSim)
00508 
00509 #endif // #ifndef __GAZEBO_ROS_CONTROL_PLUGIN_DEFAULT_ROBOT_HW_SIM_H_


gazebo_ros_control
Author(s): Jonathan Bohren, Dave Coleman
autogenerated on Fri Aug 28 2015 10:47:54