00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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
00050 }
00051 Microstrain::~Microstrain()
00052 {
00053
00054 }
00055 void Microstrain::run()
00056 {
00057
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
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
00125 ros::Time::init();
00126 ros::NodeHandle node;
00127 ros::NodeHandle private_nh("~");
00128
00129
00130
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
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
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
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
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
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
00208 float dT=0.5;
00209 if (device_setup)
00210 {
00211
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
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
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
00233
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
00239 u8 imu_decimation = (u8)((float)base_rate/ (float)imu_rate_);
00240 ROS_INFO("AHRS decimation set to %#04X",imu_decimation);
00241
00242
00243
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;
00249 data_stream_format_decimation[1] = imu_decimation;
00250 data_stream_format_decimation[2] = imu_decimation;
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
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
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
00267
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
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 }
00294
00295
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
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;
00310 data_stream_format_decimation[1] = gps_decimation;
00311 data_stream_format_decimation[2] = gps_decimation;
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
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 }
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
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
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;
00343 data_stream_format_decimation[1] = nav_decimation;
00344 data_stream_format_decimation[2] = nav_decimation;
00345 data_stream_format_decimation[3] = nav_decimation;
00346 data_stream_format_decimation[4] = nav_decimation;
00347 data_stream_format_decimation[5] = nav_decimation;
00348 data_stream_format_decimation[6] = nav_decimation;
00349 data_stream_format_decimation[7] = nav_decimation;
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
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
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
00365
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
00370 if (readback_settings)
00371 {
00372
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
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 }
00420
00421
00422
00423
00424
00425 ROS_INFO("Setting auto-initinitalization to: %#04X",auto_init);
00426 auto_init_u8 = auto_init;
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
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
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 }
00485
00486
00487 ROS_INFO("Reset filter");
00488 while(mip_filter_reset_filter(&device_interface_) != MIP_INTERFACE_OK){}
00489 ros::Duration(dT).sleep();
00490
00491
00492
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);
00506 while (ros::ok()){
00507
00508 mip_interface_update(&device_interface_);
00509 ros::spinOnce();
00510 r.sleep();
00511
00512
00513 }
00514
00515
00516 mip_sdk_port_close(device_interface_.port_handle);
00517
00518 }
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
00536 if (!publish_odom_)
00537 return;
00538
00539
00540 switch(callback_type)
00541 {
00543
00545
00546 case MIP_INTERFACE_CALLBACK_VALID_PACKET:
00547 {
00548 filter_valid_packet_count_++;
00549
00551
00553
00554 while(mip_get_next_field(packet, &field_header, &field_data, &field_offset) == MIP_OK)
00555 {
00556
00558
00560
00561 switch(field_header->descriptor)
00562 {
00564
00566
00567 case MIP_FILTER_DATA_LLH_POS:
00568 {
00569 memcpy(&curr_filter_pos_, field_data, sizeof(mip_filter_llh_pos));
00570
00571
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
00587
00588 case MIP_FILTER_DATA_NED_VEL:
00589 {
00590 memcpy(&curr_filter_vel_, field_data, sizeof(mip_filter_ned_velocity));
00591
00592
00593 mip_filter_ned_velocity_byteswap(&curr_filter_vel_);
00594
00595
00596
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];
00608 nav_msg_.twist.twist.linear.y = vel_in_sensor_frame[1];
00609 nav_msg_.twist.twist.linear.z = vel_in_sensor_frame[2];
00610 }break;
00611
00613
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
00621 mip_filter_attitude_euler_angles_byteswap(&curr_filter_angles_);
00622
00623 }break;
00624
00625
00626 case MIP_FILTER_DATA_ATT_QUATERNION:
00627 {
00628 memcpy(&curr_filter_quaternion_, field_data, sizeof(mip_filter_attitude_quaternion));
00629
00630
00631 mip_filter_attitude_quaternion_byteswap(&curr_filter_quaternion_);
00632
00633
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
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
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
00657 case MIP_FILTER_DATA_POS_UNCERTAINTY:
00658 {
00659 memcpy(&curr_filter_pos_uncertainty_, field_data, sizeof(mip_filter_llh_pos_uncertainty));
00660
00661
00662 mip_filter_llh_pos_uncertainty_byteswap(&curr_filter_pos_uncertainty_);
00663
00664
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
00671 case MIP_FILTER_DATA_VEL_UNCERTAINTY:
00672 {
00673 memcpy(&curr_filter_vel_uncertainty_, field_data, sizeof(mip_filter_ned_vel_uncertainty));
00674
00675
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
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
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
00698 case MIP_FILTER_DATA_FILTER_STATUS:
00699 {
00700 memcpy(&curr_filter_status_, field_data, sizeof(mip_filter_status));
00701
00702
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
00723 nav_pub_.publish(nav_msg_);
00724 }break;
00725
00726
00728
00730
00731 case MIP_INTERFACE_CALLBACK_CHECKSUM_ERROR:
00732 {
00733 filter_checksum_error_packet_count_++;
00734 }break;
00735
00737
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 }
00749
00750
00752
00753
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
00763 if (!publish_imu_)
00764 return;
00765
00766 switch(callback_type)
00767 {
00769
00771
00772 case MIP_INTERFACE_CALLBACK_VALID_PACKET:
00773 {
00774 ahrs_valid_packet_count_++;
00775
00777
00779
00780 while(mip_get_next_field(packet, &field_header, &field_data, &field_offset) == MIP_OK)
00781 {
00782
00784
00786
00787 switch(field_header->descriptor)
00788 {
00790
00792
00793 case MIP_AHRS_DATA_ACCEL_SCALED:
00794 {
00795 memcpy(&curr_ahrs_accel_, field_data, sizeof(mip_ahrs_scaled_accel));
00796
00797
00798 mip_ahrs_scaled_accel_byteswap(&curr_ahrs_accel_);
00799
00800
00801
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
00814
00815 case MIP_AHRS_DATA_GYRO_SCALED:
00816 {
00817 memcpy(&curr_ahrs_gyro_, field_data, sizeof(mip_ahrs_scaled_gyro));
00818
00819
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
00831
00832 case MIP_AHRS_DATA_MAG_SCALED:
00833 {
00834 memcpy(&curr_ahrs_mag_, field_data, sizeof(mip_ahrs_scaled_mag));
00835
00836
00837 mip_ahrs_scaled_mag_byteswap(&curr_ahrs_mag_);
00838
00839 }break;
00840
00841
00842 case MIP_AHRS_DATA_QUATERNION:
00843 {
00844 memcpy(&curr_ahrs_quaternion_, field_data, sizeof(mip_ahrs_quaternion));
00845
00846
00847 mip_ahrs_quaternion_byteswap(&curr_ahrs_quaternion_);
00848
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
00861 imu_pub_.publish(imu_msg_);
00862
00863 }break;
00864
00866
00868
00869 case MIP_INTERFACE_CALLBACK_CHECKSUM_ERROR:
00870 {
00871 ahrs_checksum_error_packet_count_++;
00872 }break;
00873
00875
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 }
00887
00888
00890
00891
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;
00901
00902
00903 if (!publish_gps_)
00904 return;
00905
00906 switch(callback_type)
00907 {
00909
00911
00912 case MIP_INTERFACE_CALLBACK_VALID_PACKET:
00913 {
00914 gps_valid_packet_count_++;
00915
00917
00919
00920 while(mip_get_next_field(packet, &field_header, &field_data, &field_offset) == MIP_OK)
00921 {
00922
00924
00926
00927 switch(field_header->descriptor)
00928 {
00930
00932
00933 case MIP_GPS_DATA_LLH_POS:
00934 {
00935 memcpy(&curr_llh_pos_, field_data, sizeof(mip_gps_llh_pos));
00936
00937
00938 mip_gps_llh_pos_byteswap(&curr_llh_pos_);
00939
00940
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;
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;
00950
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
00960
00961 case MIP_GPS_DATA_NED_VELOCITY:
00962 {
00963 memcpy(&curr_ned_vel_, field_data, sizeof(mip_gps_ned_vel));
00964
00965
00966 mip_gps_ned_vel_byteswap(&curr_ned_vel_);
00967
00968 }break;
00969
00971
00973
00974 case MIP_GPS_DATA_GPS_TIME:
00975 {
00976 memcpy(&curr_gps_time_, field_data, sizeof(mip_gps_time));
00977
00978
00979 mip_gps_time_byteswap(&curr_gps_time_);
00980
00981 }break;
00982
00983 default: break;
00984 }
00985 }
00986 }break;
00987
00988
00990
00992
00993 case MIP_INTERFACE_CALLBACK_CHECKSUM_ERROR:
00994 {
00995 msgvalid = 0;
00996 gps_checksum_error_packet_count_++;
00997 }break;
00998
01000
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
01013 gps_pub_.publish(gps_msg_);
01014 }
01015
01016 print_packet_stats();
01017 }
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 }
01025
01026
01027
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
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 }
01047