IOBPlugin.cpp
Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string>
00004 
00005 #include <gazebo/transport/Node.hh>
00006 #include <gazebo/common/Assert.hh>
00007 
00008 #include "IOBPlugin.h"
00009 
00010 namespace gazebo
00011 {
00012 GZ_REGISTER_MODEL_PLUGIN(IOBPlugin);
00013 
00014 IOBPlugin::IOBPlugin() {
00015 }
00016 
00017 IOBPlugin::~IOBPlugin() {
00018 }
00019 
00020 void IOBPlugin::Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf) {
00021 
00022   this->robot_name = "default";
00023   if (_sdf->HasElement("robotname")) {
00024     this->robot_name = _sdf->GetValueString("robotname");
00025   }
00026   this->controller_name = "default_controller";
00027   if (_sdf->HasElement("controller")) {
00028     this->controller_name = _sdf->GetValueString("controller");
00029   }
00030 
00031   // initialize ros
00032   if (!ros::isInitialized()) {
00033     gzerr << "Not loading plugin since ROS hasn't been "
00034           << "properly initialized.  Try starting gazebo with ros plugin:\n"
00035           << "  gazebo -s libgazebo_ros_api_plugin.so\n";
00036     return;
00037   }
00038 
00039   // ros node
00040   this->rosNode = new ros::NodeHandle("");
00041 
00042   this->model = _parent;
00043   this->world = this->model->GetWorld();
00044 
00045   // save sdf
00046   this->sdf = _sdf;
00047 
00048   // initialize update time
00049   this->lastControllerUpdateTime = this->world->GetSimTime();
00050 
00051   // creating joints from ros param
00052   if (this->rosNode->hasParam(this->controller_name)) {
00053     XmlRpc::XmlRpcValue param_val;
00054     this->rosNode->getParam(this->controller_name, param_val);
00055     if (param_val.getType() ==  XmlRpc::XmlRpcValue::TypeStruct) {
00056       std::string rname = param_val["robotname"];
00057       XmlRpc::XmlRpcValue joint_lst = param_val["joints"];
00058       XmlRpc::XmlRpcValue fsensors = param_val["force_torque_sensors"];
00059       XmlRpc::XmlRpcValue imusensors = param_val["imu_sensors"];
00060       ROS_INFO("robotname: %s", rname.c_str());
00061       // joint name
00062       if (joint_lst.getType() == XmlRpc::XmlRpcValue::TypeArray) {
00063         for(int s = 0; s < joint_lst.size(); s++) {
00064           std::string n = joint_lst[s];
00065           ROS_INFO("add joint: %s", n.c_str());
00066           this->jointNames.push_back(n);
00067         }
00068       } else {
00069         ROS_WARN("Controlled Joints: no setting exists");
00070       }
00071       if (fsensors.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00072         for(XmlRpc::XmlRpcValue::iterator f = fsensors.begin(); f != fsensors.end(); f++) {
00073           std::string sensor_name = f->first;
00074           if (f->second.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00075             std::string jn = f->second["joint_name"];
00076             std::string fi = f->second["frame_id"];
00077             ROS_INFO("force: %s, %s %s", sensor_name.c_str(), jn.c_str(), fi.c_str());
00078 
00079             struct force_sensor_info fsi;
00080             fsi.joint = this->model->GetJoint(jn);
00081             if(!fsi.joint) {
00082               gzerr << "force torque joint (" << jn << ") not found\n";
00083             } else {
00084               fsi.joint_name = jn;
00085               fsi.frame_id = fi;
00086               sensorJoints[sensor_name] = fsi;
00087             }
00088           } else {
00089             ROS_ERROR("Force-Torque sensor: %s has invalid configuration", sensor_name.c_str());
00090           }
00091         }
00092       } else {
00093         ROS_WARN("Force-Torque sensor: no setting exists");
00094       }
00095       if (imusensors.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00096         for(XmlRpc::XmlRpcValue::iterator im = imusensors.begin(); im != imusensors.end(); im++) {
00097           std::string sensor_name = im->first;
00098           if (im->second.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
00099             std::string sn = im->second["name"];
00100             std::string ln = im->second["link_name"];
00101             std::string fi = im->second["frame_id"];
00102             ROS_INFO("imu: %s, %s, %s, %s", sensor_name.c_str(), sn.c_str(),
00103                      ln.c_str(), fi.c_str());
00104 
00105             struct imu_sensor_info msi;
00106             msi.sensor_name = sn;
00107             msi.frame_id = fi;
00108             msi.link = this->model->GetLink(ln);
00109 
00110             if (!msi.link)  {
00111               gzerr << ln << " not found\n";
00112             } else {
00113               // Get imu sensors
00114               msi.sensor = boost::shared_dynamic_cast<sensors::ImuSensor>
00115                 (sensors::SensorManager::Instance()->GetSensor
00116                  (this->world->GetName() + "::" + msi.link->GetScopedName() + "::" + msi.sensor_name));
00117 
00118               if (!msi.sensor)  {
00119                 gzerr << sensor_name << "("                             \
00120                       << (this->world->GetName() + "::" + msi.link->GetScopedName() + "::" + msi.sensor_name) \
00121                       <<" not found\n" << "\n";
00122               }
00123               imuSensors[sensor_name] = msi;
00124             }
00125           } else {
00126             ROS_ERROR("IMU sensor: %s has invalid configuration", sensor_name.c_str());
00127           }
00128         }
00129       } else {
00130         ROS_WARN("IMU sensor: no setting exists");
00131       }
00132     } else {
00133       ROS_WARN_STREAM("param: " << this->controller_name << ", configuration is not an array.");
00134     }
00135   } else {
00136     ROS_ERROR_STREAM("controller: " << this->controller_name << " has no parameter.");
00137   }
00138 
00139   // get pointers to joints from gazebo
00140   this->joints.resize(this->jointNames.size());
00141   ROS_INFO("joints size = %ld", this->joints.size());
00142   for (unsigned int i = 0; i < this->joints.size(); ++i) {
00143     this->joints[i] = this->model->GetJoint(this->jointNames[i]);
00144     if (!this->joints[i])  {
00145       ROS_ERROR("%s robot expected joint[%s] not present, plugin not loaded",
00146                 this->robot_name.c_str(), this->jointNames[i].c_str());
00147       return;
00148     }
00149   }
00150 
00151   // get effort limits from gazebo
00152   this->effortLimit.resize(this->jointNames.size());
00153   for (unsigned i = 0; i < this->effortLimit.size(); ++i) {
00154     this->effortLimit[i] = this->joints[i]->GetEffortLimit(0);
00155     ROS_DEBUG("effort_limit: %s %f", this->joints[i]->GetName().c_str(), this->joints[i]->GetEffortLimit(0));
00156   }
00157 
00158   {
00159     // initialize PID states: error terms
00160     this->errorTerms.resize(this->joints.size());
00161     for (unsigned i = 0; i < this->errorTerms.size(); ++i) {
00162       this->errorTerms[i].q_p = 0;
00163       this->errorTerms[i].d_q_p_dt = 0;
00164       this->errorTerms[i].k_i_q_i = 0;
00165       this->errorTerms[i].qd_p = 0;
00166     }
00167   }
00168 
00169   {
00170     // We are not sending names due to the fact that there is an enum
00171     // joint indices in ...
00172     this->robotState.position.resize(this->joints.size());
00173     this->robotState.velocity.resize(this->joints.size());
00174     this->robotState.effort.resize(this->joints.size());
00175     this->robotState.kp_position.resize(this->joints.size());
00176     this->robotState.ki_position.resize(this->joints.size());
00177     this->robotState.kd_position.resize(this->joints.size());
00178     this->robotState.kp_velocity.resize(this->joints.size());
00179     this->robotState.i_effort_min.resize(this->joints.size());
00180     this->robotState.i_effort_max.resize(this->joints.size());
00181   }
00182 
00183   {
00184     this->jointCommand.position.resize(this->joints.size());
00185     this->jointCommand.velocity.resize(this->joints.size());
00186     this->jointCommand.effort.resize(this->joints.size());
00187     this->jointCommand.kp_position.resize(this->joints.size());
00188     this->jointCommand.ki_position.resize(this->joints.size());
00189     this->jointCommand.kd_position.resize(this->joints.size());
00190     this->jointCommand.kp_velocity.resize(this->joints.size());
00191     this->jointCommand.i_effort_min.resize(this->joints.size());
00192     this->jointCommand.i_effort_max.resize(this->joints.size());
00193 
00194     this->ZeroJointCommand();
00195   }
00196 
00197   // ros callback queue for processing subscription
00198   this->deferredLoadThread = boost::thread(boost::bind(&IOBPlugin::DeferredLoad, this));
00199 }
00200 
00201 void IOBPlugin::ZeroJointCommand() {
00202   for (unsigned i = 0; i < this->jointNames.size(); ++i) {
00203     this->jointCommand.position[i] = 0;
00204     this->jointCommand.velocity[i] = 0;
00205     this->jointCommand.effort[i] = 0;
00206     // store these directly on altasState, more efficient for pub later
00207     this->robotState.kp_position[i] = 0;
00208     this->robotState.ki_position[i] = 0;
00209     this->robotState.kd_position[i] = 0;
00210     this->robotState.kp_velocity[i] = 0;
00211     this->robotState.i_effort_min[i] = 0;
00212     this->robotState.i_effort_max[i] = 0;
00213   }
00214   this->jointCommand.desired_controller_period_ms = 0;
00215 }
00216 
00217 void IOBPlugin::LoadPIDGainsFromParameter() {
00218   // pull down controller parameters
00219   std::string namestr(this->controller_name);
00220 
00221   for (unsigned int i = 0; i < this->joints.size(); ++i) {
00222     std::string joint_ns(namestr);
00223     joint_ns += ("/gains/" + this->joints[i]->GetName() + "/");
00224 
00225     // this is so ugly
00226     double p_val = 0, i_val = 0, d_val = 0, i_clamp_val = 0;
00227     std::string p_str = std::string(joint_ns)+"p";
00228     std::string i_str = std::string(joint_ns)+"i";
00229     std::string d_str = std::string(joint_ns)+"d";
00230     std::string i_clamp_str = std::string(joint_ns)+"i_clamp";
00231     if (!this->rosNode->getParam(p_str, p_val) ||
00232         !this->rosNode->getParam(i_str, i_val) ||
00233         !this->rosNode->getParam(d_str, d_val) ||
00234         !this->rosNode->getParam(i_clamp_str, i_clamp_val))
00235       {
00236         ROS_ERROR("couldn't find a param for %s", joint_ns.c_str());
00237         continue;
00238       }
00239     // store these directly on altasState, more efficient for pub later
00240     this->robotState.kp_position[i]  =  p_val;
00241     this->robotState.ki_position[i]  =  i_val;
00242     this->robotState.kd_position[i]  =  d_val;
00243     this->robotState.i_effort_min[i] = -i_clamp_val;
00244     this->robotState.i_effort_max[i] =  i_clamp_val;
00245   }
00246 }
00247 
00248 void IOBPlugin::DeferredLoad() {
00249   // publish multi queue
00250   this->pmq.startServiceThread();
00251 
00252   // pull down controller parameters
00253   this->LoadPIDGainsFromParameter();
00254 
00255   // ROS Controller API
00256   this->pubRobotStateQueue = this->pmq.addPub<RobotState>();
00257   this->pubRobotState = this->rosNode->advertise<RobotState>(this->robot_name + "/robot_state", 100, true);
00258 
00259   // ros topic subscribtions
00260   ros::SubscribeOptions IOBCommandSo =
00261     ros::SubscribeOptions::create<JointCommand>(this->robot_name + "/joint_command", 100,
00262                                                 boost::bind(&IOBPlugin::SetJointCommand, this, _1),
00263                                                 ros::VoidPtr(), &this->rosQueue);
00264   // Enable TCP_NODELAY because TCP causes bursty communication with high jitter,
00265   IOBCommandSo.transport_hints = ros::TransportHints().reliable().tcpNoDelay(true);
00266   this->subIOBCommand = this->rosNode->subscribe(IOBCommandSo);
00267 
00268   // ros callback queue for processing subscription
00269   this->callbackQueeuThread = boost::thread(boost::bind(&IOBPlugin::RosQueueThread, this));
00270 
00271   //
00272   this->updateConnection =
00273     event::Events::ConnectWorldUpdateBegin(boost::bind(&IOBPlugin::UpdateStates, this));
00274 }
00275 
00276 void IOBPlugin::SetJointCommand(const JointCommand::ConstPtr &_msg) {
00277   // Update Joint Command
00278   boost::mutex::scoped_lock lock(this->mutex);
00279 
00280   this->jointCommand.header.stamp = _msg->header.stamp;
00281 
00282   // for jointCommand, only position, velocity and efforts are used.
00283   if (_msg->position.size() == this->jointCommand.position.size())
00284     std::copy(_msg->position.begin(), _msg->position.end(), this->jointCommand.position.begin());
00285   else
00286     ROS_DEBUG("JointCommand message contains different number of"
00287       " elements position[%ld] than expected[%ld]",
00288       _msg->position.size(), this->jointCommand.position.size());
00289 
00290   if (_msg->velocity.size() == this->jointCommand.velocity.size())
00291     std::copy(_msg->velocity.begin(), _msg->velocity.end(), this->jointCommand.velocity.begin());
00292   else
00293     ROS_DEBUG("JointCommand message contains different number of"
00294       " elements velocity[%ld] than expected[%ld]",
00295       _msg->velocity.size(), this->jointCommand.velocity.size());
00296 
00297   if (_msg->effort.size() == this->jointCommand.effort.size())
00298     std::copy(_msg->effort.begin(), _msg->effort.end(), this->jointCommand.effort.begin());
00299   else
00300     ROS_DEBUG("JointCommand message contains different number of"
00301       " elements effort[%ld] than expected[%ld]",
00302       _msg->effort.size(), this->jointCommand.effort.size());
00303 
00304   // the rest are stored in robotState for publication
00305   if (_msg->kp_position.size() == this->robotState.kp_position.size())
00306     std::copy(_msg->kp_position.begin(), _msg->kp_position.end(), this->robotState.kp_position.begin());
00307   else
00308     ROS_DEBUG("JointCommand message contains different number of"
00309       " elements kp_position[%ld] than expected[%ld]",
00310       _msg->kp_position.size(), this->robotState.kp_position.size());
00311 
00312   if (_msg->ki_position.size() == this->robotState.ki_position.size())
00313     std::copy(_msg->ki_position.begin(), _msg->ki_position.end(), this->robotState.ki_position.begin());
00314   else
00315     ROS_DEBUG("JointCommand message contains different number of"
00316       " elements ki_position[%ld] than expected[%ld]",
00317       _msg->ki_position.size(), this->robotState.ki_position.size());
00318 
00319   if (_msg->kd_position.size() == this->robotState.kd_position.size())
00320     std::copy(_msg->kd_position.begin(), _msg->kd_position.end(), this->robotState.kd_position.begin());
00321   else
00322     ROS_DEBUG("JointCommand message contains different number of"
00323       " elements kd_position[%ld] than expected[%ld]",
00324       _msg->kd_position.size(), this->robotState.kd_position.size());
00325 
00326   if (_msg->kp_velocity.size() == this->robotState.kp_velocity.size())
00327     std::copy(_msg->kp_velocity.begin(), _msg->kp_velocity.end(), this->robotState.kp_velocity.begin());
00328   else
00329     ROS_DEBUG("JointCommand message contains different number of"
00330       " elements kp_velocity[%ld] than expected[%ld]",
00331       _msg->kp_velocity.size(), this->robotState.kp_velocity.size());
00332 
00333   if (_msg->i_effort_min.size() == this->robotState.i_effort_min.size())
00334     std::copy(_msg->i_effort_min.begin(), _msg->i_effort_min.end(), this->robotState.i_effort_min.begin());
00335   else
00336     ROS_DEBUG("JointCommand message contains different number of"
00337       " elements i_effort_min[%ld] than expected[%ld]",
00338       _msg->i_effort_min.size(), this->robotState.i_effort_min.size());
00339 
00340   if (_msg->i_effort_max.size() == this->robotState.i_effort_max.size())
00341     std::copy(_msg->i_effort_max.begin(), _msg->i_effort_max.end(), this->robotState.i_effort_max.begin());
00342   else
00343     ROS_DEBUG("JointCommand message contains different number of"
00344       " elements i_effort_max[%ld] than expected[%ld]",
00345       _msg->i_effort_max.size(), this->robotState.i_effort_max.size());
00346 
00347   this->jointCommand.desired_controller_period_ms =
00348     _msg->desired_controller_period_ms;
00349 }
00350 
00351 void IOBPlugin::UpdateStates() {
00352   common::Time curTime = this->world->GetSimTime();
00353   if (curTime > this->lastControllerUpdateTime) {
00354     // update
00355 
00356     // gather robot state data and publish them
00357     this->GetAndPublishRobotStates(curTime);
00358 
00359     {
00360       boost::mutex::scoped_lock lock(this->mutex);
00361       this->UpdatePIDControl((curTime - this->lastControllerUpdateTime).Double());
00362     }
00363 
00364     this->lastControllerUpdateTime = curTime;
00365   }
00366 }
00367 
00368 void IOBPlugin::GetAndPublishRobotStates(const common::Time &_curTime){
00369 
00370   // populate robotState from robot
00371   this->robotState.header.stamp = ros::Time(_curTime.sec, _curTime.nsec);
00372 
00373   //
00374   for (unsigned int i = 0; i < this->joints.size(); ++i) {
00375     this->robotState.position[i] = this->joints[i]->GetAngle(0).Radian();
00376     this->robotState.velocity[i] = this->joints[i]->GetVelocity(0);
00377     //this->robotState.effort[i]   =
00378   }
00379 
00380   // force sensors
00381   //
00382 
00383   // imu sensors
00384   //
00385 
00386   // publish robot states
00387   this->pubRobotStateQueue->push(this->robotState, this->pubRobotState);
00388 }
00389 
00390 void IOBPlugin::UpdatePIDControl(double _dt) {
00391 
00393   for (unsigned int i = 0; i < this->joints.size(); ++i) {
00394     // truncate joint position within range of motion
00395     double positionTarget = math::clamp(this->jointCommand.position[i],
00396                                         this->joints[i]->GetLowStop(0).Radian(),
00397                                         this->joints[i]->GetHighStop(0).Radian());
00398 
00399     double q_p = positionTarget - this->robotState.position[i];
00400 
00401     if (!math::equal(_dt, 0.0))
00402       this->errorTerms[i].d_q_p_dt = (q_p - this->errorTerms[i].q_p) / _dt;
00403 
00404     this->errorTerms[i].q_p = q_p;
00405 
00406     this->errorTerms[i].qd_p =
00407       this->jointCommand.velocity[i] - this->robotState.velocity[i];
00408 
00409     this->errorTerms[i].k_i_q_i = math::clamp(this->errorTerms[i].k_i_q_i +
00410                                               _dt * this->robotState.ki_position[i] * this->errorTerms[i].q_p,
00411                                               static_cast<double>(this->robotState.i_effort_min[i]),
00412                                               static_cast<double>(this->robotState.i_effort_max[i]));
00413 
00414     // use gain params to compute force cmd
00415     double forceUnclamped =
00416       this->robotState.kp_position[i] * this->errorTerms[i].q_p +
00417       this->errorTerms[i].k_i_q_i +
00418       this->robotState.kd_position[i] * this->errorTerms[i].d_q_p_dt +
00419       this->robotState.kp_velocity[i] * this->errorTerms[i].qd_p +
00420       this->jointCommand.effort[i];
00421     //ROS_INFO("0 force:%d -> %f", i, forceUnclamped);
00422 
00423     // keep unclamped force for integral tie-back calculation
00424     double forceClamped = math::clamp(forceUnclamped, -this->effortLimit[i], this->effortLimit[i]);
00425     //ROS_INFO("1 force:%d -> %f (%f %f)", i, forceClamped, -this->effortLimit[i], this->effortLimit[i]);
00426 
00427     // integral tie-back during control saturation if using integral gain
00428     if (!math::equal(forceClamped,forceUnclamped) &&
00429         !math::equal((double)this->robotState.ki_position[i],0.0) ) {
00430       // lock integral term to provide continuous control as system moves
00431       // out of staturation
00432       this->errorTerms[i].k_i_q_i = math::clamp(this->errorTerms[i].k_i_q_i + (forceClamped - forceUnclamped),
00433                                                 static_cast<double>(this->robotState.i_effort_min[i]),
00434                                                 static_cast<double>(this->robotState.i_effort_max[i]));
00435     }
00436     //ROS_INFO("2 force:%d -> %f", i, forceClamped);
00437 
00438     // clamp force after integral tie-back
00439     forceClamped = math::clamp(forceUnclamped, -this->effortLimit[i], this->effortLimit[i]);
00440 
00441 
00442     // apply force to joint
00443     this->joints[i]->SetForce(0, forceClamped);
00444     //ROS_INFO("3 force:%d -> %f", i, forceClamped);
00445 
00446     // fill in jointState efforts
00447     this->robotState.effort[i] = forceClamped;
00448   }
00449 }
00450 
00451 void IOBPlugin::RosQueueThread() {
00452   static const double timeout = 0.01;
00453 
00454   while (this->rosNode->ok()) {
00455     this->rosQueue.callAvailable(ros::WallDuration(timeout));
00456   }
00457 }
00458 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


hrpsys_gazebo_general
Author(s): Yohei Kakiuchi
autogenerated on Tue Jul 23 2013 11:49:13