microstrain_3dm_gx5_45.cpp
Go to the documentation of this file.
00001 /* 
00002 
00003 Copyright (c) 2017, Brian Bingham
00004 All rights reserved
00005 
00006 This file is part of the microstrain_3dm_gx5_45 package.
00007 
00008 microstrain_3dm_gx5_45 is free software: you can redistribute it and/or modify
00009 it under the terms of the GNU General Public License as published by
00010 the Free Software Foundation, either version 3 of the License, or
00011 (at your option) any later version.
00012 
00013 microstrain_3dm_gx5_45 is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 GNU General Public License for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #include "microstrain_3dm_gx5_45.h"
00024 #include <tf2/LinearMath/Transform.h>
00025 #include <string>
00026 #include <algorithm>  
00027 
00028 namespace Microstrain
00029 {
00030   Microstrain::Microstrain():
00031     // Initialization list
00032     filter_valid_packet_count_(0),
00033     ahrs_valid_packet_count_(0),
00034     gps_valid_packet_count_(0),
00035     filter_timeout_packet_count_(0),
00036     ahrs_timeout_packet_count_(0),
00037     gps_timeout_packet_count_(0),
00038     filter_checksum_error_packet_count_(0),
00039     ahrs_checksum_error_packet_count_(0),
00040     gps_checksum_error_packet_count_(0),
00041     gps_frame_id_("gps_frame"),
00042     imu_frame_id_("imu_frame"),
00043     odom_frame_id_("odom_frame"),
00044     odom_child_frame_id_("odom_frame"),
00045     publish_gps_(true),
00046     publish_imu_(true),
00047     publish_odom_(true)
00048   {
00049     // pass
00050   }
00051   Microstrain::~Microstrain()
00052   {
00053     // pass
00054   }
00055   void Microstrain::run()
00056   {
00057     // Variables for device configuration, ROS parameters, etc.
00058     u32 com_port, baudrate;
00059     bool device_setup = false;
00060     bool readback_settings = true;
00061     bool save_settings = true;
00062     bool auto_init = true;
00063     u8 auto_init_u8 = 1;
00064     u8 readback_headingsource = 0;
00065     u8 readback_auto_init = 0;
00066     u8 dynamics_mode           = 0;
00067     u8 readback_dynamics_mode  = 0;
00068     int declination_source;
00069     u8 declination_source_u8;
00070     u8 readback_declination_source;
00071     double declination;
00072     
00073     // Variables
00074     tf2::Quaternion quat;
00075     base_device_info_field device_info;
00076     u8  temp_string[20] = {0};
00077     u32 bit_result;
00078     u8  enable = 1;
00079     u8  data_stream_format_descriptors[10];
00080     u16 data_stream_format_decimation[10];
00081     u8  data_stream_format_num_entries = 0;
00082     u8  readback_data_stream_format_descriptors[10] = {0};
00083     u16 readback_data_stream_format_decimation[10]  = {0};
00084     u8  readback_data_stream_format_num_entries     =  0;
00085     u16 base_rate = 0;
00086     u16 device_descriptors[128]  = {0};
00087     u16 device_descriptors_size  = 128*2;
00088     s16 i;
00089     u16 j;
00090     u8  com_mode = 0;
00091     u8  readback_com_mode = 0;
00092     float angles[3]             = {0};
00093     float readback_angles[3]    = {0};
00094     float offset[3]             = {0};
00095     float readback_offset[3]    = {0};
00096     float hard_iron[3]          = {0};
00097     float hard_iron_readback[3] = {0};
00098     float soft_iron[9]          = {0};
00099     float soft_iron_readback[9] = {0};
00100     u16 estimation_control   = 0, estimation_control_readback = 0;
00101     u8  gps_source     = 0;
00102     u8  heading_source = 0x1;
00103     float noise[3]          = {0};
00104     float readback_noise[3] = {0};
00105     float beta[3]                 = {0};
00106     float readback_beta[3]        = {0};
00107     mip_low_pass_filter_settings filter_settings;
00108     float bias_vector[3]                   = {0};
00109     u16 duration = 0;
00110     gx4_imu_diagnostic_device_status_field imu_diagnostic_field;
00111     gx4_imu_basic_status_field imu_basic_field;
00112     gx4_45_diagnostic_device_status_field diagnostic_field;
00113     gx4_45_basic_status_field basic_field;
00114     mip_filter_external_gps_update_command external_gps_update;
00115     mip_filter_external_heading_update_command external_heading_update;
00116     mip_filter_zero_update_command zero_update_control, zero_update_readback;
00117     mip_filter_external_heading_with_time_command external_heading_with_time;
00118     mip_complementary_filter_settings comp_filter_command, comp_filter_readback;
00119     
00120     mip_filter_accel_magnitude_error_adaptive_measurement_command        accel_magnitude_error_command, accel_magnitude_error_readback;
00121     mip_filter_magnetometer_magnitude_error_adaptive_measurement_command mag_magnitude_error_command, mag_magnitude_error_readback;
00122     mip_filter_magnetometer_dip_angle_error_adaptive_measurement_command mag_dip_angle_error_command, mag_dip_angle_error_readback;
00123     
00124     // ROS setup
00125     ros::Time::init();
00126     ros::NodeHandle node;
00127     ros::NodeHandle private_nh("~");
00128 
00129     // ROS Parameters
00130     // Comms Parameters
00131     std::string port;
00132     int baud, pdyn_mode;
00133     private_nh.param("port", port, std::string("/dev/ttyACM0"));
00134     private_nh.param("baudrate",baud,115200);
00135     baudrate = (u32)baud; 
00136     // Configuration Parameters
00137     private_nh.param("device_setup",device_setup,false);
00138     private_nh.param("readback_settings",readback_settings,true);
00139     private_nh.param("save_settings",save_settings,true);
00140 
00141     private_nh.param("auto_init",auto_init,true);
00142     private_nh.param("gps_rate",gps_rate_, 1);
00143     private_nh.param("imu_rate",imu_rate_, 10);
00144     private_nh.param("nav_rate",nav_rate_, 10);
00145     private_nh.param("dynamics_mode",pdyn_mode,1);
00146     dynamics_mode = (u8)pdyn_mode;
00147     if (dynamics_mode < 1 || dynamics_mode > 3){
00148       ROS_WARN("dynamics_mode can't be %#04X, must be 1, 2 or 3.  Setting to 1.",dynamics_mode);
00149       dynamics_mode = 1;
00150     }
00151     private_nh.param("declination_source",declination_source,2);
00152     if (declination_source < 1 || declination_source > 3){
00153       ROS_WARN("declination_source can't be %#04X, must be 1, 2 or 3.  Setting to 2.",declination_source);
00154       declination_source = 2;
00155     }
00156     declination_source_u8 = (u8)declination_source;
00157     //declination_source_command=(u8)declination_source;
00158     private_nh.param("declination",declination,0.23);
00159     private_nh.param("gps_frame_id",gps_frame_id_, std::string("wgs84"));
00160     private_nh.param("imu_frame_id",imu_frame_id_, std::string("base_link"));
00161     private_nh.param("odom_frame_id",odom_frame_id_, std::string("wgs84"));
00162     private_nh.param("odom_child_frame_id",odom_child_frame_id_,
00163                      std::string("base_link"));
00164     private_nh.param("publish_gps",publish_gps_, true);
00165     private_nh.param("publish_imu",publish_imu_, true);
00166     private_nh.param("publish_odom",publish_odom_, true);
00167 
00168     // ROS publishers and subscribers
00169     if (publish_gps_)
00170       gps_pub_ = node.advertise<sensor_msgs::NavSatFix>("gps/fix",100);
00171     if (publish_imu_)
00172       imu_pub_ = node.advertise<sensor_msgs::Imu>("imu/data",100);
00173     if (publish_odom_)
00174     {
00175       nav_pub_ = node.advertise<nav_msgs::Odometry>("nav/odom",100);
00176       nav_status_pub_ = node.advertise<std_msgs::Int16MultiArray>("nav/status",100);
00177     }
00178     ros::ServiceServer service = node.advertiseService("reset_kf", &Microstrain::reset_callback, this);
00179 
00180 
00181     //Initialize the serial interface to the device
00182     ROS_INFO("Attempting to open serial port <%s> at <%d> \n",
00183              port.c_str(),baudrate);
00184     if(mip_interface_init(port.c_str(), baudrate, &device_interface_, DEFAULT_PACKET_TIMEOUT_MS) != MIP_INTERFACE_OK){
00185       ROS_FATAL("Couldn't open serial port!  Is it plugged in?");
00186     }
00187 
00188 
00189     // Setup device callbacks
00190     if(mip_interface_add_descriptor_set_callback(&device_interface_, MIP_FILTER_DATA_SET, this, &filter_packet_callback_wrapper) != MIP_INTERFACE_OK)
00191       {
00192         ROS_FATAL("Can't setup filter callback!");
00193         return;
00194       }
00195     if(mip_interface_add_descriptor_set_callback(&device_interface_, MIP_AHRS_DATA_SET, this, &ahrs_packet_callback_wrapper) != MIP_INTERFACE_OK)
00196       {
00197         ROS_FATAL("Can't setup ahrs callbacks!");
00198         return;
00199       }
00200     if(mip_interface_add_descriptor_set_callback(&device_interface_, MIP_GPS_DATA_SET, this, &gps_packet_callback_wrapper) != MIP_INTERFACE_OK)
00201       {
00202         ROS_FATAL("Can't setup gpscallbacks!");
00203         return;
00204       }
00205 
00207     // Device setup
00208     float dT=0.5;  // common sleep time after setup communications
00209     if (device_setup)
00210     {
00211       // Put device into standard mode - we never really use "direct mode"
00212       ROS_INFO("Putting device communications into 'standard mode'");
00213       device_descriptors_size  = 128*2;
00214       com_mode = MIP_SDK_GX4_45_IMU_STANDARD_MODE;
00215       while(mip_system_com_mode(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, &com_mode) != MIP_INTERFACE_OK){}
00216       //Verify device mode setting
00217       ROS_INFO("Verify comm's mode");
00218       while(mip_system_com_mode(&device_interface_, MIP_FUNCTION_SELECTOR_READ, &com_mode) != MIP_INTERFACE_OK){}
00219       ROS_INFO("Sleep for a second...");
00220       ros::Duration(dT).sleep();
00221       ROS_INFO("Right mode?");
00222       if(com_mode != MIP_SDK_GX4_45_IMU_STANDARD_MODE)
00223       {
00224         ROS_ERROR("Appears we didn't get into standard mode!");
00225       }
00226 
00227       // Put into idle mode
00228       ROS_INFO("Idling Device: Stopping data streams and/or waking from sleep");
00229       while(mip_base_cmd_idle(&device_interface_) != MIP_INTERFACE_OK){}
00230       ros::Duration(dT).sleep();
00231 
00232       // AHRS Setup
00233       // Get base rate
00234       if (publish_imu_){
00235         while(mip_3dm_cmd_get_ahrs_base_rate(&device_interface_, &base_rate) != MIP_INTERFACE_OK){}
00236         ROS_INFO("AHRS Base Rate => %d Hz", base_rate);
00237         ros::Duration(dT).sleep();
00238         // Deterimine decimation to get close to goal rate
00239         u8 imu_decimation = (u8)((float)base_rate/ (float)imu_rate_);
00240         ROS_INFO("AHRS decimation set to %#04X",imu_decimation);
00241 
00242         // AHRS Message Format
00243         // Set message format
00244         ROS_INFO("Setting the AHRS message format");
00245         data_stream_format_descriptors[0] = MIP_AHRS_DATA_ACCEL_SCALED;
00246         data_stream_format_descriptors[1] = MIP_AHRS_DATA_GYRO_SCALED;
00247         data_stream_format_descriptors[2] = MIP_AHRS_DATA_QUATERNION;
00248         data_stream_format_decimation[0]  = imu_decimation;//0x32;
00249         data_stream_format_decimation[1]  = imu_decimation;//0x32;
00250         data_stream_format_decimation[2]  = imu_decimation;//0x32;
00251         data_stream_format_num_entries = 3;
00252         while(mip_3dm_cmd_ahrs_message_format(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, &data_stream_format_num_entries, data_stream_format_descriptors, data_stream_format_decimation) != MIP_INTERFACE_OK){}
00253         ros::Duration(dT).sleep();
00254         // Poll to verify
00255         ROS_INFO("Poll AHRS data to verify");
00256         while(mip_3dm_cmd_poll_ahrs(&device_interface_, MIP_3DM_POLLING_ENABLE_ACK_NACK, data_stream_format_num_entries, data_stream_format_descriptors) != MIP_INTERFACE_OK){}
00257         ros::Duration(dT).sleep();
00258         // Save
00259         if (save_settings)
00260         {
00261           ROS_INFO("Saving AHRS data settings");
00262           while(mip_3dm_cmd_ahrs_message_format(&device_interface_, MIP_FUNCTION_SELECTOR_STORE_EEPROM, 0, NULL,NULL) != MIP_INTERFACE_OK){}
00263           ros::Duration(dT).sleep();
00264         }
00265 
00266         // Declination Source
00267         // Set declination
00268         ROS_INFO("Setting declination source to %#04X",declination_source_u8);
00269         while(mip_filter_declination_source(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, &declination_source_u8) != MIP_INTERFACE_OK){}
00270         ros::Duration(dT).sleep();
00271         //Read back the declination source
00272         ROS_INFO("Reading back declination source");
00273         while(mip_filter_declination_source(&device_interface_, MIP_FUNCTION_SELECTOR_READ, &readback_declination_source) != MIP_INTERFACE_OK){}
00274         if(declination_source_u8 == readback_declination_source)
00275         {
00276           ROS_INFO("Success: Declination source set to %#04X", declination_source_u8);
00277         }
00278         else
00279         {
00280           ROS_WARN("Failed to set the declination source to %#04X!", declination_source_u8);
00281         }
00282         ros::Duration(dT).sleep();
00283         if (save_settings)
00284         {
00285           ROS_INFO("Saving declination source settings to EEPROM");
00286           while(mip_filter_declination_source(&device_interface_, 
00287                                               MIP_FUNCTION_SELECTOR_STORE_EEPROM,
00288                                               NULL) != MIP_INTERFACE_OK)
00289           {}
00290           ros::Duration(dT).sleep();
00291         }
00292         
00293       } // end of AHRS setup
00294 
00295       // GPS Setup
00296       if (publish_gps_){
00297       
00298         while(mip_3dm_cmd_get_gps_base_rate(&device_interface_, &base_rate) != MIP_INTERFACE_OK){}
00299         ROS_INFO("GPS Base Rate => %d Hz", base_rate);
00300         u8 gps_decimation = (u8)((float)base_rate/ (float)gps_rate_);
00301         ros::Duration(dT).sleep();
00302       
00304         // Set
00305         ROS_INFO("Setting GPS stream format");
00306         data_stream_format_descriptors[0] = MIP_GPS_DATA_LLH_POS;
00307         data_stream_format_descriptors[1] = MIP_GPS_DATA_NED_VELOCITY;
00308         data_stream_format_descriptors[2] = MIP_GPS_DATA_GPS_TIME;
00309         data_stream_format_decimation[0]  = gps_decimation; //0x01; //0x04;
00310         data_stream_format_decimation[1]  = gps_decimation; //0x01; //0x04;
00311         data_stream_format_decimation[2]  = gps_decimation; //0x01; //0x04;
00312         data_stream_format_num_entries = 3;
00313         while(mip_3dm_cmd_gps_message_format(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, &data_stream_format_num_entries,data_stream_format_descriptors, data_stream_format_decimation) != MIP_INTERFACE_OK){}
00314         ros::Duration(dT).sleep();
00315         // Save
00316         if (save_settings)
00317         {
00318           ROS_INFO("Saving GPS data settings");
00319           while(mip_3dm_cmd_gps_message_format(&device_interface_, MIP_FUNCTION_SELECTOR_STORE_EEPROM, 0, NULL,NULL) != MIP_INTERFACE_OK){}
00320           ros::Duration(dT).sleep();
00321         }
00322       } // end of GPS setup
00323 
00324       if (publish_odom_){
00325         while(mip_3dm_cmd_get_filter_base_rate(&device_interface_, &base_rate) != MIP_INTERFACE_OK){}
00326         ROS_INFO("FILTER Base Rate => %d Hz", base_rate);
00327         u8 nav_decimation = (u8)((float)base_rate/ (float)nav_rate_);
00328         ros::Duration(dT).sleep();
00329         
00331         // Set
00332         ROS_INFO("Setting Filter stream format");
00333         data_stream_format_descriptors[0] = MIP_FILTER_DATA_LLH_POS;
00334         data_stream_format_descriptors[1] = MIP_FILTER_DATA_NED_VEL;
00335         //data_stream_format_descriptors[2] = MIP_FILTER_DATA_ATT_EULER_ANGLES;
00336         data_stream_format_descriptors[2] = MIP_FILTER_DATA_ATT_QUATERNION;
00337         data_stream_format_descriptors[3] = MIP_FILTER_DATA_POS_UNCERTAINTY;
00338         data_stream_format_descriptors[4] = MIP_FILTER_DATA_VEL_UNCERTAINTY;
00339         data_stream_format_descriptors[5] = MIP_FILTER_DATA_ATT_UNCERTAINTY_EULER;
00340         data_stream_format_descriptors[6] = MIP_FILTER_DATA_COMPENSATED_ANGULAR_RATE;
00341         data_stream_format_descriptors[7] = MIP_FILTER_DATA_FILTER_STATUS;
00342         data_stream_format_decimation[0]  = nav_decimation; //0x32;
00343         data_stream_format_decimation[1]  = nav_decimation; //0x32;
00344         data_stream_format_decimation[2]  = nav_decimation; //0x32;
00345         data_stream_format_decimation[3]  = nav_decimation; //0x32;
00346         data_stream_format_decimation[4]  = nav_decimation; //0x32;
00347         data_stream_format_decimation[5]  = nav_decimation; //0x32;
00348         data_stream_format_decimation[6]  = nav_decimation; //0x32;
00349         data_stream_format_decimation[7]  = nav_decimation; //0x32;
00350         data_stream_format_num_entries = 8;
00351         while(mip_3dm_cmd_filter_message_format(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, &data_stream_format_num_entries,data_stream_format_descriptors, data_stream_format_decimation) != MIP_INTERFACE_OK){}
00352         ros::Duration(dT).sleep();
00353         // Poll to verify
00354         ROS_INFO("Poll filter data to test stream");
00355         while(mip_3dm_cmd_poll_filter(&device_interface_, MIP_3DM_POLLING_ENABLE_ACK_NACK, data_stream_format_num_entries, data_stream_format_descriptors) != MIP_INTERFACE_OK){}
00356         ros::Duration(dT).sleep();
00357         // Save
00358         if (save_settings)
00359         {
00360           ROS_INFO("Saving Filter data settings");
00361           while(mip_3dm_cmd_filter_message_format(&device_interface_, MIP_FUNCTION_SELECTOR_STORE_EEPROM, 0, NULL,NULL) != MIP_INTERFACE_OK){}
00362           ros::Duration(dT).sleep();
00363         }
00364         // Dynamics Mode
00365         // Set dynamics mode
00366         ROS_INFO("Setting dynamics mode to %#04X",dynamics_mode);
00367         while(mip_filter_vehicle_dynamics_mode(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, &dynamics_mode) != MIP_INTERFACE_OK){}
00368         ros::Duration(dT).sleep();
00369         // Readback dynamics mode
00370         if (readback_settings)
00371         {
00372           // Read the settings back
00373           ROS_INFO("Reading back dynamics mode setting");
00374           while(mip_filter_vehicle_dynamics_mode(&device_interface_, 
00375                                                  MIP_FUNCTION_SELECTOR_READ, 
00376                                                  &readback_dynamics_mode)
00377                 != MIP_INTERFACE_OK)
00378           {}
00379           ros::Duration(dT).sleep();
00380           if (dynamics_mode == readback_dynamics_mode)
00381             ROS_INFO("Success: Dynamics mode setting is: %#04X",readback_dynamics_mode);
00382           else
00383             ROS_ERROR("Failure: Dynamics mode set to be %#04X, but reads as %#04X",
00384                       dynamics_mode,readback_dynamics_mode);
00385         }
00386         if (save_settings)
00387         {
00388           ROS_INFO("Saving dynamics mode settings to EEPROM");
00389           while(mip_filter_vehicle_dynamics_mode(&device_interface_, 
00390                                                  MIP_FUNCTION_SELECTOR_STORE_EEPROM,
00391                                                  NULL) != MIP_INTERFACE_OK)
00392           {}
00393           ros::Duration(dT).sleep();
00394         }
00395         
00396         // Heading Source
00397         ROS_INFO("Set heading source to internal mag.");
00398         heading_source = 0x1;
00399         ROS_INFO("Setting heading source to %#04X",heading_source);
00400         while(mip_filter_heading_source(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, &heading_source) != MIP_INTERFACE_OK)
00401         {} 
00402         ros::Duration(dT).sleep();
00403         
00404         ROS_INFO("Read back heading source...");
00405         while(mip_filter_heading_source(&device_interface_, 
00406                                         MIP_FUNCTION_SELECTOR_READ, 
00407                                         &readback_headingsource)!= MIP_INTERFACE_OK){}
00408         ROS_INFO("Heading source = %#04X",readback_headingsource);
00409         ros::Duration(dT).sleep();
00410         
00411         if (save_settings)
00412         {
00413           ROS_INFO("Saving heading source to EEPROM");
00414           while(mip_filter_heading_source(&device_interface_, 
00415                                           MIP_FUNCTION_SELECTOR_STORE_EEPROM, 
00416                                           NULL)!= MIP_INTERFACE_OK){}
00417           ros::Duration(dT).sleep();
00418         }
00419       }  // end of Filter setup
00420 
00421       // I believe the auto-init pertains to the kalman filter for the -45
00422       // OR for the complementary filter for the -25  - need to test
00423       // Auto Initialization
00424       // Set auto-initialization based on ROS parameter
00425       ROS_INFO("Setting auto-initinitalization to: %#04X",auto_init);
00426       auto_init_u8 = auto_init;  // convert bool to u8
00427       while(mip_filter_auto_initialization(&device_interface_, 
00428                                            MIP_FUNCTION_SELECTOR_WRITE, 
00429                                            &auto_init_u8) != MIP_INTERFACE_OK)
00430       {}
00431       ros::Duration(dT).sleep();
00432       
00433       if (readback_settings)
00434       {
00435         // Read the settings back
00436         ROS_INFO("Reading back auto-initialization value");
00437         while(mip_filter_auto_initialization(&device_interface_, 
00438                                              MIP_FUNCTION_SELECTOR_READ, 
00439                                              &readback_auto_init)!= MIP_INTERFACE_OK)
00440         {}
00441         ros::Duration(dT).sleep();
00442         if (auto_init == readback_auto_init)
00443           ROS_INFO("Success: Auto init. setting is: %#04X",readback_auto_init);
00444         else
00445           ROS_ERROR("Failure: Auto init. setting set to be %#04X, but reads as %#04X",
00446                     auto_init,readback_auto_init);
00447       }
00448       if (save_settings)
00449       {
00450         ROS_INFO("Saving auto init. settings to EEPROM");
00451         while(mip_filter_auto_initialization(&device_interface_, 
00452                                              MIP_FUNCTION_SELECTOR_STORE_EEPROM,
00453                                              NULL) != MIP_INTERFACE_OK)
00454         {}
00455         ros::Duration(dT).sleep();
00456       }
00457 
00458       // Enable Data streams
00459       dT = 0.25;
00460       if (publish_imu_){
00461         ROS_INFO("Enabling AHRS stream");
00462         enable = 0x01;
00463         while(mip_3dm_cmd_continuous_data_stream(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, MIP_3DM_AHRS_DATASTREAM, &enable) != MIP_INTERFACE_OK){}
00464         ros::Duration(dT).sleep();
00465       }
00466       if (publish_odom_){
00467         ROS_INFO("Enabling Filter stream");
00468         enable = 0x01;
00469         while(mip_3dm_cmd_continuous_data_stream(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, MIP_3DM_INS_DATASTREAM, &enable) != MIP_INTERFACE_OK){}
00470         ros::Duration(dT).sleep();
00471       }
00472       if (publish_gps_){
00473         ROS_INFO("Enabling GPS stream");
00474         enable = 0x01;
00475         while(mip_3dm_cmd_continuous_data_stream(&device_interface_, MIP_FUNCTION_SELECTOR_WRITE, MIP_3DM_GPS_DATASTREAM, &enable) != MIP_INTERFACE_OK){}
00476         ros::Duration(dT).sleep();
00477       }
00478 
00479       ROS_INFO("End of device setup - starting streaming");
00480     } 
00481     else
00482     {
00483       ROS_INFO("Skipping device setup and listing for existing streams");
00484     } // end of device_setup
00485     
00486     // Reset filter - should be for either the KF or CF
00487     ROS_INFO("Reset filter");
00488     while(mip_filter_reset_filter(&device_interface_) != MIP_INTERFACE_OK){}
00489     ros::Duration(dT).sleep();
00490 
00491     // Loop
00492     // Determine loop rate as 2*(max update rate), but abs. max of 1kHz
00493     int max_rate = 1;
00494     if (publish_imu_){
00495       max_rate = std::max(max_rate,imu_rate_);
00496     }
00497     if (publish_gps_){
00498       max_rate = std::max(max_rate,gps_rate_);
00499     }
00500     if (publish_odom_){
00501       max_rate = std::max(max_rate,nav_rate_);
00502     }
00503     int spin_rate = std::min(3*max_rate,1000);
00504     ROS_INFO("Setting spin rate to <%d>",spin_rate);
00505     ros::Rate r(spin_rate);  // Rate in Hz
00506     while (ros::ok()){
00507       //Update the parser (this function reads the port and parses the bytes
00508       mip_interface_update(&device_interface_);
00509       ros::spinOnce();  // take care of service requests.
00510       r.sleep();
00511       
00512       //ROS_INFO("Spinning");
00513     } // end loop
00514     
00515     // close serial port
00516     mip_sdk_port_close(device_interface_.port_handle);
00517     
00518   } // End of ::run()
00519   
00520   bool Microstrain::reset_callback(std_srvs::Empty::Request &req,
00521                                    std_srvs::Empty::Response &resp)
00522   {
00523     ROS_INFO("Reseting the filter");
00524     while(mip_filter_reset_filter(&device_interface_) != MIP_INTERFACE_OK){}
00525     
00526     return true;
00527   }
00528 
00529   void Microstrain::filter_packet_callback(void *user_ptr, u8 *packet, u16 packet_size, u8 callback_type)
00530   {
00531     mip_field_header *field_header;
00532     u8               *field_data;
00533     u16              field_offset = 0;
00534 
00535     // If we aren't publishing, then return
00536     if (!publish_odom_)
00537       return;
00538     //ROS_INFO("Filter callback");
00539     //The packet callback can have several types, process them all
00540     switch(callback_type)
00541       {
00543         //Handle valid packets
00545 
00546       case MIP_INTERFACE_CALLBACK_VALID_PACKET:
00547         {
00548           filter_valid_packet_count_++;
00549 
00551           //Loop through all of the data fields
00553 
00554           while(mip_get_next_field(packet, &field_header, &field_data, &field_offset) == MIP_OK)
00555             {
00556 
00558               // Decode the field
00560 
00561               switch(field_header->descriptor)
00562                 {
00564                   // Estimated LLH Position
00566 
00567                 case MIP_FILTER_DATA_LLH_POS:
00568                   {
00569                     memcpy(&curr_filter_pos_, field_data, sizeof(mip_filter_llh_pos));
00570 
00571                     //For little-endian targets, byteswap the data field
00572                     mip_filter_llh_pos_byteswap(&curr_filter_pos_);
00573 
00574                     nav_msg_.header.seq = filter_valid_packet_count_;
00575                     nav_msg_.header.stamp = ros::Time::now();
00576                     nav_msg_.header.frame_id = odom_frame_id_;
00577                     nav_msg_.child_frame_id = odom_child_frame_id_;
00578                     nav_msg_.pose.pose.position.y = curr_filter_pos_.latitude;
00579                     nav_msg_.pose.pose.position.x = curr_filter_pos_.longitude;
00580                     nav_msg_.pose.pose.position.z = curr_filter_pos_.ellipsoid_height;
00581 
00582                   }break;
00583 
00585                   // Estimated NED Velocity
00587 
00588                 case MIP_FILTER_DATA_NED_VEL:
00589                   {
00590                     memcpy(&curr_filter_vel_, field_data, sizeof(mip_filter_ned_velocity));
00591 
00592                     //For little-endian targets, byteswap the data field
00593                     mip_filter_ned_velocity_byteswap(&curr_filter_vel_);
00594       
00595                     // rotate velocities from NED to sensor coordinates
00596                     // Constructor takes x, y, z , w
00597                     tf2::Quaternion nav_quat(curr_filter_quaternion_.q[2],
00598                                              curr_filter_quaternion_.q[1],
00599                                              -1.0*curr_filter_quaternion_.q[3],
00600                                              curr_filter_quaternion_.q[0]);
00601                                              
00602                     tf2::Vector3 vel_enu(curr_filter_vel_.east,
00603                                          curr_filter_vel_.north,
00604                                          -1.0*curr_filter_vel_.down);
00605                     tf2::Vector3 vel_in_sensor_frame = tf2::quatRotate(nav_quat.inverse(),vel_enu);
00606                       
00607                     nav_msg_.twist.twist.linear.x = vel_in_sensor_frame[0]; //curr_filter_vel_.east;
00608                     nav_msg_.twist.twist.linear.y =  vel_in_sensor_frame[1]; //curr_filter_vel_.north;
00609                     nav_msg_.twist.twist.linear.z =  vel_in_sensor_frame[2]; //-1*curr_filter_vel_.down;
00610                   }break;
00611 
00613                   // Estimated Attitude, Euler Angles
00615 
00616                 case MIP_FILTER_DATA_ATT_EULER_ANGLES:
00617                   {
00618                     memcpy(&curr_filter_angles_, field_data, sizeof(mip_filter_attitude_euler_angles));
00619 
00620                     //For little-endian targets, byteswap the data field
00621                     mip_filter_attitude_euler_angles_byteswap(&curr_filter_angles_);
00622 
00623                   }break;
00624 
00625                   // Quaternion
00626                 case MIP_FILTER_DATA_ATT_QUATERNION:
00627                   {
00628                     memcpy(&curr_filter_quaternion_, field_data, sizeof(mip_filter_attitude_quaternion));
00629 
00630                     //For little-endian targets, byteswap the data field
00631                     mip_filter_attitude_quaternion_byteswap(&curr_filter_quaternion_);
00632 
00633                     // put into ENU - swap X/Y, invert Z
00634                     nav_msg_.pose.pose.orientation.x = curr_filter_quaternion_.q[2];
00635                     nav_msg_.pose.pose.orientation.y = curr_filter_quaternion_.q[1];
00636                     nav_msg_.pose.pose.orientation.z = -1.0*curr_filter_quaternion_.q[3];
00637                     nav_msg_.pose.pose.orientation.w = curr_filter_quaternion_.q[0];
00638 
00639                   }break;
00640 
00641                   // Angular Rates
00642                 case MIP_FILTER_DATA_COMPENSATED_ANGULAR_RATE:
00643                   {
00644                     memcpy(&curr_filter_angular_rate_, field_data, sizeof(mip_filter_compensated_angular_rate));
00645 
00646                     //For little-endian targets, byteswap the data field
00647                     mip_filter_compensated_angular_rate_byteswap(&curr_filter_angular_rate_);
00648 
00649                     nav_msg_.twist.twist.angular.x = curr_filter_angular_rate_.x;
00650                     nav_msg_.twist.twist.angular.y = curr_filter_angular_rate_.y;
00651                     nav_msg_.twist.twist.angular.z = curr_filter_angular_rate_.z;
00652 
00653 
00654                   }break;
00655 
00656                   // Position Uncertainty
00657                 case MIP_FILTER_DATA_POS_UNCERTAINTY:
00658                   {
00659                     memcpy(&curr_filter_pos_uncertainty_, field_data, sizeof(mip_filter_llh_pos_uncertainty));
00660 
00661                     //For little-endian targets, byteswap the data field
00662                     mip_filter_llh_pos_uncertainty_byteswap(&curr_filter_pos_uncertainty_);
00663 
00664                     //x-axis
00665                     nav_msg_.pose.covariance[0] = curr_filter_pos_uncertainty_.east*curr_filter_pos_uncertainty_.east;
00666                     nav_msg_.pose.covariance[7] = curr_filter_pos_uncertainty_.north*curr_filter_pos_uncertainty_.north;
00667                     nav_msg_.pose.covariance[14] = curr_filter_pos_uncertainty_.down*curr_filter_pos_uncertainty_.down;
00668                   }break;
00669 
00670                   // Velocity Uncertainty
00671                 case MIP_FILTER_DATA_VEL_UNCERTAINTY:
00672                   {
00673                     memcpy(&curr_filter_vel_uncertainty_, field_data, sizeof(mip_filter_ned_vel_uncertainty));
00674 
00675                     //For little-endian targets, byteswap the data field
00676                     mip_filter_ned_vel_uncertainty_byteswap(&curr_filter_vel_uncertainty_);
00677       
00678                     nav_msg_.twist.covariance[0] = curr_filter_vel_uncertainty_.east*curr_filter_vel_uncertainty_.east;
00679                     nav_msg_.twist.covariance[7] = curr_filter_vel_uncertainty_.north*curr_filter_vel_uncertainty_.north;
00680                     nav_msg_.twist.covariance[14] = curr_filter_vel_uncertainty_.down*curr_filter_vel_uncertainty_.down;
00681 
00682                   }break;
00683 
00684                   // Attitude Uncertainty
00685                 case MIP_FILTER_DATA_ATT_UNCERTAINTY_EULER:
00686                   {
00687                     memcpy(&curr_filter_att_uncertainty_, field_data, sizeof(mip_filter_euler_attitude_uncertainty));
00688 
00689                     //For little-endian targets, byteswap the data field
00690                     mip_filter_euler_attitude_uncertainty_byteswap(&curr_filter_att_uncertainty_);
00691                     nav_msg_.pose.covariance[21] = curr_filter_att_uncertainty_.roll*curr_filter_att_uncertainty_.roll;
00692                     nav_msg_.pose.covariance[28] = curr_filter_att_uncertainty_.pitch*curr_filter_att_uncertainty_.pitch;
00693                     nav_msg_.pose.covariance[35] = curr_filter_att_uncertainty_.yaw*curr_filter_att_uncertainty_.yaw;
00694 
00695                   }break;
00696 
00697                   // Filter Status
00698                 case MIP_FILTER_DATA_FILTER_STATUS:
00699                   {
00700                     memcpy(&curr_filter_status_, field_data, sizeof(mip_filter_status));
00701 
00702                     //For little-endian targets, byteswap the data field
00703                     mip_filter_status_byteswap(&curr_filter_status_);
00704       
00705                     nav_status_msg_.data.clear();
00706                     ROS_DEBUG_THROTTLE(1.0,"Filter Status: %#06X, Dyn. Mode: %#06X, Filter State: %#06X",
00707                                        curr_filter_status_.filter_state,
00708                                        curr_filter_status_.dynamics_mode,
00709                                        curr_filter_status_.status_flags);
00710                     nav_status_msg_.data.push_back(curr_filter_status_.filter_state);
00711                     nav_status_msg_.data.push_back(curr_filter_status_.dynamics_mode);
00712                     nav_status_msg_.data.push_back(curr_filter_status_.status_flags);
00713                     nav_status_pub_.publish(nav_status_msg_);
00714 
00715 
00716                   }break;
00717 
00718                 default: break;
00719                 }
00720             }
00721 
00722           // Publish
00723           nav_pub_.publish(nav_msg_);
00724         }break;
00725 
00726 
00728         //Handle checksum error packets
00730 
00731       case MIP_INTERFACE_CALLBACK_CHECKSUM_ERROR:
00732         {
00733           filter_checksum_error_packet_count_++;
00734         }break;
00735 
00737         //Handle timeout packets
00739 
00740       case MIP_INTERFACE_CALLBACK_TIMEOUT:
00741         {
00742           filter_timeout_packet_count_++;
00743         }break;
00744       default: break;
00745       }
00746 
00747     print_packet_stats();
00748   } // filter_packet_callback
00749 
00750 
00752   //
00753   // AHRS Packet Callback
00754   //
00756 
00757   void Microstrain::ahrs_packet_callback(void *user_ptr, u8 *packet, u16 packet_size, u8 callback_type)
00758   {
00759     mip_field_header *field_header;
00760     u8               *field_data;
00761     u16              field_offset = 0;
00762     // If we aren't publishing, then return
00763     if (!publish_imu_)
00764       return;
00765     //The packet callback can have several types, process them all
00766     switch(callback_type)
00767       {
00769         //Handle valid packets
00771 
00772       case MIP_INTERFACE_CALLBACK_VALID_PACKET:
00773         {
00774           ahrs_valid_packet_count_++;
00775 
00777           //Loop through all of the data fields
00779 
00780           while(mip_get_next_field(packet, &field_header, &field_data, &field_offset) == MIP_OK)
00781             {
00782 
00784               // Decode the field
00786 
00787               switch(field_header->descriptor)
00788                 {
00790                   // Scaled Accelerometer
00792 
00793                 case MIP_AHRS_DATA_ACCEL_SCALED:
00794                   {
00795                     memcpy(&curr_ahrs_accel_, field_data, sizeof(mip_ahrs_scaled_accel));
00796 
00797                     //For little-endian targets, byteswap the data field
00798                     mip_ahrs_scaled_accel_byteswap(&curr_ahrs_accel_);
00799       
00800                     // Stuff into ROS message - acceleration in m/s^2
00801                     // Header
00802                     imu_msg_.header.seq = ahrs_valid_packet_count_;
00803                     imu_msg_.header.stamp = ros::Time::now();
00804                     imu_msg_.header.frame_id = imu_frame_id_;
00805                     imu_msg_.linear_acceleration.x = 9.81*curr_ahrs_accel_.scaled_accel[0];
00806                     imu_msg_.linear_acceleration.y = 9.81*curr_ahrs_accel_.scaled_accel[1];
00807                     imu_msg_.linear_acceleration.z = 9.81*curr_ahrs_accel_.scaled_accel[2];
00808       
00809                   }break;
00810 
00812                   // Scaled Gyro
00814 
00815                 case MIP_AHRS_DATA_GYRO_SCALED:
00816                   {
00817                     memcpy(&curr_ahrs_gyro_, field_data, sizeof(mip_ahrs_scaled_gyro));
00818 
00819                     //For little-endian targets, byteswap the data field
00820                     mip_ahrs_scaled_gyro_byteswap(&curr_ahrs_gyro_);
00821       
00822                     imu_msg_.angular_velocity.x = curr_ahrs_gyro_.scaled_gyro[0];
00823                     imu_msg_.angular_velocity.y = curr_ahrs_gyro_.scaled_gyro[1];
00824                     imu_msg_.angular_velocity.z = curr_ahrs_gyro_.scaled_gyro[2];
00825 
00826                   }break;
00827 
00829                   // Scaled Magnetometer
00831 
00832                 case MIP_AHRS_DATA_MAG_SCALED:
00833                   {
00834                     memcpy(&curr_ahrs_mag_, field_data, sizeof(mip_ahrs_scaled_mag));
00835 
00836                     //For little-endian targets, byteswap the data field
00837                     mip_ahrs_scaled_mag_byteswap(&curr_ahrs_mag_);
00838 
00839                   }break;
00840 
00841                   // Quaternion
00842                 case MIP_AHRS_DATA_QUATERNION:
00843                   {
00844                     memcpy(&curr_ahrs_quaternion_, field_data, sizeof(mip_ahrs_quaternion));
00845 
00846                     //For little-endian targets, byteswap the data field
00847                     mip_ahrs_quaternion_byteswap(&curr_ahrs_quaternion_);
00848                     // put into ENU - swap X/Y, invert Z
00849                     imu_msg_.orientation.x = curr_ahrs_quaternion_.q[2];
00850                     imu_msg_.orientation.y = curr_ahrs_quaternion_.q[1];
00851                     imu_msg_.orientation.z = -1.0*curr_ahrs_quaternion_.q[3];
00852                     imu_msg_.orientation.w = curr_ahrs_quaternion_.q[0];
00853 
00854                   }break;
00855 
00856                 default: break;
00857                 }
00858             }
00859    
00860           // Publish
00861           imu_pub_.publish(imu_msg_);
00862 
00863         }break;
00864 
00866         //Handle checksum error packets
00868 
00869       case MIP_INTERFACE_CALLBACK_CHECKSUM_ERROR:
00870         {
00871           ahrs_checksum_error_packet_count_++;
00872         }break;
00873 
00875         //Handle timeout packets
00877 
00878       case MIP_INTERFACE_CALLBACK_TIMEOUT:
00879         {
00880           ahrs_timeout_packet_count_++;
00881         }break;
00882       default: break;
00883       }
00884 
00885     print_packet_stats();
00886   } // ahrs_packet_callback
00887 
00888 
00890   //
00891   // GPS Packet Callback
00892   //
00894 
00895   void Microstrain::gps_packet_callback(void *user_ptr, u8 *packet, u16 packet_size, u8 callback_type)
00896   {
00897     mip_field_header *field_header;
00898     u8               *field_data;
00899     u16              field_offset = 0;
00900     u8 msgvalid = 1;  // keep track of message validity
00901 
00902     // If we aren't publishing, then return
00903     if (!publish_gps_)
00904       return;
00905     //The packet callback can have several types, process them all
00906     switch(callback_type)
00907       {
00909         //Handle valid packets
00911 
00912       case MIP_INTERFACE_CALLBACK_VALID_PACKET:
00913         {
00914           gps_valid_packet_count_++;
00915 
00917           //Loop through all of the data fields
00919 
00920           while(mip_get_next_field(packet, &field_header, &field_data, &field_offset) == MIP_OK)
00921             {
00922 
00924               // Decode the field
00926 
00927               switch(field_header->descriptor)
00928                 {
00930                   // LLH Position
00932 
00933                 case MIP_GPS_DATA_LLH_POS:
00934                   {
00935                     memcpy(&curr_llh_pos_, field_data, sizeof(mip_gps_llh_pos));
00936 
00937                     //For little-endian targets, byteswap the data field
00938                     mip_gps_llh_pos_byteswap(&curr_llh_pos_);
00939 
00940                     // push into ROS message
00941                     gps_msg_.latitude = curr_llh_pos_.latitude;
00942                     gps_msg_.longitude = curr_llh_pos_.longitude;
00943                     gps_msg_.altitude = curr_llh_pos_.ellipsoid_height;
00944                     gps_msg_.position_covariance_type = 2;  // diagnals known
00945                     gps_msg_.position_covariance[0] = curr_llh_pos_.horizontal_accuracy*curr_llh_pos_.horizontal_accuracy;
00946                     gps_msg_.position_covariance[4] = curr_llh_pos_.horizontal_accuracy*curr_llh_pos_.horizontal_accuracy;
00947                     gps_msg_.position_covariance[8] = curr_llh_pos_.vertical_accuracy*curr_llh_pos_.vertical_accuracy;
00948                     gps_msg_.status.status = curr_llh_pos_.valid_flags - 1;
00949                     gps_msg_.status.service = 1;  // assumed
00950                     // Header
00951                     gps_msg_.header.seq = gps_valid_packet_count_;
00952                     gps_msg_.header.stamp = ros::Time::now();
00953                     gps_msg_.header.frame_id = gps_frame_id_;
00954 
00955                   }break;
00956 
00958                   // NED Velocity
00960 
00961                 case MIP_GPS_DATA_NED_VELOCITY:
00962                   {
00963                     memcpy(&curr_ned_vel_, field_data, sizeof(mip_gps_ned_vel));
00964 
00965                     //For little-endian targets, byteswap the data field
00966                     mip_gps_ned_vel_byteswap(&curr_ned_vel_);
00967 
00968                   }break;
00969 
00971                   // GPS Time
00973 
00974                 case MIP_GPS_DATA_GPS_TIME:
00975                   {
00976                     memcpy(&curr_gps_time_, field_data, sizeof(mip_gps_time));
00977 
00978                     //For little-endian targets, byteswap the data field
00979                     mip_gps_time_byteswap(&curr_gps_time_);
00980 
00981                   }break;
00982 
00983                 default: break;
00984                 }
00985             }
00986         }break;
00987 
00988 
00990         //Handle checksum error packets
00992 
00993       case MIP_INTERFACE_CALLBACK_CHECKSUM_ERROR:
00994         {
00995           msgvalid = 0;
00996           gps_checksum_error_packet_count_++;
00997         }break;
00998 
01000         //Handle timeout packets
01002 
01003       case MIP_INTERFACE_CALLBACK_TIMEOUT:
01004         {
01005           msgvalid = 0;
01006           gps_timeout_packet_count_++;
01007         }break;
01008       default: break;
01009       }
01010 
01011     if (msgvalid){
01012       // Publish the message
01013       gps_pub_.publish(gps_msg_);
01014     }
01015 
01016     print_packet_stats();
01017   } // gps_packet_callback
01018 
01019   void Microstrain::print_packet_stats()
01020   {
01021     ROS_DEBUG_THROTTLE(1.0,"%u FILTER (%u errors)    %u AHRS (%u errors)    %u GPS (%u errors) Packets", filter_valid_packet_count_,  filter_timeout_packet_count_ + filter_checksum_error_packet_count_,
01022                        ahrs_valid_packet_count_, ahrs_timeout_packet_count_ + ahrs_checksum_error_packet_count_,
01023                        gps_valid_packet_count_,  gps_timeout_packet_count_ + gps_checksum_error_packet_count_);
01024   } // print_packet_stats
01025 
01026 
01027   // Wrapper callbacks
01028   void filter_packet_callback_wrapper(void *user_ptr, u8 *packet, u16 packet_size, u8 callback_type)
01029   {
01030     Microstrain* ustrain = (Microstrain*) user_ptr;
01031     ustrain->filter_packet_callback(user_ptr,packet,packet_size,callback_type);
01032   }
01033 
01034   void ahrs_packet_callback_wrapper(void *user_ptr, u8 *packet, u16 packet_size, u8 callback_type)
01035   {
01036     Microstrain* ustrain = (Microstrain*) user_ptr;
01037     ustrain->ahrs_packet_callback(user_ptr,packet,packet_size,callback_type);
01038   }
01039   // Wrapper callbacks
01040   void gps_packet_callback_wrapper(void *user_ptr, u8 *packet, u16 packet_size, u8 callback_type)
01041   {
01042     Microstrain* ustrain = (Microstrain*) user_ptr;
01043     ustrain->gps_packet_callback(user_ptr,packet,packet_size,callback_type);
01044   }
01045 
01046 } // Microstrain namespace
01047 


microstrain_3dm_gx5_45
Author(s): Brian Bingham
autogenerated on Tue Apr 18 2017 02:59:09