imu_3dm_gx4.cpp
Go to the documentation of this file.
1 #include <ros/ros.h>
2 #include <ros/node_handle.h>
5 
6 #include <sensor_msgs/Imu.h>
7 #include <sensor_msgs/MagneticField.h>
8 #include <sensor_msgs/FluidPressure.h>
9 #include <geometry_msgs/Vector3Stamped.h>
10 #include <geometry_msgs/QuaternionStamped.h>
11 
12 #include <thormang3_imu_3dm_gx4/FilterOutput.h>
13 
15 
16 using namespace imu_3dm_gx4;
17 
18 #define kEarthGravity (9.80665)
19 
24 std::string frameId;
25 sensor_msgs::Imu imuFilterData;
26 
29 
30 // diagnostic_updater resources
31 std::shared_ptr<diagnostic_updater::Updater> updater;
32 std::shared_ptr<diagnostic_updater::TopicDiagnostic> imuDiag;
33 std::shared_ptr<diagnostic_updater::TopicDiagnostic> filterDiag;
34 
35 void publishData(const Imu::IMUData &data) {
36  sensor_msgs::Imu imu;
37  sensor_msgs::MagneticField field;
38  sensor_msgs::FluidPressure pressure;
39 
40  // assume we have all of these since they were requested
42  assert(data.fields & Imu::IMUData::Accelerometer);
43  assert(data.fields & Imu::IMUData::Magnetometer);
44  assert(data.fields & Imu::IMUData::Barometer);
45  assert(data.fields & Imu::IMUData::Gyroscope);
46 
47  // timestamp identically
48  imu.header.stamp = ros::Time::now();
49  imu.header.frame_id = frameId;
50  field.header.stamp = imu.header.stamp;
51  field.header.frame_id = frameId;
52  pressure.header.stamp = imu.header.stamp;
53  pressure.header.frame_id = frameId;
54 
55  imu.orientation_covariance[0] =
56  -1; // orientation data is on a separate topic
57 
58  imu.orientation = imuFilterData.orientation;
59  imu.linear_acceleration.x = data.accel[0] * kEarthGravity;
60  imu.linear_acceleration.y = data.accel[1] * kEarthGravity;
61  imu.linear_acceleration.z = data.accel[2] * kEarthGravity;
62  imu.angular_velocity.x = data.gyro[0];
63  imu.angular_velocity.y = data.gyro[1];
64  imu.angular_velocity.z = data.gyro[2];
65 
66  field.magnetic_field.x = data.mag[0];
67  field.magnetic_field.y = data.mag[1];
68  field.magnetic_field.z = data.mag[2];
69 
70  pressure.fluid_pressure = data.pressure;
71 
72  // publish
73  pubIMU.publish(imu);
74  pubMag.publish(field);
75  pubPressure.publish(pressure);
76  if (imuDiag) {
77  imuDiag->tick(imu.header.stamp);
78  }
79 }
80 
81 void publishFilter(const Imu::FilterData &data) {
82  assert(data.fields & Imu::FilterData::Quaternion);
83  assert(data.fields & Imu::FilterData::Bias);
86 
87  thormang3_imu_3dm_gx4::FilterOutput output;
88  output.header.stamp = ros::Time::now();
89  output.header.frame_id = frameId;
90  output.orientation.w = data.quaternion[0];
91  output.orientation.x = data.quaternion[1];
92  output.orientation.y = data.quaternion[2];
93  output.orientation.z = data.quaternion[3];
94  imuFilterData.orientation.w = data.quaternion[0];
95  imuFilterData.orientation.x = data.quaternion[1];
96  imuFilterData.orientation.y = data.quaternion[2];
97  imuFilterData.orientation.z = data.quaternion[3];
98  output.bias.x = data.bias[0];
99  output.bias.y = data.bias[1];
100  output.bias.z = data.bias[2];
101 
102  output.bias_covariance[0] = data.biasUncertainty[0]*data.biasUncertainty[0];
103  output.bias_covariance[4] = data.biasUncertainty[1]*data.biasUncertainty[1];
104  output.bias_covariance[8] = data.biasUncertainty[2]*data.biasUncertainty[2];
105 
106  output.orientation_covariance[0] = data.angleUncertainty[0]*
107  data.angleUncertainty[0];
108  output.orientation_covariance[4] = data.angleUncertainty[1]*
109  data.angleUncertainty[1];
110  output.orientation_covariance[8] = data.angleUncertainty[2]*
111  data.angleUncertainty[2];
112 
113  output.quat_status = data.quaternionStatus;
114  output.bias_status = data.biasStatus;
115  output.orientation_covariance_status = data.angleUncertaintyStatus;
116  output.bias_covariance_status = data.biasUncertaintyStatus;
117 
118  pubFilter.publish(output);
119  if (filterDiag) {
120  filterDiag->tick(output.header.stamp);
121  }
122 }
123 
124 std::shared_ptr<diagnostic_updater::TopicDiagnostic> configTopicDiagnostic(
125  const std::string& name, double * target) {
126  std::shared_ptr<diagnostic_updater::TopicDiagnostic> diag;
127  const double period = 1.0 / *target; // for 1000Hz, period is 1e-3
128 
129  diagnostic_updater::FrequencyStatusParam freqParam(target, target, 0.01, 10);
130  diagnostic_updater::TimeStampStatusParam timeParam(0, period * 0.5);
131  diag.reset(new diagnostic_updater::TopicDiagnostic(name,
132  *updater,
133  freqParam,
134  timeParam));
135  return diag;
136 }
137 
139  imu_3dm_gx4::Imu* imu) {
140  // add base device info
141  std::map<std::string,std::string> map = info.toMap();
142  for (const std::pair<std::string,std::string>& p : map) {
143  stat.add(p.first, p.second);
144  }
145 
146  try {
147  // try to read diagnostic info
148  imu->getDiagnosticInfo(fields);
149 
150  auto map = fields.toMap();
151  for (const std::pair<std::string, unsigned int>& p : map) {
152  stat.add(p.first, p.second);
153  }
154  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Read diagnostic info.");
155  }
156  catch (std::exception& e) {
157  const std::string message = std::string("Failed: ") + e.what();
158  stat.summary(diagnostic_msgs::DiagnosticStatus::ERROR, message);
159  }
160 }
161 
162 int main(int argc, char **argv) {
163  ros::init(argc, argv, "imu_3dm_gx4");
164  ros::NodeHandle nh("~");
165 
166  std::string device;
167  int baudrate;
168  bool enableFilter;
169  bool enableMagUpdate, enableAccelUpdate;
170  int requestedImuRate, requestedFilterRate;
171  bool verbose;
172 
173  // load parameters from launch file
174  nh.param<std::string>("device", device, "/dev/ttyACM0");
175  nh.param<int>("baudrate", baudrate, 115200);
176  nh.param<std::string>("frameId", frameId, std::string("imu"));
177  nh.param<int>("imu_rate", requestedImuRate, 100);
178  nh.param<int>("filter_rate", requestedFilterRate, 100);
179  nh.param<bool>("enable_filter", enableFilter, false);
180  nh.param<bool>("enable_mag_update", enableMagUpdate, false);
181  nh.param<bool>("enable_accel_update", enableAccelUpdate, true);
182  nh.param<bool>("verbose", verbose, false);
183 
184  if (requestedFilterRate < 0 || requestedImuRate < 0) {
185  ROS_ERROR("imu_rate and filter_rate must be > 0");
186  return -1;
187  }
188 
189  pubIMU = nh.advertise<sensor_msgs::Imu>("imu", 1);
190  pubMag = nh.advertise<sensor_msgs::MagneticField>("magnetic_field", 1);
191  pubPressure = nh.advertise<sensor_msgs::FluidPressure>("pressure", 1);
192 
193  if (enableFilter) {
194  pubFilter = nh.advertise<thormang3_imu_3dm_gx4::FilterOutput>("filter", 1);
195  }
196 
197  // new instance of the IMU
198  Imu imu(device, verbose);
199  try {
200  imu.connect();
201 
202  ROS_INFO("Selecting baud rate %u", baudrate);
203  imu.selectBaudRate(baudrate);
204 
205  ROS_INFO("Fetching device info.");
206  imu.getDeviceInfo(info);
207  std::map<std::string,std::string> map = info.toMap();
208  for (const std::pair<std::string,std::string>& p : map) {
209  ROS_INFO("\t%s: %s", p.first.c_str(), p.second.c_str());
210  }
211 
212  ROS_INFO("Idling the device");
213  imu.idle();
214 
215  // read back data rates
216  uint16_t imuBaseRate, filterBaseRate;
217  imu.getIMUDataBaseRate(imuBaseRate);
218  ROS_INFO("IMU data base rate: %u Hz", imuBaseRate);
219  imu.getFilterDataBaseRate(filterBaseRate);
220  ROS_INFO("Filter data base rate: %u Hz", filterBaseRate);
221 
222  // calculate decimation rates
223  if (static_cast<uint16_t>(requestedImuRate) > imuBaseRate) {
224  throw std::runtime_error("imu_rate cannot exceed " +
225  std::to_string(imuBaseRate));
226  }
227  if (static_cast<uint16_t>(requestedFilterRate) > filterBaseRate) {
228  throw std::runtime_error("filter_rate cannot exceed " +
229  std::to_string(filterBaseRate));
230  }
231 
232  const uint16_t imuDecimation = imuBaseRate / requestedImuRate;
233  const uint16_t filterDecimation = filterBaseRate / requestedFilterRate;
234 
235  ROS_INFO("Selecting IMU decimation: %u", imuDecimation);
236  imu.setIMUDataRate(
237  imuDecimation, Imu::IMUData::Accelerometer |
241 
242  ROS_INFO("Selecting filter decimation: %u", filterDecimation);
243  imu.setFilterDataRate(filterDecimation, Imu::FilterData::Quaternion |
247 
248  ROS_INFO("Enabling IMU data stream");
249  imu.enableIMUStream(true);
250 
251  if (enableFilter) {
252  ROS_INFO("Enabling filter data stream");
253  imu.enableFilterStream(true);
254 
255  ROS_INFO("Enabling filter measurements");
256  imu.enableMeasurements(enableAccelUpdate, enableMagUpdate);
257 
258  ROS_INFO("Enabling gyro bias estimation");
259  imu.enableBiasEstimation(true);
260  } else {
261  ROS_INFO("Disabling filter data stream");
262  imu.enableFilterStream(false);
263  }
264  imu.setIMUDataCallback(publishData);
265  imu.setFilterDataCallback(publishFilter);
266 
267  // configure diagnostic updater
268  if (!nh.hasParam("diagnostic_period")) {
269  nh.setParam("diagnostic_period", 0.2); // 5hz period
270  }
271 
273  const std::string hwId = info.modelName + "-" + info.modelNumber;
274  updater->setHardwareID(hwId);
275 
276  // calculate the actual rates we will get
277  double imuRate = imuBaseRate / (1.0 * imuDecimation);
278  double filterRate = filterBaseRate / (1.0 * filterDecimation);
279  imuDiag = configTopicDiagnostic("imu",&imuRate);
280  if (enableFilter) {
281  filterDiag = configTopicDiagnostic("filter",&filterRate);
282  }
283 
284  updater->add("diagnostic_info",
285  boost::bind(&updateDiagnosticInfo, _1, &imu));
286 
287  ROS_INFO("Resuming the device");
288  imu.resume();
289 
290  while (ros::ok()) {
291  imu.runOnce();
292  updater->update();
293  }
294  imu.disconnect();
295  }
296  catch (Imu::io_error &e) {
297  ROS_ERROR("IO error: %s\n", e.what());
298  }
299  catch (Imu::timeout_error &e) {
300  ROS_ERROR("Timeout: %s\n", e.what());
301  }
302  catch (std::exception &e) {
303  ROS_ERROR("Exception: %s\n", e.what());
304  }
305 
306  return 0;
307 }
void publishData(const Imu::IMUData &data)
Definition: imu_3dm_gx4.cpp:35
std::map< std::string, std::string > toMap() const
Device options (range of the sensor)
Definition: imu.cpp:338
std::shared_ptr< diagnostic_updater::TopicDiagnostic > configTopicDiagnostic(const std::string &name, double *target)
void publish(const boost::shared_ptr< M > &message) const
std::string modelNumber
Model name.
Definition: imu.hpp:115
std::string frameId
Definition: imu_3dm_gx4.cpp:24
sensor_msgs::Imu imuFilterData
Definition: imu_3dm_gx4.cpp:25
void summary(unsigned char lvl, const std::string s)
std::string modelName
Firmware version.
Definition: imu.hpp:114
void updateDiagnosticInfo(diagnostic_updater::DiagnosticStatusWrapper &stat, imu_3dm_gx4::Imu *imu)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::map< std::string, unsigned int > toMap() const
Convert to map of human readable strings and integers.
Definition: imu.cpp:349
int main(int argc, char **argv)
io_error Generated when a low-level IO command fails.
Definition: imu.hpp:223
DiagnosticFields struct (See 3DM documentation for these fields)
Definition: imu.hpp:129
uint16_t biasUncertaintyStatus
Definition: imu.hpp:203
void getDiagnosticInfo(Imu::DiagnosticFields &fields)
getDiagnosticInfo Get diagnostic information from the IMU.
Definition: imu.cpp:719
Imu::DiagnosticFields fields
Definition: imu_3dm_gx4.cpp:28
FilterData Estimator readings produced by the sensor.
Definition: imu.hpp:183
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
ROSCPP_DECL bool ok()
IMUData IMU readings produced by the sensor.
Definition: imu.hpp:162
ros::Publisher pubFilter
Definition: imu_3dm_gx4.cpp:23
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
timeout_error Generated when read or write times out, usually indicates device hang up...
Definition: imu.hpp:231
std::shared_ptr< diagnostic_updater::TopicDiagnostic > filterDiag
Definition: imu_3dm_gx4.cpp:33
ros::Publisher pubPressure
Definition: imu_3dm_gx4.cpp:22
std::shared_ptr< diagnostic_updater::TopicDiagnostic > imuDiag
Definition: imu_3dm_gx4.cpp:32
Imu::Info info
Definition: imu_3dm_gx4.cpp:27
uint16_t angleUncertaintyStatus
Definition: imu.hpp:200
ros::Publisher pubIMU
Definition: imu_3dm_gx4.cpp:20
void publishFilter(const Imu::FilterData &data)
Definition: imu_3dm_gx4.cpp:81
Imu Interface to the Microstrain 3DM-GX4-25 IMU.
Definition: imu.hpp:43
unsigned int fields
Definition: imu.hpp:170
static Time now()
#define kEarthGravity
Definition: imu_3dm_gx4.cpp:18
void add(const std::string &key, const T &val)
bool hasParam(const std::string &key) const
std::shared_ptr< diagnostic_updater::Updater > updater
Definition: imu_3dm_gx4.cpp:31
#define ROS_ERROR(...)
Info Structure generated by the getDeviceInfo command.
Definition: imu.hpp:112
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
ros::Publisher pubMag
Definition: imu_3dm_gx4.cpp:21


thormang3_imu_3dm_gx4
Author(s): Gareth Cross, SCH
autogenerated on Mon Jun 10 2019 15:26:53