Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <gazebo_plugins/gazebo_ros_imu.h>
00024
00025 namespace gazebo
00026 {
00027
00028 GZ_REGISTER_MODEL_PLUGIN(GazeboRosIMU)
00029
00030
00031
00032 GazeboRosIMU::GazeboRosIMU()
00033 {
00034 this->seed = 0;
00035 }
00036
00038
00039 GazeboRosIMU::~GazeboRosIMU()
00040 {
00041 event::Events::DisconnectWorldUpdateBegin(this->update_connection_);
00042
00043 this->rosnode_->shutdown();
00044 this->callback_queue_thread_.join();
00045 delete this->rosnode_;
00046 }
00047
00049
00050 void GazeboRosIMU::Load(physics::ModelPtr _parent, sdf::ElementPtr _sdf)
00051 {
00052
00053 this->world_ = _parent->GetWorld();
00054 this->sdf = _sdf;
00055
00056
00057 this->deferred_load_thread_ = boost::thread(
00058 boost::bind(&GazeboRosIMU::LoadThread, this));
00059 }
00060
00062
00063 void GazeboRosIMU::LoadThread()
00064 {
00065
00066 this->robot_namespace_ = "";
00067 if (this->sdf->HasElement("robotNamespace"))
00068 this->robot_namespace_ = this->sdf->Get<std::string>("robotNamespace") + "/";
00069
00070 if (!this->sdf->HasElement("serviceName"))
00071 {
00072 ROS_INFO("imu plugin missing <serviceName>, defaults to /default_imu");
00073 this->service_name_ = "/default_imu";
00074 }
00075 else
00076 this->service_name_ = this->sdf->Get<std::string>("serviceName");
00077
00078 if (!this->sdf->HasElement("topicName"))
00079 {
00080 ROS_INFO("imu plugin missing <topicName>, defaults to /default_imu");
00081 this->topic_name_ = "/default_imu";
00082 }
00083 else
00084 this->topic_name_ = this->sdf->Get<std::string>("topicName");
00085
00086 if (!this->sdf->HasElement("gaussianNoise"))
00087 {
00088 ROS_INFO("imu plugin missing <gaussianNoise>, defaults to 0.0");
00089 this->gaussian_noise_ = 0.0;
00090 }
00091 else
00092 this->gaussian_noise_ = this->sdf->Get<double>("gaussianNoise");
00093
00094 if (!this->sdf->HasElement("bodyName"))
00095 {
00096 ROS_FATAL("imu plugin missing <bodyName>, cannot proceed");
00097 return;
00098 }
00099 else
00100 this->link_name_ = this->sdf->Get<std::string>("bodyName");
00101
00102 if (!this->sdf->HasElement("xyzOffset"))
00103 {
00104 ROS_INFO("imu plugin missing <xyzOffset>, defaults to 0s");
00105 this->offset_.pos = math::Vector3(0, 0, 0);
00106 }
00107 else
00108 this->offset_.pos = this->sdf->Get<math::Vector3>("xyzOffset");
00109
00110 if (!this->sdf->HasElement("rpyOffset"))
00111 {
00112 ROS_INFO("imu plugin missing <rpyOffset>, defaults to 0s");
00113 this->offset_.rot = math::Vector3(0, 0, 0);
00114 }
00115 else
00116 this->offset_.rot = this->sdf->Get<math::Vector3>("rpyOffset");
00117
00118 if (!this->sdf->HasElement("updateRate"))
00119 {
00120 ROS_DEBUG("imu plugin missing <updateRate>, defaults to 0.0"
00121 " (as fast as possible)");
00122 this->update_rate_ = 0.0;
00123 }
00124 else
00125 this->update_rate_ = this->sdf->GetElement("updateRate")->Get<double>();
00126
00127 if (!this->sdf->HasElement("frameName"))
00128 {
00129 ROS_INFO("imu plugin missing <frameName>, defaults to <bodyName>");
00130 this->frame_name_ = link_name_;
00131 }
00132 else
00133 this->frame_name_ = this->sdf->Get<std::string>("frameName");
00134
00135
00136 if (!ros::isInitialized())
00137 {
00138 ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
00139 << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
00140 return;
00141 }
00142
00143 this->rosnode_ = new ros::NodeHandle(this->robot_namespace_);
00144
00145
00146 this->pmq.startServiceThread();
00147
00148
00149 this->link = boost::dynamic_pointer_cast<physics::Link>(
00150 this->world_->GetEntity(this->link_name_));
00151 if (!this->link)
00152 {
00153 ROS_FATAL("gazebo_ros_imu plugin error: bodyName: %s does not exist\n",
00154 this->link_name_.c_str());
00155 return;
00156 }
00157
00158
00159 if (this->topic_name_ != "")
00160 {
00161 this->pub_Queue = this->pmq.addPub<sensor_msgs::Imu>();
00162 this->pub_ = this->rosnode_->advertise<sensor_msgs::Imu>(
00163 this->topic_name_, 1);
00164
00165
00166 ros::AdvertiseServiceOptions aso =
00167 ros::AdvertiseServiceOptions::create<std_srvs::Empty>(
00168 this->service_name_, boost::bind(&GazeboRosIMU::ServiceCallback,
00169 this, _1, _2), ros::VoidPtr(), &this->imu_queue_);
00170 this->srv_ = this->rosnode_->advertiseService(aso);
00171 }
00172
00173
00174 this->last_time_ = this->world_->GetSimTime();
00175
00176
00177 this->last_vpos_ = this->link->GetWorldLinearVel();
00178 this->last_veul_ = this->link->GetWorldAngularVel();
00179 this->apos_ = 0;
00180 this->aeul_ = 0;
00181
00182
00183 this->callback_queue_thread_ =
00184 boost::thread(boost::bind(&GazeboRosIMU::IMUQueueThread, this));
00185
00186
00187
00188
00189
00190 this->update_connection_ = event::Events::ConnectWorldUpdateBegin(
00191 boost::bind(&GazeboRosIMU::UpdateChild, this));
00192 }
00193
00195
00196 bool GazeboRosIMU::ServiceCallback(std_srvs::Empty::Request &req,
00197 std_srvs::Empty::Response &res)
00198 {
00199 return true;
00200 }
00201
00203
00204 void GazeboRosIMU::UpdateChild()
00205 {
00206 common::Time cur_time = this->world_->GetSimTime();
00207
00208
00209 if (this->update_rate_ > 0 &&
00210 (cur_time - this->last_time_).Double() < (1.0 / this->update_rate_))
00211 return;
00212
00213 if ((this->pub_.getNumSubscribers() > 0 && this->topic_name_ != ""))
00214 {
00215 math::Pose pose;
00216 math::Quaternion rot;
00217 math::Vector3 pos;
00218
00219
00220 pose = this->link->GetWorldPose();
00221
00222 pos = pose.pos + this->offset_.pos;
00223 rot = pose.rot;
00224
00225
00226 rot = this->offset_.rot*rot;
00227 rot.Normalize();
00228
00229
00230 math::Vector3 vpos = this->link->GetWorldLinearVel();
00231 math::Vector3 veul = this->link->GetWorldAngularVel();
00232
00233
00234 double tmp_dt = this->last_time_.Double() - cur_time.Double();
00235 if (tmp_dt != 0)
00236 {
00237 this->apos_ = (this->last_vpos_ - vpos) / tmp_dt;
00238 this->aeul_ = (this->last_veul_ - veul) / tmp_dt;
00239 this->last_vpos_ = vpos;
00240 this->last_veul_ = veul;
00241 }
00242
00243
00244 this->imu_msg_.header.frame_id = this->frame_name_;
00245 this->imu_msg_.header.stamp.sec = cur_time.sec;
00246 this->imu_msg_.header.stamp.nsec = cur_time.nsec;
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 this->imu_msg_.orientation.x = rot.x;
00257 this->imu_msg_.orientation.y = rot.y;
00258 this->imu_msg_.orientation.z = rot.z;
00259 this->imu_msg_.orientation.w = rot.w;
00260
00261
00262 math::Vector3 linear_velocity(
00263 veul.x + this->GaussianKernel(0, this->gaussian_noise_),
00264 veul.y + this->GaussianKernel(0, this->gaussian_noise_),
00265 veul.z + this->GaussianKernel(0, this->gaussian_noise_));
00266
00267
00268 linear_velocity = rot.RotateVector(linear_velocity);
00269 this->imu_msg_.angular_velocity.x = linear_velocity.x;
00270 this->imu_msg_.angular_velocity.y = linear_velocity.y;
00271 this->imu_msg_.angular_velocity.z = linear_velocity.z;
00272
00273
00274 math::Vector3 linear_acceleration(
00275 apos_.x + this->GaussianKernel(0, this->gaussian_noise_),
00276 apos_.y + this->GaussianKernel(0, this->gaussian_noise_),
00277 apos_.z + this->GaussianKernel(0, this->gaussian_noise_));
00278
00279
00280 linear_acceleration = rot.RotateVector(linear_acceleration);
00281 this->imu_msg_.linear_acceleration.x = linear_acceleration.x;
00282 this->imu_msg_.linear_acceleration.y = linear_acceleration.y;
00283 this->imu_msg_.linear_acceleration.z = linear_acceleration.z;
00284
00285
00288 double gn2 = this->gaussian_noise_*this->gaussian_noise_;
00289 this->imu_msg_.orientation_covariance[0] = gn2;
00290 this->imu_msg_.orientation_covariance[4] = gn2;
00291 this->imu_msg_.orientation_covariance[8] = gn2;
00292 this->imu_msg_.angular_velocity_covariance[0] = gn2;
00293 this->imu_msg_.angular_velocity_covariance[4] = gn2;
00294 this->imu_msg_.angular_velocity_covariance[8] = gn2;
00295 this->imu_msg_.linear_acceleration_covariance[0] = gn2;
00296 this->imu_msg_.linear_acceleration_covariance[4] = gn2;
00297 this->imu_msg_.linear_acceleration_covariance[8] = gn2;
00298
00299 {
00300 boost::mutex::scoped_lock lock(this->lock_);
00301
00302 if (this->pub_.getNumSubscribers() > 0 && this->topic_name_ != "")
00303 this->pub_Queue->push(this->imu_msg_, this->pub_);
00304 }
00305
00306
00307 this->last_time_ = cur_time;
00308 }
00309 }
00310
00311
00313
00314 double GazeboRosIMU::GaussianKernel(double mu, double sigma)
00315 {
00316
00317
00318
00319
00320 double U = static_cast<double>(rand_r(&this->seed)) /
00321 static_cast<double>(RAND_MAX);
00322
00323
00324 double V = static_cast<double>(rand_r(&this->seed)) /
00325 static_cast<double>(RAND_MAX);
00326
00327 double X = sqrt(-2.0 * ::log(U)) * cos(2.0*M_PI * V);
00328
00329
00330
00331
00332 X = sigma * X + mu;
00333 return X;
00334 }
00335
00337
00338 void GazeboRosIMU::IMUQueueThread()
00339 {
00340 static const double timeout = 0.01;
00341
00342 while (this->rosnode_->ok())
00343 {
00344 this->imu_queue_.callAvailable(ros::WallDuration(timeout));
00345 }
00346 }
00347 }