37 #include "geometry_msgs/Vector3Stamped.h" 39 #include "sensor_msgs/Imu.h" 40 #include "sensor_msgs/MagneticField.h" 42 #include "std_msgs/Float32.h" 43 #include "std_msgs/Header.h" 46 #include "um7/Reset.h" 67 template<
typename RegT>
69 std::string param, std::string human_name)
73 throw std::logic_error(
"configureVector3 may only be used with 3-field registers!");
83 << x <<
", " << y <<
", " << z <<
")");
89 throw std::runtime_error(
"Unable to configure vector.");
98 template<
typename RegT>
104 throw std::runtime_error(
"Command to device failed.");
121 throw std::runtime_error(
"Unable to set CREG_COM_SETTINGS.");
126 private_nh->
param<
int>(
"update_rate", rate, 20);
127 if (rate < 20 || rate > 255)
129 ROS_WARN(
"Potentially unsupported update rate of %d", rate);
132 uint32_t rate_bits =
static_cast<uint32_t
>(rate);
133 ROS_INFO(
"Setting update rate to %uHz", rate);
138 throw std::runtime_error(
"Unable to set CREG_COM_RATES2.");
145 throw std::runtime_error(
"Unable to set CREG_COM_RATES4.");
152 throw std::runtime_error(
"Unable to set CREG_COM_RATES5.");
159 throw std::runtime_error(
"Unable to set CREG_COM_RATES6.");
164 uint32_t misc_config_reg = 0;
168 private_nh->
param<
bool>(
"mag_updates", mag_updates,
true);
175 ROS_WARN(
"Excluding magnetometer updates from EKF.");
180 private_nh->
param<
bool>(
"quat_mode", quat_mode,
true);
187 ROS_WARN(
"Excluding quaternion mode.");
193 throw std::runtime_error(
"Unable to set CREG_MISC_SETTINGS.");
198 private_nh->
param<
bool>(
"zero_gyros", zero_gyros,
true);
204 const um7::Reset::Request& req,
const um7::Reset::Response& resp)
222 if (use_magnetic_field_msg)
224 mag_pub = imu_nh->
advertise<sensor_msgs::MagneticField>(
"mag", 1,
false);
228 mag_pub = imu_nh->
advertise<geometry_msgs::Vector3Stamped>(
"mag", 1,
false);
294 ROS_ERROR(
"OuputAxes enum value invalid");
301 if (mag_pub.getNumSubscribers() > 0)
303 if (use_magnetic_field_msg)
305 sensor_msgs::MagneticField mag_msg;
306 mag_msg.header = imu_msg.header;
333 ROS_ERROR(
"OuputAxes enum value invalid");
336 mag_pub.publish(mag_msg);
340 geometry_msgs::Vector3Stamped mag_msg;
341 mag_msg.header = imu_msg.header;
368 ROS_ERROR(
"OuputAxes enum value invalid");
371 mag_pub.publish(mag_msg);
376 if (rpy_pub.getNumSubscribers() > 0)
378 geometry_msgs::Vector3Stamped rpy_msg;
379 rpy_msg.header = imu_msg.header;
406 ROS_ERROR(
"OuputAxes enum value invalid");
409 rpy_pub.publish(rpy_msg);
413 if (temp_pub.getNumSubscribers() > 0)
415 std_msgs::Float32 temp_msg;
417 temp_pub.publish(temp_msg);
424 int main(
int argc,
char **argv)
433 private_nh.
param<std::string>(
"port", port,
"/dev/ttyUSB0");
434 private_nh.
param<int32_t>(
"baud", baud, 115200);
438 ser.setBaudrate(baud);
442 sensor_msgs::Imu imu_msg;
443 double linear_acceleration_stdev, angular_velocity_stdev;
444 private_nh.
param<std::string>(
"frame_id", imu_msg.header.frame_id,
"imu_link");
446 private_nh.
param<
double>(
"linear_acceleration_stdev", linear_acceleration_stdev, (4.0 * 1e-3
f * 9.80665));
447 private_nh.
param<
double>(
"angular_velocity_stdev", angular_velocity_stdev, (0.06 * 3.14159 / 180.0));
449 double linear_acceleration_cov = linear_acceleration_stdev * linear_acceleration_stdev;
450 double angular_velocity_cov = angular_velocity_stdev * angular_velocity_stdev;
453 double orientation_x_stdev, orientation_y_stdev, orientation_z_stdev;
454 private_nh.
param<
double>(
"orientation_x_stdev", orientation_x_stdev, (3.0 * 3.14159 / 180.0));
455 private_nh.
param<
double>(
"orientation_y_stdev", orientation_y_stdev, (3.0 * 3.14159 / 180.0));
456 private_nh.
param<
double>(
"orientation_z_stdev", orientation_z_stdev, (5.0 * 3.14159 / 180.0));
458 double orientation_x_covar = orientation_x_stdev * orientation_x_stdev;
459 double orientation_y_covar = orientation_y_stdev * orientation_y_stdev;
460 double orientation_z_covar = orientation_z_stdev * orientation_z_stdev;
464 bool orientation_in_robot_frame;
465 private_nh.
param<
bool>(
"tf_ned_to_enu", tf_ned_to_enu,
true);
466 private_nh.
param<
bool>(
"orientation_in_robot_frame", orientation_in_robot_frame,
false);
468 if (tf_ned_to_enu && orientation_in_robot_frame)
470 ROS_ERROR(
"Requested IMU data in two separate frames.");
472 else if (tf_ned_to_enu)
476 else if (orientation_in_robot_frame)
482 bool use_magnetic_field_msg;
483 private_nh.
param<
bool>(
"use_magnetic_field_msg", use_magnetic_field_msg,
false);
486 imu_msg.linear_acceleration_covariance[0] = linear_acceleration_cov;
487 imu_msg.linear_acceleration_covariance[4] = linear_acceleration_cov;
488 imu_msg.linear_acceleration_covariance[8] = linear_acceleration_cov;
490 imu_msg.angular_velocity_covariance[0] = angular_velocity_cov;
491 imu_msg.angular_velocity_covariance[4] = angular_velocity_cov;
492 imu_msg.angular_velocity_covariance[8] = angular_velocity_cov;
494 imu_msg.orientation_covariance[0] = orientation_x_covar;
495 imu_msg.orientation_covariance[4] = orientation_y_covar;
496 imu_msg.orientation_covariance[8] = orientation_z_covar;
499 bool first_failure =
true;
508 ROS_WARN(
"um7_driver was unable to connect to port %s.", port.c_str());
512 ROS_INFO(
"um7_driver successfully connected to serial port %s.", port.c_str());
513 first_failure =
true;
519 ros::ServiceServer srv = imu_nh.advertiseService<um7::Reset::Request, um7::Reset::Response>(
529 publishMsgs(registers, &imu_nh, imu_msg, axes, use_magnetic_field_msg);
534 catch(
const std::exception& e)
536 if (ser.isOpen()) ser.close();
538 ROS_INFO(
"Attempting reconnection after error.");
545 << port <<
". Trying again every 1 second.");
546 first_failure =
false;
const Accessor< uint32_t > cmd_set_mag_ref
void publish(const boost::shared_ptr< M > &message) const
const Accessor< float > accel
const Accessor< uint32_t > cmd_reset_ekf
#define MAG_UPDATES_ENABLED
int main(int argc, char **argv)
bool handleResetService(um7::Comms *sensor, const um7::Reset::Request &req, const um7::Reset::Response &resp)
Provides the Registers class, which initializes with a suite of accessors suitable for reading and wr...
const Accessor< int16_t > quat
const Accessor< float > mag
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void configureVector3(um7::Comms *sensor, const um7::Accessor< RegT > ®, std::string param, std::string human_name)
const Accessor< uint32_t > comrate5
void sendCommand(um7::Comms *sensor, const um7::Accessor< RegT > ®, std::string human_name)
void set(uint8_t field, RegT value) const
void set_scaled(uint16_t field, double value) const
bool sendWaitAck(const Accessor_ &a)
void publishMsgs(um7::Registers &r, ros::NodeHandle *imu_nh, sensor_msgs::Imu &imu_msg, OutputAxisOption axes, bool use_magnetic_field_msg)
const uint8_t TRIGGER_PACKET
ROSCPP_DECL bool get(const std::string &key, std::string &s)
int16_t receive(Registers *r)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
#define ROS_WARN_STREAM_COND(cond, args)
ROSCPP_DECL bool has(const std::string &key)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const Accessor< uint32_t > comrate4
const Accessor< uint32_t > cmd_zero_gyros
const Accessor< uint32_t > comrate6
const Accessor< uint32_t > communication
const Accessor< uint32_t > comrate2
#define RATE2_ALL_RAW_START
uint32_t getNumSubscribers() const
void setPort(const std::string &port)
#define ROS_INFO_STREAM(args)
Comms class definition. Does not manage the serial connection itself, but takes care of reading and w...
#define RATE4_ALL_PROC_START
void configureSensor(um7::Comms *sensor, ros::NodeHandle *private_nh)
const Accessor< uint32_t > misc_config
#define QUATERNION_MODE_ENABLED
#define RATE6_HEALTH_START
#define ROS_ERROR_STREAM(args)
ROSCPP_DECL void spinOnce()
const Accessor< float > gyro
double get_scaled(uint16_t field) const
#define DREG_EULER_PHI_THETA
#define RATE5_EULER_START
const Accessor< float > temperature
const Accessor< int16_t > euler