00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 #include <labust/tools/conversions.hpp>
00038 #include <labust/tools/MatrixLoader.hpp>
00039 #include <labust/math/NumberManipulation.hpp>
00040 
00041 #include <std_msgs/Float32MultiArray.h>
00042 
00043 #include <std_msgs/String.h>
00044 #include <sensor_msgs/Imu.h>
00045 #include <sensor_msgs/NavSatFix.h>
00046 #include <tf/transform_broadcaster.h>
00047 #include <ros/ros.h>
00048 
00049 #include <boost/bind.hpp>
00050 #include <boost/asio.hpp>
00051 #include <boost/regex.hpp>
00052 #include <boost/thread.hpp>
00053 
00054 #include <iostream>
00055 #include <numeric>
00056 
00057 struct SharedData
00058 {
00059         enum {msg_size = 86,
00060                 data_offset=4,
00061                 checksum = 85,
00062                 float_offset=9};
00063         enum {lat=0, lon=1};
00064         ros::Publisher imuPub, gpsPub, imuinfo;
00065         tf::Transform imuPos, gpsPos, worldLatLon, world;
00066         tf::TransformBroadcaster broadcast;
00067         double magnetic_declination;
00068         unsigned char buffer[msg_size];
00069         std::vector<double> median[2];
00070         int gps_pub;
00071 };
00072 
00073 void start_receive(SharedData& shared,
00074                 boost::asio::serial_port& port, bool single=false);
00075 void handleIncoming(SharedData& shared,
00076                 boost::asio::serial_port& port,
00077                 const boost::system::error_code& error, const size_t& transferred);
00078 
00079 void sync(SharedData& shared,
00080                 boost::asio::serial_port& port,
00081                 const boost::system::error_code& error, const size_t& transferred)
00082 {
00083         if (!error)
00084         {
00085                 bool flag = true;
00086                 for(int i=0; i<SharedData::data_offset;++i) flag = flag && (shared.buffer[i] == 0xFF);
00087 
00088                 if (flag)
00089                 {
00090                         std::cout<<"Sync."<<std::endl;
00091                         boost::asio::async_read(port, boost::asio::buffer(&shared.buffer[SharedData::data_offset],
00092                                         SharedData::msg_size-SharedData::data_offset),
00093                                         boost::bind(&handleIncoming,
00094                                                         boost::ref(shared),
00095                                                         boost::ref(port),_1,_2));
00096                 }
00097                 else
00098                 {
00099                         
00100                         for(int i=0; i<SharedData::data_offset-1;++i) shared.buffer[i] = shared.buffer[i+1];
00101                         std::cout<<"No sync."<<std::endl;
00102                         start_receive(shared,port,true);
00103                 }
00104         }
00105 }
00106 
00107 void handleIncoming(SharedData& shared,
00108                 boost::asio::serial_port& port,
00109                 const boost::system::error_code& error, const size_t& transferred)
00110 {
00111         std::cout<<"Got stuff."<<std::endl;
00112         if (!error && (transferred == (SharedData::msg_size-SharedData::data_offset)))
00113         {
00114                 std::cout<<"Processing."<<std::endl;
00115                 unsigned char calc = 0;
00116                 for (size_t i=SharedData::data_offset; i<SharedData::msg_size-1; ++i){calc^=shared.buffer[i];};
00117 
00118                 if (calc != shared.buffer[SharedData::checksum])
00119                 {
00120                         ROS_ERROR("Wrong checksum for imu data.");
00121                         start_receive(shared,port);
00122                         return;
00123                 }
00124 
00125                 float* data(reinterpret_cast<float*>(&shared.buffer[SharedData::data_offset + SharedData::float_offset]));
00126                 enum {sog=0, cog, declination,
00127                         accel_x, accel_y, accel_z,
00128                         gyro_x, gyro_y, gyro_z,
00129                         mag_x, mag_y, mag_z,
00130                         roll,pitch,yaw,ry,mmm,mm};
00131 
00132                 std_msgs::Float32MultiArray info;
00133                 info.data.resize(mm+6);
00134                 for (size_t i=0; i<mm+1; ++i) info.data[i+5] = data[i];
00135 
00136                 
00137                 
00138                 
00139 
00140                 
00141                 sensor_msgs::Imu::Ptr imu(new sensor_msgs::Imu());
00142                 imu->header.stamp = ros::Time::now();
00143                 imu->header.frame_id = "imu_frame";
00144                 imu->linear_acceleration.x = data[accel_x];
00145                 imu->linear_acceleration.y = data[accel_y];
00146                 imu->linear_acceleration.z = data[accel_z];
00147                 imu->angular_velocity.x = data[gyro_x];
00148                 imu->angular_velocity.y = data[gyro_y];
00149                 imu->angular_velocity.z = data[gyro_z];
00150 
00151                 Eigen::Quaternion<float> quat;
00152                 labust::tools::quaternionFromEulerZYX(data[roll],
00153                                 data[pitch],
00154                                 labust::math::wrapRad(data[yaw] + shared.magnetic_declination), quat);
00155                 imu->orientation.x = quat.x();
00156                 imu->orientation.y = quat.y();
00157                 imu->orientation.z = quat.z();
00158                 imu->orientation.w = quat.w();
00159                 shared.broadcast.sendTransform(tf::StampedTransform(shared.imuPos, ros::Time::now(), "base_link", "imu_frame"));
00160                 shared.imuPub.publish(imu);
00161 
00162                 
00163                 sensor_msgs::NavSatFix::Ptr gps(new sensor_msgs::NavSatFix());
00164 
00165                 int16_t* latlon(reinterpret_cast<int16_t*>(&shared.buffer[SharedData::data_offset]));
00166                 enum{lat=0, fraclat,lon,fraclon};
00167                 info.data[0] = latlon[lat];
00168                 info.data[1] = latlon[fraclat];
00169                 info.data[2] = latlon[lon];
00170                 info.data[3] = latlon[fraclon];
00171                 char status = info.data[4] = shared.buffer[SharedData::data_offset+SharedData::float_offset-1];
00172                 shared.imuinfo.publish(info);
00173                 gps->latitude = latlon[lat]/100 + (latlon[lat]%100 + latlon[fraclat]/10000.)/60. ;
00174                 gps->longitude = latlon[lon]/100 + (latlon[lon]%100 + latlon[fraclon]/10000.)/60.;
00175                 gps->position_covariance[0] = 9999;
00176                 gps->position_covariance[4] = 9999;
00177                 gps->position_covariance[8] = 9999;
00178                 gps->header.frame_id = "worldLatLon";
00179                 gps->header.stamp = ros::Time::now();
00180                 shared.broadcast.sendTransform(tf::StampedTransform(shared.gpsPos, ros::Time::now(), "base_link", "gps_frame"));
00181                 static int i=0;
00182                 ++i;
00183 
00184                 if (status == 'A')
00185                 {
00186                         shared.median[SharedData::lat].push_back(gps->latitude);
00187                         shared.median[SharedData::lon].push_back(gps->longitude);
00188                         if ((i%shared.gps_pub)==0)
00189                         {
00190                                 double med[2];
00191                                 for (int i=0; i<2; ++i)
00192                                 {
00193                                         int size = shared.median[i].size();
00194                                         
00195 
00196 
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206                                         
00207                                         med[i] = std::accumulate(shared.median[i].begin(), shared.median[i].end(), 0.0)/size;
00208                                         shared.median[i].clear();
00209                                 };
00210 
00211                                 gps->latitude = med[SharedData::lat];
00212                                 gps->longitude = med[SharedData::lon];
00213                                 shared.gpsPub.publish(gps);
00214                         }
00215                 }
00216 
00217                 
00218                 
00219                 
00220         }
00221         start_receive(shared,port);
00222 }
00223 
00224 void start_receive(SharedData& shared,
00225                 boost::asio::serial_port& port, bool single)
00226 {
00227         if (single)
00228         {
00229                 boost::asio::async_read(port, boost::asio::buffer(&shared.buffer[SharedData::data_offset-1],1),
00230                                 boost::bind(&sync,
00231                                                 boost::ref(shared),
00232                                                 boost::ref(port),_1,_2));
00233         }
00234         else
00235         {
00236                 boost::asio::async_read(port, boost::asio::buffer(&shared.buffer[0],SharedData::data_offset),
00237                                 boost::bind(&sync,
00238                                                 boost::ref(shared),
00239                                                 boost::ref(port),_1,_2));
00240         }
00241 }
00242 
00243 int main(int argc, char* argv[])
00244 {
00245         ros::init(argc,argv,"imu_node");
00246         ros::NodeHandle nh,ph("~");
00247 
00248         std::string portName("/dev/ttyUSB0");
00249         int baud(115200);
00250 
00251         ph.param("PortName",portName,portName);
00252         ph.param("Baud",baud,baud);
00253 
00254         namespace ba=boost::asio;
00255         ba::io_service io;
00256         ba::serial_port port(io);
00257 
00258         port.open(portName);
00259         port.set_option(ba::serial_port::baud_rate(baud));
00260         port.set_option(ba::serial_port::flow_control(
00261                         ba::serial_port::flow_control::none));
00262 
00263         if (!port.is_open())
00264         {
00265                 std::cerr<<"Cannot open port."<<std::endl;
00266                 exit(-1);
00267         }
00268 
00269         SharedData shared;
00270         ph.param("magnetic_declination",shared.magnetic_declination,0.0);
00271         ph.param("gps_pub",shared.gps_pub,1);
00272         shared.imuPub = nh.advertise<sensor_msgs::Imu>("imu",1);
00273         shared.gpsPub = nh.advertise<sensor_msgs::NavSatFix>("fix",1);
00274         shared.imuinfo= nh.advertise<std_msgs::Float32MultiArray>("imu_info",1);
00275 
00276         
00277         Eigen::Vector3d origin(Eigen::Vector3d::Zero()),
00278                         orientation(Eigen::Vector3d::Zero());
00279 
00280         labust::tools::getMatrixParam(nh, "imu_origin", origin);
00281         labust::tools::getMatrixParam(nh, "imu_orientation", orientation);
00282         shared.imuPos.setOrigin(tf::Vector3(origin(0),origin(1),origin(2)));
00283         shared.imuPos.setRotation(tf::createQuaternionFromRPY(orientation(0),
00284                         orientation(1),orientation(2)));
00285 
00286         origin = origin.Zero();
00287         orientation = orientation.Zero();
00288         labust::tools::getMatrixParam(nh, "gps_origin", origin);
00289         labust::tools::getMatrixParam(nh, "gps_orientation", orientation);
00290         shared.gpsPos.setOrigin(tf::Vector3(origin(0),origin(1),origin(2)));
00291         shared.gpsPos.setRotation(tf::createQuaternionFromRPY(orientation(0),
00292                         orientation(1),orientation(2)));
00293 
00294         
00295         double originLat(0), originLon(0);
00296         nh.param("LocalOriginLat",originLat,originLat);
00297         nh.param("LocalOriginLon",originLon,originLon);
00298         shared.worldLatLon.setOrigin(tf::Vector3(originLon, originLat, 0));
00299         shared.worldLatLon.setRotation(tf::createQuaternionFromRPY(0,0,0));
00300         Eigen::Quaternion<float> q;
00301         labust::tools::quaternionFromEulerZYX(M_PI,0,M_PI/2,q);
00302         shared.world.setOrigin(tf::Vector3(0,0,0));
00303         shared.world.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00304 
00305         start_receive(shared,port);
00306         boost::thread t(boost::bind(&ba::io_service::run,&io));
00307 
00308         ros::spin();
00309         io.stop();
00310         t.join();
00311 
00312         return 0;
00313 }
00314 
00315