34 #include <nav_msgs/Path.h>
35 #include <std_msgs/Int32MultiArray.h>
36 #include <std_msgs/Bool.h>
37 #include <geometry_msgs/PoseArray.h>
41 #include <pcl/io/io.h>
43 #include <visualization_msgs/MarkerArray.h>
58 #include <rtabmap/core/Version.h>
66 #ifdef WITH_OCTOMAP_MSGS
67 #ifdef RTABMAP_OCTOMAP
73 #define BAD_COVARIANCE 9999
76 #include "rtabmap_msgs/Info.h"
77 #include "rtabmap_msgs/MapData.h"
78 #include "rtabmap_msgs/MapGraph.h"
79 #include "rtabmap_msgs/Path.h"
87 CoreWrapper::CoreWrapper() :
88 CommonDataSubscriber(
false),
91 lastPoseIntermediate_(
false),
92 latestNodeWasReached_(
false),
93 pubLocPoseOnlyWhenLocalizing_(
false),
95 frameId_(
"base_link"),
98 groundTruthFrameId_(
""),
99 groundTruthBaseFrameId_(
""),
101 odomDefaultAngVariance_(0.001),
102 odomDefaultLinVariance_(0.001),
103 landmarkDefaultAngVariance_(0.001),
104 landmarkDefaultLinVariance_(0.001),
105 waitForTransform_(
true),
106 waitForTransformDuration_(0.2),
107 useActionForGoal_(
false),
110 genScanMaxDepth_(4.0),
111 genScanMinDepth_(0.0),
113 genDepthDecimation_(1),
114 genDepthFillHolesSize_(0),
115 genDepthFillIterations_(1),
116 genDepthFillHolesError_(0.1),
117 scanCloudMaxPoints_(0),
118 scanCloudIs2d_(
false),
121 tfThreadRunning_(
false),
122 stereoToDepth_(
false),
124 odomSensorSync_(
false),
125 rate_(
Parameters::defaultRtabmapDetectionRate()),
126 createIntermediateNodes_(
Parameters::defaultRtabmapCreateIntermediateNodes()),
127 mappingMaxNodes_(
Parameters::defaultGridGlobalMaxNodes()),
128 mappingAltitudeDelta_(
Parameters::defaultGridGlobalAltitudeDelta()),
129 alreadyRectifiedImages_(
Parameters::defaultRtabmapImagesAlreadyRectified()),
130 twoDMapping_(
Parameters::defaultRegForce3DoF()),
134 char * rosHomePath = getenv(
"ROS_HOME");
147 bool publishTf =
true;
148 std::string initialPoseStr;
149 double tfDelay = 0.05;
150 double tfTolerance = 0.1;
151 std::string odomFrameIdInit;
158 pnh.
param(
"odom_frame_id_init", odomFrameIdInit, odomFrameIdInit);
165 "anymore! It is replaced by \"rgbd_cameras\" parameter "
166 "used when \"subscribe_rgbd\" is true");
168 if(!odomFrameIdInit.empty())
172 ROS_INFO(
"rtabmap: odom_frame_id_init = %s", odomFrameIdInit.c_str());
177 ROS_WARN(
"odom_frame_id_init (%s) is ignored if odom_frame_id (%s) is set.", odomFrameIdInit.c_str(),
odomFrameId_.c_str());
182 pnh.
param(
"log_to_rosout_level", eventLevel, eventLevel);
186 pnh.
param(
"publish_tf", publishTf, publishTf);
187 pnh.
param(
"tf_delay", tfDelay, tfDelay);
190 ROS_ERROR(
"tf_prefix parameter has been removed, use directly map_frame_id, odom_frame_id and frame_id parameters.");
192 pnh.
param(
"tf_tolerance", tfTolerance, tfTolerance);
200 pnh.
param(
"initial_pose", initialPoseStr, initialPoseStr);
213 if(pnh.
hasParam(
"scan_cloud_normal_k"))
215 ROS_WARN(
"rtabmap: Parameter \"scan_cloud_normal_k\" has been removed. RTAB-Map's parameter \"%s\" should be used instead. "
216 "The value is copied. Use \"%s\" to avoid this warning.",
217 Parameters::kMemLaserScanNormalK().
c_str(),
218 Parameters::kMemLaserScanNormalK().
c_str());
227 NODELET_WARN(
"Parameter \"flip_scan\" doesn't exist anymore. Rtabmap now "
228 "detects automatically if the laser is upside down with /tf, then if so, it "
229 "switches scan values.");
239 NODELET_INFO(
"rtabmap: ground_truth_frame_id = %s -> ground_truth_base_frame_id = %s",
244 NODELET_INFO(
"rtabmap: log_to_rosout_level = %d", eventLevel);
245 NODELET_INFO(
"rtabmap: initial_pose = %s", initialPoseStr.c_str());
248 NODELET_INFO(
"rtabmap: tf_tolerance = %f", tfTolerance);
251 bool subscribeStereo =
false;
252 pnh.
param(
"subscribe_stereo", subscribeStereo, subscribeStereo);
273 bool subscribeScanCloud =
false;
274 pnh.
param(
"subscribe_scan_cloud", subscribeScanCloud, subscribeScanCloud);
275 if(subscribeScanCloud)
321 ParametersMap allParameters = Parameters::getDefaultParameters();
323 for(ParametersMap::iterator
iter=allParameters.begin();
iter!=allParameters.end();)
325 if(
iter->first.find(
"Odom") == 0)
327 allParameters.erase(
iter++);
335 char * rosHomePath = getenv(
"ROS_HOME");
343 if(
iter->first.find(
"Odom") == 0)
354 for(ParametersMap::iterator
iter=allParameters.begin();
iter!=allParameters.end(); ++
iter)
362 NODELET_INFO(
"Setting RTAB-Map parameter \"%s\"=\"%s\"",
iter->first.c_str(), vStr.c_str());
364 if(
iter->first.compare(Parameters::kRtabmapWorkingDirectory()) == 0)
368 else if(
iter->first.compare(Parameters::kKpDictionaryPath()) == 0)
392 std::vector<std::string> argList =
getMyArgv();
393 char **
argv =
new char*[argList.size()];
394 bool deleteDbOnStart =
false;
395 for(
unsigned int i=0;
i<argList.size(); ++
i)
397 argv[
i] = &argList[
i].at(0);
398 if(strcmp(
argv[
i],
"--delete_db_on_start") == 0 || strcmp(
argv[
i],
"-d") == 0)
400 deleteDbOnStart =
true;
405 for(ParametersMap::const_iterator
iter=parameters.begin();
iter!=parameters.end(); ++
iter)
408 NODELET_INFO(
"Update RTAB-Map parameter \"%s\"=\"%s\" from arguments",
iter->first.c_str(),
iter->second.c_str());
412 for(std::map<std::string, std::pair<bool, std::string> >::const_iterator
iter=Parameters::getRemovedParameters().begin();
413 iter!=Parameters::getRemovedParameters().end();
420 std::string paramValue;
437 if(!paramValue.empty())
441 NODELET_WARN(
"Rtabmap: Parameter name changed: \"%s\" -> \"%s\". The new parameter is already used with value \"%s\", ignoring the old one with value \"%s\".",
442 iter->first.c_str(),
iter->second.second.c_str(),
parameters_.find(
iter->second.second)->second.c_str(), paramValue.c_str());
444 else if(
iter->second.first)
448 NODELET_WARN(
"Rtabmap: Parameter name changed: \"%s\" -> \"%s\". Please update your launch file accordingly. Value \"%s\" is still set to the new parameter name.",
449 iter->first.c_str(),
iter->second.second.c_str(), paramValue.c_str());
453 if(
iter->second.second.empty())
455 NODELET_ERROR(
"Rtabmap: Parameter \"%s\" doesn't exist anymore!",
456 iter->first.c_str());
460 NODELET_ERROR(
"Rtabmap: Parameter \"%s\" doesn't exist anymore! You may look at this similar parameter: \"%s\"",
461 iter->first.c_str(),
iter->second.second.c_str());
470 bool subscribeScan2d =
false;
471 bool subscribeScan3d =
false;
472 pnh.
param(
"subscribe_scan", subscribeScan2d, subscribeScan2d);
473 pnh.
param(
"subscribe_scan_cloud", subscribeScan3d, subscribeScan3d);
474 int gridSensor = Parameters::defaultGridSensor();
477 NODELET_WARN(
"Setting \"%s\" parameter to 0 (default 1) as \"subscribe_scan\", \"subscribe_scan_cloud\" or \"gen_scan\" is "
478 "true. The occupancy grid map will be constructed from "
479 "laser scans. To get occupancy grid map from camera's cloud projection, set \"%s\" "
480 "to 1. To suppress this warning, "
481 "add <param name=\"%s\" type=\"string\" value=\"0\"/>",
482 Parameters::kGridSensor().
c_str(),
483 Parameters::kGridSensor().
c_str(),
484 Parameters::kGridSensor().
c_str());
487 Parameters::parse(
parameters_, Parameters::kGridSensor(), gridSensor);
490 NODELET_INFO(
"Setting \"%s\" parameter to 0 (default %f) as \"subscribe_scan\", \"subscribe_scan_cloud\" or \"gen_scan\" is true and %s is 0.",
491 Parameters::kGridRangeMax().
c_str(),
492 Parameters::defaultGridRangeMax(),
493 Parameters::kGridSensor().
c_str());
498 NODELET_INFO(
"Setting \"%s\" parameter to 0 (default %f) as \"subscribe_scan_cloud\" is true.",
499 Parameters::kIcpPointToPlaneRadius().
c_str(),
500 Parameters::defaultIcpPointToPlaneRadius());
503 int regStrategy = Parameters::defaultRegStrategy();
504 Parameters::parse(
parameters_, Parameters::kRegStrategy(), regStrategy);
506 (regStrategy == Registration::kTypeIcp || regStrategy == Registration::kTypeVisIcp))
510 NODELET_WARN(
"Setting \"%s\" parameter to 10 (default 0) as \"%s\" is "
511 "true and \"%s\" uses ICP. Proximity detection by space will be also done by merging close "
512 "scans. To disable, set \"%s\" to 0. To suppress this warning, "
513 "add <param name=\"%s\" type=\"string\" value=\"10\"/>",
514 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
515 subscribeScan2d?
"subscribe_scan":
"scan_cloud_is_2d",
516 Parameters::kRegStrategy().
c_str(),
517 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
518 Parameters::kRGBDProximityPathMaxNeighbors().
c_str());
521 else if(subscribeScan3d)
523 NODELET_WARN(
"Setting \"%s\" parameter to 1 (default 0) as \"subscribe_scan_cloud\" is "
524 "true and \"%s\" uses ICP. To disable, set \"%s\" to 0. To suppress this warning, "
525 "add <param name=\"%s\" type=\"string\" value=\"1\"/>",
526 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
527 Parameters::kRegStrategy().
c_str(),
528 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
529 Parameters::kRGBDProximityPathMaxNeighbors().
c_str());
534 int estimationType = Parameters::defaultVisEstimationType();
535 Parameters::parse(
parameters_, Parameters::kVisEstimationType(), estimationType);
537 bool subscribeRGBD =
false;
539 pnh.
param(
"subscribe_rgbd", subscribeRGBD, subscribeRGBD);
551 for(ParametersMap::iterator
iter=dbParameters.begin();
iter!=dbParameters.end(); ++
iter)
553 if(
iter->first.compare(Parameters::kRtabmapWorkingDirectory()) == 0)
559 allParameters.find(
iter->first) != allParameters.end() &&
560 allParameters.find(
iter->first)->second.compare(
iter->second) !=0)
562 NODELET_INFO(
"Update RTAB-Map parameter \"%s\"=\"%s\" from database",
iter->first.c_str(),
iter->second.c_str());
569 parameters_.insert(allParameters.begin(), allParameters.end());
584 bool interOdomInfo =
false;
585 pnh.
getParam(
"subscribe_inter_odom_info", interOdomInfo);
588 NODELET_INFO(
"Subscribe to inter odom + info messages");
631 NODELET_WARN(
"Node paused... don't forget to call service \"resume\" to start rtabmap.");
648 NODELET_INFO(
"rtabmap: database_path parameter not set, the map will not be saved.");
660 float xMin, yMin, gridCellSize;
664 NODELET_INFO(
"rtabmap: 2D occupancy grid map loaded (%dx%d).", map.cols, map.rows);
671 NODELET_INFO(
"rtabmap: Working Memory = %d, Local map = %d.",
683 NODELET_INFO(
"rtabmap: SLAM mode (%s=true)", Parameters::kMemIncrementalMemory().
c_str());
687 NODELET_INFO(
"rtabmap: Localization mode (%s=false)", Parameters::kMemIncrementalMemory().
c_str());
721 #ifdef WITH_OCTOMAP_MSGS
722 #ifdef RTABMAP_OCTOMAP
723 octomapBinarySrv_ = nh.
advertiseService(
"octomap_binary", &CoreWrapper::octomapBinaryCallback,
this);
724 octomapFullSrv_ = nh.
advertiseService(
"octomap_full", &CoreWrapper::octomapFullCallback,
this);
733 int optimizeIterations = 0;
734 Parameters::parse(
parameters_, Parameters::kOptimizerIterations(), optimizeIterations);
735 if(publishTf && optimizeIterations != 0)
742 NODELET_WARN(
"Graph optimization is disabled (%s=0), the tf between frame \"%s\" and odometry frame will not be published. You can safely ignore this warning if you are using map_optimizer node.",
746 std::vector<diagnostic_updater::DiagnosticTask*> tasks;
747 double localizationThreshold = 0.0f;
748 pnh.
param(
"loc_thr", localizationThreshold, localizationThreshold);
751 NODELET_INFO(
"rtabmap: loc_thr = %f", localizationThreshold);
761 NODELET_WARN(
"ROS param subscribe_depth, subscribe_stereo and subscribe_rgbd are false, but RTAB-Map "
762 "parameter \"%s\" is true! Please set subscribe_depth, subscribe_stereo or subscribe_rgbd "
763 "to true to use rtabmap node for RGB-D SLAM, set \"%s\" to false for loop closure "
764 "detection on images-only or set subscribe_rgb to true to localize a single RGB camera against pre-built 3D map.",
765 Parameters::kRGBDEnabled().
c_str(),
766 Parameters::kRGBDEnabled().
c_str());
783 NODELET_WARN(
"There is no image subscription, bag-of-words loop closure detection will be disabled...");
784 int kpMaxFeatures = Parameters::defaultKpMaxFeatures();
785 int registrationStrategy = Parameters::defaultRegStrategy();
786 Parameters::parse(
parameters_, Parameters::kKpMaxFeatures(), kpMaxFeatures);
787 Parameters::parse(
parameters_, Parameters::kRegStrategy(), registrationStrategy);
788 bool updateParams =
false;
789 if(kpMaxFeatures!= -1)
792 NODELET_WARN(
"Setting %s=-1 (bag-of-words disabled)", Parameters::kKpMaxFeatures().
c_str());
801 if(modifiedParameters.find(Parameters::kRGBDProximityPathMaxNeighbors()) == modifiedParameters.end())
805 NODELET_WARN(
"Setting \"%s\" parameter to 10 (default 0) as \"subscribe_scan\" is "
806 "true and \"%s\" uses ICP. Proximity detection by space will be also done by merging close "
807 "scans. To disable, set \"%s\" to 0. To suppress this warning, "
808 "add <param name=\"%s\" type=\"string\" value=\"10\"/>",
809 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
810 Parameters::kRegStrategy().
c_str(),
811 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
812 Parameters::kRGBDProximityPathMaxNeighbors().
c_str());
817 NODELET_WARN(
"Setting \"%s\" parameter to 1 (default 0) as \"subscribe_scan_cloud\" is "
818 "true and \"%s\" uses ICP. To disable, set \"%s\" to 0. To suppress this warning, "
819 "add <param name=\"%s\" type=\"string\" value=\"1\"/>",
820 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
821 Parameters::kRegStrategy().
c_str(),
822 Parameters::kRGBDProximityPathMaxNeighbors().
c_str(),
823 Parameters::kRGBDProximityPathMaxNeighbors().
c_str());
835 if(!initialPoseStr.empty())
837 Transform intialPose = Transform::fromString(initialPoseStr);
845 NODELET_ERROR(
"Invalid initial_pose: \"%s\"", initialPoseStr.c_str());
858 #ifdef WITH_APRILTAG_ROS
861 #ifdef WITH_FIDUCIAL_MSGS
879 printf(
"rtabmap: Saving database/long-term memory... (located at %s)\n",
databasePath_.c_str());
883 float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
887 printf(
"rtabmap: 2D occupancy grid map saved.\n");
901 if(!configFile.empty())
903 NODELET_INFO(
"Loading parameters from %s", configFile.c_str());
906 NODELET_WARN(
"Config file doesn't exist! It will be generated...");
908 Parameters::readINI(configFile.c_str(), parameters);
914 if(!configFile.empty())
916 printf(
"Saving parameters to %s\n", configFile.c_str());
920 printf(
"Config file doesn't exist, a new one will be created.\n");
922 Parameters::writeINI(configFile.c_str(),
parameters_);
926 NODELET_INFO(
"Parameters are not saved! (No configuration file provided...)");
941 geometry_msgs::TransformStamped
msg;
944 msg.header.stamp = tfExpiration;
957 ros::Time stamp = imageMsg->header.stamp;
958 if(stamp.
toSec() == 0.0)
960 ROS_WARN(
"A null stamp has been detected in the input topic. Make sure the stamp is set.");
978 NODELET_ERROR(
"Input type must be image=mono8,mono16,rgb8,bgr8");
999 NODELET_WARN(
"RTAB-Map could not process the data received! (ROS id = %d)", ptrImage->header.seq);
1008 NODELET_WARN(
"Ignoring received image because its sequence ID=0. Please "
1009 "set \"Mem/GenerateIds\"=\"true\" to ignore ros generated sequence id. "
1010 "Use only \"Mem/GenerateIds\"=\"false\" for once-time run of RTAB-Map and "
1011 "when you need to have IDs output of RTAB-map synchronised with the source "
1012 "image sequence ID.");
1014 NODELET_INFO(
"rtabmap: Update rate=%fs, Limit=%fs, Processing time = %fs (%d local nodes)",
1035 static bool shown =
false;
1038 NODELET_WARN(
"We received odometry message, but we cannot get the "
1039 "corresponding TF %s->%s at data stamp %fs (odom msg stamp is %fs). Make sure TF of odometry is "
1040 "also published to get more accurate pose estimation. This "
1041 "warning is only printed once.", odomMsg->header.frame_id.c_str(),
frameId_.c_str(), stamp.
toSec(), odomMsg->header.stamp.toSec());
1044 stamp = odomMsg->header.stamp;
1054 UWARN(
"Odometry is reset (identity pose or high variance (%f) detected). Increment map id!",
MAX(odomMsg->pose.covariance[0], odomMsg->twist.covariance[0]));
1074 double variance = odomMsg->twist.covariance[0];
1078 covariance = cv::Mat(6,6,CV_64FC1, (
void*)odomMsg->pose.covariance.data()).clone();
1083 covariance = cv::Mat(6,6,CV_64FC1, (
void*)odomMsg->twist.covariance.data()).clone();
1086 if(
uIsFinite(covariance.at<
double>(0,0)) &&
1087 covariance.at<
double>(0,0) != 1.0 &&
1088 covariance.at<
double>(0,0)>0.0)
1099 bool ignoreFrame =
false;
1100 if(stamp.
toSec() == 0.0)
1102 ROS_WARN(
"A null stamp has been detected in the input topics. Make sure the stamp in all input topics is set.");
1123 else if(!ignoreFrame)
1146 UWARN(
"Odometry is reset (identity pose detected). Increment map id!");
1156 bool ignoreFrame =
false;
1157 if(stamp.
toSec() == 0.0)
1159 ROS_WARN(
"A null stamp has been detected in the input topics. Make sure the stamp in all input topics is set.");
1180 else if(!ignoreFrame)
1191 const nav_msgs::OdometryConstPtr & odomMsg,
1192 const rtabmap_msgs::UserDataConstPtr & userDataMsg,
1193 const std::vector<cv_bridge::CvImageConstPtr> & imageMsgs,
1194 const std::vector<cv_bridge::CvImageConstPtr> & depthMsgs,
1195 const std::vector<sensor_msgs::CameraInfo> & cameraInfoMsgs,
1196 const std::vector<sensor_msgs::CameraInfo> & depthCameraInfoMsgs,
1197 const sensor_msgs::LaserScan& scan2dMsg,
1198 const sensor_msgs::PointCloud2& scan3dMsg,
1199 const rtabmap_msgs::OdomInfoConstPtr& odomInfoMsg,
1200 const std::vector<rtabmap_msgs::GlobalDescriptor> & globalDescriptorMsgs,
1201 const std::vector<std::vector<rtabmap_msgs::KeyPoint> > & localKeyPoints,
1202 const std::vector<std::vector<rtabmap_msgs::Point3f> > & localPoints3d,
1203 const std::vector<cv::Mat> & localDescriptors)
1208 odomFrameId = odomMsg->header.frame_id;
1209 if(!scan2dMsg.ranges.empty())
1211 if(!
odomUpdate(odomMsg, scan2dMsg.header.stamp))
1216 else if(!scan3dMsg.data.empty())
1218 if(!
odomUpdate(odomMsg, scan3dMsg.header.stamp))
1223 else if(cameraInfoMsgs.size() == 0 || !
odomUpdate(odomMsg, cameraInfoMsgs[0].
header.stamp))
1228 else if(!scan2dMsg.ranges.empty())
1235 else if(!scan3dMsg.data.empty())
1252 depthCameraInfoMsgs,
1256 globalDescriptorMsgs,
1263 const std::string & odomFrameId,
1264 const rtabmap_msgs::UserDataConstPtr & userDataMsg,
1265 const std::vector<cv_bridge::CvImageConstPtr> & imageMsgs,
1266 const std::vector<cv_bridge::CvImageConstPtr> & depthMsgs,
1267 const std::vector<sensor_msgs::CameraInfo> & cameraInfoMsgs,
1268 const std::vector<sensor_msgs::CameraInfo> & depthCameraInfoMsgs,
1269 const sensor_msgs::LaserScan& scan2dMsg,
1270 const sensor_msgs::PointCloud2& scan3dMsg,
1271 const rtabmap_msgs::OdomInfoConstPtr& odomInfoMsg,
1272 const std::vector<rtabmap_msgs::GlobalDescriptor> & globalDescriptorMsgs,
1273 const std::vector<std::vector<rtabmap_msgs::KeyPoint> > & localKeyPointsMsgs,
1274 const std::vector<std::vector<rtabmap_msgs::Point3f> > & localPoints3dMsgs,
1275 const std::vector<cv::Mat> & localDescriptorsMsgs)
1280 std::vector<rtabmap::CameraModel> cameraModels;
1281 std::vector<rtabmap::StereoCameraModel> stereoCameraModels;
1282 std::vector<cv::KeyPoint> keypoints;
1283 std::vector<cv::Point3f> points;
1284 cv::Mat descriptors;
1290 depthCameraInfoMsgs,
1303 localDescriptorsMsgs,
1308 NODELET_ERROR(
"Could not convert rgb/depth msgs! Aborting rtabmap update...");
1311 UDEBUG(
"cameraModels=%ld stereoCameraModels=%ld", cameraModels.size(), stereoCameraModels.size());
1312 UDEBUG(
"rgb=%dx%d(type=%d), depth/right=%dx%d(type=%d)", rgb.rows, rgb.cols, rgb.type(), depth.rows, depth.cols, depth.type());
1316 UASSERT(depth.type() == CV_8UC1);
1318 if(rgb.channels() == 3)
1320 cv::cvtColor(rgb, leftMono, CV_BGR2GRAY);
1326 cv::Mat rightMono = depth;
1329 UASSERT(
int((leftMono.cols/stereoCameraModels.size())*stereoCameraModels.size()) == leftMono.cols);
1330 UASSERT(
int((rightMono.cols/stereoCameraModels.size())*stereoCameraModels.size()) == rightMono.cols);
1331 int subImageWidth = leftMono.cols/stereoCameraModels.size();
1332 for(
size_t i=0;
i<stereoCameraModels.size(); ++
i)
1334 cv::Mat left(leftMono, cv::Rect(subImageWidth*
i, 0, subImageWidth, leftMono.rows));
1335 cv::Mat right(rightMono, cv::Rect(subImageWidth*
i, 0, subImageWidth, rightMono.rows));
1342 if(disparity.empty())
1344 NODELET_ERROR(
"Could not compute disparity image (\"stereo_to_depth\" is true)!");
1349 stereoCameraModels[
i].left().
fx(),
1352 if(subDepth.empty())
1354 NODELET_ERROR(
"Could not compute depth image (\"stereo_to_depth\" is true)!");
1357 UASSERT(subDepth.type() == CV_16UC1 || subDepth.type() == CV_32FC1);
1361 depth = cv::Mat(subDepth.rows, subDepth.cols*stereoCameraModels.size(), subDepth.type());
1364 if(subDepth.type() == depth.type())
1366 subDepth.copyTo(cv::Mat(depth, cv::Rect(
i*subDepth.cols, 0, subDepth.cols, subDepth.rows)));
1370 ROS_ERROR(
"Some Depth images are not the same type!");
1374 cameraModels.push_back(stereoCameraModels[
i].left());
1376 stereoCameraModels.clear();
1380 if(!depth.empty() && depth.type() == CV_32FC1 &&
uStr2Bool(
parameters_.at(Parameters::kMemSaveDepth16Format())))
1383 static bool shown =
false;
1386 NODELET_WARN(
"Save depth data to 16 bits format: depth type detected is "
1387 "32FC1, use 16UC1 depth format to avoid this conversion "
1388 "(or set parameter \"Mem/SaveDepth16Format=false\" to use "
1389 "32bits format). This message is only printed once...");
1395 bool genMaxScanPts = 0;
1396 if(scan2dMsg.ranges.empty() && scan3dMsg.data.empty() && !depth.empty() && stereoCameraModels.empty() &&
genScan_)
1398 pcl::PointCloud<pcl::PointXYZ>::Ptr scanCloud2d(
new pcl::PointCloud<pcl::PointXYZ>);
1399 *scanCloud2d = util3d::laserScanFromDepthImages(
1404 genMaxScanPts += depth.cols;
1407 else if(!scan2dMsg.ranges.empty())
1420 NODELET_ERROR(
"Could not convert laser scan msg! Aborting rtabmap update...");
1424 else if(!scan3dMsg.data.empty())
1438 NODELET_ERROR(
"Could not convert 3d laser scan msg! Aborting rtabmap update...");
1445 for(
size_t i=0;
i<cameraModels.size(); ++
i)
1456 ROS_ERROR(
"decimation (%d) not valid for image size %dx%d! Aborting depth generation from scan...",
1459 model.imageHeight());
1465 cv::Mat depthProjected = util3d::projectCloudToCamera(
1475 depthProjected = util2d::fillDepthHoles(
1484 depth = cv::Mat::zeros(
model.imageHeight(),
model.imageWidth()*cameraModels.size(), CV_32FC1);
1486 depthProjected.copyTo(depth.colRange(
i*
model.imageWidth(), (
i+1)*
model.imageWidth()));
1492 if(userDataMsg.get())
1498 NODELET_WARN(
"Synchronized and asynchronized user data topics cannot be used at the same time. Async user data dropped!");
1510 if(!stereoCameraModels.empty())
1534 if(odomInfoMsg.get())
1539 if(!globalDescriptorMsgs.empty())
1544 if(!keypoints.empty())
1546 UASSERT(points.empty() || points.size() == keypoints.size());
1547 UASSERT(descriptors.empty() || descriptors.rows == (
int)keypoints.size());
1548 data.setFeatures(keypoints, points, descriptors);
1558 timerConversion.
ticks());
1563 const nav_msgs::OdometryConstPtr & odomMsg,
1564 const rtabmap_msgs::UserDataConstPtr & userDataMsg,
1565 const sensor_msgs::LaserScan& scan2dMsg,
1566 const sensor_msgs::PointCloud2& scan3dMsg,
1567 const rtabmap_msgs::OdomInfoConstPtr& odomInfoMsg,
1568 const rtabmap_msgs::GlobalDescriptor & globalDescriptor)
1574 odomFrameId = odomMsg->header.frame_id;
1575 if(!scan2dMsg.ranges.empty())
1577 if(!
odomUpdate(odomMsg, scan2dMsg.header.stamp))
1582 else if(!scan3dMsg.data.empty())
1584 if(!
odomUpdate(odomMsg, scan3dMsg.header.stamp))
1594 else if(!scan2dMsg.ranges.empty())
1601 else if(!scan3dMsg.data.empty())
1614 if(!scan2dMsg.ranges.empty())
1627 NODELET_ERROR(
"Could not convert laser scan msg! Aborting rtabmap update...");
1631 else if(!scan3dMsg.data.empty())
1645 NODELET_ERROR(
"Could not convert 3d laser scan msg! Aborting rtabmap update...");
1651 if(userDataMsg.get())
1657 NODELET_WARN(
"Synchronized and asynchronized user data topics cannot be used at the same time. Async user data dropped!");
1678 if(odomInfoMsg.get())
1683 if(!globalDescriptor.data.empty())
1695 timerConversion.
ticks());
1701 const nav_msgs::OdometryConstPtr & odomMsg,
1702 const rtabmap_msgs::UserDataConstPtr & userDataMsg,
1703 const rtabmap_msgs::OdomInfoConstPtr& odomInfoMsg)
1709 odomFrameId = odomMsg->header.frame_id;
1710 if(!
odomUpdate(odomMsg, odomMsg->header.stamp))
1716 if(userDataMsg.get())
1722 NODELET_WARN(
"Synchronized and asynchronized user data topics cannot be used at the same time. Async user data dropped!");
1742 if(odomInfoMsg.get())
1754 timerConversion.
ticks());
1760 const rtabmap_msgs::SensorDataConstPtr & sensorDataMsg,
1761 const nav_msgs::OdometryConstPtr & odomMsg,
1762 const rtabmap_msgs::OdomInfoConstPtr& odomInfoMsg)
1769 odomFrameId = odomMsg->header.frame_id;
1770 if(!
odomUpdate(odomMsg, sensorDataMsg->header.stamp))
1784 if(odomInfoMsg.get())
1796 timerConversion.
ticks());
1805 const std::vector<float> & odomVelocityIn,
1806 const std::string & odomFrameId,
1807 const cv::Mat & odomCovariance,
1809 double timeMsgConversion)
1828 double variance =
iter->first.twist.covariance[0];
1832 covariance = cv::Mat(6,6,CV_64FC1, (
void*)
iter->first.pose.covariance.data()).clone();
1837 covariance = cv::Mat(6,6,CV_64FC1, (
void*)
iter->first.twist.covariance.data()).clone();
1839 if(!
uIsFinite(covariance.at<
double>(0,0)) || covariance.at<
double>(0,0)<=0.0f)
1841 covariance = cv::Mat::eye(6,6,CV_64FC1);
1858 covariance.at<
double>(2,2) =
uIsFinite(covariance.at<
double>(2,2)) && covariance.at<
double>(2,2)!=0?covariance.at<
double>(2,2):1;
1859 covariance.at<
double>(3,3) =
uIsFinite(covariance.at<
double>(3,3)) && covariance.at<
double>(3,3)!=0?covariance.at<
double>(3,3):1;
1860 covariance.at<
double>(4,4) =
uIsFinite(covariance.at<
double>(4,4)) && covariance.at<
double>(4,4)!=0?covariance.at<
double>(4,4):1;
1871 std::map<std::string, float> externalStats;
1872 std::vector<float> odomVelocity;
1873 if(
iter->second.timeEstimation != 0.0f)
1878 if(
info.interval>0.0)
1880 odomVelocity.resize(6);
1883 odomVelocity[0] =
x/
info.interval;
1884 odomVelocity[1] =
y/
info.interval;
1885 odomVelocity[2] =
z/
info.interval;
1886 odomVelocity[3] =
roll/
info.interval;
1888 odomVelocity[5] =
yaw/
info.interval;
1891 if(odomVelocity.empty())
1893 odomVelocity.resize(6);
1894 odomVelocity[0] =
iter->first.twist.twist.linear.x;
1895 odomVelocity[1] =
iter->first.twist.twist.linear.y;
1896 odomVelocity[2] =
iter->first.twist.twist.linear.z;
1897 odomVelocity[3] =
iter->first.twist.twist.angular.x;
1898 odomVelocity[4] =
iter->first.twist.twist.angular.y;
1899 odomVelocity[5] =
iter->first.twist.twist.angular.z;
1902 rtabmap_.
process(interData, interOdom, covariance, odomVelocity, externalStats);
1923 data.setGroundTruth(groundTruthPose);
1935 if(!sensorToBase.
isNull())
1938 globalPose *= sensorToBase;
1950 globalPose *= correction;
1954 NODELET_WARN(
"Could not adjust global pose accordingly to latest odometry pose. "
1955 "If odometry is small since it received the global pose and "
1956 "covariance is large, this should not be a problem.");
1958 cv::Mat globalPoseCovariance = cv::Mat(6,6, CV_64FC1, (
void*)
globalPose_.pose.covariance.data()).clone();
1959 data.setGlobalPose(globalPose, globalPoseCovariance);
1981 if(!landmarks.empty())
1983 data.setLandmarks(landmarks);
2003 if(!localTransform.
isNull())
2006 data.setIMU(
IMU(cv::Vec4d(
q.x(),
q.y(),
q.z(),
q.w()), cv::Mat::eye(3,3,CV_64FC1),
2007 cv::Vec3d(), cv::Mat(),
2008 cv::Vec3d(), cv::Mat(),
2014 ROS_WARN(
"We are receiving imu data (buffer=%d), but cannot interpolate "
2015 "imu transform at time %f. IMU won't be added to graph.",
2020 double timeRtabmap = 0.0;
2021 double timeUpdateMaps = 0.0;
2022 double timePublishMaps = 0.0;
2024 cv::Mat covariance = odomCovariance;
2025 if(covariance.empty() || !
uIsFinite(covariance.at<
double>(0,0)) || covariance.at<
double>(0,0)<=0.0f)
2027 covariance = cv::Mat::eye(6,6,CV_64FC1);
2044 covariance.at<
double>(2,2) =
uIsFinite(covariance.at<
double>(2,2)) && covariance.at<
double>(2,2)!=0?covariance.at<
double>(2,2):1;
2045 covariance.at<
double>(3,3) =
uIsFinite(covariance.at<
double>(3,3)) && covariance.at<
double>(3,3)!=0?covariance.at<
double>(3,3):1;
2046 covariance.at<
double>(4,4) =
uIsFinite(covariance.at<
double>(4,4)) && covariance.at<
double>(4,4)!=0?covariance.at<
double>(4,4):1;
2049 std::map<std::string, float> externalStats;
2050 std::vector<float> odomVelocity;
2057 odomVelocity.resize(6);
2068 if(odomVelocity.empty())
2070 odomVelocity = odomVelocityIn;
2078 timeMsgConversion +=
timer.ticks();
2081 timeRtabmap =
timer.ticks();
2087 ROS_ERROR(
"Odometry received doesn't have same frame_id "
2088 "than the one previously set (old=%s, new=%s). "
2089 "Are there multiple nodes publishing on same odometry topic name? "
2090 "The new frame_id is now used.",
odomFrameId_.c_str(), odomFrameId.c_str());
2110 geometry_msgs::PoseWithCovarianceStamped poseMsg;
2112 poseMsg.header.stamp = stamp;
2117 memcpy(poseMsg.pose.covariance.data(), cov.data, cov.total()*
sizeof(
double));
2122 poseMsg.pose.covariance.data()[0] = 9999;
2123 poseMsg.pose.covariance.data()[7] = 9999;
2127 poseMsg.pose.covariance.data()[35] = 9999;
2135 std::map<int, rtabmap::Signature> tmpSignature;
2137 filteredPoses.size() == 0 ||
2145 tmpSignature.insert(std::make_pair(0,
Signature(0, -1, 0,
data.stamp(),
"", odom,
Transform(), tmpData)));
2146 filteredPoses.insert(std::make_pair(0,
mapToOdom_*odom));
2154 std::set<int> onPath;
2158 onPath.insert(nextNodes.begin(), nextNodes.end());
2160 for(std::map<int, Transform>::iterator
iter=filteredPoses.begin();
iter!=filteredPoses.end(); ++
iter)
2162 if(
iter->first == 0 || onPath.find(
iter->first) != onPath.end())
2164 nearestPoses.insert(*
iter);
2166 else if(onPath.empty())
2172 filteredPoses = nearestPoses;
2183 timeUpdateMaps =
timer.ticks();
2237 Transform goalLocalTransform = Transform::getIdentity();
2261 NODELET_ERROR(
"Planning: Local map broken, current goal id=%d (the robot may have moved to far from planned nodes)",
2278 timePublishMaps =
timer.ticks();
2285 tick(stamp,
rate_>0?
rate_:1000.0/(timeMsgConversion+timeRtabmap+timeUpdateMaps+timePublishMaps));
2290 timeRtabmap =
timer.ticks();
2292 NODELET_INFO(
"rtabmap (%d): Rate=%.2fs, Limit=%.3fs, Conversion=%.4fs, RTAB-Map=%.4fs, Maps update=%.4fs pub=%.4fs (local map=%d, WM=%d)",
2303 rtabmapROSStats_.insert(std::make_pair(std::string(
"RtabmapROS/TimeMsgConversion/ms"), timeMsgConversion*1000.0
f));
2304 rtabmapROSStats_.insert(std::make_pair(std::string(
"RtabmapROS/TimeRtabmap/ms"), timeRtabmap*1000.0
f));
2305 rtabmapROSStats_.insert(std::make_pair(std::string(
"RtabmapROS/TimeUpdatingMaps/ms"), timeUpdateMaps*1000.0
f));
2306 rtabmapROSStats_.insert(std::make_pair(std::string(
"RtabmapROS/TimePublishing/ms"), timePublishMaps*1000.0
f));
2307 rtabmapROSStats_.insert(std::make_pair(std::string(
"RtabmapROS/TimeTotal/ms"), (timeMsgConversion+timeRtabmap+timeUpdateMaps+timePublishMaps)*1000.0
f));
2311 NODELET_WARN(
"Ignoring received image because its sequence ID=0. Please "
2312 "set \"Mem/GenerateIds\"=\"true\" to ignore ros generated sequence id. "
2313 "Use only \"Mem/GenerateIds\"=\"false\" for once-time run of RTAB-Map and "
2314 "when you need to have IDs output of RTAB-map synchronized with the source "
2315 "image sequence ID.");
2320 const std::map<int, Transform> & nodes,
2323 std::map<int, Transform> output;
2326 std::map<int, float> nodesDist = graph::findNearestNodes(currentPose,
nodes, 0, 0,
mappingMaxNodes_);
2327 for(std::map<int, float>::iterator
iter=nodesDist.begin();
iter!=nodesDist.end(); ++
iter)
2332 output.insert(*
nodes.find(
iter->first));
2342 output.insert(*
iter);
2354 static bool warningShow =
false;
2357 ROS_WARN(
"Overwriting previous user data set. When asynchronous user "
2358 "data input topic rate is higher than "
2359 "map update rate (current %s=%f), only latest data is saved "
2360 "in the next node created. This message will is shown only once.",
2361 Parameters::kRtabmapDetectionRate().
c_str(),
rate_);
2380 double error = 10.0;
2381 if(gpsFixMsg->position_covariance_type != sensor_msgs::NavSatFix::COVARIANCE_TYPE_UNKNOWN)
2383 double variance =
uMax3(gpsFixMsg->position_covariance.at(0), gpsFixMsg->position_covariance.at(4), gpsFixMsg->position_covariance.at(8));
2390 gpsFixMsg->header.stamp.toSec(),
2391 gpsFixMsg->longitude,
2392 gpsFixMsg->latitude,
2393 gpsFixMsg->altitude,
2399 #ifdef WITH_APRILTAG_ROS
2400 void CoreWrapper::tagDetectionsAsyncCallback(
const apriltag_ros::AprilTagDetectionArray & tagDetections)
2404 for(
unsigned int i=0;
i<tagDetections.detections.size(); ++
i)
2406 if(tagDetections.detections[i].id.size() >= 1)
2408 geometry_msgs::PoseWithCovarianceStamped
p = tagDetections.detections[
i].pose;
2409 p.header = tagDetections.header;
2410 if(!tagDetections.detections[i].pose.header.frame_id.empty())
2412 p.header.frame_id = tagDetections.detections[
i].pose.header.frame_id;
2414 static bool warned =
false;
2416 !tagDetections.header.frame_id.empty() &&
2417 tagDetections.detections[i].pose.header.frame_id.compare(tagDetections.header.frame_id)!=0)
2419 NODELET_WARN(
"frame_id set for individual tag detections (%s) doesn't match the frame_id of the message (%s), "
2420 "the resulting pose of the tag may be wrong. This message is only printed once.",
2421 tagDetections.detections[i].pose.header.frame_id.c_str(), tagDetections.header.frame_id.c_str());
2425 if(!tagDetections.detections[i].pose.header.stamp.isZero())
2427 p.header.stamp = tagDetections.detections[
i].pose.header.stamp;
2429 static bool warned =
false;
2431 !tagDetections.header.stamp.isZero() &&
2432 tagDetections.detections[i].pose.header.stamp != tagDetections.header.stamp)
2434 NODELET_WARN(
"stamp set for individual tag detections (%f) doesn't match the stamp of the message (%f), "
2435 "the resulting pose of the tag may be wrongly interpolated. This message is only printed once.",
2436 tagDetections.detections[i].pose.header.stamp.toSec(), tagDetections.header.stamp.toSec());
2441 std::make_pair(tagDetections.detections[i].id[0],
2442 std::make_pair(p, tagDetections.detections[i].size.size()==1?(
float)tagDetections.detections[i].size[0]:0.0f)));
2449 #ifdef WITH_FIDUCIAL_MSGS
2450 void CoreWrapper::fiducialDetectionsAsyncCallback(
const fiducial_msgs::FiducialTransformArray & fiducialDetections)
2454 for(
unsigned int i=0;
i<fiducialDetections.transforms.size(); ++
i)
2456 geometry_msgs::PoseWithCovarianceStamped
p;
2457 p.pose.pose.orientation = fiducialDetections.transforms[
i].transform.rotation;
2458 p.pose.pose.position.x = fiducialDetections.transforms[
i].transform.translation.x;
2459 p.pose.pose.position.y = fiducialDetections.transforms[
i].transform.translation.y;
2460 p.pose.pose.position.z = fiducialDetections.transforms[
i].transform.translation.z;
2461 p.header = fiducialDetections.header;
2463 std::make_pair(fiducialDetections.transforms[i].fiducial_id,
2464 std::make_pair(p, 0.0f)));
2474 if(
msg->orientation.x == 0 &&
msg->orientation.y == 0 &&
msg->orientation.z == 0 &&
msg->orientation.w == 0)
2476 UERROR(
"IMU received doesn't have orientation set, it is ignored.");
2482 if(
imus_.size() > 1000)
2488 ROS_ERROR(
"IMU frame_id has changed from %s to %s! Are "
2489 "multiple nodes publishing "
2490 "on same topic %s? IMU buffer is cleared!",
2492 msg->header.frame_id.c_str(),
2514 interOdoms_.push_back(std::make_pair(*
msg, rtabmap_msgs::OdomInfo()));
2522 interOdoms_.push_back(std::make_pair(*msg1, *msg2));
2529 Transform mapToPose = Transform::getIdentity();
2530 if(
msg->header.frame_id.empty())
2532 NODELET_WARN(
"Received initialpose doesn't have frame_id set, assuming it is in %s frame.",
mapFrameId_.c_str());
2539 NODELET_ERROR(
"Failed to transform initialpose from frame %s to map frame %s",
msg->header.frame_id.c_str(),
mapFrameId_.c_str());
2557 NODELET_INFO(
"initialpose received: %s in %s frame, transformed to %s in %s frame.",
2559 msg->header.frame_id.c_str(),
2560 (mapToPose * initialPose).prettyPrint().c_str(),
2568 const std::string & label,
2569 const std::string & frameId,
2572 double * planningTime)
2596 *planningTime = 0.0;
2599 bool success =
false;
2608 const std::vector<std::pair<int, Transform> > & poses =
rtabmap_.
getPath();
2614 if(poses.size() == 0)
2616 NODELET_WARN(
"Planning: Goal already reached (RGBD/GoalReachedRadius=%fm).",
2632 NODELET_INFO(
"Planning: Path successfully created (size=%d)", (
int)poses.size());
2641 Transform goalLocalTransform = Transform::getIdentity();
2659 std::stringstream
stream;
2660 for(std::vector<std::pair<int, Transform> >::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
2662 if(
iter != poses.begin())
2677 else if(!label.empty())
2679 NODELET_ERROR(
"Planning: Node with label \"%s\" not found!", label.c_str());
2685 NODELET_ERROR(
"Planning: Could not plan to node %d! The node is not in map's graph (look for warnings before this message for more details).",
id);
2689 NODELET_ERROR(
"Planning: Could not plan to landmark %d! The landmark is not in map's graph (look for warnings before this message for more details).",
id);
2718 if(!
msg->header.frame_id.empty() &&
mapFrameId_.compare(
msg->header.frame_id) != 0)
2723 NODELET_ERROR(
"Cannot transform goal pose from \"%s\" frame to \"%s\" frame!",
2733 targetPose =
t * targetPose;
2742 if(
msg->node_id == 0 &&
msg->node_label.empty())
2767 NODELET_INFO(
"Setting RTAB-Map parameter \"%s\"=\"%s\"",
iter->first.c_str(), vStr.c_str());
2768 iter->second = vStr;
2888 NODELET_INFO(
"LoadDatabase: Loading database (%s, clear=%s)...", req.database_path.c_str(), req.clear?
"true":
"false");
2893 ROS_ERROR(
"Directory %s doesn't exist! Cannot load database \"%s\"", newDatabasePath.c_str(), dir.c_str());
2907 float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
2911 printf(
"rtabmap: 2D occupancy grid map saved.\n");
2955 for(ParametersMap::iterator
iter=dbParameters.begin();
iter!=dbParameters.end(); ++
iter)
2957 if(
iter->first.compare(Parameters::kRtabmapWorkingDirectory()) == 0)
2965 NODELET_WARN(
"RTAB-Map parameter \"%s\" from database (%s) is different "
2966 "from the current used one (%s). We still keep the "
2967 "current parameter value (%s). If you want to switch between databases "
2968 "with different configurations, restart rtabmap node instead of using this service.",
2969 iter->first.c_str(),
iter->second.c_str(),
2978 NODELET_INFO(
"LoadDatabase: Loading database... done!");
2984 float xMin, yMin, gridCellSize;
2988 NODELET_INFO(
"LoadDatabase: 2D occupancy grid map loaded (%dx%d).", map.cols, map.rows);
2995 NODELET_INFO(
"LoadDatabase: Working Memory = %d, Local map = %d.",
3007 NODELET_INFO(
"LoadDatabase: SLAM mode (%s=true)", Parameters::kMemIncrementalMemory().
c_str());
3011 NODELET_INFO(
"LoadDatabase: Localization mode (%s=false)", Parameters::kMemIncrementalMemory().
c_str());
3033 float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
3037 printf(
"rtabmap: 2D occupancy grid map saved.\n");
3077 rtabmap_msgs::MapDataPtr
msg(
new rtabmap_msgs::MapData);
3078 msg->header.stamp = stamp;
3084 std::map<int, Signature>(),
3093 rtabmap_msgs::MapGraphPtr
msg(
new rtabmap_msgs::MapGraph);
3094 msg->header.stamp = stamp;
3109 NODELET_WARN(
"Detect more loop closures service called");
3112 float clusterRadiusMax = 1;
3113 float clusterRadiusMin = 0;
3114 float clusterAngle = 0;
3116 bool intraSession =
true;
3117 bool interSession =
true;
3118 if(req.cluster_radius_max > 0.0f)
3120 clusterRadiusMax = req.cluster_radius_max;
3122 if(req.cluster_radius_min >= 0.0f)
3124 clusterRadiusMin = req.cluster_radius_min;
3126 if(req.cluster_angle >= 0.0f)
3128 clusterAngle = req.cluster_angle;
3130 if(req.iterations >= 1.0f)
3132 iterations = (
int)req.iterations;
3136 interSession =
false;
3138 else if(req.inter_only)
3140 intraSession =
false;
3142 NODELET_WARN(
"Post-Processing service called: Detecting more loop closures "
3143 "(max radius=%f, min radius=%f, angle=%f, iterations=%d, intra=%s, inter=%s)...",
3148 intraSession?
"true":
"false",
3149 interSession?
"true":
"false");
3152 clusterAngle*
M_PI/180.0,
3160 NODELET_ERROR(
"Post-Processing: Detecting more loop closures failed!");
3164 NODELET_WARN(
"Post-Processing: Detected %d loop closures! (%fs)",
res.detected,
timer.ticks());
3180 bool filterScans =
false;
3181 if(req.radius > 1.0f)
3183 radius = (
int)req.radius;
3185 filterScans = req.filter_scans;
3186 float xMin, yMin, gridCellSize;
3190 NODELET_ERROR(
"Post-Processing: Cleanup local grids failed! There is no optimized map.");
3194 NODELET_WARN(
"Post-Processing: Cleanup local grids... (radius=%d, filter scans=%s)",
3196 filterScans?
"true":
"false");
3200 NODELET_ERROR(
"Post-Processing: Cleanup local grids failed!");
3206 NODELET_WARN(
"Post-Processing: %d grids and scans modified! (%fs)",
res.modified,
timer.ticks());
3212 if(
res.modified > 0)
3227 NODELET_WARN(
"Global bundle adjustment service called");
3230 int optimizer = (
int)Optimizer::kTypeG2O;
3231 int iterations = Parameters::defaultOptimizerIterations();
3232 float pixelVariance = Parameters::defaultg2oPixelVariance();
3233 bool rematchFeatures =
true;
3234 Parameters::parse(
parameters_, Parameters::kOptimizerIterations(), iterations);
3235 Parameters::parse(
parameters_, Parameters::kg2oPixelVariance(), pixelVariance);
3236 if(req.type == 1.0f)
3238 optimizer = (
int)Optimizer::kTypeCVSBA;
3240 if(req.iterations >= 1.0f)
3242 iterations = req.iterations;
3244 if(req.pixel_variance > 0.0f)
3246 pixelVariance = req.pixel_variance;
3248 rematchFeatures = !req.voc_matches;
3250 NODELET_WARN(
"Post-Processing: Global Bundle Adjustment... "
3251 "(Optimizer=%s, iterations=%d, pixel variance=%f, rematch=%s)...",
3252 optimizer==Optimizer::kTypeG2O?
"g2o":
"cvsba",
3255 rematchFeatures?
"true":
"false");
3259 NODELET_ERROR(
"Post-Processing: Global Bundle Adjustment failed!");
3263 NODELET_WARN(
"Post-Processing: Global Bundle Adjustment... done! (%fs)",
timer.ticks());
3277 nh.
setParam(rtabmap::Parameters::kMemIncrementalMemory(),
"false");
3289 nh.
setParam(rtabmap::Parameters::kMemIncrementalMemory(),
"true");
3322 NODELET_INFO(
"rtabmap: Getting node data (%d node(s), images=%s scan=%s grid=%s user_data=%s)...",
3323 (
int)req.ids.size(),
3324 req.images?
"true":
"false",
3325 req.scan?
"true":
"false",
3326 req.grid?
"true":
"false",
3327 req.user_data?
"true":
"false");
3333 for(
size_t i=0;
i<req.ids.size(); ++
i)
3335 int id = req.ids[
i];
3340 rtabmap_msgs::Node
msg;
3346 return !
res.data.empty();
3351 NODELET_INFO(
"rtabmap: Getting map (global=%s optimized=%s graphOnly=%s)...",
3352 req.global?
"true":
"false",
3353 req.optimized?
"true":
"false",
3354 req.graphOnly?
"true":
"false");
3355 std::map<int, Signature> signatures;
3356 std::map<int, Transform> poses;
3357 std::multimap<int, rtabmap::Link> constraints;
3385 NODELET_INFO(
"rtabmap: Getting map (global=%s optimized=%s with_images=%s with_scans=%s with_user_data=%s with_grids=%s)...",
3386 req.global?
"true":
"false",
3387 req.optimized?
"true":
"false",
3388 req.with_images?
"true":
"false",
3389 req.with_scans?
"true":
"false",
3390 req.with_user_data?
"true":
"false",
3391 req.with_grids?
"true":
"false");
3392 std::map<int, Signature> signatures;
3393 std::map<int, Transform> poses;
3394 std::multimap<int, rtabmap::Link> constraints;
3407 req.with_global_descriptors);
3427 NODELET_WARN(
"/get_proj_map service is deprecated! Call /get_grid_map service "
3428 "instead with <param name=\"%s\" type=\"string\" value=\"1\"/>. "
3429 "Do \"$ rosrun rtabmap_slam rtabmap --params | grep Grid\" to see "
3430 "all occupancy grid parameters.",
3431 Parameters::kGridSensor().
c_str());
3435 NODELET_WARN(
"/get_proj_map service is deprecated! Call /get_grid_map service instead.");
3442 NODELET_WARN(
"/get_grid_map service is deprecated! Call /get_map service instead.");
3453 float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
3459 res.map.info.resolution = gridCellSize;
3460 res.map.info.origin.position.x = 0.0;
3461 res.map.info.origin.position.y = 0.0;
3462 res.map.info.origin.position.z = 0.0;
3463 res.map.info.origin.orientation.x = 0.0;
3464 res.map.info.origin.orientation.y = 0.0;
3465 res.map.info.origin.orientation.z = 0.0;
3466 res.map.info.origin.orientation.w = 1.0;
3468 res.map.info.width = pixels.cols;
3469 res.map.info.height = pixels.rows;
3470 res.map.info.origin.position.x = xMin;
3471 res.map.info.origin.position.y = yMin;
3472 res.map.data.resize(
res.map.info.width *
res.map.info.height);
3474 memcpy(
res.map.data.data(), pixels.data,
res.map.info.width *
res.map.info.height);
3494 float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
3500 res.map.info.resolution = gridCellSize;
3501 res.map.info.origin.position.x = 0.0;
3502 res.map.info.origin.position.y = 0.0;
3503 res.map.info.origin.position.z = 0.0;
3504 res.map.info.origin.orientation.x = 0.0;
3505 res.map.info.origin.orientation.y = 0.0;
3506 res.map.info.origin.orientation.z = 0.0;
3507 res.map.info.origin.orientation.w = 1.0;
3509 res.map.info.width = pixels.cols;
3510 res.map.info.height = pixels.rows;
3511 res.map.info.origin.position.x = xMin;
3512 res.map.info.origin.position.y = yMin;
3513 res.map.data.resize(
res.map.info.width *
res.map.info.height);
3515 memcpy(
res.map.data.data(), pixels.data,
res.map.info.width *
res.map.info.height);
3538 std::map<int, Transform> poses;
3539 std::multimap<int, rtabmap::Link> constraints;
3540 std::map<int, Signature > signatures;
3555 rtabmap_msgs::MapDataPtr
msg(
new rtabmap_msgs::MapData);
3556 msg->header.stamp = now;
3570 rtabmap_msgs::MapGraphPtr
msg(
new rtabmap_msgs::MapGraph);
3571 msg->header.stamp = now;
3583 visualization_msgs::MarkerArray markers;
3586 geometry_msgs::PoseArrayPtr
msg(
new geometry_msgs::PoseArray);
3587 msg->header.stamp = now;
3589 for(std::map<int, Transform>::const_iterator
iter=poses.begin();
iter!=poses.end() &&
iter->first<0; ++
iter)
3591 geometry_msgs::Pose
p;
3593 msg->poses.push_back(
p);
3598 visualization_msgs::Marker marker;
3600 marker.header.stamp = now;
3601 marker.ns =
"landmarks";
3602 marker.id =
iter->first;
3603 marker.action = visualization_msgs::Marker::ADD;
3604 marker.pose.position.x =
iter->second.x();
3605 marker.pose.position.y =
iter->second.y();
3606 marker.pose.position.z =
iter->second.z();
3607 marker.pose.orientation.x = 0.0;
3608 marker.pose.orientation.y = 0.0;
3609 marker.pose.orientation.z = 0.0;
3610 marker.pose.orientation.w = 1.0;
3613 marker.scale.z = 0.35;
3614 marker.color.a = 0.5;
3615 marker.color.r = 1.0;
3616 marker.color.g = 1.0;
3617 marker.color.b = 0.0;
3620 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
3623 markers.markers.push_back(marker);
3634 std::map<int, Transform> filteredPoses(poses.lower_bound(1), poses.end());
3637 std::map<int, Transform> nearestPoses =
filterNodesToAssemble(filteredPoses, filteredPoses.rbegin()->second);
3639 if(signatures.size())
3662 if(pubLabels || pubPath)
3664 if(poses.size() && signatures.size())
3666 nav_msgs::Path
path;
3669 path.poses.resize(poses.size());
3672 for(std::map<int, Signature>::const_iterator
iter=signatures.begin();
3673 iter!=signatures.end();
3676 std::map<int, Transform>::const_iterator poseIter= poses.find(
iter->first);
3677 if(poseIter!=poses.end())
3682 if(!
iter->second.getLabel().empty())
3684 visualization_msgs::Marker marker;
3686 marker.header.stamp = now;
3687 marker.ns =
"labels";
3688 marker.id =
iter->first;
3689 marker.action = visualization_msgs::Marker::ADD;
3690 marker.pose.position.x = poseIter->second.x();
3691 marker.pose.position.y = poseIter->second.y();
3692 marker.pose.position.z = poseIter->second.z();
3693 marker.pose.orientation.x = 0.0;
3694 marker.pose.orientation.y = 0.0;
3695 marker.pose.orientation.z = 0.0;
3696 marker.pose.orientation.w = 1.0;
3699 marker.scale.z = 0.5;
3700 marker.color.a = 0.7;
3701 marker.color.r = 1.0;
3702 marker.color.g = 0.0;
3703 marker.color.b = 0.0;
3705 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
3706 marker.text =
iter->second.getLabel();
3708 markers.markers.push_back(marker);
3711 visualization_msgs::Marker marker;
3713 marker.header.stamp = now;
3715 marker.id =
iter->first;
3716 marker.action = visualization_msgs::Marker::ADD;
3717 marker.pose.position.x = poseIter->second.x();
3718 marker.pose.position.y = poseIter->second.y();
3719 marker.pose.position.z = poseIter->second.z();
3720 marker.pose.orientation.x = 0.0;
3721 marker.pose.orientation.y = 0.0;
3722 marker.pose.orientation.z = 0.0;
3723 marker.pose.orientation.w = 1.0;
3726 marker.scale.z = 0.2;
3727 marker.color.a = 0.5;
3728 marker.color.r = 1.0;
3729 marker.color.g = 1.0;
3730 marker.color.b = 1.0;
3733 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
3736 markers.markers.push_back(marker);
3748 if(pubLabels && markers.markers.size())
3755 path.header.stamp = now;
3756 path.poses.resize(oi);
3764 UWARN(
"No subscribers, don't need to publish!");
3782 Transform coordinateTransform = Transform::getIdentity();
3783 if(!req.goal.header.frame_id.empty() &&
mapFrameId_.compare(req.goal.header.frame_id) != 0)
3786 if(coordinateTransform.
isNull())
3788 NODELET_ERROR(
"Cannot transform goal pose from \"%s\" frame to \"%s\" frame!",
3789 req.goal.header.frame_id.c_str(),
mapFrameId_.c_str());
3792 pose = coordinateTransform * pose;
3797 coordinateTransform = coordinateTransform.
inverse();
3802 const std::vector<std::pair<int, Transform> > & poses =
rtabmap_.
getPath();
3803 res.plan.header.frame_id = req.goal.header.frame_id;
3804 res.plan.header.stamp = req.goal.header.stamp;
3805 if(poses.size() == 0)
3807 NODELET_WARN(
"Planning: Goal already reached (RGBD/GoalReachedRadius=%fm).",
3810 res.plan.poses.resize(1);
3815 res.plan.poses.resize(poses.size());
3817 for(std::vector<std::pair<int, Transform> >::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
3819 res.plan.poses[oi].header =
res.plan.header;
3825 res.plan.poses.resize(
res.plan.poses.size()+1);
3826 res.plan.poses[
res.plan.poses.size()-1].header =
res.plan.header;
3832 std::stringstream
stream;
3833 for(std::vector<std::pair<int, Transform> >::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
3835 if(
iter != poses.begin())
3852 if(req.goal_node <= 0)
3857 if(req.goal_node > 0 || !pose.
isNull())
3859 Transform coordinateTransform = Transform::getIdentity();
3861 if(!pose.
isNull() && !req.goal.header.frame_id.empty() &&
mapFrameId_.compare(req.goal.header.frame_id) != 0)
3864 if(coordinateTransform.
isNull())
3866 NODELET_ERROR(
"Cannot transform goal pose from \"%s\" frame to \"%s\" frame!",
3867 req.goal.header.frame_id.c_str(),
mapFrameId_.c_str());
3872 pose = coordinateTransform * pose;
3878 coordinateTransform = coordinateTransform.
inverse();
3884 const std::vector<std::pair<int, Transform> > & poses =
rtabmap_.
getPath();
3886 res.plan.header.stamp = req.goal_node > 0?
ros::Time::now():req.goal.header.stamp;
3887 if(poses.size() == 0)
3889 NODELET_WARN(
"Planning: Goal already reached (RGBD/GoalReachedRadius=%fm).",
3894 res.plan.poses.resize(1);
3895 res.plan.nodeIds.resize(1);
3897 res.plan.nodeIds[0] = 0;
3902 res.plan.poses.resize(poses.size());
3903 res.plan.nodeIds.resize(poses.size());
3905 for(std::vector<std::pair<int, Transform> >::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
3908 res.plan.nodeIds[oi] =
iter->first;
3913 res.plan.poses.resize(
res.plan.poses.size()+1);
3914 res.plan.nodeIds.resize(
res.plan.nodeIds.size()+1);
3917 res.plan.nodeIds[
res.plan.nodeIds.size()-1] = 0;
3921 std::stringstream
stream;
3922 for(std::vector<std::pair<int, Transform> >::const_iterator
iter=poses.begin();
iter!=poses.end(); ++
iter)
3924 if(
iter != poses.begin())
3940 double planningTime = 0.0;
3943 res.path_ids.resize(
path.size());
3944 res.path_poses.resize(
path.size());
3945 res.planning_time = planningTime;
3946 for(
unsigned int i=0;
i<
path.size(); ++
i)
3985 NODELET_INFO(
"Set label \"%s\" to node %d", req.node_label.c_str(), req.node_id);
3989 NODELET_INFO(
"Set label \"%s\" to last node", req.node_label.c_str());
3996 NODELET_ERROR(
"Could not set label \"%s\" to node %d", req.node_label.c_str(), req.node_id);
4000 NODELET_ERROR(
"Could not set label \"%s\" to last node", req.node_label.c_str());
4013 NODELET_INFO(
"List labels service: %d labels found.", (
int)
res.labels.size());
4025 NODELET_WARN(
"Label \"%s\" not found in the map, cannot remove it!", req.label.c_str());
4029 NODELET_ERROR(
"Failed removing label \"%s\".", req.label.c_str());
4033 NODELET_INFO(
"Removed label \"%s\".", req.label.c_str());
4043 ROS_INFO(
"Adding external link %d -> %d", req.link.fromId, req.link.toId);
4052 ROS_INFO(
"Get nodes in radius (%f): node_id=%d pose=(%f,%f,%f)", req.radius, req.node_id, req.x, req.y, req.z);
4053 std::map<int, Transform> poses;
4054 std::map<int, float> dists;
4055 if(req.node_id != 0 || (req.x == 0.0f && req.y == 0.0f && req.z == 0.0f))
4065 res.ids.resize(poses.size());
4066 res.poses.resize(poses.size());
4067 res.distsSqr.resize(poses.size());
4069 for(std::map<int, rtabmap::Transform>::const_iterator
iter = poses.begin();
4070 iter != poses.end();
4076 res.distsSqr[index] = dists.at(
iter->first);
4085 UDEBUG(
"Publishing stats...");
4091 rtabmap_msgs::InfoPtr
msg(
new rtabmap_msgs::Info);
4092 msg->header.stamp = stamp;
4101 rtabmap_msgs::MapDataPtr
msg(
new rtabmap_msgs::MapData);
4102 msg->header.stamp = stamp;
4107 stats.constraints(),
4108 stats.getSignaturesData(),
4109 stats.mapCorrection(),
4123 rtabmap_msgs::MapGraphPtr
msg(
new rtabmap_msgs::MapGraph);
4124 msg->header.stamp = stamp;
4129 stats.constraints(),
4130 stats.mapCorrection(),
4145 rtabmap_msgs::MapGraphPtr
msg(
new rtabmap_msgs::MapGraph);
4146 msg->header.stamp = stamp;
4150 std::map<int, Transform> poses =
stats.odomCachePoses();
4152 for(std::map<int, Transform>::iterator
iter=poses.begin();
4158 for(std::multimap<int, rtabmap::Link>::const_iterator
iter=
stats.odomCacheConstraints().begin();
4159 iter!=
stats.odomCacheConstraints().end();
4162 std::map<int, Transform>::const_iterator pter =
stats.poses().find(
iter->second.to());
4163 if(pter !=
stats.poses().end())
4165 poses.insert(*pter);
4170 stats.odomCacheConstraints(),
4171 stats.mapCorrection(),
4180 sensor_msgs::PointCloud2
msg;
4182 msg.header.stamp = stamp;
4189 sensor_msgs::PointCloud2
msg;
4191 msg.header.stamp = stamp;
4198 sensor_msgs::PointCloud2
msg;
4200 msg.header.stamp = stamp;
4206 visualization_msgs::MarkerArray markers;
4209 geometry_msgs::PoseArrayPtr
msg(
new geometry_msgs::PoseArray);
4210 msg->header.stamp = stamp;
4214 geometry_msgs::Pose
p;
4216 msg->poses.push_back(
p);
4221 visualization_msgs::Marker marker;
4223 marker.header.stamp = stamp;
4224 marker.ns =
"landmarks";
4225 marker.id =
iter->first;
4226 marker.action = visualization_msgs::Marker::ADD;
4227 marker.pose.position.x =
iter->second.x();
4228 marker.pose.position.y =
iter->second.y();
4229 marker.pose.position.z =
iter->second.z();
4230 marker.pose.orientation.x = 0.0;
4231 marker.pose.orientation.y = 0.0;
4232 marker.pose.orientation.z = 0.0;
4233 marker.pose.orientation.w = 1.0;
4236 marker.scale.z = 0.35;
4237 marker.color.a = 0.7;
4238 marker.color.r = 0.0;
4239 marker.color.g = 1.0;
4240 marker.color.b = 0.0;
4243 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
4246 markers.markers.push_back(marker);
4254 if(pubLabels || pubPath)
4256 if(
stats.poses().size())
4258 nav_msgs::Path
path;
4265 for(std::map<int, Transform>::const_iterator poseIter=
stats.poses().begin();
4266 poseIter!=
stats.poses().end();
4275 visualization_msgs::Marker marker;
4277 marker.header.stamp = stamp;
4278 marker.ns =
"labels";
4279 marker.id = -poseIter->first;
4280 marker.action = visualization_msgs::Marker::ADD;
4281 marker.pose.position.x = poseIter->second.x();
4282 marker.pose.position.y = poseIter->second.y();
4283 marker.pose.position.z = poseIter->second.z();
4284 marker.pose.orientation.x = 0.0;
4285 marker.pose.orientation.y = 0.0;
4286 marker.pose.orientation.z = 0.0;
4287 marker.pose.orientation.w = 1.0;
4290 marker.scale.z = 0.5;
4291 marker.color.a = 0.7;
4292 marker.color.r = 1.0;
4293 marker.color.g = 0.0;
4294 marker.color.b = 0.0;
4296 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
4297 marker.text = lter->second;
4299 markers.markers.push_back(marker);
4303 visualization_msgs::Marker marker;
4305 marker.header.stamp = stamp;
4307 marker.id = poseIter->first;
4308 marker.action = visualization_msgs::Marker::ADD;
4309 marker.pose.position.x = poseIter->second.x();
4310 marker.pose.position.y = poseIter->second.y();
4311 marker.pose.position.z = poseIter->second.z();
4312 marker.pose.orientation.x = 0.0;
4313 marker.pose.orientation.y = 0.0;
4314 marker.pose.orientation.z = 0.0;
4315 marker.pose.orientation.w = 1.0;
4318 marker.scale.z = 0.2;
4319 marker.color.a = 0.5;
4320 marker.color.r = 1.0;
4321 marker.color.g = 1.0;
4322 marker.color.b = 1.0;
4325 marker.type = visualization_msgs::Marker::TEXT_VIEW_FACING;
4328 markers.markers.push_back(marker);
4334 path.poses.at(oi).header.stamp = stamp;
4339 if(pubLabels && markers.markers.size())
4346 path.header.stamp = stamp;
4347 path.poses.resize(oi);
4361 geometry_msgs::PoseStamped poseMsg;
4363 poseMsg.header.stamp = stamp;
4370 NODELET_INFO(
"Connecting to move_base action server...");
4379 move_base_msgs::MoveBaseGoal goal;
4380 goal.target_pose = poseMsg;
4406 const move_base_msgs::MoveBaseResultConstPtr& result)
4408 bool ignore =
false;
4417 NODELET_WARN(
"Planning: move_base reached current goal but it is not "
4418 "the last one planned by rtabmap. A new goal should be sent when "
4419 "rtabmap will be able to retrieve next locations on the path.");
4429 NODELET_ERROR(
"Planning: move_base failed for some reason. Aborting the plan...");
4472 nav_msgs::Path
path;
4473 rtabmap_msgs::Path pathNodes;
4475 path.header.stamp = pathNodes.header.stamp = stamp;
4476 path.poses.resize(poses.size());
4477 pathNodes.nodeIds.resize(poses.size());
4478 pathNodes.poses.resize(poses.size());
4480 for(std::vector<std::pair<int, Transform> >::
iterator iter=poses.begin();
iter!=poses.end(); ++
iter)
4482 path.poses[oi].header =
path.header;
4484 pathNodes.poses[oi] =
path.poses[oi].pose;
4485 pathNodes.nodeIds[oi] =
iter->first;
4511 nav_msgs::Path
path;
4512 rtabmap_msgs::Path pathNodes;
4514 path.header.stamp = pathNodes.header.stamp = stamp;
4521 path.poses[oi].header =
path.header;
4523 pathNodes.poses[oi] =
path.poses[oi].pose;
4524 pathNodes.nodeIds[oi] =
iter->first;
4527 Transform goalLocalTransform = Transform::getIdentity();
4539 path.poses.resize(
path.poses.size()+1);
4541 pathNodes.nodeIds.resize(pathNodes.nodeIds.size()+1);
4542 pathNodes.poses.resize(pathNodes.poses.size()+1);
4545 pathNodes.poses[pathNodes.poses.size()-1] =
path.poses[
path.poses.size()-1].pose;
4546 pathNodes.nodeIds[pathNodes.nodeIds.size()-1] = 0;
4562 localizationThreshold_(0.0),
4563 localizationError_(9999)
4568 localizationThreshold_ =
value;
4573 if(localizationThreshold_ > 0.0 && !cov.empty())
4575 if(cov.at<
double>(0,0) >= 9999.0)
4577 localizationError_ = 9999.0;
4581 localizationError_ =
sqrt(
uMax3(cov.at<
double>(0,0), cov.at<
double>(1,1), twoDMapping?0.0:cov.at<
double>(2,2)));
4588 if(localizationError_>=9999)
4590 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Not localized!");
4592 else if(localizationError_ > localizationThreshold_)
4594 stat.
summary(diagnostic_msgs::DiagnosticStatus::ERROR,
"Localization error is high!");
4598 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
"Localized.");
4600 stat.
add(
"Localization error (m)", localizationError_);
4601 stat.
add(
"loc_thr (m)", localizationThreshold_);
4604 #ifdef WITH_OCTOMAP_MSGS
4605 #ifdef RTABMAP_OCTOMAP
4606 bool CoreWrapper::octomapBinaryCallback(
4607 octomap_msgs::GetOctomap::Request &req,
4608 octomap_msgs::GetOctomap::Response &res)
4610 NODELET_INFO(
"Sending binary map data on service request");
4627 bool CoreWrapper::octomapFullCallback(
4628 octomap_msgs::GetOctomap::Request &req,
4629 octomap_msgs::GetOctomap::Response &res)
4631 NODELET_INFO(
"Sending full map data on service request");