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
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
00040 this->rosNode = new ros::NodeHandle("");
00041
00042 this->model = _parent;
00043 this->world = this->model->GetWorld();
00044
00045
00046 this->sdf = _sdf;
00047
00048
00049 this->lastControllerUpdateTime = this->world->GetSimTime();
00050
00051
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
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
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
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
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
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
00171
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
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
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
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
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
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
00250 this->pmq.startServiceThread();
00251
00252
00253 this->LoadPIDGainsFromParameter();
00254
00255
00256 this->pubRobotStateQueue = this->pmq.addPub<RobotState>();
00257 this->pubRobotState = this->rosNode->advertise<RobotState>(this->robot_name + "/robot_state", 100, true);
00258
00259
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
00265 IOBCommandSo.transport_hints = ros::TransportHints().reliable().tcpNoDelay(true);
00266 this->subIOBCommand = this->rosNode->subscribe(IOBCommandSo);
00267
00268
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
00278 boost::mutex::scoped_lock lock(this->mutex);
00279
00280 this->jointCommand.header.stamp = _msg->header.stamp;
00281
00282
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
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
00355
00356
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
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
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
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
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
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
00422
00423
00424 double forceClamped = math::clamp(forceUnclamped, -this->effortLimit[i], this->effortLimit[i]);
00425
00426
00427
00428 if (!math::equal(forceClamped,forceUnclamped) &&
00429 !math::equal((double)this->robotState.ki_position[i],0.0) ) {
00430
00431
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
00437
00438
00439 forceClamped = math::clamp(forceUnclamped, -this->effortLimit[i], this->effortLimit[i]);
00440
00441
00442
00443 this->joints[i]->SetForce(0, forceClamped);
00444
00445
00446
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 }