mrpt_icp_slam_2d_wrapper.cpp
Go to the documentation of this file.
00001 /*
00002  * File: mrpt_icp_slam_2d_wrapper.cpp
00003  * Author: Vladislav Tananaev
00004  *
00005  */
00006 
00007 #include "mrpt_icp_slam_2d/mrpt_icp_slam_2d_wrapper.h"
00008 #include <mrpt/version.h>
00009 #if MRPT_VERSION >= 0x150
00010 #include <mrpt_bridge/utils.h>
00011 #endif
00012 
00013 ICPslamWrapper::ICPslamWrapper()
00014 {
00015   rawlog_play_ = false;
00016   stamp = ros::Time(0);
00017   // Default parameters for 3D window
00018   SHOW_PROGRESS_3D_REAL_TIME = false;
00019   SHOW_PROGRESS_3D_REAL_TIME_DELAY_MS = 0;  // this parameter is not used
00020   SHOW_LASER_SCANS_3D = true;
00021   CAMERA_3DSCENE_FOLLOWS_ROBOT = true;
00022   isObsBasedRawlog = true;
00023 }
00024 ICPslamWrapper::~ICPslamWrapper()
00025 {
00026         try {
00027                 std::string sOutMap = "mrpt_icpslam_";
00028                 mrpt::system::TTimeParts parts;
00029                 mrpt::system::timestampToParts(now(), parts, true);
00030                 sOutMap += format("%04u-%02u-%02u_%02uh%02um%02us",
00031                         (unsigned int)parts.year,
00032                         (unsigned int)parts.month,
00033                         (unsigned int)parts.day,
00034                         (unsigned int)parts.hour,
00035                         (unsigned int)parts.minute,
00036                         (unsigned int)parts.second );
00037                 sOutMap += ".simplemap";
00038 
00039                 sOutMap = mrpt::system::fileNameStripInvalidChars( sOutMap );
00040                 ROS_INFO("Saving built map to `%s`", sOutMap.c_str());
00041                 mapBuilder.saveCurrentMapToFile(sOutMap);
00042         } catch (std::exception &e)
00043         {
00044                 ROS_ERROR("Exception: %s",e.what());
00045         }
00046 }
00047 bool ICPslamWrapper::is_file_exists(const std::string &name)
00048 {
00049   std::ifstream f(name.c_str());
00050   return f.good();
00051 }
00052 
00053 void ICPslamWrapper::read_iniFile(std::string ini_filename)
00054 {
00055   CConfigFile iniFile(ini_filename);
00056 
00057   mapBuilder.ICP_options.loadFromConfigFile(iniFile, "MappingApplication");
00058   mapBuilder.ICP_params.loadFromConfigFile(iniFile, "ICP");
00059   mapBuilder.initialize();
00060 
00061 #if MRPT_VERSION < 0x150
00062   mapBuilder.options.verbose = true;
00063 #else
00064   log4cxx::LoggerPtr ros_logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME);
00065   mapBuilder.setVerbosityLevel(mrpt_bridge::rosLoggerLvlToMRPTLoggerLvl(ros_logger->getLevel()));
00066   mapBuilder.logging_enable_console_output = false;
00067   mapBuilder.logRegisterCallback(static_cast<output_logger_callback_t>(&mrpt_bridge::mrptToROSLoggerCallback));
00068 #endif
00069   mapBuilder.options.alwaysInsertByClass.fromString(
00070       iniFile.read_string("MappingApplication", "alwaysInsertByClass", ""));
00071 
00072   mapBuilder.ICP_params.dumpToConsole();
00073   mapBuilder.ICP_options.dumpToConsole();
00074 
00075   // parameters for mrpt3D window
00076   CAMERA_3DSCENE_FOLLOWS_ROBOT =
00077       iniFile.read_bool("MappingApplication", "CAMERA_3DSCENE_FOLLOWS_ROBOT", true, /*Force existence:*/ true);
00078   MRPT_LOAD_CONFIG_VAR(SHOW_PROGRESS_3D_REAL_TIME, bool, iniFile, "MappingApplication");
00079   MRPT_LOAD_CONFIG_VAR(SHOW_LASER_SCANS_3D, bool, iniFile, "MappingApplication");
00080   MRPT_LOAD_CONFIG_VAR(SHOW_PROGRESS_3D_REAL_TIME_DELAY_MS, int, iniFile, "MappingApplication");
00081 }
00082 
00083 void ICPslamWrapper::get_param()
00084 {
00085   ROS_INFO("READ PARAM FROM LAUNCH FILE");
00086   n_.param<double>("rawlog_play_delay", rawlog_play_delay, 0.1);
00087   ROS_INFO("rawlog_play_delay: %f", rawlog_play_delay);
00088 
00089   n_.getParam("rawlog_filename", rawlog_filename);
00090   ROS_INFO("rawlog_filename: %s", rawlog_filename.c_str());
00091 
00092   n_.getParam("ini_filename", ini_filename);
00093   ROS_INFO("ini_filename: %s", ini_filename.c_str());
00094 
00095   n_.param<std::string>("global_frame_id", global_frame_id, "map");
00096   ROS_INFO("global_frame_id: %s", global_frame_id.c_str());
00097 
00098   n_.param<std::string>("odom_frame_id", odom_frame_id, "odom");
00099   ROS_INFO("odom_frame_id: %s", odom_frame_id.c_str());
00100 
00101   n_.param<std::string>("base_frame_id", base_frame_id, "base_link");
00102   ROS_INFO("base_frame_id: %s", base_frame_id.c_str());
00103 
00104   n_.param<std::string>("sensor_source", sensor_source, "scan");
00105   ROS_INFO("sensor_source: %s", sensor_source.c_str());
00106 
00107   n_.param("trajectory_update_rate", trajectory_update_rate, 10.0);
00108   ROS_INFO("trajectory_update_rate: %f", trajectory_update_rate);
00109 
00110   n_.param("trajectory_publish_rate", trajectory_publish_rate, 5.0);
00111   ROS_INFO("trajectory_publish_rate: %f", trajectory_publish_rate);
00112 }
00113 void ICPslamWrapper::init3Dwindow()
00114 {
00115 #if MRPT_HAS_WXWIDGETS
00116   if (SHOW_PROGRESS_3D_REAL_TIME)
00117   {
00118     win3D_ = mrpt::gui::CDisplayWindow3D::Create("pf-localization - The MRPT project", 1000, 600);
00119     win3D_->setCameraZoom(20);
00120     win3D_->setCameraAzimuthDeg(-45);
00121   }
00122 
00123 #endif
00124 }
00125 
00126 void ICPslamWrapper::run3Dwindow()
00127 {
00128   // Create 3D window if requested (the code is copied from ../mrpt/apps/icp-slam/icp-slam_main.cpp):
00129   if (SHOW_PROGRESS_3D_REAL_TIME && win3D_.present())
00130   {
00131     // get currently builded map
00132     metric_map_ = mapBuilder.getCurrentlyBuiltMetricMap();
00133 
00134     lst_current_laser_scans.clear();
00135 
00136     CPose3D robotPose;
00137     mapBuilder.getCurrentPoseEstimation()->getMean(robotPose);
00138     COpenGLScenePtr scene = COpenGLScene::Create();
00139 
00140     COpenGLViewportPtr view = scene->getViewport("main");
00141 
00142     COpenGLViewportPtr view_map = scene->createViewport("mini-map");
00143     view_map->setBorderSize(2);
00144     view_map->setViewportPosition(0.01, 0.01, 0.35, 0.35);
00145     view_map->setTransparent(false);
00146 
00147     {
00148       mrpt::opengl::CCamera &cam = view_map->getCamera();
00149       cam.setAzimuthDegrees(-90);
00150       cam.setElevationDegrees(90);
00151       cam.setPointingAt(robotPose);
00152       cam.setZoomDistance(20);
00153       cam.setOrthogonal();
00154     }
00155 
00156     // The ground:
00157     mrpt::opengl::CGridPlaneXYPtr groundPlane = mrpt::opengl::CGridPlaneXY::Create(-200, 200, -200, 200, 0, 5);
00158     groundPlane->setColor(0.4, 0.4, 0.4);
00159     view->insert(groundPlane);
00160     view_map->insert(CRenderizablePtr(groundPlane));  // A copy
00161 
00162     // The camera pointing to the current robot pose:
00163     if (CAMERA_3DSCENE_FOLLOWS_ROBOT)
00164     {
00165       scene->enableFollowCamera(true);
00166 
00167       mrpt::opengl::CCamera &cam = view_map->getCamera();
00168       cam.setAzimuthDegrees(-45);
00169       cam.setElevationDegrees(45);
00170       cam.setPointingAt(robotPose);
00171     }
00172 
00173     // The maps:
00174     {
00175       opengl::CSetOfObjectsPtr obj = opengl::CSetOfObjects::Create();
00176       metric_map_->getAs3DObject(obj);
00177       view->insert(obj);
00178 
00179       // Only the point map:
00180       opengl::CSetOfObjectsPtr ptsMap = opengl::CSetOfObjects::Create();
00181       if (metric_map_->m_pointsMaps.size())
00182       {
00183         metric_map_->m_pointsMaps[0]->getAs3DObject(ptsMap);
00184         view_map->insert(ptsMap);
00185       }
00186     }
00187 
00188     // Draw the robot path:
00189     CPose3DPDFPtr posePDF = mapBuilder.getCurrentPoseEstimation();
00190     CPose3D curRobotPose;
00191     posePDF->getMean(curRobotPose);
00192     {
00193       opengl::CSetOfObjectsPtr obj = opengl::stock_objects::RobotPioneer();
00194       obj->setPose(curRobotPose);
00195       view->insert(obj);
00196     }
00197     {
00198       opengl::CSetOfObjectsPtr obj = opengl::stock_objects::RobotPioneer();
00199       obj->setPose(curRobotPose);
00200       view_map->insert(obj);
00201     }
00202 
00203     opengl::COpenGLScenePtr &ptrScene = win3D_->get3DSceneAndLock();
00204     ptrScene = scene;
00205 
00206     win3D_->unlockAccess3DScene();
00207 
00208     // Move camera:
00209     win3D_->setCameraPointingToPoint(curRobotPose.x(), curRobotPose.y(), curRobotPose.z());
00210 
00211     // Update:
00212     win3D_->forceRepaint();
00213 
00214     // Build list of scans:
00215     if (SHOW_LASER_SCANS_3D)
00216     {
00217       // Rawlog in "Observation-only" format:
00218       if (isObsBasedRawlog)
00219       {
00220         if (IS_CLASS(observation, CObservation2DRangeScan))
00221         {
00222           lst_current_laser_scans.push_back(CObservation2DRangeScanPtr(observation));
00223         }
00224       }
00225       else
00226       {
00227         // Rawlog in the Actions-SF format:
00228         for (size_t i = 0;; i++)
00229         {
00230           CObservation2DRangeScanPtr new_obs = observations->getObservationByClass<CObservation2DRangeScan>(i);
00231           if (!new_obs)
00232             break;  // There're no more scans
00233           else
00234             lst_current_laser_scans.push_back(new_obs);
00235         }
00236       }
00237     }
00238 
00239     // Draw laser scanners in 3D:
00240     if (SHOW_LASER_SCANS_3D)
00241     {
00242       for (size_t i = 0; i < lst_current_laser_scans.size(); i++)
00243       {
00244         // Create opengl object and load scan data from the scan observation:
00245         opengl::CPlanarLaserScanPtr obj = opengl::CPlanarLaserScan::Create();
00246         obj->setScan(*lst_current_laser_scans[i]);
00247         obj->setPose(curRobotPose);
00248         obj->setSurfaceColor(1.0f, 0.0f, 0.0f, 0.5f);
00249         // inser into the scene:
00250         view->insert(obj);
00251       }
00252     }
00253   }
00254 }
00255 void ICPslamWrapper::init()
00256 {
00257   // get parameters from ini file
00258   if (!is_file_exists(ini_filename))
00259   {
00260     ROS_ERROR_STREAM("CAN'T READ INI FILE");
00261     return;
00262   }
00263   read_iniFile(ini_filename);
00264   // read rawlog file if it  exists
00265   if (is_file_exists(rawlog_filename))
00266   {
00267     ROS_WARN_STREAM("PLAY FROM RAWLOG FILE: " << rawlog_filename.c_str());
00268     rawlog_play_ = true;
00269   }
00270 
00272   // publish grid map
00273   pub_map_ = n_.advertise<nav_msgs::OccupancyGrid>("map", 1, true);
00274   pub_metadata_ = n_.advertise<nav_msgs::MapMetaData>("map_metadata", 1, true);
00275   // publish point map
00276   pub_point_cloud_ = n_.advertise<sensor_msgs::PointCloud>("PointCloudMap", 1, true);
00277 
00278   trajectory_pub_ = n_.advertise<nav_msgs::Path>("trajectory", 1, true);
00279 
00280   // robot pose
00281   pub_pose_ = n_.advertise<geometry_msgs::PoseStamped>("robot_pose", 1);
00282 
00283   update_trajector_timer = n_.createTimer(ros::Duration(1.0 / trajectory_update_rate),
00284           &ICPslamWrapper::updateTrajectoryTimerCallback, this ,false);
00285 
00286   publish_trajectory_timer = n_.createTimer(ros::Duration(1.0 / trajectory_publish_rate),
00287           &ICPslamWrapper::publishTrajectoryTimerCallback, this, false);
00288 
00289   // read sensor topics
00290   std::vector<std::string> lstSources;
00291   mrpt::system::tokenize(sensor_source, " ,\t\n", lstSources);
00292   ROS_ASSERT_MSG(!lstSources.empty(), "*Fatal*: At least one sensor source must be provided in ~sensor_sources (e.g. "
00293                                       "\"scan\" or \"beacon\")");
00294 
00296   sensorSub_.resize(lstSources.size());
00297   for (size_t i = 0; i < lstSources.size(); i++)
00298   {
00299     if (lstSources[i].find("scan") != std::string::npos)
00300     {
00301       sensorSub_[i] = n_.subscribe(lstSources[i], 1, &ICPslamWrapper::laserCallback, this);
00302     }
00303     else
00304     {
00305       std::cout << "Sensor topics should be 2d laser scans which inlude in the name the word scan "
00306                 << "\n";
00307     }
00308   }
00309 
00310   init3Dwindow();
00311 }
00312 
00313 void ICPslamWrapper::laserCallback(const sensor_msgs::LaserScan &_msg)
00314 {
00315 #if MRPT_VERSION >= 0x130
00316   using namespace mrpt::maps;
00317   using namespace mrpt::obs;
00318 #else
00319   using namespace mrpt::slam;
00320 #endif
00321   CObservation2DRangeScanPtr laser = CObservation2DRangeScan::Create();
00322   if (laser_poses_.find(_msg.header.frame_id) == laser_poses_.end())
00323   {
00324     updateSensorPose(_msg.header.frame_id);
00325   }
00326   else
00327   {
00328     mrpt::poses::CPose3D pose = laser_poses_[_msg.header.frame_id];
00329     mrpt_bridge::convert(_msg, laser_poses_[_msg.header.frame_id], *laser);
00330     // CObservationPtr obs = CObservationPtr(laser);
00331     observation = CObservationPtr(laser);
00332     stamp = ros::Time(0);
00333     tictac.Tic();
00334     mapBuilder.processObservation(observation);
00335     t_exec = tictac.Tac();
00336     ROS_INFO("Map building executed in %.03fms", 1000.0f * t_exec);
00337 
00338     run3Dwindow();
00339     publishTF();
00340     publishMapPose();
00341   }
00342 }
00343 void ICPslamWrapper::publishMapPose()
00344 {
00345   // get currently builded map
00346   metric_map_ = mapBuilder.getCurrentlyBuiltMetricMap();
00347 
00348   // publish map
00349   if (metric_map_->m_gridMaps.size())
00350   {
00351     nav_msgs::OccupancyGrid _msg;
00352     // if we have new map for current sensor update it
00353     mrpt_bridge::convert(*metric_map_->m_gridMaps[0], _msg);
00354     pub_map_.publish(_msg);
00355     pub_metadata_.publish(_msg.info);
00356   }
00357   if (metric_map_->m_pointsMaps.size())
00358   {
00359     sensor_msgs::PointCloud _msg;
00360     std_msgs::Header header;
00361     header.stamp = ros::Time(0);
00362     header.frame_id = global_frame_id;
00363     // if we have new map for current sensor update it
00364     mrpt_bridge::point_cloud::mrpt2ros(*metric_map_->m_pointsMaps[0], header, _msg);
00365     pub_point_cloud_.publish(_msg);
00366   }
00367 
00368   CPose3D robotPose;
00369   mapBuilder.getCurrentPoseEstimation()->getMean(robotPose);
00370 
00371   // publish pose
00372   // geometry_msgs::PoseStamped pose;
00373   pose.header.frame_id = global_frame_id;
00374 
00375   // the pose
00376   pose.pose.position.x = robotPose.x();
00377   pose.pose.position.y = robotPose.y();
00378   pose.pose.position.z = 0.0;
00379   pose.pose.orientation = tf::createQuaternionMsgFromYaw(robotPose.yaw());
00380 
00381   pub_pose_.publish(pose);
00382 }
00383 void ICPslamWrapper::updateSensorPose(std::string _frame_id)
00384 {
00385   CPose3D pose;
00386   tf::StampedTransform transform;
00387   try
00388   {
00389     listenerTF_.lookupTransform(base_frame_id, _frame_id, ros::Time(0), transform);
00390 
00391     tf::Vector3 translation = transform.getOrigin();
00392     tf::Quaternion quat = transform.getRotation();
00393     pose.x() = translation.x();
00394     pose.y() = translation.y();
00395     pose.z() = translation.z();
00396     double roll, pitch, yaw;
00397     tf::Matrix3x3 Rsrc(quat);
00398     CMatrixDouble33 Rdes;
00399     for (int c = 0; c < 3; c++)
00400       for (int r = 0; r < 3; r++)
00401         Rdes(r, c) = Rsrc.getRow(r)[c];
00402     pose.setRotationMatrix(Rdes);
00403     laser_poses_[_frame_id] = pose;
00404   }
00405   catch (tf::TransformException ex)
00406   {
00407     ROS_ERROR("%s", ex.what());
00408     ros::Duration(1.0).sleep();
00409   }
00410 }
00411 bool ICPslamWrapper::rawlogPlay()
00412 {
00413   if (rawlog_play_ == false)
00414   {
00415     return false;
00416   }
00417   else
00418   {
00419     size_t rawlogEntry = 0;
00420     CFileGZInputStream rawlogFile(rawlog_filename);
00421     CActionCollectionPtr action;
00422 
00423     for (;;)
00424     {
00425       if (ros::ok())
00426       {
00427         if (!CRawlog::getActionObservationPairOrObservation(rawlogFile, action, observations, observation, rawlogEntry))
00428         {
00429           break;  // file EOF
00430         }
00431         isObsBasedRawlog = observation.present();
00432         // Execute:
00433         // ----------------------------------------
00434         tictac.Tic();
00435         if (isObsBasedRawlog)
00436           mapBuilder.processObservation(observation);
00437         else
00438           mapBuilder.processActionObservation(*action, *observations);
00439         t_exec = tictac.Tac();
00440         ROS_INFO("Map building executed in %.03fms", 1000.0f * t_exec);
00441 
00442         ros::Duration(rawlog_play_delay).sleep();
00443 
00444         metric_map_ = mapBuilder.getCurrentlyBuiltMetricMap();
00445 
00446         CPose3D robotPose;
00447         mapBuilder.getCurrentPoseEstimation()->getMean(robotPose);
00448 
00449         // publish map
00450         if (metric_map_->m_gridMaps.size())
00451         {
00452           nav_msgs::OccupancyGrid _msg;
00453 
00454           // if we have new map for current sensor update it
00455           mrpt_bridge::convert(*metric_map_->m_gridMaps[0], _msg);
00456           pub_map_.publish(_msg);
00457           pub_metadata_.publish(_msg.info);
00458         }
00459 
00460         if (metric_map_->m_pointsMaps.size())
00461         {
00462           sensor_msgs::PointCloud _msg;
00463           std_msgs::Header header;
00464           header.stamp = ros::Time(0);
00465           header.frame_id = global_frame_id;
00466           // if we have new map for current sensor update it
00467           mrpt_bridge::point_cloud::mrpt2ros(*metric_map_->m_pointsMaps[0], header, _msg);
00468           pub_point_cloud_.publish(_msg);
00469           // pub_metadata_.publish(_msg.info)
00470         }
00471 
00472         // publish pose
00473         // geometry_msgs::PoseStamped pose;
00474         pose.header.frame_id = global_frame_id;
00475 
00476         // the pose
00477         pose.pose.position.x = robotPose.x();
00478         pose.pose.position.y = robotPose.y();
00479         pose.pose.position.z = 0.0;
00480         pose.pose.orientation = tf::createQuaternionMsgFromYaw(robotPose.yaw());
00481 
00482         pub_pose_.publish(pose);
00483       }
00484 
00485       run3Dwindow();
00486       ros::spinOnce();
00487     }
00488 
00489     // if there is mrpt_gui it will wait until push any key in order to close the window
00490     if (win3D_)
00491       win3D_->waitForKey();
00492 
00493     return true;
00494   }
00495 }
00496 
00497 void ICPslamWrapper::publishTF()
00498 {
00499   // Most of this code was copy and pase from ros::amcl
00500   mrpt::poses::CPose3D robotPoseTF;
00501   mapBuilder.getCurrentPoseEstimation()->getMean(robotPoseTF);
00502 
00503   stamp = ros::Time(0);
00504   tf::Stamped<tf::Pose> odom_to_map;
00505   tf::Transform tmp_tf;
00506   mrpt_bridge::convert(robotPoseTF, tmp_tf);
00507 
00508   try
00509   {
00510     tf::Stamped<tf::Pose> tmp_tf_stamped(tmp_tf.inverse(), stamp, base_frame_id);
00511     listenerTF_.transformPose(odom_frame_id, tmp_tf_stamped, odom_to_map);
00512   }
00513   catch (tf::TransformException)
00514   {
00515     ROS_INFO("Failed to subtract global_frame (%s) from odom_frame (%s)", global_frame_id.c_str(),
00516              odom_frame_id.c_str());
00517     return;
00518   }
00519 
00520   tf::Transform latest_tf_ =
00521       tf::Transform(tf::Quaternion(odom_to_map.getRotation()), tf::Point(odom_to_map.getOrigin()));
00522 
00523   tf::StampedTransform tmp_tf_stamped(latest_tf_.inverse(), stamp, global_frame_id, odom_frame_id);
00524 
00525   tf_broadcaster_.sendTransform(tmp_tf_stamped);
00526 }
00527 
00528 void ICPslamWrapper::updateTrajectoryTimerCallback(const ros::TimerEvent& event)
00529 {
00530     ROS_DEBUG("update trajectory");
00531     path.header.frame_id = global_frame_id;
00532     path.header.stamp = ros::Time(0);
00533     path.poses.push_back(pose);
00534 }
00535 
00536 void ICPslamWrapper::publishTrajectoryTimerCallback(const ros::TimerEvent& event)
00537 {
00538     ROS_DEBUG("publish trajectory");
00539     trajectory_pub_.publish(path);
00540 }


mrpt_icp_slam_2d
Author(s): Jose Luis Blanco Claraco, Vladislav Tananaev
autogenerated on Sun Sep 17 2017 03:02:10