main.cpp
Go to the documentation of this file.
00001 
00035 #include <string>
00036 
00037 #include "geometry_msgs/Vector3Stamped.h"
00038 #include "ros/ros.h"
00039 #include "sensor_msgs/Imu.h"
00040 #include "serial/serial.h"
00041 #include "std_msgs/Float32.h"
00042 #include "std_msgs/Header.h"
00043 #include "um6/comms.h"
00044 #include "um6/registers.h"
00045 #include "um6/Reset.h"
00046 
00047 // Don't try to be too clever. Arrival of this message triggers
00048 // us to publish everything we have.
00049 const uint8_t TRIGGER_PACKET = UM6_TEMPERATURE;
00050 
00055 template<typename RegT>
00056 void configureVector3(um6::Comms* sensor, const um6::Accessor<RegT>& reg,
00057                       std::string param, std::string human_name)
00058 {
00059   if (reg.length != 3)
00060   {
00061     throw std::logic_error("configureVector3 may only be used with 3-field registers!");
00062   }
00063 
00064   if (ros::param::has(param))
00065   {
00066     double x, y, z;
00067     ros::param::get(param + "/x", x);
00068     ros::param::get(param + "/y", y);
00069     ros::param::get(param + "/z", z);
00070     ROS_INFO_STREAM("Configuring " << human_name << " to ("
00071                     << x << ", " << y << ", " << z << ")");
00072     reg.set_scaled(0, x);
00073     reg.set_scaled(1, y);
00074     reg.set_scaled(2, z);
00075     if (sensor->sendWaitAck(reg))
00076     {
00077       throw std::runtime_error("Unable to configure vector.");
00078     }
00079   }
00080 }
00081 
00086 template<typename RegT>
00087 void sendCommand(um6::Comms* sensor, const um6::Accessor<RegT>& reg, std::string human_name)
00088 {
00089   ROS_INFO_STREAM("Sending command: " << human_name);
00090   if (!sensor->sendWaitAck(reg))
00091   {
00092     throw std::runtime_error("Command to device failed.");
00093   }
00094 }
00095 
00096 
00101 void configureSensor(um6::Comms* sensor)
00102 {
00103   um6::Registers r;
00104 
00105   // Enable outputs we need.
00106   const uint8_t UM6_BAUD_115200 = 0x5;
00107   uint32_t comm_reg = UM6_BROADCAST_ENABLED |
00108                       UM6_GYROS_PROC_ENABLED | UM6_ACCELS_PROC_ENABLED | UM6_MAG_PROC_ENABLED |
00109                       UM6_QUAT_ENABLED | UM6_EULER_ENABLED | UM6_COV_ENABLED | UM6_TEMPERATURE_ENABLED |
00110                       UM6_BAUD_115200 << UM6_BAUD_START_BIT;
00111   r.communication.set(0, comm_reg);
00112   if (!sensor->sendWaitAck(r.communication))
00113   {
00114     throw std::runtime_error("Unable to set communication register.");
00115   }
00116 
00117   // Optionally disable mag and accel updates in the sensor's EKF.
00118   bool mag_updates, accel_updates;
00119   ros::param::param<bool>("~mag_updates", mag_updates, true);
00120   ros::param::param<bool>("~accel_updates", accel_updates, true);
00121   uint32_t misc_config_reg = UM6_QUAT_ESTIMATE_ENABLED;
00122   if (mag_updates)
00123   {
00124     misc_config_reg |= UM6_MAG_UPDATE_ENABLED;
00125   }
00126   else
00127   {
00128     ROS_WARN("Excluding magnetometer updates from EKF.");
00129   }
00130   if (accel_updates)
00131   {
00132     misc_config_reg |= UM6_ACCEL_UPDATE_ENABLED;
00133   }
00134   else
00135   {
00136     ROS_WARN("Excluding accelerometer updates from EKF.");
00137   }
00138   r.misc_config.set(0, misc_config_reg);
00139   if (!sensor->sendWaitAck(r.misc_config))
00140   {
00141     throw std::runtime_error("Unable to set misc config register.");
00142   }
00143 
00144   // Optionally disable the gyro reset on startup. A user might choose to do this
00145   // if there's an external process which can ascertain when the vehicle is stationary
00146   // and periodically call the /reset service.
00147   bool zero_gyros;
00148   ros::param::param<bool>("~zero_gyros", zero_gyros, true);
00149   if (zero_gyros) sendCommand(sensor, r.cmd_zero_gyros, "zero gyroscopes");
00150 
00151   // Configurable vectors.
00152   configureVector3(sensor, r.mag_ref, "~mag_ref", "magnetic reference vector");
00153   configureVector3(sensor, r.accel_ref, "~accel_ref", "accelerometer reference vector");
00154   configureVector3(sensor, r.mag_bias, "~mag_bias", "magnetic bias vector");
00155   configureVector3(sensor, r.accel_bias, "~accel_bias", "accelerometer bias vector");
00156   configureVector3(sensor, r.gyro_bias, "~gyro_bias", "gyroscope bias vector");
00157 }
00158 
00159 
00160 bool handleResetService(um6::Comms* sensor,
00161                         const um6::Reset::Request& req, const um6::Reset::Response& resp)
00162 {
00163   um6::Registers r;
00164   if (req.zero_gyros) sendCommand(sensor, r.cmd_zero_gyros, "zero gyroscopes");
00165   if (req.reset_ekf) sendCommand(sensor, r.cmd_reset_ekf, "reset EKF");
00166   if (req.set_mag_ref) sendCommand(sensor, r.cmd_set_mag_ref, "set magnetometer reference");
00167   if (req.set_accel_ref) sendCommand(sensor, r.cmd_set_accel_ref, "set accelerometer reference");
00168   return true;
00169 }
00170 
00175 void publishMsgs(um6::Registers& r, ros::NodeHandle* n, const std_msgs::Header& header)
00176 {
00177   static ros::Publisher imu_pub = n->advertise<sensor_msgs::Imu>("imu/data", 1, false);
00178   static ros::Publisher mag_pub = n->advertise<geometry_msgs::Vector3Stamped>("imu/mag", 1, false);
00179   static ros::Publisher rpy_pub = n->advertise<geometry_msgs::Vector3Stamped>("imu/rpy", 1, false);
00180   static ros::Publisher temp_pub = n->advertise<std_msgs::Float32>("imu/temperature", 1, false);
00181 
00182   if (imu_pub.getNumSubscribers() > 0)
00183   {
00184     sensor_msgs::Imu imu_msg;
00185     imu_msg.header = header;
00186 
00187     // IMU outputs [w,x,y,z] NED, convert to [x,y,z,w] ENU
00188     imu_msg.orientation.x = r.quat.get_scaled(2);
00189     imu_msg.orientation.y = r.quat.get_scaled(1);
00190     imu_msg.orientation.z = -r.quat.get_scaled(3);
00191     imu_msg.orientation.w = r.quat.get_scaled(0);
00192 
00193     // IMU reports a 4x4 wxyz covariance, ROS requires only 3x3 xyz.
00194     // NED -> ENU conversion req'd?
00195     imu_msg.orientation_covariance[0] = r.covariance.get_scaled(5);
00196     imu_msg.orientation_covariance[1] = r.covariance.get_scaled(6);
00197     imu_msg.orientation_covariance[2] = r.covariance.get_scaled(7);
00198     imu_msg.orientation_covariance[3] = r.covariance.get_scaled(9);
00199     imu_msg.orientation_covariance[4] = r.covariance.get_scaled(10);
00200     imu_msg.orientation_covariance[5] = r.covariance.get_scaled(11);
00201     imu_msg.orientation_covariance[6] = r.covariance.get_scaled(13);
00202     imu_msg.orientation_covariance[7] = r.covariance.get_scaled(14);
00203     imu_msg.orientation_covariance[8] = r.covariance.get_scaled(15);
00204 
00205     // NED -> ENU conversion.
00206     imu_msg.angular_velocity.x = r.gyro.get_scaled(1);
00207     imu_msg.angular_velocity.y = r.gyro.get_scaled(0);
00208     imu_msg.angular_velocity.z = -r.gyro.get_scaled(2);
00209 
00210     // NED -> ENU conversion.
00211     imu_msg.linear_acceleration.x = r.accel.get_scaled(1);
00212     imu_msg.linear_acceleration.y = r.accel.get_scaled(0);
00213     imu_msg.linear_acceleration.z = -r.accel.get_scaled(2);
00214 
00215     imu_pub.publish(imu_msg);
00216   }
00217 
00218   if (mag_pub.getNumSubscribers() > 0)
00219   {
00220     geometry_msgs::Vector3Stamped mag_msg;
00221     mag_msg.header = header;
00222     mag_msg.vector.x = r.mag.get_scaled(1);
00223     mag_msg.vector.y = r.mag.get_scaled(0);
00224     mag_msg.vector.z = -r.mag.get_scaled(2);
00225     mag_pub.publish(mag_msg);
00226   }
00227 
00228   if (rpy_pub.getNumSubscribers() > 0)
00229   {
00230     geometry_msgs::Vector3Stamped rpy_msg;
00231     rpy_msg.header = header;
00232     rpy_msg.vector.x = r.euler.get_scaled(1);
00233     rpy_msg.vector.y = r.euler.get_scaled(0);
00234     rpy_msg.vector.z = -r.euler.get_scaled(2);
00235     rpy_pub.publish(rpy_msg);
00236   }
00237 
00238   if (temp_pub.getNumSubscribers() > 0)
00239   {
00240     std_msgs::Float32 temp_msg;
00241     temp_msg.data = r.temperature.get_scaled(0);
00242     temp_pub.publish(temp_msg);
00243   }
00244 }
00245 
00246 
00250 int main(int argc, char **argv)
00251 {
00252   ros::init(argc, argv, "um6_driver");
00253 
00254   // Load parameters from private node handle.
00255   std::string port;
00256   int32_t baud;
00257   ros::param::param<std::string>("~port", port, "/dev/ttyUSB0");
00258   ros::param::param<int32_t>("~baud", baud, 115200);
00259 
00260   serial::Serial ser;
00261   ser.setPort(port);
00262   ser.setBaudrate(baud);
00263   serial::Timeout to = serial::Timeout(50, 50, 0, 50, 0);
00264   ser.setTimeout(to);
00265 
00266   ros::NodeHandle n;
00267   std_msgs::Header header;
00268   ros::param::param<std::string>("~frame_id", header.frame_id, "imu_link");
00269 
00270   bool first_failure = true;
00271   while (ros::ok())
00272   {
00273     try
00274     {
00275       ser.open();
00276     }
00277     catch(const serial::IOException& e)
00278     {
00279       ROS_DEBUG("Unable to connect to port.");
00280     }
00281     if (ser.isOpen())
00282     {
00283       ROS_INFO("Successfully connected to serial port.");
00284       first_failure = true;
00285       try
00286       {
00287         um6::Comms sensor(&ser);
00288         configureSensor(&sensor);
00289         um6::Registers registers;
00290         ros::ServiceServer srv = n.advertiseService<um6::Reset::Request, um6::Reset::Response>(
00291                                    "reset", boost::bind(handleResetService, &sensor, _1, _2));
00292 
00293         while (ros::ok())
00294         {
00295           if (sensor.receive(&registers) == TRIGGER_PACKET)
00296           {
00297             // Triggered by arrival of final message in group.
00298             header.stamp = ros::Time::now();
00299             publishMsgs(registers, &n, header);
00300             ros::spinOnce();
00301           }
00302         }
00303       }
00304       catch(const std::exception& e)
00305       {
00306         if (ser.isOpen()) ser.close();
00307         ROS_ERROR_STREAM(e.what());
00308         ROS_INFO("Attempting reconnection after error.");
00309         ros::Duration(1.0).sleep();
00310       }
00311     }
00312     else
00313     {
00314       ROS_WARN_STREAM_COND(first_failure, "Could not connect to serial device "
00315                            << port << ". Trying again every 1 second.");
00316       first_failure = false;
00317       ros::Duration(1.0).sleep();
00318     }
00319   }
00320 }


um6
Author(s): Mike Purvis
autogenerated on Thu Aug 27 2015 15:31:34