00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <gazebo/physics/physics.hh>
00019 #include <gazebo/transport/transport.hh>
00020 #include "rotors_gazebo_plugins/external/gazebo_gimbal_controller_plugin.h"
00021
00022 using namespace gazebo;
00023 using namespace std;
00024
00025 GZ_REGISTER_MODEL_PLUGIN(GimbalControllerPlugin)
00026
00027
00028 GimbalControllerPlugin::GimbalControllerPlugin()
00029 :status("closed")
00030 {
00032 this->pitchPid.Init(5, 0, 0, 0, 0, 0.3, -0.3);
00033 this->rollPid.Init(5, 0, 0, 0, 0, 0.3, -0.3);
00034 this->yawPid.Init(1.0, 0, 0, 0, 0, 1.0, -1.0);
00035 this->pitchCommand = 0.5* M_PI;
00036 this->rollCommand = 0;
00037 this->yawCommand = 0;
00038 }
00039
00041 void GimbalControllerPlugin::Load(
00042 physics::ModelPtr _model,
00043 sdf::ElementPtr _sdf)
00044 {
00045
00046 if(kPrintOnPluginLoad) {
00047 gzdbg << __FUNCTION__ << "() called." << std::endl;
00048 }
00049
00050 this->model = _model;
00051
00052 this->sdf = _sdf;
00053
00054 std::string yawJointName = "cgo3_vertical_arm_joint";
00055 this->yawJoint = this->model->GetJoint(yawJointName);
00056 if (this->sdf->HasElement("joint_yaw"))
00057 {
00058
00059 yawJointName = sdf->Get<std::string>("joint_yaw");
00060 if (this->model->GetJoint(yawJointName))
00061 {
00062 this->yawJoint = this->model->GetJoint(yawJointName);
00063 }
00064 else
00065 {
00066 gzwarn << "joint_yaw [" << yawJointName << "] does not exist?\n";
00067 }
00068 }
00069 if (!this->yawJoint)
00070 {
00071 gzerr << "GimbalControllerPlugin::Load ERROR! Can't get yaw joint '"
00072 << yawJointName << "' " << endl;
00073 }
00074
00075 std::string rollJointName = "cgo3_horizontal_arm_joint";
00076 this->rollJoint = this->model->GetJoint(rollJointName);
00077 if (this->sdf->HasElement("joint_roll"))
00078 {
00079
00080 rollJointName = sdf->Get<std::string>("joint_roll");
00081 if (this->model->GetJoint(rollJointName))
00082 {
00083 this->rollJoint = this->model->GetJoint(rollJointName);
00084 }
00085 else
00086 {
00087 gzwarn << "joint_roll [" << rollJointName << "] does not exist?\n";
00088 }
00089 }
00090 if (!this->rollJoint)
00091 {
00092 gzerr << "GimbalControllerPlugin::Load ERROR! Can't get roll joint '"
00093 << rollJointName << "' " << endl;
00094 }
00095
00096
00097 std::string pitchJointName = "cgo3_camera_joint";
00098 this->pitchJoint = this->model->GetJoint(pitchJointName);
00099 if (this->sdf->HasElement("joint_pitch"))
00100 {
00101
00102 pitchJointName = sdf->Get<std::string>("joint_pitch");
00103 if (this->model->GetJoint(pitchJointName))
00104 {
00105 this->pitchJoint = this->model->GetJoint(pitchJointName);
00106 }
00107 else
00108 {
00109 gzwarn << "joint_pitch [" << pitchJointName << "] does not exist?\n";
00110 }
00111 }
00112 if (!this->pitchJoint)
00113 {
00114 gzerr << "GimbalControllerPlugin::Load ERROR! Can't get pitch joint '"
00115 << pitchJointName << "' " << endl;
00116 }
00117
00118
00119
00120 std::string imuSensorName = "camera_imu";
00121 if (this->sdf->HasElement("imu"))
00122 {
00123
00124 imuSensorName = sdf->Get<std::string>("imu");
00125 }
00126
00127 this->imuSensor = std::static_pointer_cast<sensors::ImuSensor>(
00128 sensors::SensorManager::Instance()->GetSensor(imuSensorName));
00129
00130 if (!this->imuSensor)
00131 {
00132 gzerr << "GimbalControllerPlugin::Load ERROR! Can't get imu sensor '"
00133 << imuSensorName << "' " << endl;
00134 }
00135 }
00136
00138 void GimbalControllerPlugin::Init()
00139 {
00140 this->node = transport::NodePtr(new transport::Node());
00141 this->node->Init(this->model->GetWorld()->GetName());
00142
00143 this->lastUpdateTime = this->model->GetWorld()->GetSimTime();
00144
00145
00146 std::string pitchTopic = std::string("~/") + this->model->GetName() +
00147 "/gimbal_pitch_cmd";
00148 this->pitchSub = this->node->Subscribe(pitchTopic,
00149 &GimbalControllerPlugin::OnPitchStringMsg, this);
00150
00151 std::string rollTopic = std::string("~/") + this->model->GetName() +
00152 "/gimbal_roll_cmd";
00153 this->rollSub = this->node->Subscribe(rollTopic,
00154 &GimbalControllerPlugin::OnRollStringMsg, this);
00155
00156 std::string yawTopic = std::string("~/") + this->model->GetName() +
00157 "/gimbal_yaw_cmd";
00158 this->yawSub = this->node->Subscribe(yawTopic,
00159 &GimbalControllerPlugin::OnYawStringMsg, this);
00160
00161
00162 this->connections.push_back(event::Events::ConnectWorldUpdateBegin(
00163 boost::bind(&GimbalControllerPlugin::OnUpdate, this)));
00164
00165
00166 pitchTopic = std::string("~/") + this->model->GetName()
00167 + "/gimbal_pitch_status";
00168 this->pitchPub = node->Advertise<gazebo::msgs::Any>(pitchTopic);
00169
00170
00171 rollTopic = std::string("~/") + this->model->GetName()
00172 + "/gimbal_roll_status";
00173 this->rollPub = node->Advertise<gazebo::msgs::Any>(rollTopic);
00174
00175
00176
00177 yawTopic = std::string("~/") + this->model->GetName()
00178 + "/gimbal_yaw_status";
00179 this->yawPub = node->Advertise<gazebo::msgs::Any>(yawTopic);
00180
00181 gzmsg << "GimbalControllerPlugin::Init" << std::endl;
00182 }
00183
00185 void GimbalControllerPlugin::OnPitchStringMsg(ConstAnyPtr &_msg)
00186 {
00187
00188 this->pitchCommand = _msg->double_value();
00189 }
00190
00192 void GimbalControllerPlugin::OnRollStringMsg(ConstAnyPtr &_msg)
00193 {
00194
00195 this->rollCommand = _msg->double_value();
00196 }
00197
00199 void GimbalControllerPlugin::OnYawStringMsg(ConstAnyPtr &_msg)
00200 {
00201
00202 this->yawCommand = _msg->double_value();
00203 }
00204
00206 ignition::ignition::math::Vector3d GimbalControllerPlugin::ThreeAxisRot(
00207 double r11, double r12, double r21, double r31, double r32)
00208 {
00209 return ignition::ignition::math::Vector3d d(
00210 atan2( r31, r32 ),
00211 asin ( r21 ),
00212 atan2( r11, r12 ));
00213 }
00214
00216 ignition::ignition::math::Vector3d GimbalControllerPlugin::QtoZXY(
00217 const ignition::math::Quaterniond &_q)
00218 {
00219
00220
00221
00222 ignition::ignition::math::Vector3d result = this->ThreeAxisRot(
00223 -2*(_q.X()*_q.Y() - _q.W()*_q.Z()),
00224 _q.W()*_q.W() - _q.X()*_q.X() + _q.Y()*_q.Y() - _q.Z()*_q.Z(),
00225 2*(_q.Y()*_q.Z() + _q.W()*_q.X()),
00226 -2*(_q.X()*_q.Z() - _q.W()*_q.Y()),
00227 _q.W()*_q.W() - _q.X()*_q.X() - _q.Y()*_q.Y() + _q.Z()*_q.Z());
00228 return result;
00229 }
00230
00232 void GimbalControllerPlugin::OnUpdate()
00233 {
00234 if (!this->pitchJoint || !this->rollJoint || !this->yawJoint)
00235 return;
00236
00237 common::Time time = this->model->GetWorld()->GetSimTime();
00238 if (time < this->lastUpdateTime)
00239 {
00240 gzerr << "time reset event\n";
00241 this->lastUpdateTime = time;
00242 return;
00243 }
00244 else if (time > this->lastUpdateTime)
00245 {
00246 double dt = (this->lastUpdateTime - time).Double();
00247
00248
00249
00250
00251 const double rDir = -1;
00252 const double pDir = -1;
00253 const double yDir = 1;
00254
00255
00256 double rollLimited = ignition::math::clamp(this->rollCommand,
00257 rDir*this->rollJoint->GetUpperLimit(0).Radian(),
00258 rDir*this->rollJoint->GetLowerLimit(0).Radian());
00259 double pitchLimited = ignition::math::clamp(this->pitchCommand,
00260 pDir*this->pitchJoint->GetUpperLimit(0).Radian(),
00261 pDir*this->pitchJoint->GetLowerLimit(0).Radian());
00262 double yawLimited = ignition::math::clamp(this->yawCommand,
00263 yDir*this->yawJoint->GetLowerLimit(0).Radian(),
00264 yDir*this->yawJoint->GetUpperLimit(0).Radian());
00265
00266 ignition::math::Quaterniond commandRPY(
00267 rollLimited, pitchLimited, yawLimited);
00268
00269
00271
00274 ignition::ignition::math::Vector3d currentAngleYPRVariable(
00275 this->imuSensor->Orientation().Euler());
00276 ignition::ignition::math::Vector3d currentAnglePRYVariable(
00277 this->QtoZXY(currentAngleYPRVariable));
00278
00281 ignition::ignition::math::Vector3d lowerLimitsPRY
00282 (pDir*this->pitchJoint->GetLowerLimit(0).Radian(),
00283 rDir*this->rollJoint->GetLowerLimit(0).Radian(),
00284 yDir*this->yawJoint->GetLowerLimit(0).Radian());
00285 ignition::ignition::math::Vector3d upperLimitsPRY
00286 (pDir*this->pitchJoint->GetUpperLimit(0).Radian(),
00287 rDir*this->rollJoint->GetUpperLimit(0).Radian(),
00288 yDir*this->yawJoint->GetUpperLimit(0).Radian());
00289
00290
00291 double pitchError = this->ShortestAngularDistance(
00292 pitchLimited, currentAnglePRYVariable.X());
00293 double rollError = this->ShortestAngularDistance(
00294 rollLimited, currentAnglePRYVariable.Y());
00295 double yawError = this->ShortestAngularDistance(
00296 yawLimited, currentAnglePRYVariable.Z());
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 if (lowerLimitsPRY.X() < upperLimitsPRY.X())
00308 {
00309 pitchError = ignition::math::clamp(pitchError,
00310 currentAnglePRYVariable.X() - upperLimitsPRY.X(),
00311 currentAnglePRYVariable.X() - lowerLimitsPRY.X());
00312 }
00313 else
00314 {
00315 pitchError = ignition::math::clamp(pitchError,
00316 currentAnglePRYVariable.X() - lowerLimitsPRY.X(),
00317 currentAnglePRYVariable.X() - upperLimitsPRY.X());
00318 }
00319 if (lowerLimitsPRY.Y() < upperLimitsPRY.Y())
00320 {
00321 rollError = ignition::math::clamp(rollError,
00322 currentAnglePRYVariable.Y() - upperLimitsPRY.Y(),
00323 currentAnglePRYVariable.Y() - lowerLimitsPRY.Y());
00324 }
00325 else
00326 {
00327 rollError = ignition::math::clamp(rollError,
00328 currentAnglePRYVariable.Y() - lowerLimitsPRY.Y(),
00329 currentAnglePRYVariable.Y() - upperLimitsPRY.Y());
00330 }
00331 if (lowerLimitsPRY.Z() < upperLimitsPRY.Z())
00332 {
00333 yawError = ignition::math::clamp(yawError,
00334 currentAnglePRYVariable.Z() - upperLimitsPRY.Z(),
00335 currentAnglePRYVariable.Z() - lowerLimitsPRY.Z());
00336 }
00337 else
00338 {
00339 yawError = ignition::math::clamp(yawError,
00340 currentAnglePRYVariable.Z() - lowerLimitsPRY.Z(),
00341 currentAnglePRYVariable.Z() - upperLimitsPRY.Z());
00342 }
00343
00344
00345 double pitchForce = this->pitchPid.Update(pitchError, dt);
00346 this->pitchJoint->SetForce(0, pDir*pitchForce);
00347
00348 double rollForce = this->rollPid.Update(rollError, dt);
00349 this->rollJoint->SetForce(0, rDir*rollForce);
00350
00351 double yawForce = this->yawPid.Update(yawError, dt);
00352 this->yawJoint->SetForce(0, yDir*yawForce);
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364 this->lastUpdateTime = time;
00365 }
00366
00367 static int i =1000;
00368 if (++i>100)
00369 {
00370 i = 0;
00371
00372 gazebo::msgs::Any m;
00373 m.set_type(gazebo::msgs::Any_ValueType_DOUBLE);
00374
00375 m.set_double_value(this->pitchJoint->GetAngle(0).Radian());
00376 this->pitchPub->Publish(m);
00377
00378 m.set_double_value(this->rollJoint->GetAngle(0).Radian());
00379 this->rollPub->Publish(m);
00380
00381 m.set_double_value(this->yawJoint->GetAngle(0).Radian());
00382 this->yawPub->Publish(m);
00383 }
00384 }
00385
00387 double GimbalControllerPlugin::NormalizeAbout(double _angle, double reference)
00388 {
00389 double diff = _angle - reference;
00390
00391 while (diff <= -M_PI)
00392 {
00393 diff += 2.0*M_PI;
00394 }
00395 while (diff > M_PI)
00396 {
00397 diff -= 2.0*M_PI;
00398 }
00399 return diff + reference;
00400 }
00401
00403 double GimbalControllerPlugin::ShortestAngularDistance(double _from, double _to)
00404 {
00405 return this->NormalizeAbout(_to, _from) - _from;
00406 }