slam_exporter.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <sensor_msgs/PointCloud.h>
00003 #include <std_msgs/String.h>
00004 #include <sensor_msgs/PointCloud2.h>
00005 #include <tf/transform_listener.h>
00006 #include "globals.icc"
00007 #include <pcl_ros/transforms.h>
00008 
00009 #include <fstream>
00010 using std::ofstream;
00011 #include <iostream>
00012 using std::cout;
00013 using std::endl;
00014 
00015 tf::TransformListener *tl_;
00016 
00017 bool needRequest_, requested_;
00018 std::string fixed_frame_;
00019 std::string robot_frame_;
00020 
00021 bool getTransform(double *t, double *ti, double *rP, double *rPT, tf::TransformListener *listener, ros::Time time)
00022 {
00023   tf::StampedTransform transform;
00024 
00025   std::string error_msg;
00026   bool success = listener->waitForTransform(fixed_frame_, robot_frame_, time, ros::Duration(3.0), ros::Duration(0.01),
00027                                             &error_msg);
00028 
00029   if (!success)
00030   {
00031     ROS_WARN("Could not get transform, ignoring point cloud! %s", error_msg.c_str());
00032     return false;
00033   }
00034 
00035   listener->lookupTransform(fixed_frame_, robot_frame_, time, transform);
00036 
00037   double mat[9];
00038   double x = transform.getOrigin().getX() * 100;
00039   double y = transform.getOrigin().getY() * 100;
00040   double z = transform.getOrigin().getZ() * 100;
00041   mat[0] = transform.getBasis().getRow(0).getX();
00042   mat[1] = transform.getBasis().getRow(0).getY();
00043   mat[2] = transform.getBasis().getRow(0).getZ();
00044 
00045   mat[3] = transform.getBasis().getRow(1).getX();
00046   mat[4] = transform.getBasis().getRow(1).getY();
00047   mat[5] = transform.getBasis().getRow(1).getZ();
00048 
00049   mat[6] = transform.getBasis().getRow(2).getX();
00050   mat[7] = transform.getBasis().getRow(2).getY();
00051   mat[8] = transform.getBasis().getRow(2).getZ();
00052 
00053   t[0] = mat[4];
00054   t[1] = -mat[7];
00055   t[2] = -mat[1];
00056   t[3] = 0.0;
00057 
00058   t[4] = -mat[5];
00059   t[5] = mat[8];
00060   t[6] = mat[2];
00061   t[7] = 0.0;
00062 
00063   t[8] = -mat[3];
00064   t[9] = mat[6];
00065   t[10] = mat[0];
00066   t[11] = 0.0;
00067 
00068   // translation
00069   t[12] = -y;
00070   t[13] = z;
00071   t[14] = x;
00072   t[15] = 1;
00073   M4inv(t, ti);
00074   Matrix4ToEuler(t, rPT, rP);
00075 
00076   return true;
00077 }
00078 
00079 void writePose(int j, double rP[3], double rPT[3])
00080 {
00081   char pose_str[13];
00082   sprintf(pose_str, "scan%03d.pose", j);
00083   ofstream pose(pose_str);
00084   pose << rP[0] << " " << rP[1] << " " << rP[2] << endl << deg(rPT[0]) << " " << deg(rPT[1]) << " " << deg(rPT[2]);
00085   pose.close();
00086 }
00087 
00088 void reqCallback(const std_msgs::String::ConstPtr& e)
00089 {
00090   ROS_INFO_STREAM("Request received: " << e->data);
00091   requested_ = true;
00092 }
00093 
00094 void pcCallback(const sensor_msgs::PointCloud::ConstPtr& untransformed_cloud)
00095 {
00096   //ignore first scan (tf can't transform it and its incomplete anyway)
00097   static bool first = true;
00098   if (first)
00099   {
00100     first = false;
00101     return;
00102   }
00103 
00104   if (needRequest_ && !requested_)
00105   {
00106     return;
00107   }
00108 
00109   static int j = 0;
00110 
00111   // ----- write transform fixed_frame --> robot_frame to pose file
00112   double t[16], ti[16], rP[3], rPT[3];
00113   bool success = getTransform(t, ti, rP, rPT, tl_, untransformed_cloud->header.stamp);
00114   if (!success)
00115     return;
00116 
00117   writePose(j, rP, rPT);
00118 
00119   // ----- transform point cloud from sensor frame to robot_frame
00120   boost::shared_ptr<sensor_msgs::PointCloud> cloud(new sensor_msgs::PointCloud);
00121   tl_->transformPointCloud(robot_frame_, *untransformed_cloud, *cloud);
00122 
00123   if (!success)
00124     return;
00125 
00126   char scan_str[11];
00127   sprintf(scan_str, "scan%03d.3d", j++);
00128   ofstream scan(scan_str);
00129 
00130   size_t i;
00131   double p[3];
00132   for (i = 0; i < cloud->points.size(); i++)
00133   {
00134     p[0] = cloud->points[i].y * -100;
00135     p[1] = cloud->points[i].z * 100;
00136     p[2] = cloud->points[i].x * 100;
00137 
00138     // transform3(ti, p);
00139 
00140     if (!isnan(p[0]) && !isnan(p[1]) && !isnan(p[2]))
00141     {
00142       scan << p[0] << " " << p[1] << " " << p[2] << endl;
00143     }
00144   }
00145   scan.close();
00146   ROS_INFO("wrote %zu points to file %s (backlog: %f s)", i, scan_str, (ros::Time::now() - cloud->header.stamp).toSec());
00147 
00148   requested_ = false;
00149 }
00150 
00151 inline int32_t findChannelIndex(const sensor_msgs::PointCloud2ConstPtr& cloud, const std::string& channel)
00152 {
00153   for (size_t i = 0; i < cloud->fields.size(); ++i)
00154   {
00155     if (cloud->fields[i].name == channel)
00156     {
00157       return i;
00158     }
00159   }
00160 
00161   return -1;
00162 }
00163 
00164 void pc2aCallback(const sensor_msgs::PointCloud2Ptr& untransformed_cloud)
00165 {
00166   static int j = 0;
00167 
00168   // ----- write transform fixed_frame --> robot_frame to pose file
00169   double t[16], ti[16], rP[3], rPT[3];
00170   bool success = getTransform(t, ti, rP, rPT, tl_, untransformed_cloud->header.stamp);
00171   if (!success)
00172     return;
00173 
00174   writePose(j, rP, rPT);
00175 
00176   // ----- transform point cloud from sensor frame to robot_frame
00177   boost::shared_ptr<sensor_msgs::PointCloud2> cloud(new sensor_msgs::PointCloud2);
00178   success = pcl_ros::transformPointCloud(robot_frame_, *untransformed_cloud, *cloud, *tl_);
00179   if (!success)
00180     return;
00181 
00182   char scan_str[11];
00183   sprintf(scan_str, "scan%03d.3d", j++);
00184   ofstream scan(scan_str);
00185 
00186   int32_t xi = findChannelIndex(cloud, "x");
00187   int32_t yi = findChannelIndex(cloud, "y");
00188   int32_t zi = findChannelIndex(cloud, "z");
00189   int32_t rgbi = findChannelIndex(cloud, "rgb");
00190 
00191   if (xi == -1 || yi == -1 || zi == -1)
00192   {
00193     return;
00194   }
00195 
00196   const uint32_t xoff = cloud->fields[xi].offset;
00197   const uint32_t yoff = cloud->fields[yi].offset;
00198   const uint32_t zoff = cloud->fields[zi].offset;
00199   uint32_t rgboff = -1;
00200   if (rgbi != -1)
00201     rgboff = cloud->fields[rgbi].offset;
00202   const uint32_t point_step = cloud->point_step;
00203   const size_t point_count = cloud->width * cloud->height;
00204 
00205   if (point_count == 0)
00206   {
00207     return;
00208   }
00209 
00210   const uint8_t* ptr = &cloud->data.front();
00211   size_t i;
00212   double p[3];
00213   for (i = 0; i < point_count; ++i)
00214   {
00215     p[0] = *reinterpret_cast<const float*>(ptr + yoff) * -100;
00216     p[1] = *reinterpret_cast<const float*>(ptr + zoff) * 100;
00217     p[2] = *reinterpret_cast<const float*>(ptr + xoff) * 100;
00218 
00219     // transform3(ti, p);
00220 
00221     if (!isnan(p[0]) && !isnan(p[1]) && !isnan(p[2]))
00222     {
00223       scan << p[0] << " " << p[1] << " " << p[2];
00224 
00225       if (rgbi != -1)
00226       {
00227         uint32_t rgb = *reinterpret_cast<const uint32_t*>(ptr + rgboff);
00228         int r = ((rgb >> 16) & 0xff);
00229         int g = ((rgb >> 8) & 0xff);
00230         int b = (rgb & 0xff);
00231 
00232         scan << " " << r << " " << g << " " << b;
00233       }
00234       scan << endl;
00235     }
00236 
00237     ptr += point_step;
00238   }
00239 
00240   scan.close();
00241   ROS_INFO("wrote %zu points to file %s (backlog: %f s)", i, scan_str, (ros::Time::now() - cloud->header.stamp).toSec());
00242 }
00243 
00244 int main(int argc, char **argv)
00245 {
00246   ros::init(argc, argv, "slam_exporter");
00247 
00248   // Only dump points to file when request received.
00249   if (argc > 1 && strcmp(argv[1], "--withrequest") == 0)
00250   {
00251     ROS_INFO("Scan will only be exported when requested as defined by parameter.");
00252     needRequest_ = true;
00253   }
00254   else
00255     needRequest_ = false;
00256 
00257   requested_ = false;
00258 
00259   ros::NodeHandle n;
00260   ros::NodeHandle pn("~");
00261 
00262   tl_ = new tf::TransformListener(ros::Duration(60.0));
00263 
00264   bool use_point_cloud2;
00265   pn.param("fixed_frame", fixed_frame_, std::string("odom_combined"));
00266   pn.param("robot_frame", robot_frame_, std::string("base_link"));
00267   pn.param("use_point_cloud2", use_point_cloud2, true);
00268 
00269   ros::Subscriber sub; // must be declared outside of "if" scope
00270   if (use_point_cloud2)
00271     sub = n.subscribe("points2_in", 100, pc2aCallback);
00272   else
00273     sub = n.subscribe("points_in", 100, pcCallback);
00274 
00275   ros::Subscriber scanRequest = n.subscribe("/request", 1, reqCallback);
00276 
00277   ROS_INFO("slam_exporter initialized with fixed_frame = \"%s\", robot_frame = \"%s\", ", fixed_frame_.c_str(), robot_frame_.c_str());
00278   ros::spin();
00279   return 0;
00280 }


slam_exporter
Author(s): Jochen Sprickerhof
autogenerated on Wed Aug 26 2015 16:38:24