gyro_bias_remover.cpp
Go to the documentation of this file.
1 
9 #include <geometry_msgs/Vector3Stamped.h>
10 #include <nodelet/nodelet.h>
13 #include <std_msgs/String.h>
14 
16 
18 
19 namespace cras
20 {
21 
23 {
24  auto nh = this->getNodeHandle();
25  auto pnh = this->getPrivateNodeHandle();
26  auto params = this->privateParams();
27 
28  this->initialCalibrationDuration = params->getParam("initial_calibration_duration", ros::Duration(15), "s");
29  this->minCalibrationSamples = params->getParam("min_calibration_samples", 1000_sz, "IMU samples");
30  this->gyroBiasEstimationRate = params->getParam("bias_estimation_rate", 0.01);
31  this->gyroThreshold = params->getParam("gyro_not_moving_threshold", 0.05, "rad/s");
32  this->cmdVelThreshold = params->getParam("cmd_vel_threshold", 1e-3, "m/s or rad/s");
33  this->notMovingDurationThreshold = params->getParam("not_moving_duration_threshold", ros::Duration(2), "s");
34  this->skipCalibration = params->getParam("skip_calibration", false);
35  this->shouldProduceDiagnostics = params->getParam("produce_diagnostics", true);
36 
37  if (this->skipCalibration)
39 
41  this->stopLockMsg.data = true;
42  this->stopUnlockMsg.data = false;
43 
44  this->imuPub = this->advertiseDiagnosed<sensor_msgs::Imu>(nh, pnh, "output", "imu_unbiased/data", 100);
45  this->biasPub = nh.advertise<geometry_msgs::Vector3Stamped>("imu/gyro_bias", 100, true);
46  this->speakInfoPub = nh.advertise<std_msgs::String>("speak/info", 2);
47  this->speakWarnPub = nh.advertise<std_msgs::String>("speak/warn", 2);
48  this->speakErrPub = nh.advertise<std_msgs::String>("speak/err", 2);
49  this->stopCommandPub = nh.advertise<geometry_msgs::Twist>("emergency_stop/cmd_vel", 2);
50  this->stopLockPub = nh.advertise<std_msgs::Bool>("emergency_stop", 2);
51 
52  this->imuSub = nh.subscribe("imu/data", 100, &GyroBiasRemoverNodelet::onImuMsg, this);
53  this->isMovingSub = nh.subscribe("odom_cmd_vel", 100, &GyroBiasRemoverNodelet::onOdomMsg, this);
54  this->resetSub = nh.subscribe("reset", 1, &GyroBiasRemoverNodelet::onReset, this);
55 
56  if (this->shouldProduceDiagnostics)
57  {
59  this->startDiagTimer();
60  }
61 
62  CRAS_INFO("IMU calibration has started.");
63  this->speak("Calibrating gyro, do not move me.", ros::console::levels::Warn);
64 }
65 
66 void GyroBiasRemoverNodelet::onImuMsg(const sensor_msgs::ImuConstPtr& msg)
67 {
68  if (ros::Time::now() + ros::Duration(3) < this->lastReceiveTime)
69  {
70  CRAS_WARN("ROS time has jumped back, resetting.");
71  this->reset();
72  }
74 
75  this->estimateBias(*msg);
76 
78  return;
79 
80  sensor_msgs::Imu unbiased = *msg;
81  unbiased.angular_velocity.x -= this->gyroBias.vector.x;
82  unbiased.angular_velocity.y -= this->gyroBias.vector.y;
83  unbiased.angular_velocity.z -= this->gyroBias.vector.z;
84 
85  this->imuPub->publish(unbiased);
86 }
87 
88 void GyroBiasRemoverNodelet::onOdomMsg(const nav_msgs::OdometryConstPtr& msg)
89 {
90  this->hasOdomMsg = true;
91  CRAS_DEBUG_THROTTLE(1.0, "State is %i", static_cast<std::underlying_type<BiasObserverState>::type>(this->state));
92 
93  const auto& v = msg->twist.twist.linear;
94  const auto& w = msg->twist.twist.angular;
95 
96  const auto& th = this->cmdVelThreshold;
97 
98  const auto isNowMoving = std::abs(v.x) > th || std::abs(v.y) > th || std::abs(v.z) > th || std::abs(w.x) > th
99  || std::abs(w.y) > th || std::abs(w.z) > th;
100 
101  if (isNowMoving && this->state == BiasObserverState::INITIAL_CALIBRATION)
102  {
103  CRAS_ERROR("Robot has moved during IMU calibration!");
104  this->speak("Gyro calibration failed, I moved!", ros::console::levels::Error);
105  }
106 
107  if (isNowMoving)
108  {
110  {
112  this->reportBiasChange();
114  }
115  this->notMovingDuration = {0, 0};
116  this->lastNotMovingTime = {0, 0};
117  return;
118  }
119 
120  if (this->state == BiasObserverState::MOVING)
121  {
123  this->lastNotMovingTime = msg->header.stamp;
124  this->notMovingDuration = {0, 0};
125  return;
126  }
127 
128  this->notMovingDuration += msg->header.stamp - this->lastNotMovingTime;
129  this->lastNotMovingTime = msg->header.stamp;
131  {
134  else
136  }
137 }
138 
139 void GyroBiasRemoverNodelet::estimateBias(const sensor_msgs::Imu& msg)
140 {
142  return;
143 
144  const auto& w = msg.angular_velocity;
145  auto& bias = this->gyroBias.vector;
146 
148  {
149  bias.x += w.x;
150  bias.y += w.y;
151  bias.z += w.z;
152  this->numCalibrationSamples++;
153 
154  const auto calibDuration = msg.header.stamp - this->calibrationStartedTime;
155  if (this->numCalibrationSamples >= this->minCalibrationSamples && calibDuration >= this->initialCalibrationDuration)
156  {
157  bias.x /= static_cast<double>(this->numCalibrationSamples);
158  bias.y /= static_cast<double>(this->numCalibrationSamples);
159  bias.z /= static_cast<double>(this->numCalibrationSamples);
160 
161  this->gyroBias.header = msg.header;
162  this->biasPub.publish(this->gyroBias);
163 
164  if (this->lastNotMovingTime == ros::Time(0, 0))
166  else if (this->notMovingDuration >= this->notMovingDurationThreshold)
168  else
170  CRAS_WARN("IMU calibration finished.");
171  this->speak("Gyros calibrated!", ros::console::levels::Warn);
172  this->stopLockPub.publish(this->stopUnlockMsg);
173  this->reportBiasChange();
174  }
175  else
176  {
177  CRAS_WARN_THROTTLE(1.0, "IMU is calibrating, do not move the robot.");
178  this->stopCommandPub.publish(this->stopCommand);
179  this->stopLockPub.publish(this->stopLockMsg);
180  }
181  }
182  else
183  {
184  auto th = this->gyroThreshold;
185 
186  if (std::abs(w.x - bias.x) > th || std::abs(w.y - bias.y) > th || std::abs(w.z - bias.z) > th)
187  {
189  this->lastNotMovingTime = {0, 0};
190  this->notMovingDuration = {0, 0};
191  this->reportBiasChange();
192  return;
193  }
194 
195  const auto& rate = this->gyroBiasEstimationRate;
196 
197  bias.x = (1 - rate) * bias.x + rate * w.x;
198  bias.y = (1 - rate) * bias.y + rate * w.y;
199  bias.z = (1 - rate) * bias.z + rate * w.z;
200 
201  this->gyroBias.header.frame_id = msg.header.frame_id;
202  this->gyroBias.header.stamp = msg.header.stamp;
203 
204  this->biasPub.publish(this->gyroBias);
205  }
206 }
207 
209 {
211  this->numCalibrationSamples = 0;
212  this->gyroBias.vector.x = this->gyroBias.vector.y = this->gyroBias.vector.z = 0;
213  this->notMovingDuration = {0, 0};
214  this->lastNotMovingTime = {0, 0};
216  this->hasOdomMsg = false;
217  if (this->shouldProduceDiagnostics)
218  this->getDiagUpdater().force_update();
219 }
220 
222 {
223  this->reset();
224 }
225 
227 {
229  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Initial calibration");
230  else if (this->hasOdomMsg)
231  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Running");
232  else
233  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "No odom messages received");
234 
235  switch (this->state)
236  {
238  stat.add("State", "Initial calibration");
239  stat.addf("Num samples", "%lu", this->numCalibrationSamples);
240  stat.add("Duration of calibration", cras::to_string(ros::Time::now() - this->calibrationStartedTime));
241  break;
243  stat.add("State", "Moving");
244  break;
246  stat.add("State", "Just stopped");
247  stat.add("Last motion before", cras::to_string(this->notMovingDuration));
248  break;
250  stat.add("State", "Standing still, calibrating bias");
251  stat.add("Last motion before", cras::to_string(this->notMovingDuration));
252  break;
253  }
254 }
255 
257 {
258  CRAS_INFO("Estimated gyro bias is: x=%.6f y=%.6f z=%.6f",
259  this->gyroBias.vector.x, this->gyroBias.vector.y, this->gyroBias.vector.z);
260 }
261 
262 void GyroBiasRemoverNodelet::speak(const std::string& message, const ros::console::levels::Level level)
263 {
264  std_msgs::String msg;
265  msg.data = message;
266 
267  switch (level)
268  {
270  this->speakInfoPub.publish(msg);
271  break;
273  this->speakWarnPub.publish(msg);
274  break;
275  default:
276  this->speakErrPub.publish(msg);
277  break;
278  }
279 }
280 
281 }
282 
void onOdomMsg(const nav_msgs::OdometryConstPtr &msg)
msg
::cras::DiagnosticUpdater & getDiagUpdater(bool forceNew=false) const
ros::Duration initialCalibrationDuration
void produceDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
::cras::BoundParamHelperPtr privateParams(const ::std::string &ns="") const
geometry_msgs::Twist stopCommand
#define CRAS_WARN(...)
void summary(unsigned char lvl, const std::string s)
ros::NodeHandle & getNodeHandle() const
#define CRAS_INFO(...)
std::unique_ptr< cras::DiagnosedPublisher< sensor_msgs::Imu > > imuPub
void add(const std::string &name, TaskFunction f)
inline ::std::string to_string(const ::XmlRpc::XmlRpcValue &value)
ros::NodeHandle & getPrivateNodeHandle() const
ros::Duration notMovingDurationThreshold
void estimateBias(const sensor_msgs::Imu &msg)
void addf(const std::string &key, const char *format,...)
geometry_msgs::Vector3Stamped gyroBias
void publish(const boost::shared_ptr< M > &message) const
void speak(const std::string &message, ros::console::levels::Level level)
#define CRAS_DEBUG_THROTTLE(period,...)
::cras::BoundParamHelperPtr params(const ::ros::NodeHandle &node, const ::std::string &ns="") const
static Time now()
void add(const std::string &key, const T &val)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
#define CRAS_ERROR(...)
#define CRAS_WARN_THROTTLE(period,...)
void onImuMsg(const sensor_msgs::ImuConstPtr &msg)
void onReset(const topic_tools::ShapeShifter &)


cras_imu_tools
Author(s): Martin Pecka
autogenerated on Fri Jun 23 2023 02:44:02