00001
00002
00003
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
00018 SHOW_PROGRESS_3D_REAL_TIME = false;
00019 SHOW_PROGRESS_3D_REAL_TIME_DELAY_MS = 0;
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
00076 CAMERA_3DSCENE_FOLLOWS_ROBOT =
00077 iniFile.read_bool("MappingApplication", "CAMERA_3DSCENE_FOLLOWS_ROBOT", true, 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
00129 if (SHOW_PROGRESS_3D_REAL_TIME && win3D_.present())
00130 {
00131
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
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));
00161
00162
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
00174 {
00175 opengl::CSetOfObjectsPtr obj = opengl::CSetOfObjects::Create();
00176 metric_map_->getAs3DObject(obj);
00177 view->insert(obj);
00178
00179
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
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
00209 win3D_->setCameraPointingToPoint(curRobotPose.x(), curRobotPose.y(), curRobotPose.z());
00210
00211
00212 win3D_->forceRepaint();
00213
00214
00215 if (SHOW_LASER_SCANS_3D)
00216 {
00217
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
00228 for (size_t i = 0;; i++)
00229 {
00230 CObservation2DRangeScanPtr new_obs = observations->getObservationByClass<CObservation2DRangeScan>(i);
00231 if (!new_obs)
00232 break;
00233 else
00234 lst_current_laser_scans.push_back(new_obs);
00235 }
00236 }
00237 }
00238
00239
00240 if (SHOW_LASER_SCANS_3D)
00241 {
00242 for (size_t i = 0; i < lst_current_laser_scans.size(); i++)
00243 {
00244
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
00250 view->insert(obj);
00251 }
00252 }
00253 }
00254 }
00255 void ICPslamWrapper::init()
00256 {
00257
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
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
00273 pub_map_ = n_.advertise<nav_msgs::OccupancyGrid>("map", 1, true);
00274 pub_metadata_ = n_.advertise<nav_msgs::MapMetaData>("map_metadata", 1, true);
00275
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
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
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
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
00346 metric_map_ = mapBuilder.getCurrentlyBuiltMetricMap();
00347
00348
00349 if (metric_map_->m_gridMaps.size())
00350 {
00351 nav_msgs::OccupancyGrid _msg;
00352
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
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
00372
00373 pose.header.frame_id = global_frame_id;
00374
00375
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;
00430 }
00431 isObsBasedRawlog = observation.present();
00432
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
00450 if (metric_map_->m_gridMaps.size())
00451 {
00452 nav_msgs::OccupancyGrid _msg;
00453
00454
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
00467 mrpt_bridge::point_cloud::mrpt2ros(*metric_map_->m_pointsMaps[0], header, _msg);
00468 pub_point_cloud_.publish(_msg);
00469
00470 }
00471
00472
00473
00474 pose.header.frame_id = global_frame_id;
00475
00476
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
00490 if (win3D_)
00491 win3D_->waitForKey();
00492
00493 return true;
00494 }
00495 }
00496
00497 void ICPslamWrapper::publishTF()
00498 {
00499
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 }