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 odometryPublisher_.publish(tmp);
00330 }
00331
00332 if (p_pub_map_odom_transform_)
00333 {
00334 tf::StampedTransform odom_to_base;
00335
00336 try
00337 {
00338 tf_.waitForTransform(p_odom_frame_, p_base_frame_, scan.header.stamp, ros::Duration(0.5));
00339 tf_.lookupTransform(p_odom_frame_, p_base_frame_, scan.header.stamp, odom_to_base);
00340 }
00341 catch(tf::TransformException e)
00342 {
00343 ROS_ERROR("Transform failed during publishing of map_odom transform: %s",e.what());
00344 odom_to_base.setIdentity();
00345 }
00346 map_to_odom_ = tf::Transform(poseInfoContainer_.getTfTransform() * odom_to_base.inverse());
00347 tfB_->sendTransform( tf::StampedTransform (map_to_odom_, scan.header.stamp, p_map_frame_, p_odom_frame_));
00348 }
00349
00350 if (p_pub_map_scanmatch_transform_){
00351 tfB_->sendTransform( tf::StampedTransform(poseInfoContainer_.getTfTransform(), scan.header.stamp, p_map_frame_, p_tf_map_scanmatch_transform_frame_name_));
00352 }
00353 }
00354
00355 void HectorMappingRos::sysMsgCallback(const std_msgs::String& string)
00356 {
00357 ROS_INFO("HectorSM sysMsgCallback, msg contents: %s", string.data.c_str());
00358
00359 if (string.data == "reset")
00360 {
00361 ROS_INFO("HectorSM reset");
00362 slamProcessor->reset();
00363 }
00364 }
00365
00366 bool HectorMappingRos::mapCallback(nav_msgs::GetMap::Request &req,
00367 nav_msgs::GetMap::Response &res)
00368 {
00369 ROS_INFO("HectorSM Map service called");
00370 res = mapPubContainer[0].map_;
00371 return true;
00372 }
00373
00374 void HectorMappingRos::publishMap(MapPublisherContainer& mapPublisher, const hectorslam::GridMap& gridMap, ros::Time timestamp, MapLockerInterface* mapMutex)
00375 {
00376 nav_msgs::GetMap::Response& map_ (mapPublisher.map_);
00377
00378
00379 if (lastGetMapUpdateIndex != gridMap.getUpdateIndex())
00380 {
00381
00382 int sizeX = gridMap.getSizeX();
00383 int sizeY = gridMap.getSizeY();
00384
00385 int size = sizeX * sizeY;
00386
00387 std::vector<int8_t>& data = map_.map.data;
00388
00389
00390 memset(&data[0], -1, sizeof(int8_t) * size);
00391
00392 if (mapMutex)
00393 {
00394 mapMutex->lockMap();
00395 }
00396
00397 for(int i=0; i < size; ++i)
00398 {
00399 if(gridMap.isFree(i))
00400 {
00401 data[i] = 0;
00402 }
00403 else if (gridMap.isOccupied(i))
00404 {
00405 data[i] = 100;
00406 }
00407 }
00408
00409 lastGetMapUpdateIndex = gridMap.getUpdateIndex();
00410
00411 if (mapMutex)
00412 {
00413 mapMutex->unlockMap();
00414 }
00415 }
00416
00417 map_.map.header.stamp = timestamp;
00418
00419 mapPublisher.mapPublisher_.publish(map_.map);
00420 }
00421
00422 bool HectorMappingRos::rosLaserScanToDataContainer(const sensor_msgs::LaserScan& scan, hectorslam::DataContainer& dataContainer, float scaleToMap)
00423 {
00424 size_t size = scan.ranges.size();
00425
00426 float angle = scan.angle_min;
00427
00428 dataContainer.clear();
00429
00430 dataContainer.setOrigo(Eigen::Vector2f::Zero());
00431
00432 float maxRangeForContainer = scan.range_max - 0.1f;
00433
00434 for (size_t i = 0; i < size; ++i)
00435 {
00436 float dist = scan.ranges[i];
00437
00438 if ( (dist > scan.range_min) && (dist < maxRangeForContainer))
00439 {
00440 dist *= scaleToMap;
00441 dataContainer.add(Eigen::Vector2f(cos(angle) * dist, sin(angle) * dist));
00442 }
00443
00444 angle += scan.angle_increment;
00445 }
00446
00447 return true;
00448 }
00449
00450 bool HectorMappingRos::rosPointCloudToDataContainer(const sensor_msgs::PointCloud& pointCloud, const tf::StampedTransform& laserTransform, hectorslam::DataContainer& dataContainer, float scaleToMap)
00451 {
00452 size_t size = pointCloud.points.size();
00453
00454
00455 dataContainer.clear();
00456
00457 tf::Vector3 laserPos (laserTransform.getOrigin());
00458 dataContainer.setOrigo(Eigen::Vector2f(laserPos.x(), laserPos.y())*scaleToMap);
00459
00460 for (size_t i = 0; i < size; ++i)
00461 {
00462
00463 const geometry_msgs::Point32& currPoint(pointCloud.points[i]);
00464
00465 float dist_sqr = currPoint.x*currPoint.x + currPoint.y* currPoint.y;
00466
00467 if ( (dist_sqr > p_sqr_laser_min_dist_) && (dist_sqr < p_sqr_laser_max_dist_) ){
00468
00469 if ( (currPoint.x < 0.0f) && (dist_sqr < 0.50f)){
00470 continue;
00471 }
00472
00473 tf::Vector3 pointPosBaseFrame(laserTransform * tf::Vector3(currPoint.x, currPoint.y, currPoint.z));
00474
00475 float pointPosLaserFrameZ = pointPosBaseFrame.z() - laserPos.z();
00476
00477 if (pointPosLaserFrameZ > p_laser_z_min_value_ && pointPosLaserFrameZ < p_laser_z_max_value_)
00478 {
00479 dataContainer.add(Eigen::Vector2f(pointPosBaseFrame.x(),pointPosBaseFrame.y())*scaleToMap);
00480 }
00481 }
00482 }
00483
00484 return true;
00485 }
00486
00487 void HectorMappingRos::setServiceGetMapData(nav_msgs::GetMap::Response& map_, const hectorslam::GridMap& gridMap)
00488 {
00489 Eigen::Vector2f mapOrigin (gridMap.getWorldCoords(Eigen::Vector2f::Zero()));
00490 mapOrigin.array() -= gridMap.getCellLength()*0.5f;
00491
00492 map_.map.info.origin.position.x = mapOrigin.x();
00493 map_.map.info.origin.position.y = mapOrigin.y();
00494 map_.map.info.origin.orientation.w = 1.0;
00495
00496 map_.map.info.resolution = gridMap.getCellLength();
00497
00498 map_.map.info.width = gridMap.getSizeX();
00499 map_.map.info.height = gridMap.getSizeY();
00500
00501 map_.map.header.frame_id = p_map_frame_;
00502 map_.map.data.resize(map_.map.info.width * map_.map.info.height);
00503 }
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520 void HectorMappingRos::publishMapLoop(double map_pub_period)
00521 {
00522 ros::Rate r(1.0 / map_pub_period);
00523 while(ros::ok())
00524 {
00525
00526 ros::Time mapTime (ros::Time::now());
00527
00528
00529 publishMap(mapPubContainer[0],slamProcessor->getGridMap(0), mapTime, slamProcessor->getMapMutex(0));
00530
00531
00532
00533
00534
00535
00536 r.sleep();
00537 }
00538 }
00539
00540 void HectorMappingRos::staticMapCallback(const nav_msgs::OccupancyGrid& map)
00541 {
00542
00543 }
00544
00545 void HectorMappingRos::initialPoseCallback(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg)
00546 {
00547 initial_pose_set_ = true;
00548
00549 tf::Pose pose;
00550 tf::poseMsgToTF(msg->pose.pose, pose);
00551 initial_pose_ = Eigen::Vector3f(msg->pose.pose.position.x, msg->pose.pose.position.y, tf::getYaw(pose.getRotation()));
00552 ROS_INFO("Setting initial pose with world coords x: %f y: %f yaw: %f", initial_pose_[0], initial_pose_[1], initial_pose_[2]);
00553 }
00554
00555