gazebo_ros_actuator_array.cpp
Go to the documentation of this file.
00001 /*
00002  *  Copyright (c) 2011, A.M.Howard, S.Williams
00003  *  All rights reserved.
00004  *
00005  *  Redistribution and use in source and binary forms, with or without
00006  *  modification, are permitted provided that the following conditions are met:
00007  *      * Redistributions of source code must retain the above copyright
00008  *        notice, this list of conditions and the following disclaimer.
00009  *      * Redistributions in binary form must reproduce the above copyright
00010  *        notice, this list of conditions and the following disclaimer in the
00011  *        documentation and/or other materials provided with the distribution.
00012  *      * Neither the name of the <organization> nor the
00013  *        names of its contributors may be used to endorse or promote products
00014  *        derived from this software without specific prior written permission.
00015  *
00016  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019  *  DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
00020  *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 /*
00028  * gazebo_ros_actuator_array.cpp
00029  *
00030  *  Created on: Feb 6, 2011
00031  *      Author: Stephen Williams
00032  */
00033 
00034 #include <limits>
00035 
00036 #include <gazebo/Global.hh>
00037 #include <gazebo/XMLConfig.hh>
00038 #include <gazebo/Simulator.hh>
00039 #include <gazebo/gazebo.h>
00040 #include <gazebo/GazeboError.hh>
00041 #include <gazebo/ControllerFactory.hh>
00042 
00043 #include <angles/angles.h>
00044 #include <urdf/model.h>
00045 
00046 #include <actuator_array_gazebo_plugin/gazebo_ros_actuator_array.h>
00047 
00048 namespace gazebo
00049 {
00050 
00051 GZ_REGISTER_DYNAMIC_CONTROLLER("gazebo_ros_actuator_array", GazeboRosActuatorArray);
00052 
00054 // Constructor
00055 GazeboRosActuatorArray::GazeboRosActuatorArray(Entity *parent) :
00056   Controller(parent)
00057 {
00058   this->myParent = dynamic_cast<Model*> (this->parent);
00059 
00060   if (!this->myParent)
00061     gzthrow("GazeboRosActuatorArray controller requires a Model as its parent");
00062 
00063   Param::Begin(&this->parameters);
00064   this->robotNamespaceP = new ParamT<std::string> ("robotNamespace", "/", 0);
00065   this->robotParamP = new ParamT<std::string> ("robotParam", "robot_description", 1);
00066   Param::End();
00067 }
00068 
00070 // Destructor
00071 GazeboRosActuatorArray::~GazeboRosActuatorArray()
00072 {
00073   delete this->robotNamespaceP;
00074   delete this->robotParamP;
00075 }
00076 
00078 // Load the controller
00079 void GazeboRosActuatorArray::LoadChild(XMLConfigNode *node)
00080 {
00081   this->robotNamespaceP->Load(node);
00082   this->robot_namespace_ = this->robotNamespaceP->GetValue();
00083   this->robotParamP->Load(node);
00084   this->robot_description_parameter_ = this->robotParamP->GetValue();
00085 
00086   int argc = 0;
00087   char** argv = NULL;
00088   ros::init(argc, argv, "gazebo", ros::init_options::NoSigintHandler | ros::init_options::AnonymousName);
00089   ros::NodeHandle ros_node = ros::NodeHandle(this->robot_namespace_);
00090 
00091 
00092   // Read the list of joints specified in the controller (as child nodes)
00093   // This is done instead of using the provided function 'parse_actuator_list' in the base class
00094   std::string joint_name;
00095   unsigned int joint_index = 0;
00096   double kp, ki, kd, imax, imin;
00097   gazebo::XMLConfigNode *child_node;
00098   child_node = node->GetChild("joint");
00099   while (child_node)
00100   {
00101     joint_name = child_node->GetString("name", "", 1);
00102     kp = child_node->GetDouble("p", 1.0, 0);
00103     ki = child_node->GetDouble("i", 0.0, 0);
00104     kd = child_node->GetDouble("d", 0.0, 0);
00105     imax = child_node->GetDouble("iClamp", 0.0, 0);
00106     imin = -imax;
00107 
00108     // Check that the joint exists
00109     if (dynamic_cast<gazebo::Joint*> (this->myParent->GetJoint(joint_name)) == NULL)
00110     {
00111       ROS_FATAL("GazeboRosActuatorArray plugin error: joint: %s does not exist\n", joint_name.c_str());
00112     }
00113     else
00114     {
00115       GazeboJointProperties joint;
00116       joint.joint_index = joint_index++;
00117       joint.joint_ptr = dynamic_cast<gazebo::Joint*> (this->myParent->GetJoint(joint_name));
00118       joint.pid.initPid(kp, ki, kd, imax, imin);
00119       joint.position = 0.0;
00120       joint.home_position = child_node->GetDouble("home", 0.0, 0);
00121 
00122       // Add joint to list
00123       this->joints_[joint_name] = joint;
00124     }
00125 
00126     child_node = child_node->GetNext("joint");
00127   }
00128 
00129   // Read additional properties from the URDF
00130   parse_urdf(ros_node);
00131 
00132   // Resize joint_state, controller_state for the proper number of joints
00133   unsigned int joint_count = this->joints_.size();
00134   this->joint_state_msg_.name.resize(joint_count);
00135   this->joint_state_msg_.position.resize(joint_count);
00136   this->joint_state_msg_.velocity.resize(joint_count);
00137   this->joint_state_msg_.effort.resize(joint_count);
00138   this->command_msg_.name.resize(joint_count);
00139   this->command_msg_.position.resize(joint_count);
00140   this->command_msg_.velocity.resize(joint_count);
00141   this->command_msg_.effort.resize(joint_count);
00142   for(std::map<std::string, GazeboJointProperties>::iterator joint = joints_.begin(); joint != joints_.end(); ++joint)
00143   {
00144     const std::string& joint_name = joint->first;
00145     GazeboJointProperties& joint_properties = joint->second;
00146 
00147     // Fill in any properties provided by the URDF for this joint
00148     update_joint_from_urdf(joint_name, joint_properties);
00149 
00150     // Copy Home position for each joint into the commanded position
00151     this->command_msg_.position[joint_properties.joint_index] = joint_properties.home_position;
00152 
00153     // Add joint names to the joint state messages
00154     this->joint_state_msg_.name[joint_properties.joint_index] = joint_name;
00155     this->command_msg_.name[joint_properties.joint_index] = joint_name;
00156   }
00157 
00158   // read in mimic joint properties
00159   parse_mimic_joints(ros_node);
00160 
00161   // Advertise and subscribe to the required services and topics
00162   // Because Gazebo uses a custom message queue, this is done instead of using the
00163   // provided function 'advertise_and_subscribe' in the base class
00164 #ifdef USE_CBQ
00165 
00166   // subscribe to JointState commands
00167   ros::SubscribeOptions so = ros::SubscribeOptions::create<sensor_msgs::JointState>("command", 1,
00168                                                                                     boost::bind(&GazeboRosActuatorArray::command_callback, this, _1),
00169                                                                                     ros::VoidPtr(), &this->queue_);
00170   this->command_sub_ = ros_node.subscribe(so);
00171 
00172   // advertise Stop service
00173   ros::AdvertiseServiceOptions stop_aso = ros::AdvertiseServiceOptions::create<std_srvs::Empty>("stop",
00174                                                                                                 boost::bind(&GazeboRosActuatorArray::stop_callback, this, _1, _2),
00175                                                                                                 ros::VoidPtr(), &this->queue_);
00176   this->stop_srv_ = ros_node.advertiseService(stop_aso);
00177 
00178   // advertise Home service
00179   ros::AdvertiseServiceOptions home_aso = ros::AdvertiseServiceOptions::create<std_srvs::Empty>("home",
00180                                                                                                 boost::bind(&GazeboRosActuatorArray::home_callback, this, _1, _2),
00181                                                                                                 ros::VoidPtr(), &this->queue_);
00182   this->home_srv_ = ros_node.advertiseService(home_aso);
00183 
00184   // advertise JointState messages
00185   ros::AdvertiseOptions joint_state_ao = ros::AdvertiseOptions::create<sensor_msgs::JointState>("joint_states", 1,
00186                                                                                               ros::SubscriberStatusCallback(),
00187                                                                                               ros::SubscriberStatusCallback(),
00188                                                                                               ros::VoidPtr(), &this->queue_);
00189   this->joint_state_pub_ = ros_node.advertise(joint_state_ao);
00190 
00191 #else
00192   this->command_sub_ = ros_node.subscribe<sensor_msgs::JointState>("command", 1, boost::bind(&GazeboRosActuatorArray::command_callback, this, _1));
00193   this->stop_srv_ = ros_node.advertiseService<std_srvs::Empty>("stop", boost::bind(&GazeboRosActuatorArray::stop_callback, this, _1, _2));
00194   this->home_srv_ = ros_node.advertiseService<std_srvs::Empty>("home", boost::bind(&GazeboRosActuatorArray::home_callback, this, _1, _2));
00195   this->joint_state_pub_ = ros_node.advertise<sensor_msgs::JointState>("joint_states", 1);
00196 #endif
00197 
00198 }
00199 
00201 // Initialize the controller
00202 void GazeboRosActuatorArray::InitChild()
00203 {
00204   // Get the current time
00205   this->last_time_ = Simulator::Instance()->GetSimTime();
00206 
00207 #ifdef USE_CBQ
00208   // start custom queue
00209   this->callback_queue_thread_ = boost::thread(boost::bind(&GazeboRosActuatorArray::QueueThread, this));
00210 #endif
00211 }
00212 
00214 // Update the controller
00215 void GazeboRosActuatorArray::UpdateChild()
00216 {
00217   // Get the current time for the message header
00218   gazebo::Time current_time = Simulator::Instance()->GetSimTime();
00219   double dt = (current_time - this->last_time_).Double();
00220 
00221 
00222   this->lock_.lock();
00223 
00224   // Update the JointState message
00225   this->joint_state_msg_.header.stamp.sec = current_time.sec;
00226   this->joint_state_msg_.header.stamp.nsec = current_time.nsec;
00227 
00228   //  Update PID loops, and Copy the state from the gazebo joints into a JointState message
00229   for(std::map<std::string, GazeboJointProperties>::iterator joint = this->joints_.begin(); joint != this->joints_.end(); ++joint)
00230   {
00231     GazeboJointProperties& joint_properties = joint->second;
00232 
00233     if (!joint_properties.joint_ptr)
00234       continue;
00235 
00236     // Update the PID loop and send command to joint
00237     update_joint(joint_properties, this->command_msg_.position[joint_properties.joint_index], this->command_msg_.velocity[joint_properties.joint_index], this->command_msg_.effort[joint_properties.joint_index], dt);
00238 
00239     // Update the JointState message
00240     this->joint_state_msg_.position[joint_properties.joint_index] = joint_properties.position;
00241     this->joint_state_msg_.velocity[joint_properties.joint_index] = joint_properties.joint_ptr->GetVelocity(0);
00242     this->joint_state_msg_.effort[joint_properties.joint_index] = joint_properties.joint_ptr->GetForce(0);
00243   }
00244 
00245   // Send commands to Mimic Joints
00246   for(std::map<std::string, MimicJointProperties>::iterator joint = this->mimic_joints_.begin(); joint != this->mimic_joints_.end(); ++joint)
00247   {
00248     MimicJointProperties& joint_properties = joint->second;
00249 
00250     if (!joint_properties.joint_ptr)
00251       continue;
00252 
00253     // Calculate the target position based on the master joint
00254     double command_position = joint_properties.multiplier*(this->command_msg_.position[joint_properties.master_joint_index] - joint_properties.offset);
00255     double command_velocity = joint_properties.multiplier*(this->command_msg_.velocity[joint_properties.master_joint_index]);
00256 
00257     // Update the PID loop and send command to joint
00258     update_joint(joint_properties, command_position, command_velocity, 0, dt);
00259   }
00260 
00261   // Publish joint state
00262   if(this->joint_state_pub_.getNumSubscribers() > 0)
00263   {
00264     this->joint_state_pub_.publish(this->joint_state_msg_);
00265   }
00266 
00267   this->lock_.unlock();
00268 
00269 
00270   // save last time stamp
00271   this->last_time_ = current_time;
00272 }
00273 
00275 // Finalize the controller
00276 void GazeboRosActuatorArray::FiniChild()
00277 {
00278 #ifdef USE_CBQ
00279   this->queue_.clear();
00280   this->queue_.disable();
00281   this->callback_queue_thread_.join();
00282 #endif
00283 }
00284 
00285 #ifdef USE_CBQ
00286 
00287 // The thread responsible for managing the message queue
00288 void GazeboRosActuatorArray::QueueThread()
00289 {
00290   static const double timeout = 0.01;
00291 
00292   ros::NodeHandle node;
00293   while (node.ok())
00294   {
00295     this->queue_.callAvailable(ros::WallDuration(timeout));
00296   }
00297 }
00298 #endif
00299 
00301 // ???
00302 void GazeboRosActuatorArray::update_joint(GazeboJointProperties& joint, double command_position, double command_velocity, double command_effort, double dt)
00303 {
00304   // Calculate the new joint position and the joint error based on type
00305   double error = 0.0;
00306   switch(joint.joint_ptr->GetType())
00307   {
00308     // Update the joint position based of the joint type
00309     case gazebo::Joint::HINGE:
00310     {
00311       joint.position = joint.position + angles::shortest_angular_distance(joint.position, joint.joint_ptr->GetAngle(0).GetAsRadian());
00312       angles::shortest_angular_distance_with_limits(command_position, joint.position, joint.min_position, joint.max_position, error);
00313       break;
00314     }
00315     case gazebo::Joint::SLIDER:
00316     {
00317       joint.position = joint.joint_ptr->GetAngle(0).GetAsRadian();
00318       error = joint.position - command_position;
00319       break;
00320     }
00321     default:
00322     {
00323       abort();
00324     }
00325   }
00326 
00327   // Update the PID for this joint and get the joint command
00328   joint.pid.setCurrentCmd(command_position);
00329   double velocity = joint.pid.updatePid(error, ros::Duration(dt));
00330 
00331   // Limit command to max velocity provided in the robot_description
00332   if(joint.has_velocity_limits)
00333   {
00334     if(velocity > joint.max_velocity)
00335     {
00336       velocity = joint.max_velocity;
00337     }
00338     else if(velocity < -joint.max_velocity)
00339     {
00340       velocity = -joint.max_velocity;
00341     }
00342   }
00343 
00344   // Limit command velocity to max velocity provided by the command_msg (if any)
00345   if(command_velocity > 0)
00346   {
00347     if(velocity > command_velocity)
00348     {
00349       velocity = command_velocity;
00350     }
00351     else if(velocity < -command_velocity)
00352     {
00353       velocity = -command_velocity;
00354     }
00355   }
00356 
00357   // Limit effort to the smaller of the maximum joint effort and the commanded effort
00358   double effort = std::numeric_limits<float>::max();
00359   if(joint.has_effort_limits)
00360   {
00361     effort = std::min(effort, joint.max_effort);
00362   }
00363   if(command_effort > 0)
00364   {
00365     effort = std::min(effort, command_effort);
00366   }
00367 
00368   // Send command to joint
00369   joint.joint_ptr->SetVelocity(0, velocity);
00370   joint.joint_ptr->SetMaxForce(0, effort);
00371 }
00372 
00374 // Gazebo has a special class of joint called a 'Mimic Joint'. This allows one joint
00375 // to control the behavior of one or more mimic joints. This is perhaps most useful
00376 // for situations where a single motion controls multiple links through some sort of
00377 // complex drive train that does not need to be explicitly modeled. Instead, a multiplier
00378 // (similar to gear ratio) is supplied. This function parses the robot description for
00379 // these special Gazebo joints and stores them in a secondary map.
00380 void GazeboRosActuatorArray::parse_mimic_joints(const ros::NodeHandle& node)
00381 {
00382   // Construct a model from the robot description parameter
00383   std::string full_name = node.resolveName(this->robot_description_parameter_);
00384   urdf::Model urdf_model;
00385   while(!node.hasParam(full_name))
00386   {
00387     ROS_INFO("ActuatorArrayDriver: waiting for robot_description at %s on the parameter server.", full_name.c_str());
00388     usleep(100000);
00389   }
00390   urdf_model.initParam(full_name);
00391 
00392   // Loop over all joints and check for "mimic" data
00393   std::map< std::string, boost::shared_ptr< urdf::Joint > >::const_iterator urdf_joint_map;
00394   for(urdf_joint_map = urdf_model.joints_.begin(); urdf_joint_map != urdf_model.joints_.end(); ++urdf_joint_map)
00395   {
00396     // Check if the joint has a "mimic" element
00397     const boost::shared_ptr< urdf::Joint >& urdf_joint = urdf_joint_map->second;
00398     if(urdf_joint->mimic)
00399     {
00400       // Find the parent joint
00401       std::map<std::string, GazeboJointProperties>::iterator parent_joint = joints_.find(urdf_joint->mimic->joint_name);
00402 
00403       // If the parent joint is a controlled joint, add it to the mimic list
00404       if((parent_joint != joints_.end()) && (dynamic_cast<gazebo::Joint*> (this->myParent->GetJoint(urdf_joint->name))))
00405       {
00406         const std::string& parent_name = parent_joint->first;
00407         GazeboJointProperties& parent_properties = parent_joint->second;
00408 
00409         std::string mimic_name = urdf_joint->name;
00410         MimicJointProperties mimic_properties;
00411 
00412         // Store joint properties from the urdf
00413         if(urdf_joint->limits)
00414         {
00415           mimic_properties.min_position = urdf_joint->limits->lower;
00416           mimic_properties.max_position = urdf_joint->limits->upper;
00417           mimic_properties.has_position_limits = (mimic_properties.max_position > mimic_properties.min_position);
00418           mimic_properties.max_velocity = urdf_joint->limits->velocity;
00419           mimic_properties.has_velocity_limits = (mimic_properties.max_velocity > 0.0);
00420           mimic_properties.max_effort = urdf_joint->limits->effort;
00421           mimic_properties.has_effort_limits = (mimic_properties.max_effort > 0.0);
00422         }
00423 
00424         if(urdf_joint->dynamics)
00425         {
00426           mimic_properties.damping = urdf_joint->dynamics->damping;
00427           mimic_properties.friction = urdf_joint->dynamics->friction;
00428         }
00429 
00430         // Store additional Gazebo properties
00431         double kp, ki, kd, imax, imin;
00432         parent_properties.pid.getGains(kp, ki, kd, imax, imin);
00433         mimic_properties.joint_ptr = dynamic_cast<gazebo::Joint*> (this->myParent->GetJoint(mimic_name));
00434         mimic_properties.pid.initPid(kp, ki, kd, imax, imin);
00435         mimic_properties.position = 0.0;
00436         mimic_properties.master_joint_index = parent_properties.joint_index;
00437         mimic_properties.master_joint_name = parent_name;
00438         mimic_properties.multiplier = urdf_joint->mimic->multiplier;
00439         mimic_properties.offset = urdf_joint->mimic->offset;
00440 
00441         // Add joint to list
00442         this->mimic_joints_[mimic_name] = mimic_properties;
00443 
00444       } // end: if
00445     } // end: if(urdf_joint->mimic)
00446   } // end: for(urdf_joint_map
00447 
00448 }
00449 
00451 // Function to execute when a command message is received
00452 bool GazeboRosActuatorArray::command_()
00453 {
00454   // the Gazebo Update() function actually handles changing the joint positions. Do nothing here.
00455   return true;
00456 }
00457 
00459 // Function to execute when a 'stop' command is received
00460 bool GazeboRosActuatorArray::stop_()
00461 {
00462   for(unsigned int i = 0; i < this->command_msg_.name.size(); ++i)
00463   {
00464     const GazeboJointProperties& joint_properties = joints_[this->command_msg_.name[i]];
00465 
00466     this->command_msg_.position[i] = joint_properties.position;
00467     this->command_msg_.velocity[i] = 0.0;
00468     this->command_msg_.effort[i] = 0.0;
00469   }
00470 
00471   return true;
00472 }
00473 
00475 // Function to execute when the 'home' command is received
00476 bool GazeboRosActuatorArray::home_()
00477 {
00478   for(unsigned int i = 0; i < this->command_msg_.name.size(); ++i)
00479   {
00480     const GazeboJointProperties& joint_properties = joints_[this->command_msg_.name[i]];
00481 
00482     this->command_msg_.position[i] = joint_properties.home_position;
00483     this->command_msg_.velocity[i] = 0.0;
00484     this->command_msg_.effort[i] = 0.0;
00485   }
00486 
00487   return true;
00488 }
00489 
00491 // Function to execute during every 'read' cycle
00492 bool GazeboRosActuatorArray::read_(ros::Time ts)
00493 {
00494   // the Gazebo Update() function actually handles changing the joint positions. Do nothing here.
00495   return true;
00496 }
00497 
00498 }


actuator_array_gazebo_plugin
Author(s): Stephen Williams
autogenerated on Wed Nov 27 2013 12:00:55