imu_ros_i.cpp
Go to the documentation of this file.
2 
3 namespace phidgets {
4 
6  : Imu(),
7  nh_(nh),
8  nh_private_(nh_private),
9  is_connected_(false),
10  error_number_(0),
11  target_publish_freq_(0.0),
12  serial_number_(-1)
13 {
14  ROS_INFO("Starting Phidgets IMU");
15 
16  // **** get parameters
17 
18  if (!nh_private_.getParam("period", period_))
19  {
20  period_ = 8; // 8 ms
21  }
22  if (!nh_private_.getParam("frame_id", frame_id_))
23  {
24  frame_id_ = "imu";
25  }
26  if (!nh_private_.getParam("angular_velocity_stdev",
28  {
29  // 0.095 deg/s gyroscope white noise sigma, as per manual
30  angular_velocity_stdev_ = 0.095 * (M_PI / 180.0);
31  }
32  if (!nh_private_.getParam("linear_acceleration_stdev",
34  {
35  // 280 ug accelerometer white noise sigma, as per manual
36  linear_acceleration_stdev_ = 280.0 * 1e-6 * G;
37  }
38  if (!nh_private_.getParam("magnetic_field_stdev", magnetic_field_stdev_))
39  {
40  // 1.1 milligauss magnetometer white noise sigma, as per manual
41  magnetic_field_stdev_ = 1.1 * 1e-3 * 1e-4;
42  }
44  "serial_number",
45  serial_number_)) // optional param serial_number, default is -1
46  {
48  "Searching for device with serial number: " << serial_number_);
49  }
50 
51  nh_private_.param("use_imu_time", use_imu_time_, true);
52 
53  bool has_compass_params =
54  nh_private_.getParam("cc_mag_field", cc_mag_field_) &&
55  nh_private_.getParam("cc_offset0", cc_offset0_) &&
56  nh_private_.getParam("cc_offset1", cc_offset1_) &&
57  nh_private_.getParam("cc_offset2", cc_offset2_) &&
58  nh_private_.getParam("cc_gain0", cc_gain0_) &&
59  nh_private_.getParam("cc_gain1", cc_gain1_) &&
60  nh_private_.getParam("cc_gain2", cc_gain2_) &&
61  nh_private_.getParam("cc_t0", cc_T0_) &&
62  nh_private_.getParam("cc_t1", cc_T1_) &&
63  nh_private_.getParam("cc_t2", cc_T2_) &&
64  nh_private_.getParam("cc_t3", cc_T3_) &&
65  nh_private_.getParam("cc_t4", cc_T4_) &&
66  nh_private_.getParam("cc_t5", cc_T5_);
67 
68  // **** advertise topics
69 
70  imu_publisher_ = nh_.advertise<ImuMsg>("imu/data_raw", 5);
71  mag_publisher_ = nh_.advertise<MagMsg>("imu/mag", 5);
72  cal_publisher_ = nh_.advertise<std_msgs::Bool>("imu/is_calibrated", 5,
73  true /* latched */);
74 
75  // Set up the topic publisher diagnostics monitor for imu/data_raw
76  // 1. The frequency status component monitors if imu data is published
77  // within 10% tolerance of the desired frequency of 1.0 / period
78  // 2. The timstamp status component monitors the delay between
79  // the header.stamp of the imu message and the real (ros) time
80  // the maximum tolerable drift is +- 100ms
81  target_publish_freq_ = 1000.0 / static_cast<double>(period_);
83  std::make_shared<diagnostic_updater::TopicDiagnostic>(
84  "imu/data_raw", std::ref(diag_updater_),
86  &target_publish_freq_, &target_publish_freq_, 0.1, 5),
88 
89  // **** advertise services
90 
91  cal_srv_ =
92  nh_.advertiseService("imu/calibrate", &ImuRosI::calibrateService, this);
93 
94  // **** initialize variables and device
95 
96  // ---- IMU message
97 
98  imu_msg_.header.frame_id = frame_id_;
99 
100  // build covariance matrices
101 
102  double ang_vel_var = angular_velocity_stdev_ * angular_velocity_stdev_;
103  double lin_acc_var =
105 
106  for (int i = 0; i < 3; ++i)
107  {
108  for (int j = 0; j < 3; ++j)
109  {
110  int idx = j * 3 + i;
111 
112  if (i == j)
113  {
114  imu_msg_.angular_velocity_covariance[idx] = ang_vel_var;
115  imu_msg_.linear_acceleration_covariance[idx] = lin_acc_var;
116  } else
117  {
118  imu_msg_.angular_velocity_covariance[idx] = 0.0;
119  imu_msg_.linear_acceleration_covariance[idx] = 0.0;
120  }
121  }
122  }
123 
124  // ---- magnetic field message
125 
126  mag_msg_.header.frame_id = frame_id_;
127 
128  // build covariance matrix
129 
130  double mag_field_var = magnetic_field_stdev_ * magnetic_field_stdev_;
131 
132  for (int i = 0; i < 3; ++i)
133  {
134  for (int j = 0; j < 3; ++j)
135  {
136  int idx = j * 3 + i;
137 
138  if (i == j)
139  {
140  mag_msg_.magnetic_field_covariance[idx] = mag_field_var;
141  } else
142  {
143  mag_msg_.magnetic_field_covariance[idx] = 0.0;
144  }
145  }
146  }
147 
148  // init diagnostics, we set the hardware id properly when the device is
149  // connected
151  diag_updater_.add("IMU Driver Status", this,
153 
154  initDevice();
155 
156  if (has_compass_params)
157  {
158  int result = setCompassCorrectionParameters(
161  cc_T5_);
162  if (result)
163  {
164  std::string err = Phidget::getErrorDescription(result);
165  ROS_ERROR(
166  "Problem while trying to set compass correction params: '%s'.",
167  err.c_str());
168  }
169  } else
170  {
171  ROS_INFO("No compass correction params found.");
172  }
173 }
174 
176 {
177  ROS_INFO_STREAM("Opening device");
178 
179  ROS_INFO("Waiting for IMU to be attached...");
180  int result = openAndWaitForAttachment(
181  serial_number_, 10000); // optional param serial_number, default is -1
182  if (result)
183  {
184  is_connected_ = false;
185  error_number_ = result;
187  std::string err = Phidget::getErrorDescription(result);
188  ROS_FATAL(
189  "Problem waiting for IMU attachment: %s Make sure the USB cable is "
190  "connected and you have executed the "
191  "phidgets_api/share/setup-udev.sh script.",
192  err.c_str());
193  }
194 
195  // calibrate on startup
196  calibrate();
197 
198  // set the hardware id for diagnostics
199  diag_updater_.setHardwareIDf("%s-%d", getDeviceName().c_str(),
201 }
202 
203 bool ImuRosI::calibrateService(std_srvs::Empty::Request &req,
204  std_srvs::Empty::Response &res)
205 {
206  (void)req;
207  (void)res;
208  calibrate();
209  return true;
210 }
211 
213 {
214  ROS_INFO(
215  "Calibrating IMU, this takes around 2 seconds to finish. "
216  "Make sure that the device is not moved during this time.");
217  zero();
218  // The API call returns directly, so we "enforce" the recommended 2 sec
219  // here. See: https://github.com/ros-drivers/phidgets_drivers/issues/40
220  ros::Duration(2.).sleep();
221  ROS_INFO("Calibrating IMU done.");
222 
224 
225  // publish message
226  std_msgs::Bool is_calibrated_msg;
227  is_calibrated_msg.data = true;
228  cal_publisher_.publish(is_calibrated_msg);
229 }
230 
231 void ImuRosI::dataHandler(const double acceleration[3],
232  const double angularRate[3],
233  const double magneticField[3], double timestamp)
234 {
235  // **** calculate time from timestamp
236  ros::Duration time_imu(timestamp);
237 
238  ros::Time time_now = time_zero_ + time_imu;
239 
240  if (use_imu_time_)
241  {
242  double timediff = time_now.toSec() - ros::Time::now().toSec();
243  if (::fabs(timediff) > MAX_TIMEDIFF_SECONDS)
244  {
245  ROS_WARN(
246  "IMU time lags behind by %f seconds, resetting IMU time "
247  "offset!",
248  timediff);
249  time_zero_ = ros::Time::now() - time_imu;
250  time_now = ros::Time::now();
251  }
252 
253  // Ensure that we only publish strictly ordered timestamps,
254  // also in case a time reset happened.
255  if (time_now <= last_published_time_)
256  {
257  ROS_WARN_THROTTLE(1.0, "Ignoring data with out-of-order time.");
258  return;
259  }
260  } else
261  {
262  time_now = ros::Time::now();
263  }
264 
265  // **** create and publish imu message
266 
267  std::shared_ptr<ImuMsg> imu_msg = std::make_shared<ImuMsg>(imu_msg_);
268 
269  imu_msg->header.stamp = time_now;
270 
271  // set linear acceleration
272  imu_msg->linear_acceleration.x = -acceleration[0] * G;
273  imu_msg->linear_acceleration.y = -acceleration[1] * G;
274  imu_msg->linear_acceleration.z = -acceleration[2] * G;
275 
276  // set angular velocities
277  imu_msg->angular_velocity.x = angularRate[0] * (M_PI / 180.0);
278  imu_msg->angular_velocity.y = angularRate[1] * (M_PI / 180.0);
279  imu_msg->angular_velocity.z = angularRate[2] * (M_PI / 180.0);
280 
281  imu_publisher_.publish(*imu_msg);
282  imu_publisher_diag_ptr_->tick(time_now);
283 
284  // **** create and publish magnetic field message
285 
286  std::shared_ptr<MagMsg> mag_msg = std::make_shared<MagMsg>(mag_msg_);
287 
288  mag_msg->header.stamp = time_now;
289 
290  if (magneticField[0] != PUNK_DBL)
291  {
292  // device reports data in Gauss, multiply by 1e-4 to convert to Tesla
293  mag_msg->magnetic_field.x = magneticField[0] * 1e-4;
294  mag_msg->magnetic_field.y = magneticField[1] * 1e-4;
295  mag_msg->magnetic_field.z = magneticField[2] * 1e-4;
296  } else
297  {
298  double nan = std::numeric_limits<double>::quiet_NaN();
299 
300  mag_msg->magnetic_field.x = nan;
301  mag_msg->magnetic_field.y = nan;
302  mag_msg->magnetic_field.z = nan;
303  }
304 
305  mag_publisher_.publish(*mag_msg);
306 
307  // diagnostics
309 
310  last_published_time_ = time_now;
311 }
312 
314 {
316  is_connected_ = true;
317  // Reset error number to no error if the prev error was disconnect
318  if (error_number_ == 13)
319  {
320  error_number_ = 0;
321  }
323 
324  // Set device params. This is in attachHandler(), since it has to be
325  // repeated on reattachment.
327 }
328 
330 {
332  is_connected_ = false;
334 }
335 
336 void ImuRosI::errorHandler(int error)
337 {
338  Imu::errorHandler(error);
339  error_number_ = error;
341 }
342 
345 {
346  if (is_connected_)
347  {
348  stat.summary(diagnostic_msgs::DiagnosticStatus::OK,
349  "The Phidget is connected.");
350  stat.add("Device Serial Number", getDeviceSerialNumber());
351  stat.add("Device Name", getDeviceName());
352  stat.add("Device Type", getDeviceType());
353  } else
354  {
355  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR,
356  "The Phidget is not connected. Check the USB.");
357  }
358 
359  if (error_number_ != 0)
360  {
361  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR,
362  "The Phidget reports error.");
363  stat.add("Error Number", error_number_);
364  stat.add("Error message", getErrorDescription(error_number_));
365  }
366 }
367 
368 } // namespace phidgets
int openAndWaitForAttachment(int serial_number, int timeout)
ros::ServiceServer cal_srv_
Definition: imu_ros_i.h:39
std::string frame_id_
Definition: imu_ros_i.h:62
#define ROS_FATAL(...)
#define ROS_WARN_THROTTLE(rate,...)
void publish(const boost::shared_ptr< M > &message) const
double cc_offset2_
Definition: imu_ros_i.h:75
void setDataRate(int rate)
void summary(unsigned char lvl, const std::string s)
void setHardwareID(const std::string &hwid)
const float MAX_TIMEDIFF_SECONDS
Definition: imu_ros_i.h:20
bool sleep() const
ImuRosI(ros::NodeHandle nh, ros::NodeHandle nh_private)
Definition: imu_ros_i.cpp:5
void add(const std::string &name, TaskFunction f)
ros::NodeHandle nh_
Definition: imu_ros_i.h:34
int getDeviceSerialNumber()
virtual void detachHandler()
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
double target_publish_freq_
Definition: imu_ros_i.h:50
ros::Time time_zero_
Definition: imu_ros_i.h:58
#define ROS_WARN(...)
double cc_gain0_
Definition: imu_ros_i.h:76
ros::Publisher imu_publisher_
Definition: imu_ros_i.h:36
double linear_acceleration_stdev_
Definition: imu_ros_i.h:66
static std::string getErrorDescription(int errorCode)
int setCompassCorrectionParameters(double cc_mag_field, double cc_offset0, double cc_offset1, double cc_offset2, double cc_gain0, double cc_gain1, double cc_gain2, double cc_T0, double cc_T1, double cc_T2, double cc_T3, double cc_T4, double cc_T5)
virtual void errorHandler(int error)
sensor_msgs::MagneticField MagMsg
Definition: imu_ros_i.h:25
sensor_msgs::Imu ImuMsg
Definition: imu_ros_i.h:24
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void attachHandler() override
Definition: imu_ros_i.cpp:313
virtual void attachHandler()
std::string getDeviceType()
bool calibrateService(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: imu_ros_i.cpp:203
void errorHandler(int error) override
Definition: imu_ros_i.cpp:336
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
double cc_gain2_
Definition: imu_ros_i.h:78
ros::Time last_published_time_
Definition: imu_ros_i.h:52
std::shared_ptr< diagnostic_updater::TopicDiagnostic > imu_publisher_diag_ptr_
Definition: imu_ros_i.h:45
double magnetic_field_stdev_
Definition: imu_ros_i.h:67
const float G
Definition: imu_ros_i.h:19
double angular_velocity_stdev_
Definition: imu_ros_i.h:65
void phidgetsDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
Main diagnostic method that takes care of collecting diagnostic data.
Definition: imu_ros_i.cpp:343
ros::NodeHandle nh_private_
Definition: imu_ros_i.h:35
#define ROS_INFO_STREAM(args)
double cc_offset1_
Definition: imu_ros_i.h:74
bool getParam(const std::string &key, std::string &s) const
double cc_offset0_
Definition: imu_ros_i.h:73
static Time now()
ros::Publisher cal_publisher_
Definition: imu_ros_i.h:38
double cc_mag_field_
Definition: imu_ros_i.h:72
void add(const std::string &key, const T &val)
void setHardwareIDf(const char *format,...)
ros::Publisher mag_publisher_
Definition: imu_ros_i.h:37
diagnostic_updater::Updater diag_updater_
updater object of class Update. Used to add diagnostic tasks, set ID etc. refer package API...
Definition: imu_ros_i.h:43
void detachHandler() override
Definition: imu_ros_i.cpp:329
#define ROS_ERROR(...)
void dataHandler(const double acceleration[3], const double angularRate[3], const double magneticField[3], double timestamp) override
Definition: imu_ros_i.cpp:231
double cc_gain1_
Definition: imu_ros_i.h:77
std::string getDeviceName()


phidgets_imu
Author(s): Ivan Dryanovski
autogenerated on Fri Apr 9 2021 02:56:04