gazebo_imu_plugin.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015 Fadri Furrer, ASL, ETH Zurich, Switzerland
3  * Copyright 2015 Michael Burri, ASL, ETH Zurich, Switzerland
4  * Copyright 2015 Mina Kamel, ASL, ETH Zurich, Switzerland
5  * Copyright 2015 Janosch Nikolic, ASL, ETH Zurich, Switzerland
6  * Copyright 2015 Markus Achtelik, ASL, ETH Zurich, Switzerland
7  * Copyright 2016 Geoffrey Hunter <gbmhunter@gmail.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 // MODULE HEADER
24 
25 // SYSTEM LIBS
26 #include <stdio.h>
27 #include <boost/bind.hpp>
28 #include <chrono>
29 #include <cmath>
30 #include <iostream>
31 
32 // 3RD PARTY
34 
35 // USER HEADERS
36 #include "ConnectGazeboToRosTopic.pb.h"
37 
38 namespace gazebo {
39 
41  : ModelPlugin(),
42  node_handle_(0),
43  velocity_prev_W_(0, 0, 0),
44  pubs_and_subs_created_(false) {}
45 
47 }
48 
49 void GazeboImuPlugin::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf) {
50  if (kPrintOnPluginLoad) {
51  gzdbg << __FUNCTION__ << "() called." << std::endl;
52  }
53 
54  gzdbg << "_model = " << _model->GetName() << std::endl;
55 
56  // Store the pointer to the model
57  model_ = _model;
58  world_ = model_->GetWorld();
59 
60  // default params
61  namespace_.clear();
62 
63  //==============================================//
64  //========== READ IN PARAMS FROM SDF ===========//
65  //==============================================//
66 
67  if (_sdf->HasElement("robotNamespace"))
68  namespace_ = _sdf->GetElement("robotNamespace")->Get<std::string>();
69  else
70  gzerr << "[gazebo_imu_plugin] Please specify a robotNamespace.\n";
71 
72  // Get node handle
73  node_handle_ = transport::NodePtr(new transport::Node());
74 
75  // Initialise with default namespace (typically /gazebo/default/)
76  node_handle_->Init();
77 
78  if (_sdf->HasElement("linkName"))
79  link_name_ = _sdf->GetElement("linkName")->Get<std::string>();
80  else
81  gzerr << "[gazebo_imu_plugin] Please specify a linkName.\n";
82  // Get the pointer to the link
83  link_ = model_->GetLink(link_name_);
84  if (link_ == NULL)
85  gzthrow("[gazebo_imu_plugin] Couldn't find specified link \"" << link_name_
86  << "\".");
87 
89 
90  getSdfParam<std::string>(_sdf, "imuTopic", imu_topic_,
92  getSdfParam<double>(_sdf, "gyroscopeNoiseDensity",
95  getSdfParam<double>(_sdf, "gyroscopeBiasRandomWalk",
98  getSdfParam<double>(_sdf, "gyroscopeBiasCorrelationTime",
102  getSdfParam<double>(_sdf, "gyroscopeTurnOnBiasSigma",
105  getSdfParam<double>(_sdf, "accelerometerNoiseDensity",
108  getSdfParam<double>(_sdf, "accelerometerRandomWalk",
111  getSdfParam<double>(_sdf, "accelerometerBiasCorrelationTime",
115  getSdfParam<double>(_sdf, "accelerometerTurnOnBiasSigma",
118 
119  last_time_ = world_->SimTime();
120 
121  // Listen to the update event. This event is broadcast every
122  // simulation iteration.
123  this->updateConnection_ = event::Events::ConnectWorldUpdateBegin(
124  boost::bind(&GazeboImuPlugin::OnUpdate, this, _1));
125 
126  //==============================================//
127  //====== POPULATE STATIC PARTS OF IMU MSG ======//
128  //==============================================//
129 
130  // imu_message_.header.frame_id = frame_id_;
131  imu_message_.mutable_header()->set_frame_id(frame_id_);
132 
133  // We assume uncorrelated noise on the 3 channels -> only set diagonal
134  // elements. Only the broadband noise component is considered, specified as a
135  // continuous-time density (two-sided spectrum); not the true covariance of
136  // the measurements.
137 
138  for (int i = 0; i < 9; i++) {
139  switch (i) {
140  case 0:
141  imu_message_.add_angular_velocity_covariance(
144 
145  imu_message_.add_orientation_covariance(-1.0);
146 
147  imu_message_.add_linear_acceleration_covariance(
150  break;
151  case 1:
152  case 2:
153  case 3:
154  imu_message_.add_angular_velocity_covariance(0.0);
155 
156  imu_message_.add_orientation_covariance(-1.0);
157 
158  imu_message_.add_linear_acceleration_covariance(0.0);
159  break;
160  case 4:
161  imu_message_.add_angular_velocity_covariance(
164 
165  imu_message_.add_orientation_covariance(-1.0);
166 
167  imu_message_.add_linear_acceleration_covariance(
170  break;
171  case 5:
172  case 6:
173  case 7:
174  imu_message_.add_angular_velocity_covariance(0.0);
175 
176  imu_message_.add_orientation_covariance(-1.0);
177 
178  imu_message_.add_linear_acceleration_covariance(0.0);
179  break;
180  case 8:
181  imu_message_.add_angular_velocity_covariance(
184 
185  imu_message_.add_orientation_covariance(-1.0);
186 
187  imu_message_.add_linear_acceleration_covariance(
190  break;
191  }
192  }
193 
194  gravity_W_ = world_->Gravity();
196 
197  standard_normal_distribution_ = std::normal_distribution<double>(0.0, 1.0);
198 
199  double sigma_bon_g = imu_parameters_.gyroscope_turn_on_bias_sigma;
201  for (int i = 0; i < 3; ++i) {
206  }
207 
208  // TODO(nikolicj) incorporate steady-state covariance of bias process
209  gyroscope_bias_.setZero();
210  accelerometer_bias_.setZero();
211 }
212 
213 void GazeboImuPlugin::AddNoise(Eigen::Vector3d* linear_acceleration,
214  Eigen::Vector3d* angular_velocity,
215  const double dt) {
216  GZ_ASSERT(linear_acceleration != nullptr, "Linear acceleration was null.");
217  GZ_ASSERT(angular_velocity != nullptr, "Angular velocity was null.");
218  GZ_ASSERT(dt > 0.0, "Change in time must be greater than 0.");
219 
220  // Gyrosocpe
222  // Discrete-time standard deviation equivalent to an "integrating" sampler
223  // with integration time dt.
224  double sigma_g_d = 1 / sqrt(dt) * imu_parameters_.gyroscope_noise_density;
225  double sigma_b_g = imu_parameters_.gyroscope_random_walk;
226  // Compute exact covariance of the process after dt [Maybeck 4-114].
227  double sigma_b_g_d = sqrt(-sigma_b_g * sigma_b_g * tau_g / 2.0 *
228  (exp(-2.0 * dt / tau_g) - 1.0));
229  // Compute state-transition.
230  double phi_g_d = exp(-1.0 / tau_g * dt);
231  // Simulate gyroscope noise processes and add them to the true angular rate.
232  for (int i = 0; i < 3; ++i) {
233  gyroscope_bias_[i] =
234  phi_g_d * gyroscope_bias_[i] +
236  (*angular_velocity)[i] =
237  (*angular_velocity)[i] + gyroscope_bias_[i] +
240  }
241 
242  // Accelerometer
244  // Discrete-time standard deviation equivalent to an "integrating" sampler
245  // with integration time dt.
246  double sigma_a_d = 1 / sqrt(dt) * imu_parameters_.accelerometer_noise_density;
247  double sigma_b_a = imu_parameters_.accelerometer_random_walk;
248  // Compute exact covariance of the process after dt [Maybeck 4-114].
249  double sigma_b_a_d = sqrt(-sigma_b_a * sigma_b_a * tau_a / 2.0 *
250  (exp(-2.0 * dt / tau_a) - 1.0));
251  // Compute state-transition.
252  double phi_a_d = exp(-1.0 / tau_a * dt);
253  // Simulate accelerometer noise processes and add them to the true linear
254  // acceleration.
255  for (int i = 0; i < 3; ++i) {
257  phi_a_d * accelerometer_bias_[i] +
259  (*linear_acceleration)[i] =
260  (*linear_acceleration)[i] + accelerometer_bias_[i] +
263  }
264 }
265 
266 void GazeboImuPlugin::OnUpdate(const common::UpdateInfo& _info) {
267  if (kPrintOnUpdates) {
268  gzdbg << __FUNCTION__ << "() called." << std::endl;
269  }
270 
271  if (!pubs_and_subs_created_) {
273  pubs_and_subs_created_ = true;
274  }
275 
276  common::Time current_time = world_->SimTime();
277  double dt = (current_time - last_time_).Double();
278  last_time_ = current_time;
279  double t = current_time.Double();
280 
281  ignition::math::Pose3d T_W_I = link_->WorldPose(); // TODO(burrimi): Check tf.
282  ignition::math::Quaterniond C_W_I = T_W_I.Rot();
283 
284  ignition::math::Vector3d acceleration_I =
285  link_->RelativeLinearAccel() - C_W_I.RotateVectorReverse(gravity_W_);
286 
287  ignition::math::Vector3d angular_vel_I = link_->RelativeAngularVel();
288 
289  Eigen::Vector3d linear_acceleration_I(acceleration_I.X(), acceleration_I.Y(),
290  acceleration_I.Z());
291  Eigen::Vector3d angular_velocity_I(angular_vel_I.X(), angular_vel_I.Y(),
292  angular_vel_I.Z());
293 
294  AddNoise(&linear_acceleration_I, &angular_velocity_I, dt);
295 
296  // Fill IMU message.
297  // imu_message_.header.stamp.sec = current_time.sec;
298  imu_message_.mutable_header()->mutable_stamp()->set_sec(current_time.sec);
299 
300  // imu_message_.header.stamp.nsec = current_time.nsec;
301  imu_message_.mutable_header()->mutable_stamp()->set_nsec(current_time.nsec);
302 
304  // NOTE: rotors_simulator used to set the orientation to "0", since it is
305  // not raw IMU data but rather a calculation (and could confuse users).
306  // However, the orientation is now set as it is used by PX4.
307  /*gazebo::msgs::Quaternion* orientation = new gazebo::msgs::Quaternion();
308  orientation->set_x(0);
309  orientation->set_y(0);
310  orientation->set_z(0);
311  orientation->set_w(1);
312  imu_message_.set_allocated_orientation(orientation);*/
313 
315  gazebo::msgs::Quaternion* orientation = new gazebo::msgs::Quaternion();
316  orientation->set_w(C_W_I.W());
317  orientation->set_x(C_W_I.X());
318  orientation->set_y(C_W_I.Y());
319  orientation->set_z(C_W_I.Z());
320  imu_message_.set_allocated_orientation(orientation);
321 
322  gazebo::msgs::Vector3d* linear_acceleration = new gazebo::msgs::Vector3d();
323  linear_acceleration->set_x(linear_acceleration_I[0]);
324  linear_acceleration->set_y(linear_acceleration_I[1]);
325  linear_acceleration->set_z(linear_acceleration_I[2]);
326  imu_message_.set_allocated_linear_acceleration(linear_acceleration);
327 
328  gazebo::msgs::Vector3d* angular_velocity = new gazebo::msgs::Vector3d();
329  angular_velocity->set_x(angular_velocity_I[0]);
330  angular_velocity->set_y(angular_velocity_I[1]);
331  angular_velocity->set_z(angular_velocity_I[2]);
332  imu_message_.set_allocated_angular_velocity(angular_velocity);
333 
334  // Publish the IMU message
335  imu_pub_->Publish(imu_message_);
336 
337  // std::cout << "Published IMU message.\n";
338 }
339 
341  // Create temporary "ConnectGazeboToRosTopic" publisher and message
342  gazebo::transport::PublisherPtr connect_gazebo_to_ros_topic_pub =
343  node_handle_->Advertise<gz_std_msgs::ConnectGazeboToRosTopic>(
344  "~/" + kConnectGazeboToRosSubtopic, 1);
345 
346  // ============================================ //
347  // =============== IMU MSG SETUP ============== //
348  // ============================================ //
349 
350  imu_pub_ = node_handle_->Advertise<gz_sensor_msgs::Imu>(
351  "~/" + namespace_ + "/" + imu_topic_, 1);
352 
353  gz_std_msgs::ConnectGazeboToRosTopic connect_gazebo_to_ros_topic_msg;
354  // connect_gazebo_to_ros_topic_msg.set_gazebo_namespace(namespace_);
355  connect_gazebo_to_ros_topic_msg.set_gazebo_topic("~/" + namespace_ + "/" +
356  imu_topic_);
357  connect_gazebo_to_ros_topic_msg.set_ros_topic(namespace_ + "/" + imu_topic_);
358  connect_gazebo_to_ros_topic_msg.set_msgtype(
359  gz_std_msgs::ConnectGazeboToRosTopic::IMU);
360  connect_gazebo_to_ros_topic_pub->Publish(connect_gazebo_to_ros_topic_msg,
361  true);
362 }
363 
365 
366 } // namespace gazebo
physics::LinkPtr link_
Pointer to the link.
Eigen::Vector3d gyroscope_bias_
bool pubs_and_subs_created_
Flag that is set to true once CreatePubsAndSubs() is called, used to prevent CreatePubsAndSubs() from...
Eigen::Vector3d accelerometer_turn_on_bias_
void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
double gyroscope_random_walk
Gyroscope bias random walk [rad/s/s/sqrt(Hz)].
std::default_random_engine random_generator_
void OnUpdate(const common::UpdateInfo &)
This gets called by the world update start event.
event::ConnectionPtr updateConnection_
Pointer to the update event connection.
physics::ModelPtr model_
Pointer to the model.
physics::WorldPtr world_
Pointer to the world.
gz_sensor_msgs::Imu imu_message_
IMU message.
ignition::math::Vector3d gravity_W_
double accelerometer_turn_on_bias_sigma
Accelerometer turn on bias standard deviation [m/s^2].
void AddNoise(Eigen::Vector3d *linear_acceleration, Eigen::Vector3d *angular_velocity, const double dt)
This method adds noise to acceleration and angular rates for accelerometer and gyroscope measurement ...
void CreatePubsAndSubs()
Creates all required publishers and subscribers, incl. routing of messages to/from ROS if required...
double accelerometer_random_walk
Accelerometer bias random walk. [m/s^2/s/sqrt(Hz)].
double gyroscope_bias_correlation_time
Gyroscope bias correlation time constant [s].
static const bool kPrintOnPluginLoad
Definition: common.h:41
Eigen::Vector3d gyroscope_turn_on_bias_
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
double gyroscope_turn_on_bias_sigma
Gyroscope turn on bias standard deviation [rad/s].
double accelerometer_noise_density
Accelerometer noise density (two-sided spectrum) [m/s^2/sqrt(Hz)].
INLINE Rall1d< T, V, S > exp(const Rall1d< T, V, S > &arg)
double gyroscope_noise_density
Gyroscope noise density (two-sided spectrum) [rad/s/sqrt(Hz)].
std::normal_distribution< double > standard_normal_distribution_
transport::NodePtr node_handle_
Handle for the Gazebo node.
static const bool kPrintOnUpdates
Definition: common.h:42
static constexpr char IMU[]
Eigen::Vector3d accelerometer_bias_
double gravity_magnitude
Norm of the gravitational acceleration [m/s^2].
GZ_REGISTER_MODEL_PLUGIN(GazeboRosP3D)
transport::PublisherPtr imu_pub_
static const std::string kConnectGazeboToRosSubtopic
Definition: common.h:56
double accelerometer_bias_correlation_time
Accelerometer bias correlation time constant [s].


rotors_gazebo_plugins
Author(s): Fadri Furrer, Michael Burri, Mina Kamel, Janosch Nikolic, Markus Achtelik
autogenerated on Mon Feb 28 2022 23:39:03