37 #include <boost/bind.hpp>
38 #include <boost/thread/mutex.hpp>
55 #include "sensor_msgs/LaserScan.h"
56 #include "geometry_msgs/PoseWithCovarianceStamped.h"
57 #include "geometry_msgs/PoseArray.h"
58 #include "geometry_msgs/Pose.h"
59 #include "geometry_msgs/PoseStamped.h"
60 #include "nav_msgs/GetMap.h"
61 #include "nav_msgs/SetMap.h"
62 #include "std_srvs/Empty.h"
76 #include "dynamic_reconfigure/server.h"
77 #include "gmcl/GMCLConfig.h"
82 #include <boost/foreach.hpp>
87 #define NEW_UNIFORM_SAMPLING 1
108 return atan2(sin(z),cos(z));
117 d2 = 2*M_PI - fabs(d1);
120 if(fabs(d1) < fabs(d2))
134 std::string out = in;
135 if ( ( !in.empty() ) && (in[0] ==
'/') )
152 void runFromBag(
const std::string &in_bag_fn,
bool trigger_global_localization =
false);
155 void savePoseToServer();
158 std::shared_ptr<tf2_ros::TransformBroadcaster>
tfb_;
159 std::shared_ptr<tf2_ros::TransformListener>
tfl_;
160 std::shared_ptr<tf2_ros::Buffer>
tf_;
169 static pf_vector_t uniformPoseGenerator(
pf_t *pf,
void* arg ,
void* e_arg );
170 #if NEW_UNIFORM_SAMPLING
174 bool globalLocalizationCallback(std_srvs::Empty::Request& req,
175 std_srvs::Empty::Response& res);
176 bool nomotionUpdateCallback(std_srvs::Empty::Request& req,
177 std_srvs::Empty::Response& res);
178 bool setMapCallback(nav_msgs::SetMap::Request& req,
179 nav_msgs::SetMap::Response& res);
182 void handelNewLaser(
const sensor_msgs::LaserScanConstPtr& laser_scan);
183 void laserReceived(
const sensor_msgs::LaserScanConstPtr& laser_scan);
184 void initialPoseReceived(
const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg);
185 void handleInitialPoseMessage(
const geometry_msgs::PoseWithCovarianceStamped& msg);
186 void mapReceived(
const nav_msgs::OccupancyGridConstPtr& msg);
188 void handleMapMessage(
const nav_msgs::OccupancyGrid& msg);
189 void freeMapDependentMemory();
190 map_t* convertMap(
const nav_msgs::OccupancyGrid& map_msg );
191 void updatePoseFromServer();
192 void applyInitialPose();
259 bool getOdomPose(geometry_msgs::PoseStamped& pose,
260 double& x,
double& y,
double& yaw,
261 const ros::Time& t,
const std::string& f);
289 dynamic_reconfigure::Server<gmcl::GMCLConfig> *
dsrv_;
294 double alpha1_, alpha2_, alpha3_, alpha4_,
alpha5_;
297 double z_hit_,
z_short_, z_max_, z_rand_, sigma_hit_, lambda_short_;
303 double init_pose_[3];
310 void reconfigureCB(gmcl::GMCLConfig &config, uint32_t level);
316 #if NEW_UNIFORM_SAMPLING
320 #define USAGE "USAGE: gmcl"
348 else if ((argc >= 3) && (std::string(argv[1]) ==
"--run-from-bag"))
354 else if ((argc == 4) && (std::string(argv[3]) ==
"--global-localization"))
368 sent_first_transform_(false),
369 latest_tf_valid_(false),
376 initial_pose_hyp_(NULL),
377 first_map_received_(false),
378 first_reconfigure_call_(true)
394 {
ROS_ERROR(
"don't set either of energy map resolutions to zero");
439 std::string tmp_model_type;
440 private_nh_.
param(
"laser_model_type", tmp_model_type, std::string(
"likelihood_field"));
441 if(tmp_model_type ==
"beam")
443 else if(tmp_model_type ==
"likelihood_field")
445 else if(tmp_model_type ==
"likelihood_field_prob"){
450 ROS_WARN(
"Unknown laser model type \"%s\"; defaulting to likelihood_field model",
451 tmp_model_type.c_str());
456 if(tmp_model_type ==
"diff")
458 else if(tmp_model_type ==
"omni")
460 else if(tmp_model_type ==
"diff-corrected")
462 else if(tmp_model_type ==
"omni-corrected")
466 ROS_WARN(
"Unknown odom model type \"%s\"; defaulting to diff model",
467 tmp_model_type.c_str());
494 double bag_scan_period;
532 ROS_INFO(
"Subscribed to map topic.");
539 dynamic_reconfigure::Server<gmcl::GMCLConfig>::CallbackType cb = boost::bind(&
GmclNode::reconfigureCB,
this, _1, _2);
540 dsrv_->setCallback(cb);
564 if(config.restore_defaults) {
567 config.restore_defaults =
false;
573 {
ROS_ERROR(
"don't set either of energy map resolutions to zero");
599 z_hit_ = config.laser_z_hit;
601 z_max_ = config.laser_z_max;
607 if(config.laser_model_type ==
"beam")
609 else if(config.laser_model_type ==
"likelihood_field")
611 else if(config.laser_model_type ==
"likelihood_field_prob")
614 if(config.odom_model_type ==
"diff")
616 else if(config.odom_model_type ==
"omni")
618 else if(config.odom_model_type ==
"diff-corrected")
620 else if(config.odom_model_type ==
"omni-corrected")
623 if(config.min_particles > config.max_particles)
625 ROS_WARN(
"You've set min_particles to be greater than max particles, this isn't allowed so they'll be set to be equal.");
626 config.max_particles = config.min_particles;
650 GMCLLaserData::sldata.clear();
665 ROS_INFO(
"general particel filter initialized : ");
667 std::cout<<(
"\t\twith optimal filter on \n");
669 std::cout<<(
"\t\twith optimal filter off \n");
671 std::cout<<(
"\t\twith intelligent filter on \n");
673 std::cout<<(
"\t\twith intelligent filter off \n");
675 std::cout<<(
"\t\twith self adaptive on \n");
677 std::cout<<(
"\t\twith self adaptive off \n");
679 std::cout<<(
"\t\twith kld sampling on \n");
681 std::cout<<(
"\t\twith kld sampling off \n");
684 pf_z_ = config.kld_z;
697 pf_init(
pf_, pf_init_pose_mean, pf_init_pose_cov);
714 ROS_INFO(
"Initializing likelihood field model; this can take some time on large maps...");
719 ROS_INFO(
"Done initializing likelihood field model with probabilities.");
722 ROS_INFO(
"Initializing likelihood field model; this can take some time on large maps...");
725 ROS_INFO(
"Done initializing likelihood field model.");
750 std::vector<std::string> topics;
751 topics.push_back(std::string(
"tf"));
752 std::string scan_topic_name =
"base_scan";
753 topics.push_back(scan_topic_name);
779 if (trigger_global_localization)
781 std_srvs::Empty empty_srv;
795 tf2_msgs::TFMessage::ConstPtr tf_msg =
msg.instantiate<tf2_msgs::TFMessage>();
799 for (
size_t ii=0; ii<tf_msg->transforms.size(); ++ii)
801 tf_->setTransform(tf_msg->transforms[ii],
"rosbag_authority");
806 sensor_msgs::LaserScan::ConstPtr base_scan =
msg.instantiate<sensor_msgs::LaserScan>();
807 if (base_scan != NULL)
824 ROS_INFO(
"Bag complete, took %.1f seconds to process, shutting down", runtime);
827 double yaw, pitch, roll;
829 ROS_INFO(
"Final location %.3f, %.3f, %.3f with stamp=%f",
870 init_cov_[2] = (M_PI/12.0) * (M_PI/12.0);
874 if(!std::isnan(tmp_pos))
877 ROS_WARN(
"ignoring NAN in initial pose X position");
879 if(!std::isnan(tmp_pos))
882 ROS_WARN(
"ignoring NAN in initial pose Y position");
884 if(!std::isnan(tmp_pos))
887 ROS_WARN(
"ignoring NAN in initial pose Yaw");
889 if(!std::isnan(tmp_pos))
892 ROS_WARN(
"ignoring NAN in initial covariance XX");
894 if(!std::isnan(tmp_pos))
897 ROS_WARN(
"ignoring NAN in initial covariance YY");
899 if(!std::isnan(tmp_pos))
902 ROS_WARN(
"ignoring NAN in initial covariance AA");
911 ROS_WARN(
"No laser scan received (and thus no pose updates have been published) for %f seconds. Verify that data is being published on the %s topic.",
923 nav_msgs::GetMap::Request req;
924 nav_msgs::GetMap::Response resp;
928 ROS_WARN(
"Request for map failed; trying again...");
952 ROS_INFO(
"Received a %d X %d map @ %.3f m/pix\n",
955 msg.info.resolution);
958 ROS_WARN(
"Frame_id of map received:'%s' doesn't match global_frame_id:'%s'. This could cause issues with reading published topics",
959 msg.header.frame_id.c_str(),
967 GMCLLaserData::sldata.clear();
977 ROS_INFO(
"energy map has been created with a %d X %d \n energy cell @ resoultion_x %.2f m and resoultion_y %.2f m \n",
981 #if NEW_UNIFORM_SAMPLING
995 ROS_INFO(
"general particle filter initialized : ");
997 std::cout<<(
"\t\twith optimal filter on \n");
999 std::cout<<(
"\t\twith optimal filter off \n");
1001 std::cout<<(
"\t\twith intelligent filter on \n");
1003 std::cout<<(
"\t\twith intelligent filter off \n");
1005 std::cout<<(
"\t\twith self adaptive on \n");
1007 std::cout<<(
"\t\twith self adaptive off \n");
1009 std::cout<<(
"\t\twith kld sampling on \n");
1011 std::cout<<(
"\t\twith kld sampling off \n");
1027 pf_init(
pf_, pf_init_pose_mean, pf_init_pose_cov);
1044 ROS_INFO(
"Initializing likelihood field model; this can take some time on large maps...");
1049 ROS_INFO(
"Done initializing likelihood field model.");
1053 ROS_INFO(
"Initializing likelihood field model; this can take some time on large maps...");
1056 ROS_INFO(
"Done initializing likelihood field model.");
1068 if(
map_ != NULL ) {
1096 map->
size_x = map_msg.info.width;
1097 map->
size_y = map_msg.info.height;
1098 map->
scale = map_msg.info.resolution;
1106 if(map_msg.data[i] == 0)
1108 else if(map_msg.data[i] == 100)
1128 double& x,
double& y,
double& yaw,
1129 const ros::Time& t,
const std::string& f)
1132 geometry_msgs::PoseStamped ident;
1134 ident.header.stamp =
t;
1142 ROS_WARN(
"Failed to compute odom pose, skipping scan (%s)", e.what());
1145 x = odom_pose.pose.position.x;
1146 y = odom_pose.pose.position.y;
1158 double max_weight = 0;
1172 double pose_weight = 1.0 ;
1177 pose_weight *=
self->PoseWeight(t_p[loop] , GMCLLaserData::sldata[
laser_index]);
1181 if ( pose_weight > max_weight)
1184 max_weight = pose_weight;
1196 #if NEW_UNIFORM_SAMPLING
1203 t_p[loop].
v[0] =
MAP_WXGX(map, free_point.first);
1204 t_p[loop].
v[1] =
MAP_WYGY(map, free_point.second);
1205 t_p[loop].
v[2] =
drand48() * 2 * M_PI - M_PI;
1207 double min_x, max_x, min_y, max_y;
1216 ROS_DEBUG(
"Generating new uniform sample");
1219 t_p[loop].
v[0] = min_x +
drand48() * (max_x - min_x);
1220 t_p[loop].
v[1] = min_y +
drand48() * (max_y - min_y);
1221 t_p[loop].
v[2] =
drand48() * 2 * M_PI - M_PI;
1231 double pose_weight = 1.0 ;
1235 pose_weight *=
self->PoseWeight(t_p[loop] , GMCLLaserData::sldata[
laser_index]);
1238 if ( pose_weight > max_weight)
1241 max_weight = pose_weight;
1264 #if NEW_UNIFORM_SAMPLING
1268 p.
v[0] =
MAP_WXGX(map, free_point.first);
1269 p.
v[1] =
MAP_WYGY(map, free_point.second);
1270 p.
v[2] =
drand48() * 2 * M_PI - M_PI;
1272 double min_x, max_x, min_y, max_y;
1281 ROS_DEBUG(
"Generating new uniform sample");
1284 p.
v[0] = min_x +
drand48() * (max_x - min_x);
1285 p.
v[1] = min_y +
drand48() * (max_y - min_y);
1286 p.
v[2] =
drand48() * 2 * M_PI - M_PI;
1301 std_srvs::Empty::Response& res)
1303 if(
map_ == NULL ) {
1311 ROS_INFO(
"Initializing with uniform distribution");
1314 ROS_INFO(
"Initializing with uniform distribution in energy map");
1318 ROS_INFO(
"Global initialisation done!");
1326 std_srvs::Empty::Response& res)
1335 nav_msgs::SetMap::Response& res)
1356 std::string laser_scan_frame_id =
stripSlash(laser_scan->header.frame_id);
1357 geometry_msgs::PoseStamped ident;
1358 ident.header.frame_id = laser_scan_frame_id;
1361 geometry_msgs::PoseStamped laser_pose;
1368 ROS_ERROR(
"Couldn't transform from %s to %s, "
1369 "even though the message notifier is in use",
1370 laser_scan_frame_id.c_str(),
1376 laser_pose_v.
v[0] = laser_pose.pose.position.x;
1377 laser_pose_v.
v[1] = laser_pose.pose.position.y;
1379 laser_pose_v.
v[2] = 0;
1381 ROS_DEBUG(
"Received laser's pose wrt robot: %.3f %.3f %.3f",
1391 q.
setRPY(0.0, 0.0, laser_scan->angle_min);
1392 geometry_msgs::QuaternionStamped min_q, inc_q;
1393 min_q.header.stamp = laser_scan->header.stamp;
1394 min_q.header.frame_id =
stripSlash(laser_scan->header.frame_id);
1397 q.
setRPY(0.0, 0.0, laser_scan->angle_min + laser_scan->angle_increment);
1398 inc_q.header = min_q.header;
1407 ROS_WARN(
"Unable to transform min/max laser angles into base frame: %s",
1412 double angle_increment =
tf2::getYaw(inc_q.quaternion) - angle_min;
1415 angle_increment = fmod(angle_increment + 5*M_PI, 2*M_PI) - M_PI;
1418 double range_max , range_min ;
1423 range_max = laser_scan->range_max;
1428 range_min = laser_scan->range_min;
1432 t_laser_scan.
range_count = laser_scan->ranges.size();
1438 for(
int i=0; i<laser_scan->ranges.size(); i++)
1452 ROS_INFO(
"adding Laser %d to energy map; this can take some time on large maps with high resolution...",
laser_index);
1466 std::string laser_scan_frame_id =
stripSlash(laser_scan->header.frame_id);
1468 if(
map_ == NULL ) {
1490 ROS_ERROR(
"Couldn't determine robot's pose associated with laser scan");
1505 if ( fabs (delta.
v[0] )> 2.0 || fabs (delta.
v[1] )> 2.0)
1524 bool force_publication =
false;
1537 force_publication =
true;
1553 odata.
delta = delta;
1562 bool resampled =
false;
1572 for(
int i=0;i<laser_scan->ranges.size();i++)
1607 delete t_laser_scan;
1630 geometry_msgs::PoseArray energy_cloud_msg;
1635 for (
int i=0 ; i<accepted_count ; i++ )
1637 energy_cloud_msg.poses[i].position.x = poses[accepted_index[i]].
pose_x;
1638 energy_cloud_msg.poses[i].position.y = poses[accepted_index[i]].
pose_y;
1639 energy_cloud_msg.poses[i].position.z = 0;
1641 q.
setRPY(0, 0,poses[accepted_index[i]].orientation_yaw);
1647 geometry_msgs::PoseArray cloud_msg;
1650 cloud_msg.poses.resize(
set->sample_count);
1652 for(
int i=0;i<
set->sample_count;i++)
1654 cloud_msg.poses[i].position.x =
set->samples[i].pose.v[0];
1655 cloud_msg.poses[i].position.y =
set->samples[i].pose.v[1];
1656 cloud_msg.poses[i].position.z = 0;
1658 q.
setRPY(0, 0,
set->samples[i].pose.v[2]);
1666 if(resampled || force_publication)
1669 double max_weight = 0.0;
1670 int max_weight_hyp = -1;
1671 std::vector<gmcl_hyp_t> hyps;
1673 for(
int hyp_count = 0;
1681 ROS_ERROR(
"Couldn't get stats on cluster %d", hyp_count);
1684 hyps[hyp_count].weight = weight;
1685 hyps[hyp_count].pf_pose_mean = pose_mean;
1686 hyps[hyp_count].pf_pose_cov = pose_cov;
1688 if(hyps[hyp_count].weight > max_weight)
1690 max_weight = hyps[hyp_count].weight;
1691 max_weight_hyp = hyp_count;
1695 if(max_weight > 0.0)
1697 ROS_DEBUG(
"Max weight pose: %.3f %.3f %.3f",
1698 hyps[max_weight_hyp].pf_pose_mean.v[0],
1699 hyps[max_weight_hyp].pf_pose_mean.v[1],
1700 hyps[max_weight_hyp].pf_pose_mean.v[2]);
1708 geometry_msgs::PoseWithCovarianceStamped p;
1711 p.header.stamp = laser_scan->header.stamp;
1713 p.pose.pose.position.x = hyps[max_weight_hyp].pf_pose_mean.v[0];
1714 p.pose.pose.position.y = hyps[max_weight_hyp].pf_pose_mean.v[1];
1717 q.
setRPY(0, 0, hyps[max_weight_hyp].pf_pose_mean.v[2]);
1721 for(
int i=0; i<2; i++)
1723 for(
int j=0; j<2; j++)
1728 p.pose.covariance[6*i+j] =
set->cov.m[i][j];
1731 p.pose.covariance[6*3] =
set->cov.m[2][0];
1735 p.pose.covariance[6*5+5] =
set->cov.m[2][2];
1750 ROS_DEBUG(
"New pose: %6.3f %6.3f %6.3f",
1751 hyps[max_weight_hyp].pf_pose_mean.v[0],
1752 hyps[max_weight_hyp].pf_pose_mean.v[1],
1753 hyps[max_weight_hyp].pf_pose_mean.v[2]);
1756 geometry_msgs::PoseStamped odom_to_map;
1760 q.
setRPY(0, 0, hyps[max_weight_hyp].pf_pose_mean.v[2]);
1761 tf2::Transform tmp_tf(q, tf2::Vector3(hyps[max_weight_hyp].pf_pose_mean.v[0],
1762 hyps[max_weight_hyp].pf_pose_mean.v[1],
1765 geometry_msgs::PoseStamped tmp_tf_stamped;
1767 tmp_tf_stamped.header.stamp = laser_scan->header.stamp;
1774 ROS_DEBUG(
"Failed to subtract base to odom transform");
1785 ros::Time transform_expiration = (laser_scan->header.stamp +
1787 geometry_msgs::TransformStamped tmp_tf_stamped;
1789 tmp_tf_stamped.header.stamp = transform_expiration;
1793 this->
tfb_->sendTransform(tmp_tf_stamped);
1808 ros::Time transform_expiration = (laser_scan->header.stamp +
1810 geometry_msgs::TransformStamped tmp_tf_stamped;
1812 tmp_tf_stamped.header.stamp = transform_expiration;
1815 this->
tfb_->sendTransform(tmp_tf_stamped);
1841 if(
msg.header.frame_id ==
"")
1844 ROS_WARN(
"Received initial pose with empty frame_id. You should always supply a frame_id.");
1849 ROS_WARN(
"Ignoring initial pose in frame \"%s\"; initial poses must be in the global frame, \"%s\"",
1857 geometry_msgs::TransformStamped tx_odom;
1873 ROS_WARN(
"Failed to transform initial pose in time (%s)", e.what());
1881 pose_new = pose_old * tx_odom_tf2;
1885 ROS_INFO(
"Setting pose (%.6f): %.3f %.3f %.3f",
1892 pf_init_pose_mean.
v[0] = pose_new.
getOrigin().x();
1893 pf_init_pose_mean.
v[1] = pose_new.
getOrigin().y();
1897 for(
int i=0; i<2; i++)
1899 for(
int j=0; j<2; j++)
1901 pf_init_pose_cov.
m[i][j] =
msg.pose.covariance[6*i+j];
1904 pf_init_pose_cov.
m[2][2] =
msg.pose.covariance[6*5+5];
1938 diagnostic_status.
add(
"std_x", std_x);
1939 diagnostic_status.
add(
"std_y", std_y);
1940 diagnostic_status.
add(
"std_yaw", std_yaw);
1947 diagnostic_status.
summary(diagnostic_msgs::DiagnosticStatus::WARN,
"Too large");
1951 diagnostic_status.
summary(diagnostic_msgs::DiagnosticStatus::OK,
"OK");