00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "HectorMappingRos.h"
00030
00031 #include "map/GridMap.h"
00032
00033 #include <geometry_msgs/PoseWithCovarianceStamped.h>
00034 #include <nav_msgs/Odometry.h>
00035
00036 #include "sensor_msgs/PointCloud2.h"
00037
00038 #include "HectorDrawings.h"
00039 #include "HectorDebugInfoProvider.h"
00040 #include "HectorMapMutex.h"
00041
00042 #ifndef TF_SCALAR_H
00043 typedef btScalar tfScalar;
00044 #endif
00045
00046 HectorMappingRos::HectorMappingRos()
00047 : debugInfoProvider(0)
00048 , hectorDrawings(0)
00049 , lastGetMapUpdateIndex(-100)
00050 , tfB_(0)
00051 , map__publish_thread_(0)
00052 , initial_pose_set_(false)
00053 {
00054 ros::NodeHandle private_nh_("~");
00055
00056 std::string mapTopic_ = "map";
00057
00058 private_nh_.param("pub_drawings", p_pub_drawings, false);
00059 private_nh_.param("pub_debug_output", p_pub_debug_output_, false);
00060 private_nh_.param("pub_map_odom_transform", p_pub_map_odom_transform_,true);
00061 private_nh_.param("pub_odometry", p_pub_odometry_,false);
00062 private_nh_.param("advertise_map_service", p_advertise_map_service_,true);
00063 private_nh_.param("scan_subscriber_queue_size", p_scan_subscriber_queue_size_, 5);
00064
00065 private_nh_.param("map_resolution", p_map_resolution_, 0.025);
00066 private_nh_.param("map_size", p_map_size_, 1024);
00067 private_nh_.param("map_start_x", p_map_start_x_, 0.5);
00068 private_nh_.param("map_start_y", p_map_start_y_, 0.5);
00069 private_nh_.param("map_multi_res_levels", p_map_multi_res_levels_, 3);
00070
00071 private_nh_.param("update_factor_free", p_update_factor_free_, 0.4);
00072 private_nh_.param("update_factor_occupied", p_update_factor_occupied_, 0.9);
00073
00074 private_nh_.param("map_update_distance_thresh", p_map_update_distance_threshold_, 0.4);
00075 private_nh_.param("map_update_angle_thresh", p_map_update_angle_threshold_, 0.9);
00076
00077 private_nh_.param("scan_topic", p_scan_topic_, std::string("scan"));
00078 private_nh_.param("sys_msg_topic", p_sys_msg_topic_, std::string("syscommand"));
00079 private_nh_.param("pose_update_topic", p_pose_update_topic_, std::string("poseupdate"));
00080
00081 private_nh_.param("use_tf_scan_transformation", p_use_tf_scan_transformation_,true);
00082 private_nh_.param("use_tf_pose_start_estimate", p_use_tf_pose_start_estimate_,false);
00083 private_nh_.param("map_with_known_poses", p_map_with_known_poses_, false);
00084
00085 private_nh_.param("base_frame", p_base_frame_, std::string("base_link"));
00086 private_nh_.param("map_frame", p_map_frame_, std::string("map"));
00087 private_nh_.param("odom_frame", p_odom_frame_, std::string("odom"));
00088
00089 private_nh_.param("pub_map_scanmatch_transform", p_pub_map_scanmatch_transform_,true);
00090 private_nh_.param("tf_map_scanmatch_transform_frame_name", p_tf_map_scanmatch_transform_frame_name_, std::string("scanmatcher_frame"));
00091
00092 private_nh_.param("output_timing", p_timing_output_,false);
00093
00094 private_nh_.param("map_pub_period", p_map_pub_period_, 2.0);
00095
00096 double tmp = 0.0;
00097 private_nh_.param("laser_min_dist", tmp, 0.4);
00098 p_sqr_laser_min_dist_ = static_cast<float>(tmp*tmp);
00099
00100 private_nh_.param("laser_max_dist", tmp, 30.0);
00101 p_sqr_laser_max_dist_ = static_cast<float>(tmp*tmp);
00102
00103 private_nh_.param("laser_z_min_value", tmp, -1.0);
00104 p_laser_z_min_value_ = static_cast<float>(tmp);
00105
00106 private_nh_.param("laser_z_max_value", tmp, 1.0);
00107 p_laser_z_max_value_ = static_cast<float>(tmp);
00108
00109 if (p_pub_drawings)
00110 {
00111 ROS_INFO("HectorSM publishing debug drawings");
00112 hectorDrawings = new HectorDrawings();
00113 }
00114
00115 if(p_pub_debug_output_)
00116 {
00117 ROS_INFO("HectorSM publishing debug info");
00118 debugInfoProvider = new HectorDebugInfoProvider();
00119 }
00120
00121 if(p_pub_odometry_)
00122 {
00123 odometryPublisher_ = node_.advertise<nav_msgs::Odometry>("scanmatch_odom", 50);
00124 }
00125
00126 slamProcessor = new hectorslam::HectorSlamProcessor(static_cast<float>(p_map_resolution_), p_map_size_, p_map_size_, Eigen::Vector2f(p_map_start_x_, p_map_start_y_), p_map_multi_res_levels_, hectorDrawings, debugInfoProvider);
00127 slamProcessor->setUpdateFactorFree(p_update_factor_free_);
00128 slamProcessor->setUpdateFactorOccupied(p_update_factor_occupied_);
00129 slamProcessor->setMapUpdateMinDistDiff(p_map_update_distance_threshold_);
00130 slamProcessor->setMapUpdateMinAngleDiff(p_map_update_angle_threshold_);
00131
00132 int mapLevels = slamProcessor->getMapLevels();
00133 mapLevels = 1;
00134
00135 for (int i = 0; i < mapLevels; ++i)
00136 {
00137 mapPubContainer.push_back(MapPublisherContainer());
00138 slamProcessor->addMapMutex(i, new HectorMapMutex());
00139
00140 std::string mapTopicStr(mapTopic_);
00141
00142 if (i != 0)
00143 {
00144 mapTopicStr.append("_" + boost::lexical_cast<std::string>(i));
00145 }
00146
00147 std::string mapMetaTopicStr(mapTopicStr);
00148 mapMetaTopicStr.append("_metadata");
00149
00150 MapPublisherContainer& tmp = mapPubContainer[i];
00151 tmp.mapPublisher_ = node_.advertise<nav_msgs::OccupancyGrid>(mapTopicStr, 1, true);
00152 tmp.mapMetadataPublisher_ = node_.advertise<nav_msgs::MapMetaData>(mapMetaTopicStr, 1, true);
00153
00154 if ( (i == 0) && p_advertise_map_service_)
00155 {
00156 tmp.dynamicMapServiceServer_ = node_.advertiseService("dynamic_map", &HectorMappingRos::mapCallback, this);
00157 }
00158
00159 setServiceGetMapData(tmp.map_, slamProcessor->getGridMap(i));
00160
00161 if ( i== 0){
00162 mapPubContainer[i].mapMetadataPublisher_.publish(mapPubContainer[i].map_.map.info);
00163 }
00164 }
00165
00166 ROS_INFO("HectorSM p_base_frame_: %s", p_base_frame_.c_str());
00167 ROS_INFO("HectorSM p_map_frame_: %s", p_map_frame_.c_str());
00168 ROS_INFO("HectorSM p_odom_frame_: %s", p_odom_frame_.c_str());
00169 ROS_INFO("HectorSM p_scan_topic_: %s", p_scan_topic_.c_str());
00170 ROS_INFO("HectorSM p_use_tf_scan_transformation_: %s", p_use_tf_scan_transformation_ ? ("true") : ("false"));
00171 ROS_INFO("HectorSM p_pub_map_odom_transform_: %s", p_pub_map_odom_transform_ ? ("true") : ("false"));
00172 ROS_INFO("HectorSM p_scan_subscriber_queue_size_: %d", p_scan_subscriber_queue_size_);
00173 ROS_INFO("HectorSM p_map_pub_period_: %f", p_map_pub_period_);
00174 ROS_INFO("HectorSM p_update_factor_free_: %f", p_update_factor_free_);
00175 ROS_INFO("HectorSM p_update_factor_occupied_: %f", p_update_factor_occupied_);
00176 ROS_INFO("HectorSM p_map_update_distance_threshold_: %f ", p_map_update_distance_threshold_);
00177 ROS_INFO("HectorSM p_map_update_angle_threshold_: %f", p_map_update_angle_threshold_);
00178 ROS_INFO("HectorSM p_laser_z_min_value_: %f", p_laser_z_min_value_);
00179 ROS_INFO("HectorSM p_laser_z_max_value_: %f", p_laser_z_max_value_);
00180
00181 scanSubscriber_ = node_.subscribe(p_scan_topic_, p_scan_subscriber_queue_size_, &HectorMappingRos::scanCallback, this);
00182 sysMsgSubscriber_ = node_.subscribe(p_sys_msg_topic_, 2, &HectorMappingRos::sysMsgCallback, this);
00183
00184 poseUpdatePublisher_ = node_.advertise<geometry_msgs::PoseWithCovarianceStamped>(p_pose_update_topic_, 1, false);
00185 posePublisher_ = node_.advertise<geometry_msgs::PoseStamped>("slam_out_pose", 1, false);
00186
00187 scan_point_cloud_publisher_ = node_.advertise<sensor_msgs::PointCloud>("slam_cloud",1,false);
00188
00189 tfB_ = new tf::TransformBroadcaster();
00190 ROS_ASSERT(tfB_);
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 initial_pose_sub_ = new message_filters::Subscriber<geometry_msgs::PoseWithCovarianceStamped>(node_, "initialpose", 2);
00201 initial_pose_filter_ = new tf::MessageFilter<geometry_msgs::PoseWithCovarianceStamped>(*initial_pose_sub_, tf_, p_map_frame_, 2);
00202 initial_pose_filter_->registerCallback(boost::bind(&HectorMappingRos::initialPoseCallback, this, _1));
00203
00204
00205 map__publish_thread_ = new boost::thread(boost::bind(&HectorMappingRos::publishMapLoop, this, p_map_pub_period_));
00206
00207 map_to_odom_.setIdentity();
00208
00209 lastMapPublishTime = ros::Time(0,0);
00210 }
00211
00212 HectorMappingRos::~HectorMappingRos()
00213 {
00214 delete slamProcessor;
00215
00216 if (hectorDrawings)
00217 delete hectorDrawings;
00218
00219 if (debugInfoProvider)
00220 delete debugInfoProvider;
00221
00222 if (tfB_)
00223 delete tfB_;
00224
00225 if(map__publish_thread_)
00226 delete map__publish_thread_;
00227 }
00228
00229 void HectorMappingRos::scanCallback(const sensor_msgs::LaserScan& scan)
00230 {
00231 if (hectorDrawings)
00232 {
00233 hectorDrawings->setTime(scan.header.stamp);
00234 }
00235
00236 ros::WallTime startTime = ros::WallTime::now();
00237
00238 if (!p_use_tf_scan_transformation_)
00239 {
00240 if (rosLaserScanToDataContainer(scan, laserScanContainer,slamProcessor->getScaleToMap()))
00241 {
00242 slamProcessor->update(laserScanContainer,slamProcessor->getLastScanMatchPose());
00243 }
00244 }
00245 else
00246 {
00247 ros::Duration dur (0.5);
00248
00249 if (tf_.waitForTransform(p_base_frame_,scan.header.frame_id, scan.header.stamp,dur))
00250 {
00251 tf::StampedTransform laserTransform;
00252 tf_.lookupTransform(p_base_frame_,scan.header.frame_id, scan.header.stamp, laserTransform);
00253
00254
00255 projector_.projectLaser(scan, laser_point_cloud_,30.0);
00256
00257 if (scan_point_cloud_publisher_.getNumSubscribers() > 0){
00258 scan_point_cloud_publisher_.publish(laser_point_cloud_);
00259 }
00260
00261 Eigen::Vector3f startEstimate(Eigen::Vector3f::Zero());
00262
00263 if(rosPointCloudToDataContainer(laser_point_cloud_, laserTransform, laserScanContainer, slamProcessor->getScaleToMap()))
00264 {
00265 if (initial_pose_set_){
00266 initial_pose_set_ = false;
00267 startEstimate = initial_pose_;
00268 }else if (p_use_tf_pose_start_estimate_){
00269
00270 try
00271 {
00272 tf::StampedTransform stamped_pose;
00273
00274 tf_.waitForTransform(p_map_frame_,p_base_frame_, scan.header.stamp, ros::Duration(0.5));
00275 tf_.lookupTransform(p_map_frame_, p_base_frame_, scan.header.stamp, stamped_pose);
00276
00277 tfScalar yaw, pitch, roll;
00278 stamped_pose.getBasis().getEulerYPR(yaw, pitch, roll);
00279
00280 startEstimate = Eigen::Vector3f(stamped_pose.getOrigin().getX(),stamped_pose.getOrigin().getY(), yaw);
00281 }
00282 catch(tf::TransformException e)
00283 {
00284 ROS_ERROR("Transform from %s to %s failed\n", p_map_frame_.c_str(), p_base_frame_.c_str());
00285 startEstimate = slamProcessor->getLastScanMatchPose();
00286 }
00287
00288 }else{
00289 startEstimate = slamProcessor->getLastScanMatchPose();
00290 }
00291
00292
00293 if (p_map_with_known_poses_){
00294 slamProcessor->update(laserScanContainer, startEstimate, true);
00295 }else{
00296 slamProcessor->update(laserScanContainer, startEstimate);
00297 }
00298 }
00299
00300 }else{
00301 ROS_INFO("lookupTransform %s to %s timed out. Could not transform laser scan into base_frame.", p_base_frame_.c_str(), scan.header.frame_id.c_str());
00302 return;
00303 }
00304 }
00305
00306 if (p_timing_output_)
00307 {
00308 ros::WallDuration duration = ros::WallTime::now() - startTime;
00309 ROS_INFO("HectorSLAM Iter took: %f milliseconds", duration.toSec()*1000.0f );
00310 }
00311
00312
00313 if (p_map_with_known_poses_)
00314 {
00315 return;
00316 }
00317
00318 poseInfoContainer_.update(slamProcessor->getLastScanMatchPose(), slamProcessor->getLastScanMatchCovariance(), scan.header.stamp, p_map_frame_);
00319
00320 poseUpdatePublisher_.publish(poseInfoContainer_.getPoseWithCovarianceStamped());
00321 posePublisher_.publish(poseInfoContainer_.getPoseStamped());
00322
00323 if(p_pub_odometry_)
00324 {
00325 nav_msgs::Odometry tmp;
00326 tmp.pose = poseInfoContainer_.getPoseWithCovarianceStamped().pose;
00327
00328 tmp.header = poseInfoContainer_.getPoseWithCovarianceStamped().header;
00329 tmp.child_frame_id = p_base_frame_;
00330 odometryPublisher_.publish(tmp);
00331 }
00332
00333 if (p_pub_map_odom_transform_)
00334 {
00335 tf::StampedTransform odom_to_base;
00336
00337 try
00338 {
00339 tf_.waitForTransform(p_odom_frame_, p_base_frame_, scan.header.stamp, ros::Duration(0.5));
00340 tf_.lookupTransform(p_odom_frame_, p_base_frame_, scan.header.stamp, odom_to_base);
00341 }
00342 catch(tf::TransformException e)
00343 {
00344 ROS_ERROR("Transform failed during publishing of map_odom transform: %s",e.what());
00345 odom_to_base.setIdentity();
00346 }
00347 map_to_odom_ = tf::Transform(poseInfoContainer_.getTfTransform() * odom_to_base.inverse());
00348 tfB_->sendTransform( tf::StampedTransform (map_to_odom_, scan.header.stamp, p_map_frame_, p_odom_frame_));
00349 }
00350
00351 if (p_pub_map_scanmatch_transform_){
00352 tfB_->sendTransform( tf::StampedTransform(poseInfoContainer_.getTfTransform(), scan.header.stamp, p_map_frame_, p_tf_map_scanmatch_transform_frame_name_));
00353 }
00354 }
00355
00356 void HectorMappingRos::sysMsgCallback(const std_msgs::String& string)
00357 {
00358 ROS_INFO("HectorSM sysMsgCallback, msg contents: %s", string.data.c_str());
00359
00360 if (string.data == "reset")
00361 {
00362 ROS_INFO("HectorSM reset");
00363 slamProcessor->reset();
00364 }
00365 }
00366
00367 bool HectorMappingRos::mapCallback(nav_msgs::GetMap::Request &req,
00368 nav_msgs::GetMap::Response &res)
00369 {
00370 ROS_INFO("HectorSM Map service called");
00371 res = mapPubContainer[0].map_;
00372 return true;
00373 }
00374
00375 void HectorMappingRos::publishMap(MapPublisherContainer& mapPublisher, const hectorslam::GridMap& gridMap, ros::Time timestamp, MapLockerInterface* mapMutex)
00376 {
00377 nav_msgs::GetMap::Response& map_ (mapPublisher.map_);
00378
00379
00380 if (lastGetMapUpdateIndex != gridMap.getUpdateIndex())
00381 {
00382
00383 int sizeX = gridMap.getSizeX();
00384 int sizeY = gridMap.getSizeY();
00385
00386 int size = sizeX * sizeY;
00387
00388 std::vector<int8_t>& data = map_.map.data;
00389
00390
00391 memset(&data[0], -1, sizeof(int8_t) * size);
00392
00393 if (mapMutex)
00394 {
00395 mapMutex->lockMap();
00396 }
00397
00398 for(int i=0; i < size; ++i)
00399 {
00400 if(gridMap.isFree(i))
00401 {
00402 data[i] = 0;
00403 }
00404 else if (gridMap.isOccupied(i))
00405 {
00406 data[i] = 100;
00407 }
00408 }
00409
00410 lastGetMapUpdateIndex = gridMap.getUpdateIndex();
00411
00412 if (mapMutex)
00413 {
00414 mapMutex->unlockMap();
00415 }
00416 }
00417
00418 map_.map.header.stamp = timestamp;
00419
00420 mapPublisher.mapPublisher_.publish(map_.map);
00421 }
00422
00423 bool HectorMappingRos::rosLaserScanToDataContainer(const sensor_msgs::LaserScan& scan, hectorslam::DataContainer& dataContainer, float scaleToMap)
00424 {
00425 size_t size = scan.ranges.size();
00426
00427 float angle = scan.angle_min;
00428
00429 dataContainer.clear();
00430
00431 dataContainer.setOrigo(Eigen::Vector2f::Zero());
00432
00433 float maxRangeForContainer = scan.range_max - 0.1f;
00434
00435 for (size_t i = 0; i < size; ++i)
00436 {
00437 float dist = scan.ranges[i];
00438
00439 if ( (dist > scan.range_min) && (dist < maxRangeForContainer))
00440 {
00441 dist *= scaleToMap;
00442 dataContainer.add(Eigen::Vector2f(cos(angle) * dist, sin(angle) * dist));
00443 }
00444
00445 angle += scan.angle_increment;
00446 }
00447
00448 return true;
00449 }
00450
00451 bool HectorMappingRos::rosPointCloudToDataContainer(const sensor_msgs::PointCloud& pointCloud, const tf::StampedTransform& laserTransform, hectorslam::DataContainer& dataContainer, float scaleToMap)
00452 {
00453 size_t size = pointCloud.points.size();
00454
00455
00456 dataContainer.clear();
00457
00458 tf::Vector3 laserPos (laserTransform.getOrigin());
00459 dataContainer.setOrigo(Eigen::Vector2f(laserPos.x(), laserPos.y())*scaleToMap);
00460
00461 for (size_t i = 0; i < size; ++i)
00462 {
00463
00464 const geometry_msgs::Point32& currPoint(pointCloud.points[i]);
00465
00466 float dist_sqr = currPoint.x*currPoint.x + currPoint.y* currPoint.y;
00467
00468 if ( (dist_sqr > p_sqr_laser_min_dist_) && (dist_sqr < p_sqr_laser_max_dist_) ){
00469
00470 if ( (currPoint.x < 0.0f) && (dist_sqr < 0.50f)){
00471 continue;
00472 }
00473
00474 tf::Vector3 pointPosBaseFrame(laserTransform * tf::Vector3(currPoint.x, currPoint.y, currPoint.z));
00475
00476 float pointPosLaserFrameZ = pointPosBaseFrame.z() - laserPos.z();
00477
00478 if (pointPosLaserFrameZ > p_laser_z_min_value_ && pointPosLaserFrameZ < p_laser_z_max_value_)
00479 {
00480 dataContainer.add(Eigen::Vector2f(pointPosBaseFrame.x(),pointPosBaseFrame.y())*scaleToMap);
00481 }
00482 }
00483 }
00484
00485 return true;
00486 }
00487
00488 void HectorMappingRos::setServiceGetMapData(nav_msgs::GetMap::Response& map_, const hectorslam::GridMap& gridMap)
00489 {
00490 Eigen::Vector2f mapOrigin (gridMap.getWorldCoords(Eigen::Vector2f::Zero()));
00491 mapOrigin.array() -= gridMap.getCellLength()*0.5f;
00492
00493 map_.map.info.origin.position.x = mapOrigin.x();
00494 map_.map.info.origin.position.y = mapOrigin.y();
00495 map_.map.info.origin.orientation.w = 1.0;
00496
00497 map_.map.info.resolution = gridMap.getCellLength();
00498
00499 map_.map.info.width = gridMap.getSizeX();
00500 map_.map.info.height = gridMap.getSizeY();
00501
00502 map_.map.header.frame_id = p_map_frame_;
00503 map_.map.data.resize(map_.map.info.width * map_.map.info.height);
00504 }
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521 void HectorMappingRos::publishMapLoop(double map_pub_period)
00522 {
00523 ros::Rate r(1.0 / map_pub_period);
00524 while(ros::ok())
00525 {
00526
00527 ros::Time mapTime (ros::Time::now());
00528
00529
00530 publishMap(mapPubContainer[0],slamProcessor->getGridMap(0), mapTime, slamProcessor->getMapMutex(0));
00531
00532
00533
00534
00535
00536
00537 r.sleep();
00538 }
00539 }
00540
00541 void HectorMappingRos::staticMapCallback(const nav_msgs::OccupancyGrid& map)
00542 {
00543
00544 }
00545
00546 void HectorMappingRos::initialPoseCallback(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg)
00547 {
00548 initial_pose_set_ = true;
00549
00550 tf::Pose pose;
00551 tf::poseMsgToTF(msg->pose.pose, pose);
00552 initial_pose_ = Eigen::Vector3f(msg->pose.pose.position.x, msg->pose.pose.position.y, tf::getYaw(pose.getRotation()));
00553 ROS_INFO("Setting initial pose with world coords x: %f y: %f yaw: %f", initial_pose_[0], initial_pose_[1], initial_pose_[2]);
00554 }
00555
00556