amcl_node.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008, Willow Garage, Inc.
3  * All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20 
21 /* Author: Brian Gerkey */
22 
23 #include <algorithm>
24 #include <vector>
25 #include <map>
26 #include <cmath>
27 
28 #include <boost/bind.hpp>
29 #include <boost/thread/mutex.hpp>
30 
31 // Signal handling
32 #include <signal.h>
33 
34 #include "amcl/map/map.h"
35 #include "amcl/pf/pf.h"
36 #include "amcl/sensors/amcl_odom.h"
38 
39 #include "ros/assert.h"
40 
41 // roscpp
42 #include "ros/ros.h"
43 
44 // Messages that I need
45 #include "sensor_msgs/LaserScan.h"
46 #include "geometry_msgs/PoseWithCovarianceStamped.h"
47 #include "geometry_msgs/PoseArray.h"
48 #include "geometry_msgs/Pose.h"
49 #include "nav_msgs/GetMap.h"
50 #include "nav_msgs/SetMap.h"
51 #include "std_srvs/Empty.h"
52 
53 // For transform support
55 #include "tf/transform_listener.h"
56 #include "tf/message_filter.h"
57 #include "tf/tf.h"
59 
60 // Dynamic_reconfigure
61 #include "dynamic_reconfigure/server.h"
62 #include "amcl/AMCLConfig.h"
63 
64 // Allows AMCL to run from bag file
65 #include <rosbag/bag.h>
66 #include <rosbag/view.h>
67 #include <boost/foreach.hpp>
68 
69 #define NEW_UNIFORM_SAMPLING 1
70 
71 using namespace amcl;
72 
73 // Pose hypothesis
74 typedef struct
75 {
76  // Total weight (weights sum to 1)
77  double weight;
78 
79  // Mean of pose esimate
81 
82  // Covariance of pose estimate
84 
85 } amcl_hyp_t;
86 
87 static double
88 normalize(double z)
89 {
90  return atan2(sin(z),cos(z));
91 }
92 static double
93 angle_diff(double a, double b)
94 {
95  double d1, d2;
96  a = normalize(a);
97  b = normalize(b);
98  d1 = a-b;
99  d2 = 2*M_PI - fabs(d1);
100  if(d1 > 0)
101  d2 *= -1.0;
102  if(fabs(d1) < fabs(d2))
103  return(d1);
104  else
105  return(d2);
106 }
107 
108 static const std::string scan_topic_ = "scan";
109 
110 class AmclNode
111 {
112  public:
113  AmclNode();
114  ~AmclNode();
115 
119  void runFromBag(const std::string &in_bag_fn);
120 
121  int process();
122  void savePoseToServer();
123 
124  private:
126 
127  // Use a child class to get access to tf2::Buffer class inside of tf_
129  {
130  inline tf2_ros::Buffer &getBuffer() {return tf2_buffer_;}
131  };
132 
134 
136 
139 
140  // Pose-generating function used to uniformly distribute particles over
141  // the map
142  static pf_vector_t uniformPoseGenerator(void* arg);
143 #if NEW_UNIFORM_SAMPLING
144  static std::vector<std::pair<int,int> > free_space_indices;
145 #endif
146  // Callbacks
147  bool globalLocalizationCallback(std_srvs::Empty::Request& req,
148  std_srvs::Empty::Response& res);
149  bool nomotionUpdateCallback(std_srvs::Empty::Request& req,
150  std_srvs::Empty::Response& res);
151  bool setMapCallback(nav_msgs::SetMap::Request& req,
152  nav_msgs::SetMap::Response& res);
153 
154  void laserReceived(const sensor_msgs::LaserScanConstPtr& laser_scan);
155  void initialPoseReceived(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg);
156  void handleInitialPoseMessage(const geometry_msgs::PoseWithCovarianceStamped& msg);
157  void mapReceived(const nav_msgs::OccupancyGridConstPtr& msg);
158 
159  void handleMapMessage(const nav_msgs::OccupancyGrid& msg);
160  void freeMapDependentMemory();
161  map_t* convertMap( const nav_msgs::OccupancyGrid& map_msg );
162  void updatePoseFromServer();
163  void applyInitialPose();
164 
165  double getYaw(tf::Pose& t);
166 
167  //parameter for what odom to use
168  std::string odom_frame_id_;
169 
170  //paramater to store latest odom pose
172 
173  //parameter for what base to use
174  std::string base_frame_id_;
175  std::string global_frame_id_;
176 
179 
183 
184  geometry_msgs::PoseWithCovarianceStamped last_published_pose;
185 
187  char* mapdata;
188  int sx, sy;
189  double resolution;
190 
194  std::vector< AMCLLaser* > lasers_;
195  std::vector< bool > lasers_update_;
196  std::map< std::string, int > frame_to_laser_;
197 
198  // Particle filter
200  double pf_err_, pf_z_;
201  bool pf_init_;
203  double d_thresh_, a_thresh_;
208 
209  //Nomotion update control
210  bool m_force_update; // used to temporarily let amcl update samples even when no motion occurs...
211 
214 
217 
218  // For slowing play-back when reading directly from a bag file
220 
221  void requestMap();
222 
223  // Helper to get odometric pose from transform system
224  bool getOdomPose(tf::Stamped<tf::Pose>& pose,
225  double& x, double& y, double& yaw,
226  const ros::Time& t, const std::string& f);
227 
228  //time for tolerance on the published transform,
229  //basically defines how long a map->odom transform is good for
231 
237  ros::ServiceServer nomotion_update_srv_; //to let amcl update samples without requiring motion
241 
245 
246  boost::recursive_mutex configuration_mutex_;
247  dynamic_reconfigure::Server<amcl::AMCLConfig> *dsrv_;
248  amcl::AMCLConfig default_config_;
250 
251  int max_beams_, min_particles_, max_particles_;
252  double alpha1_, alpha2_, alpha3_, alpha4_, alpha5_;
253  double alpha_slow_, alpha_fast_;
254  double z_hit_, z_short_, z_max_, z_rand_, sigma_hit_, lambda_short_;
255  //beam skip related params
257  double beam_skip_distance_, beam_skip_threshold_, beam_skip_error_threshold_;
260  double init_pose_[3];
261  double init_cov_[3];
264 
265  void reconfigureCB(amcl::AMCLConfig &config, uint32_t level);
266 
269  void checkLaserReceived(const ros::TimerEvent& event);
270 };
271 
272 std::vector<std::pair<int,int> > AmclNode::free_space_indices;
273 
274 #define USAGE "USAGE: amcl"
275 
277 
278 void sigintHandler(int sig)
279 {
280  // Save latest pose as we're shutting down.
281  amcl_node_ptr->savePoseToServer();
282  ros::shutdown();
283 }
284 
285 int
286 main(int argc, char** argv)
287 {
288  ros::init(argc, argv, "amcl");
289  ros::NodeHandle nh;
290 
291  // Override default sigint handler
292  signal(SIGINT, sigintHandler);
293 
294  // Make our node available to sigintHandler
295  amcl_node_ptr.reset(new AmclNode());
296 
297  if (argc == 1)
298  {
299  // run using ROS input
300  ros::spin();
301  }
302  else if ((argc == 3) && (std::string(argv[1]) == "--run-from-bag"))
303  {
304  amcl_node_ptr->runFromBag(argv[2]);
305  }
306 
307  // Without this, our boost locks are not shut down nicely
308  amcl_node_ptr.reset();
309 
310  // To quote Morgan, Hooray!
311  return(0);
312 }
313 
315  sent_first_transform_(false),
316  latest_tf_valid_(false),
317  map_(NULL),
318  pf_(NULL),
319  resample_count_(0),
320  odom_(NULL),
321  laser_(NULL),
322  private_nh_("~"),
323  initial_pose_hyp_(NULL),
324  first_map_received_(false),
325  first_reconfigure_call_(true)
326 {
327  boost::recursive_mutex::scoped_lock l(configuration_mutex_);
328 
329  // Grab params off the param server
330  private_nh_.param("use_map_topic", use_map_topic_, false);
331  private_nh_.param("first_map_only", first_map_only_, false);
332 
333  double tmp;
334  private_nh_.param("gui_publish_rate", tmp, -1.0);
336  private_nh_.param("save_pose_rate", tmp, 0.5);
337  save_pose_period = ros::Duration(1.0/tmp);
338 
339  private_nh_.param("laser_min_range", laser_min_range_, -1.0);
340  private_nh_.param("laser_max_range", laser_max_range_, -1.0);
341  private_nh_.param("laser_max_beams", max_beams_, 30);
342  private_nh_.param("min_particles", min_particles_, 100);
343  private_nh_.param("max_particles", max_particles_, 5000);
344  private_nh_.param("kld_err", pf_err_, 0.01);
345  private_nh_.param("kld_z", pf_z_, 0.99);
346  private_nh_.param("odom_alpha1", alpha1_, 0.2);
347  private_nh_.param("odom_alpha2", alpha2_, 0.2);
348  private_nh_.param("odom_alpha3", alpha3_, 0.2);
349  private_nh_.param("odom_alpha4", alpha4_, 0.2);
350  private_nh_.param("odom_alpha5", alpha5_, 0.2);
351 
352  private_nh_.param("do_beamskip", do_beamskip_, false);
353  private_nh_.param("beam_skip_distance", beam_skip_distance_, 0.5);
354  private_nh_.param("beam_skip_threshold", beam_skip_threshold_, 0.3);
355  private_nh_.param("beam_skip_error_threshold_", beam_skip_error_threshold_, 0.9);
356 
357  private_nh_.param("laser_z_hit", z_hit_, 0.95);
358  private_nh_.param("laser_z_short", z_short_, 0.1);
359  private_nh_.param("laser_z_max", z_max_, 0.05);
360  private_nh_.param("laser_z_rand", z_rand_, 0.05);
361  private_nh_.param("laser_sigma_hit", sigma_hit_, 0.2);
362  private_nh_.param("laser_lambda_short", lambda_short_, 0.1);
363  private_nh_.param("laser_likelihood_max_dist", laser_likelihood_max_dist_, 2.0);
364  std::string tmp_model_type;
365  private_nh_.param("laser_model_type", tmp_model_type, std::string("likelihood_field"));
366  if(tmp_model_type == "beam")
368  else if(tmp_model_type == "likelihood_field")
370  else if(tmp_model_type == "likelihood_field_prob"){
372  }
373  else
374  {
375  ROS_WARN("Unknown laser model type \"%s\"; defaulting to likelihood_field model",
376  tmp_model_type.c_str());
378  }
379 
380  private_nh_.param("odom_model_type", tmp_model_type, std::string("diff"));
381  if(tmp_model_type == "diff")
383  else if(tmp_model_type == "omni")
385  else if(tmp_model_type == "diff-corrected")
387  else if(tmp_model_type == "omni-corrected")
389  else
390  {
391  ROS_WARN("Unknown odom model type \"%s\"; defaulting to diff model",
392  tmp_model_type.c_str());
394  }
395 
396  private_nh_.param("update_min_d", d_thresh_, 0.2);
397  private_nh_.param("update_min_a", a_thresh_, M_PI/6.0);
398  private_nh_.param("odom_frame_id", odom_frame_id_, std::string("odom"));
399  private_nh_.param("base_frame_id", base_frame_id_, std::string("base_link"));
400  private_nh_.param("global_frame_id", global_frame_id_, std::string("map"));
401  private_nh_.param("resample_interval", resample_interval_, 2);
402  double tmp_tol;
403  private_nh_.param("transform_tolerance", tmp_tol, 0.1);
404  private_nh_.param("recovery_alpha_slow", alpha_slow_, 0.001);
405  private_nh_.param("recovery_alpha_fast", alpha_fast_, 0.1);
406  private_nh_.param("tf_broadcast", tf_broadcast_, true);
407 
408  transform_tolerance_.fromSec(tmp_tol);
409 
410  {
411  double bag_scan_period;
412  private_nh_.param("bag_scan_period", bag_scan_period, -1.0);
413  bag_scan_period_.fromSec(bag_scan_period);
414  }
415 
417 
421 
422  pose_pub_ = nh_.advertise<geometry_msgs::PoseWithCovarianceStamped>("amcl_pose", 2, true);
423  particlecloud_pub_ = nh_.advertise<geometry_msgs::PoseArray>("particlecloud", 2, true);
424  global_loc_srv_ = nh_.advertiseService("global_localization",
426  this);
429 
433  *tf_,
435  100);
436  laser_scan_filter_->registerCallback(boost::bind(&AmclNode::laserReceived,
437  this, _1));
438  initial_pose_sub_ = nh_.subscribe("initialpose", 2, &AmclNode::initialPoseReceived, this);
439 
440  if(use_map_topic_) {
441  map_sub_ = nh_.subscribe("map", 1, &AmclNode::mapReceived, this);
442  ROS_INFO("Subscribed to map topic.");
443  } else {
444  requestMap();
445  }
446  m_force_update = false;
447 
448  dsrv_ = new dynamic_reconfigure::Server<amcl::AMCLConfig>(ros::NodeHandle("~"));
449  dynamic_reconfigure::Server<amcl::AMCLConfig>::CallbackType cb = boost::bind(&AmclNode::reconfigureCB, this, _1, _2);
450  dsrv_->setCallback(cb);
451 
452  // 15s timer to warn on lack of receipt of laser scans, #5209
454  check_laser_timer_ = nh_.createTimer(laser_check_interval_,
455  boost::bind(&AmclNode::checkLaserReceived, this, _1));
456 }
457 
458 void AmclNode::reconfigureCB(AMCLConfig &config, uint32_t level)
459 {
460  boost::recursive_mutex::scoped_lock cfl(configuration_mutex_);
461 
462  //we don't want to do anything on the first call
463  //which corresponds to startup
465  {
466  first_reconfigure_call_ = false;
467  default_config_ = config;
468  return;
469  }
470 
471  if(config.restore_defaults) {
472  config = default_config_;
473  //avoid looping
474  config.restore_defaults = false;
475  }
476 
477  d_thresh_ = config.update_min_d;
478  a_thresh_ = config.update_min_a;
479 
480  resample_interval_ = config.resample_interval;
481 
482  laser_min_range_ = config.laser_min_range;
483  laser_max_range_ = config.laser_max_range;
484 
485  gui_publish_period = ros::Duration(1.0/config.gui_publish_rate);
486  save_pose_period = ros::Duration(1.0/config.save_pose_rate);
487 
488  transform_tolerance_.fromSec(config.transform_tolerance);
489 
490  max_beams_ = config.laser_max_beams;
491  alpha1_ = config.odom_alpha1;
492  alpha2_ = config.odom_alpha2;
493  alpha3_ = config.odom_alpha3;
494  alpha4_ = config.odom_alpha4;
495  alpha5_ = config.odom_alpha5;
496 
497  z_hit_ = config.laser_z_hit;
498  z_short_ = config.laser_z_short;
499  z_max_ = config.laser_z_max;
500  z_rand_ = config.laser_z_rand;
501  sigma_hit_ = config.laser_sigma_hit;
502  lambda_short_ = config.laser_lambda_short;
503  laser_likelihood_max_dist_ = config.laser_likelihood_max_dist;
504 
505  if(config.laser_model_type == "beam")
507  else if(config.laser_model_type == "likelihood_field")
509  else if(config.laser_model_type == "likelihood_field_prob")
511 
512  if(config.odom_model_type == "diff")
514  else if(config.odom_model_type == "omni")
516  else if(config.odom_model_type == "diff-corrected")
518  else if(config.odom_model_type == "omni-corrected")
520 
521  if(config.min_particles > config.max_particles)
522  {
523  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.");
524  config.max_particles = config.min_particles;
525  }
526 
527  min_particles_ = config.min_particles;
528  max_particles_ = config.max_particles;
529  alpha_slow_ = config.recovery_alpha_slow;
530  alpha_fast_ = config.recovery_alpha_fast;
531  tf_broadcast_ = config.tf_broadcast;
532 
533  do_beamskip_= config.do_beamskip;
534  beam_skip_distance_ = config.beam_skip_distance;
535  beam_skip_threshold_ = config.beam_skip_threshold;
536 
540  (void *)map_);
541  pf_err_ = config.kld_err;
542  pf_z_ = config.kld_z;
543  pf_->pop_err = pf_err_;
544  pf_->pop_z = pf_z_;
545 
546  // Initialize the filter
547  pf_vector_t pf_init_pose_mean = pf_vector_zero();
548  pf_init_pose_mean.v[0] = last_published_pose.pose.pose.position.x;
549  pf_init_pose_mean.v[1] = last_published_pose.pose.pose.position.y;
550  pf_init_pose_mean.v[2] = tf::getYaw(last_published_pose.pose.pose.orientation);
551  pf_matrix_t pf_init_pose_cov = pf_matrix_zero();
552  pf_init_pose_cov.m[0][0] = last_published_pose.pose.covariance[6*0+0];
553  pf_init_pose_cov.m[1][1] = last_published_pose.pose.covariance[6*1+1];
554  pf_init_pose_cov.m[2][2] = last_published_pose.pose.covariance[6*5+5];
555  pf_init(pf_, pf_init_pose_mean, pf_init_pose_cov);
556  pf_init_ = false;
557 
558  // Instantiate the sensor objects
559  // Odometry
560  delete odom_;
561  odom_ = new AMCLOdom();
562  ROS_ASSERT(odom_);
564  // Laser
565  delete laser_;
570  sigma_hit_, lambda_short_, 0.0);
572  ROS_INFO("Initializing likelihood field model; this can take some time on large maps...");
577  ROS_INFO("Done initializing likelihood field model with probabilities.");
578  }
580  ROS_INFO("Initializing likelihood field model; this can take some time on large maps...");
583  ROS_INFO("Done initializing likelihood field model.");
584  }
585 
586  odom_frame_id_ = config.odom_frame_id;
587  base_frame_id_ = config.base_frame_id;
588  global_frame_id_ = config.global_frame_id;
589 
590  delete laser_scan_filter_;
593  *tf_,
595  100);
597  this, _1));
598 
599  initial_pose_sub_ = nh_.subscribe("initialpose", 2, &AmclNode::initialPoseReceived, this);
600 }
601 
602 
603 void AmclNode::runFromBag(const std::string &in_bag_fn)
604 {
605  rosbag::Bag bag;
606  bag.open(in_bag_fn, rosbag::bagmode::Read);
607  std::vector<std::string> topics;
608  topics.push_back(std::string("tf"));
609  std::string scan_topic_name = "base_scan"; // TODO determine what topic this actually is from ROS
610  topics.push_back(scan_topic_name);
611  rosbag::View view(bag, rosbag::TopicQuery(topics));
612 
613  ros::Publisher laser_pub = nh_.advertise<sensor_msgs::LaserScan>(scan_topic_name, 100);
614  ros::Publisher tf_pub = nh_.advertise<tf2_msgs::TFMessage>("/tf", 100);
615 
616  // Sleep for a second to let all subscribers connect
617  ros::WallDuration(1.0).sleep();
618 
620 
621  // Wait for map
622  while (ros::ok())
623  {
624  {
625  boost::recursive_mutex::scoped_lock cfl(configuration_mutex_);
626  if (map_)
627  {
628  ROS_INFO("Map is ready");
629  break;
630  }
631  }
632  ROS_INFO("Waiting for map...");
634  }
635 
636  BOOST_FOREACH(rosbag::MessageInstance const msg, view)
637  {
638  if (!ros::ok())
639  {
640  break;
641  }
642 
643  // Process any ros messages or callbacks at this point
645 
646  tf2_msgs::TFMessage::ConstPtr tf_msg = msg.instantiate<tf2_msgs::TFMessage>();
647  if (tf_msg != NULL)
648  {
649  tf_pub.publish(msg);
650  for (size_t ii=0; ii<tf_msg->transforms.size(); ++ii)
651  {
652  tf_->getBuffer().setTransform(tf_msg->transforms[ii], "rosbag_authority");
653  }
654  continue;
655  }
656 
657  sensor_msgs::LaserScan::ConstPtr base_scan = msg.instantiate<sensor_msgs::LaserScan>();
658  if (base_scan != NULL)
659  {
660  laser_pub.publish(msg);
661  laser_scan_filter_->add(base_scan);
663  {
665  }
666  continue;
667  }
668 
669  ROS_WARN_STREAM("Unsupported message type" << msg.getTopic());
670  }
671 
672  bag.close();
673 
674  double runtime = (ros::WallTime::now() - start).toSec();
675  ROS_INFO("Bag complete, took %.1f seconds to process, shutting down", runtime);
676 
677  const geometry_msgs::Quaternion & q(last_published_pose.pose.pose.orientation);
678  double yaw, pitch, roll;
679  tf::Matrix3x3(tf::Quaternion(q.x, q.y, q.z, q.w)).getEulerYPR(yaw,pitch,roll);
680  ROS_INFO("Final location %.3f, %.3f, %.3f with stamp=%f",
681  last_published_pose.pose.pose.position.x,
682  last_published_pose.pose.pose.position.y,
683  yaw, last_published_pose.header.stamp.toSec()
684  );
685 
686  ros::shutdown();
687 }
688 
689 
691 {
692  // We need to apply the last transform to the latest odom pose to get
693  // the latest map pose to store. We'll take the covariance from
694  // last_published_pose.
696  double yaw,pitch,roll;
697  map_pose.getBasis().getEulerYPR(yaw, pitch, roll);
698 
699  ROS_DEBUG("Saving pose to server. x: %.3f, y: %.3f", map_pose.getOrigin().x(), map_pose.getOrigin().y() );
700 
701  private_nh_.setParam("initial_pose_x", map_pose.getOrigin().x());
702  private_nh_.setParam("initial_pose_y", map_pose.getOrigin().y());
703  private_nh_.setParam("initial_pose_a", yaw);
704  private_nh_.setParam("initial_cov_xx",
705  last_published_pose.pose.covariance[6*0+0]);
706  private_nh_.setParam("initial_cov_yy",
707  last_published_pose.pose.covariance[6*1+1]);
708  private_nh_.setParam("initial_cov_aa",
709  last_published_pose.pose.covariance[6*5+5]);
710 }
711 
713 {
714  init_pose_[0] = 0.0;
715  init_pose_[1] = 0.0;
716  init_pose_[2] = 0.0;
717  init_cov_[0] = 0.5 * 0.5;
718  init_cov_[1] = 0.5 * 0.5;
719  init_cov_[2] = (M_PI/12.0) * (M_PI/12.0);
720  // Check for NAN on input from param server, #5239
721  double tmp_pos;
722  private_nh_.param("initial_pose_x", tmp_pos, init_pose_[0]);
723  if(!std::isnan(tmp_pos))
724  init_pose_[0] = tmp_pos;
725  else
726  ROS_WARN("ignoring NAN in initial pose X position");
727  private_nh_.param("initial_pose_y", tmp_pos, init_pose_[1]);
728  if(!std::isnan(tmp_pos))
729  init_pose_[1] = tmp_pos;
730  else
731  ROS_WARN("ignoring NAN in initial pose Y position");
732  private_nh_.param("initial_pose_a", tmp_pos, init_pose_[2]);
733  if(!std::isnan(tmp_pos))
734  init_pose_[2] = tmp_pos;
735  else
736  ROS_WARN("ignoring NAN in initial pose Yaw");
737  private_nh_.param("initial_cov_xx", tmp_pos, init_cov_[0]);
738  if(!std::isnan(tmp_pos))
739  init_cov_[0] =tmp_pos;
740  else
741  ROS_WARN("ignoring NAN in initial covariance XX");
742  private_nh_.param("initial_cov_yy", tmp_pos, init_cov_[1]);
743  if(!std::isnan(tmp_pos))
744  init_cov_[1] = tmp_pos;
745  else
746  ROS_WARN("ignoring NAN in initial covariance YY");
747  private_nh_.param("initial_cov_aa", tmp_pos, init_cov_[2]);
748  if(!std::isnan(tmp_pos))
749  init_cov_[2] = tmp_pos;
750  else
751  ROS_WARN("ignoring NAN in initial covariance AA");
752 }
753 
754 void
756 {
758  if(d > laser_check_interval_)
759  {
760  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.",
761  d.toSec(),
763  }
764 }
765 
766 void
768 {
769  boost::recursive_mutex::scoped_lock ml(configuration_mutex_);
770 
771  // get map via RPC
772  nav_msgs::GetMap::Request req;
773  nav_msgs::GetMap::Response resp;
774  ROS_INFO("Requesting the map...");
775  while(!ros::service::call("static_map", req, resp))
776  {
777  ROS_WARN("Request for map failed; trying again...");
778  ros::Duration d(0.5);
779  d.sleep();
780  }
781  handleMapMessage( resp.map );
782 }
783 
784 void
785 AmclNode::mapReceived(const nav_msgs::OccupancyGridConstPtr& msg)
786 {
788  return;
789  }
790 
791  handleMapMessage( *msg );
792 
793  first_map_received_ = true;
794 }
795 
796 void
797 AmclNode::handleMapMessage(const nav_msgs::OccupancyGrid& msg)
798 {
799  boost::recursive_mutex::scoped_lock cfl(configuration_mutex_);
800 
801  ROS_INFO("Received a %d X %d map @ %.3f m/pix\n",
802  msg.info.width,
803  msg.info.height,
804  msg.info.resolution);
805 
806  if(msg.header.frame_id != global_frame_id_)
807  ROS_WARN("Frame_id of map received:'%s' doesn't match global_frame_id:'%s'. This could cause issues with reading published topics",
808  msg.header.frame_id.c_str(),
809  global_frame_id_.c_str());
810 
812  // Clear queued laser objects because they hold pointers to the existing
813  // map, #5202.
814  lasers_.clear();
815  lasers_update_.clear();
816  frame_to_laser_.clear();
817 
818  map_ = convertMap(msg);
819 
820 #if NEW_UNIFORM_SAMPLING
821  // Index of free space
822  free_space_indices.resize(0);
823  for(int i = 0; i < map_->size_x; i++)
824  for(int j = 0; j < map_->size_y; j++)
825  if(map_->cells[MAP_INDEX(map_,i,j)].occ_state == -1)
826  free_space_indices.push_back(std::make_pair(i,j));
827 #endif
828  // Create the particle filter
832  (void *)map_);
833  pf_->pop_err = pf_err_;
834  pf_->pop_z = pf_z_;
835 
836  // Initialize the filter
838  pf_vector_t pf_init_pose_mean = pf_vector_zero();
839  pf_init_pose_mean.v[0] = init_pose_[0];
840  pf_init_pose_mean.v[1] = init_pose_[1];
841  pf_init_pose_mean.v[2] = init_pose_[2];
842  pf_matrix_t pf_init_pose_cov = pf_matrix_zero();
843  pf_init_pose_cov.m[0][0] = init_cov_[0];
844  pf_init_pose_cov.m[1][1] = init_cov_[1];
845  pf_init_pose_cov.m[2][2] = init_cov_[2];
846  pf_init(pf_, pf_init_pose_mean, pf_init_pose_cov);
847  pf_init_ = false;
848 
849  // Instantiate the sensor objects
850  // Odometry
851  delete odom_;
852  odom_ = new AMCLOdom();
853  ROS_ASSERT(odom_);
855  // Laser
856  delete laser_;
861  sigma_hit_, lambda_short_, 0.0);
863  ROS_INFO("Initializing likelihood field model; this can take some time on large maps...");
868  ROS_INFO("Done initializing likelihood field model.");
869  }
870  else
871  {
872  ROS_INFO("Initializing likelihood field model; this can take some time on large maps...");
875  ROS_INFO("Done initializing likelihood field model.");
876  }
877 
878  // In case the initial pose message arrived before the first map,
879  // try to apply the initial pose now that the map has arrived.
881 
882 }
883 
884 void
886 {
887  if( map_ != NULL ) {
888  map_free( map_ );
889  map_ = NULL;
890  }
891  if( pf_ != NULL ) {
892  pf_free( pf_ );
893  pf_ = NULL;
894  }
895  delete odom_;
896  odom_ = NULL;
897  delete laser_;
898  laser_ = NULL;
899 }
900 
905 map_t*
906 AmclNode::convertMap( const nav_msgs::OccupancyGrid& map_msg )
907 {
908  map_t* map = map_alloc();
909  ROS_ASSERT(map);
910 
911  map->size_x = map_msg.info.width;
912  map->size_y = map_msg.info.height;
913  map->scale = map_msg.info.resolution;
914  map->origin_x = map_msg.info.origin.position.x + (map->size_x / 2) * map->scale;
915  map->origin_y = map_msg.info.origin.position.y + (map->size_y / 2) * map->scale;
916  // Convert to player format
917  map->cells = (map_cell_t*)malloc(sizeof(map_cell_t)*map->size_x*map->size_y);
918  ROS_ASSERT(map->cells);
919  for(int i=0;i<map->size_x * map->size_y;i++)
920  {
921  if(map_msg.data[i] == 0)
922  map->cells[i].occ_state = -1;
923  else if(map_msg.data[i] == 100)
924  map->cells[i].occ_state = +1;
925  else
926  map->cells[i].occ_state = 0;
927  }
928 
929  return map;
930 }
931 
933 {
934  delete dsrv_;
936  delete laser_scan_filter_;
937  delete laser_scan_sub_;
938  delete tfb_;
939  delete tf_;
940  // TODO: delete everything allocated in constructor
941 }
942 
943 bool
945  double& x, double& y, double& yaw,
946  const ros::Time& t, const std::string& f)
947 {
948  // Get the robot's pose
950  tf::Vector3(0,0,0)), t, f);
951  try
952  {
953  this->tf_->transformPose(odom_frame_id_, ident, odom_pose);
954  }
955  catch(tf::TransformException e)
956  {
957  ROS_WARN("Failed to compute odom pose, skipping scan (%s)", e.what());
958  return false;
959  }
960  x = odom_pose.getOrigin().x();
961  y = odom_pose.getOrigin().y();
962  double pitch,roll;
963  odom_pose.getBasis().getEulerYPR(yaw, pitch, roll);
964 
965  return true;
966 }
967 
968 
971 {
972  map_t* map = (map_t*)arg;
973 #if NEW_UNIFORM_SAMPLING
974  unsigned int rand_index = drand48() * free_space_indices.size();
975  std::pair<int,int> free_point = free_space_indices[rand_index];
976  pf_vector_t p;
977  p.v[0] = MAP_WXGX(map, free_point.first);
978  p.v[1] = MAP_WYGY(map, free_point.second);
979  p.v[2] = drand48() * 2 * M_PI - M_PI;
980 #else
981  double min_x, max_x, min_y, max_y;
982 
983  min_x = (map->size_x * map->scale)/2.0 - map->origin_x;
984  max_x = (map->size_x * map->scale)/2.0 + map->origin_x;
985  min_y = (map->size_y * map->scale)/2.0 - map->origin_y;
986  max_y = (map->size_y * map->scale)/2.0 + map->origin_y;
987 
988  pf_vector_t p;
989 
990  ROS_DEBUG("Generating new uniform sample");
991  for(;;)
992  {
993  p.v[0] = min_x + drand48() * (max_x - min_x);
994  p.v[1] = min_y + drand48() * (max_y - min_y);
995  p.v[2] = drand48() * 2 * M_PI - M_PI;
996  // Check that it's a free cell
997  int i,j;
998  i = MAP_GXWX(map, p.v[0]);
999  j = MAP_GYWY(map, p.v[1]);
1000  if(MAP_VALID(map,i,j) && (map->cells[MAP_INDEX(map,i,j)].occ_state == -1))
1001  break;
1002  }
1003 #endif
1004  return p;
1005 }
1006 
1007 bool
1008 AmclNode::globalLocalizationCallback(std_srvs::Empty::Request& req,
1009  std_srvs::Empty::Response& res)
1010 {
1011  if( map_ == NULL ) {
1012  return true;
1013  }
1014  boost::recursive_mutex::scoped_lock gl(configuration_mutex_);
1015  ROS_INFO("Initializing with uniform distribution");
1017  (void *)map_);
1018  ROS_INFO("Global initialisation done!");
1019  pf_init_ = false;
1020  return true;
1021 }
1022 
1023 // force nomotion updates (amcl updating without requiring motion)
1024 bool
1025 AmclNode::nomotionUpdateCallback(std_srvs::Empty::Request& req,
1026  std_srvs::Empty::Response& res)
1027 {
1028  m_force_update = true;
1029  //ROS_INFO("Requesting no-motion update");
1030  return true;
1031 }
1032 
1033 bool
1034 AmclNode::setMapCallback(nav_msgs::SetMap::Request& req,
1035  nav_msgs::SetMap::Response& res)
1036 {
1037  handleMapMessage(req.map);
1038  handleInitialPoseMessage(req.initial_pose);
1039  res.success = true;
1040  return true;
1041 }
1042 
1043 void
1044 AmclNode::laserReceived(const sensor_msgs::LaserScanConstPtr& laser_scan)
1045 {
1047  if( map_ == NULL ) {
1048  return;
1049  }
1050  boost::recursive_mutex::scoped_lock lr(configuration_mutex_);
1051  int laser_index = -1;
1052 
1053  // Do we have the base->base_laser Tx yet?
1054  if(frame_to_laser_.find(laser_scan->header.frame_id) == frame_to_laser_.end())
1055  {
1056  ROS_DEBUG("Setting up laser %d (frame_id=%s)\n", (int)frame_to_laser_.size(), laser_scan->header.frame_id.c_str());
1057  lasers_.push_back(new AMCLLaser(*laser_));
1058  lasers_update_.push_back(true);
1059  laser_index = frame_to_laser_.size();
1060 
1062  tf::Vector3(0,0,0)),
1063  ros::Time(), laser_scan->header.frame_id);
1064  tf::Stamped<tf::Pose> laser_pose;
1065  try
1066  {
1067  this->tf_->transformPose(base_frame_id_, ident, laser_pose);
1068  }
1069  catch(tf::TransformException& e)
1070  {
1071  ROS_ERROR("Couldn't transform from %s to %s, "
1072  "even though the message notifier is in use",
1073  laser_scan->header.frame_id.c_str(),
1074  base_frame_id_.c_str());
1075  return;
1076  }
1077 
1078  pf_vector_t laser_pose_v;
1079  laser_pose_v.v[0] = laser_pose.getOrigin().x();
1080  laser_pose_v.v[1] = laser_pose.getOrigin().y();
1081  // laser mounting angle gets computed later -> set to 0 here!
1082  laser_pose_v.v[2] = 0;
1083  lasers_[laser_index]->SetLaserPose(laser_pose_v);
1084  ROS_DEBUG("Received laser's pose wrt robot: %.3f %.3f %.3f",
1085  laser_pose_v.v[0],
1086  laser_pose_v.v[1],
1087  laser_pose_v.v[2]);
1088 
1089  frame_to_laser_[laser_scan->header.frame_id] = laser_index;
1090  } else {
1091  // we have the laser pose, retrieve laser index
1092  laser_index = frame_to_laser_[laser_scan->header.frame_id];
1093  }
1094 
1095  // Where was the robot when this scan was taken?
1096  pf_vector_t pose;
1097  if(!getOdomPose(latest_odom_pose_, pose.v[0], pose.v[1], pose.v[2],
1098  laser_scan->header.stamp, base_frame_id_))
1099  {
1100  ROS_ERROR("Couldn't determine robot's pose associated with laser scan");
1101  return;
1102  }
1103 
1104 
1105  pf_vector_t delta = pf_vector_zero();
1106 
1107  if(pf_init_)
1108  {
1109  // Compute change in pose
1110  //delta = pf_vector_coord_sub(pose, pf_odom_pose_);
1111  delta.v[0] = pose.v[0] - pf_odom_pose_.v[0];
1112  delta.v[1] = pose.v[1] - pf_odom_pose_.v[1];
1113  delta.v[2] = angle_diff(pose.v[2], pf_odom_pose_.v[2]);
1114 
1115  // See if we should update the filter
1116  bool update = fabs(delta.v[0]) > d_thresh_ ||
1117  fabs(delta.v[1]) > d_thresh_ ||
1118  fabs(delta.v[2]) > a_thresh_;
1119  update = update || m_force_update;
1120  m_force_update=false;
1121 
1122  // Set the laser update flags
1123  if(update)
1124  for(unsigned int i=0; i < lasers_update_.size(); i++)
1125  lasers_update_[i] = true;
1126  }
1127 
1128  bool force_publication = false;
1129  if(!pf_init_)
1130  {
1131  // Pose at last filter update
1132  pf_odom_pose_ = pose;
1133 
1134  // Filter is now initialized
1135  pf_init_ = true;
1136 
1137  // Should update sensor data
1138  for(unsigned int i=0; i < lasers_update_.size(); i++)
1139  lasers_update_[i] = true;
1140 
1141  force_publication = true;
1142 
1143  resample_count_ = 0;
1144  }
1145  // If the robot has moved, update the filter
1146  else if(pf_init_ && lasers_update_[laser_index])
1147  {
1148  //printf("pose\n");
1149  //pf_vector_fprintf(pose, stdout, "%.3f");
1150 
1151  AMCLOdomData odata;
1152  odata.pose = pose;
1153  // HACK
1154  // Modify the delta in the action data so the filter gets
1155  // updated correctly
1156  odata.delta = delta;
1157 
1158  // Use the action data to update the filter
1159  odom_->UpdateAction(pf_, (AMCLSensorData*)&odata);
1160 
1161  // Pose at last filter update
1162  //this->pf_odom_pose = pose;
1163  }
1164 
1165  bool resampled = false;
1166  // If the robot has moved, update the filter
1167  if(lasers_update_[laser_index])
1168  {
1169  AMCLLaserData ldata;
1170  ldata.sensor = lasers_[laser_index];
1171  ldata.range_count = laser_scan->ranges.size();
1172 
1173  // To account for lasers that are mounted upside-down, we determine the
1174  // min, max, and increment angles of the laser in the base frame.
1175  //
1176  // Construct min and max angles of laser, in the base_link frame.
1177  tf::Quaternion q;
1178  q.setRPY(0.0, 0.0, laser_scan->angle_min);
1179  tf::Stamped<tf::Quaternion> min_q(q, laser_scan->header.stamp,
1180  laser_scan->header.frame_id);
1181  q.setRPY(0.0, 0.0, laser_scan->angle_min + laser_scan->angle_increment);
1182  tf::Stamped<tf::Quaternion> inc_q(q, laser_scan->header.stamp,
1183  laser_scan->header.frame_id);
1184  try
1185  {
1186  tf_->transformQuaternion(base_frame_id_, min_q, min_q);
1187  tf_->transformQuaternion(base_frame_id_, inc_q, inc_q);
1188  }
1189  catch(tf::TransformException& e)
1190  {
1191  ROS_WARN("Unable to transform min/max laser angles into base frame: %s",
1192  e.what());
1193  return;
1194  }
1195 
1196  double angle_min = tf::getYaw(min_q);
1197  double angle_increment = tf::getYaw(inc_q) - angle_min;
1198 
1199  // wrapping angle to [-pi .. pi]
1200  angle_increment = fmod(angle_increment + 5*M_PI, 2*M_PI) - M_PI;
1201 
1202  ROS_DEBUG("Laser %d angles in base frame: min: %.3f inc: %.3f", laser_index, angle_min, angle_increment);
1203 
1204  // Apply range min/max thresholds, if the user supplied them
1205  if(laser_max_range_ > 0.0)
1206  ldata.range_max = std::min(laser_scan->range_max, (float)laser_max_range_);
1207  else
1208  ldata.range_max = laser_scan->range_max;
1209  double range_min;
1210  if(laser_min_range_ > 0.0)
1211  range_min = std::max(laser_scan->range_min, (float)laser_min_range_);
1212  else
1213  range_min = laser_scan->range_min;
1214  // The AMCLLaserData destructor will free this memory
1215  ldata.ranges = new double[ldata.range_count][2];
1216  ROS_ASSERT(ldata.ranges);
1217  for(int i=0;i<ldata.range_count;i++)
1218  {
1219  // amcl doesn't (yet) have a concept of min range. So we'll map short
1220  // readings to max range.
1221  if(laser_scan->ranges[i] <= range_min)
1222  ldata.ranges[i][0] = ldata.range_max;
1223  else
1224  ldata.ranges[i][0] = laser_scan->ranges[i];
1225  // Compute bearing
1226  ldata.ranges[i][1] = angle_min +
1227  (i * angle_increment);
1228  }
1229 
1230  lasers_[laser_index]->UpdateSensor(pf_, (AMCLSensorData*)&ldata);
1231 
1232  lasers_update_[laser_index] = false;
1233 
1234  pf_odom_pose_ = pose;
1235 
1236  // Resample the particles
1238  {
1240  resampled = true;
1241  }
1242 
1243  pf_sample_set_t* set = pf_->sets + pf_->current_set;
1244  ROS_DEBUG("Num samples: %d\n", set->sample_count);
1245 
1246  // Publish the resulting cloud
1247  // TODO: set maximum rate for publishing
1248  if (!m_force_update) {
1249  geometry_msgs::PoseArray cloud_msg;
1250  cloud_msg.header.stamp = ros::Time::now();
1251  cloud_msg.header.frame_id = global_frame_id_;
1252  cloud_msg.poses.resize(set->sample_count);
1253  for(int i=0;i<set->sample_count;i++)
1254  {
1256  tf::Vector3(set->samples[i].pose.v[0],
1257  set->samples[i].pose.v[1], 0)),
1258  cloud_msg.poses[i]);
1259  }
1260  particlecloud_pub_.publish(cloud_msg);
1261  }
1262  }
1263 
1264  if(resampled || force_publication)
1265  {
1266  // Read out the current hypotheses
1267  double max_weight = 0.0;
1268  int max_weight_hyp = -1;
1269  std::vector<amcl_hyp_t> hyps;
1270  hyps.resize(pf_->sets[pf_->current_set].cluster_count);
1271  for(int hyp_count = 0;
1272  hyp_count < pf_->sets[pf_->current_set].cluster_count; hyp_count++)
1273  {
1274  double weight;
1275  pf_vector_t pose_mean;
1276  pf_matrix_t pose_cov;
1277  if (!pf_get_cluster_stats(pf_, hyp_count, &weight, &pose_mean, &pose_cov))
1278  {
1279  ROS_ERROR("Couldn't get stats on cluster %d", hyp_count);
1280  break;
1281  }
1282 
1283  hyps[hyp_count].weight = weight;
1284  hyps[hyp_count].pf_pose_mean = pose_mean;
1285  hyps[hyp_count].pf_pose_cov = pose_cov;
1286 
1287  if(hyps[hyp_count].weight > max_weight)
1288  {
1289  max_weight = hyps[hyp_count].weight;
1290  max_weight_hyp = hyp_count;
1291  }
1292  }
1293 
1294  if(max_weight > 0.0)
1295  {
1296  ROS_DEBUG("Max weight pose: %.3f %.3f %.3f",
1297  hyps[max_weight_hyp].pf_pose_mean.v[0],
1298  hyps[max_weight_hyp].pf_pose_mean.v[1],
1299  hyps[max_weight_hyp].pf_pose_mean.v[2]);
1300 
1301  /*
1302  puts("");
1303  pf_matrix_fprintf(hyps[max_weight_hyp].pf_pose_cov, stdout, "%6.3f");
1304  puts("");
1305  */
1306 
1307  geometry_msgs::PoseWithCovarianceStamped p;
1308  // Fill in the header
1309  p.header.frame_id = global_frame_id_;
1310  p.header.stamp = laser_scan->header.stamp;
1311  // Copy in the pose
1312  p.pose.pose.position.x = hyps[max_weight_hyp].pf_pose_mean.v[0];
1313  p.pose.pose.position.y = hyps[max_weight_hyp].pf_pose_mean.v[1];
1314  tf::quaternionTFToMsg(tf::createQuaternionFromYaw(hyps[max_weight_hyp].pf_pose_mean.v[2]),
1315  p.pose.pose.orientation);
1316  // Copy in the covariance, converting from 3-D to 6-D
1317  pf_sample_set_t* set = pf_->sets + pf_->current_set;
1318  for(int i=0; i<2; i++)
1319  {
1320  for(int j=0; j<2; j++)
1321  {
1322  // Report the overall filter covariance, rather than the
1323  // covariance for the highest-weight cluster
1324  //p.covariance[6*i+j] = hyps[max_weight_hyp].pf_pose_cov.m[i][j];
1325  p.pose.covariance[6*i+j] = set->cov.m[i][j];
1326  }
1327  }
1328  // Report the overall filter covariance, rather than the
1329  // covariance for the highest-weight cluster
1330  //p.covariance[6*5+5] = hyps[max_weight_hyp].pf_pose_cov.m[2][2];
1331  p.pose.covariance[6*5+5] = set->cov.m[2][2];
1332 
1333  /*
1334  printf("cov:\n");
1335  for(int i=0; i<6; i++)
1336  {
1337  for(int j=0; j<6; j++)
1338  printf("%6.3f ", p.covariance[6*i+j]);
1339  puts("");
1340  }
1341  */
1342 
1343  pose_pub_.publish(p);
1344  last_published_pose = p;
1345 
1346  ROS_DEBUG("New pose: %6.3f %6.3f %6.3f",
1347  hyps[max_weight_hyp].pf_pose_mean.v[0],
1348  hyps[max_weight_hyp].pf_pose_mean.v[1],
1349  hyps[max_weight_hyp].pf_pose_mean.v[2]);
1350 
1351  // subtracting base to odom from map to base and send map to odom instead
1352  tf::Stamped<tf::Pose> odom_to_map;
1353  try
1354  {
1355  tf::Transform tmp_tf(tf::createQuaternionFromYaw(hyps[max_weight_hyp].pf_pose_mean.v[2]),
1356  tf::Vector3(hyps[max_weight_hyp].pf_pose_mean.v[0],
1357  hyps[max_weight_hyp].pf_pose_mean.v[1],
1358  0.0));
1359  tf::Stamped<tf::Pose> tmp_tf_stamped (tmp_tf.inverse(),
1360  laser_scan->header.stamp,
1361  base_frame_id_);
1363  tmp_tf_stamped,
1364  odom_to_map);
1365  }
1366  catch(tf::TransformException)
1367  {
1368  ROS_DEBUG("Failed to subtract base to odom transform");
1369  return;
1370  }
1371 
1372  latest_tf_ = tf::Transform(tf::Quaternion(odom_to_map.getRotation()),
1373  tf::Point(odom_to_map.getOrigin()));
1374  latest_tf_valid_ = true;
1375 
1376  if (tf_broadcast_ == true)
1377  {
1378  // We want to send a transform that is good up until a
1379  // tolerance time so that odom can be used
1380  ros::Time transform_expiration = (laser_scan->header.stamp +
1382  tf::StampedTransform tmp_tf_stamped(latest_tf_.inverse(),
1383  transform_expiration,
1385  this->tfb_->sendTransform(tmp_tf_stamped);
1386  sent_first_transform_ = true;
1387  }
1388  }
1389  else
1390  {
1391  ROS_ERROR("No pose!");
1392  }
1393  }
1394  else if(latest_tf_valid_)
1395  {
1396  if (tf_broadcast_ == true)
1397  {
1398  // Nothing changed, so we'll just republish the last transform, to keep
1399  // everybody happy.
1400  ros::Time transform_expiration = (laser_scan->header.stamp +
1402  tf::StampedTransform tmp_tf_stamped(latest_tf_.inverse(),
1403  transform_expiration,
1405  this->tfb_->sendTransform(tmp_tf_stamped);
1406  }
1407 
1408  // Is it time to save our last pose to the param server
1409  ros::Time now = ros::Time::now();
1410  if((save_pose_period.toSec() > 0.0) &&
1412  {
1413  this->savePoseToServer();
1414  save_pose_last_time = now;
1415  }
1416  }
1417 
1418 }
1419 
1420 double
1422 {
1423  double yaw, pitch, roll;
1424  t.getBasis().getEulerYPR(yaw,pitch,roll);
1425  return yaw;
1426 }
1427 
1428 void
1429 AmclNode::initialPoseReceived(const geometry_msgs::PoseWithCovarianceStampedConstPtr& msg)
1430 {
1432 }
1433 
1434 void
1435 AmclNode::handleInitialPoseMessage(const geometry_msgs::PoseWithCovarianceStamped& msg)
1436 {
1437  boost::recursive_mutex::scoped_lock prl(configuration_mutex_);
1438  if(msg.header.frame_id == "")
1439  {
1440  // This should be removed at some point
1441  ROS_WARN("Received initial pose with empty frame_id. You should always supply a frame_id.");
1442  }
1443  // We only accept initial pose estimates in the global frame, #5148.
1444  else if(tf_->resolve(msg.header.frame_id) != tf_->resolve(global_frame_id_))
1445  {
1446  ROS_WARN("Ignoring initial pose in frame \"%s\"; initial poses must be in the global frame, \"%s\"",
1447  msg.header.frame_id.c_str(),
1448  global_frame_id_.c_str());
1449  return;
1450  }
1451 
1452  // In case the client sent us a pose estimate in the past, integrate the
1453  // intervening odometric change.
1454  tf::StampedTransform tx_odom;
1455  try
1456  {
1457  ros::Time now = ros::Time::now();
1458  // wait a little for the latest tf to become available
1459  tf_->waitForTransform(base_frame_id_, msg.header.stamp,
1460  base_frame_id_, now,
1462  tf_->lookupTransform(base_frame_id_, msg.header.stamp,
1463  base_frame_id_, now,
1464  odom_frame_id_, tx_odom);
1465  }
1466  catch(tf::TransformException e)
1467  {
1468  // If we've never sent a transform, then this is normal, because the
1469  // global_frame_id_ frame doesn't exist. We only care about in-time
1470  // transformation for on-the-move pose-setting, so ignoring this
1471  // startup condition doesn't really cost us anything.
1473  ROS_WARN("Failed to transform initial pose in time (%s)", e.what());
1474  tx_odom.setIdentity();
1475  }
1476 
1477  tf::Pose pose_old, pose_new;
1478  tf::poseMsgToTF(msg.pose.pose, pose_old);
1479  pose_new = pose_old * tx_odom;
1480 
1481  // Transform into the global frame
1482 
1483  ROS_INFO("Setting pose (%.6f): %.3f %.3f %.3f",
1484  ros::Time::now().toSec(),
1485  pose_new.getOrigin().x(),
1486  pose_new.getOrigin().y(),
1487  getYaw(pose_new));
1488  // Re-initialize the filter
1489  pf_vector_t pf_init_pose_mean = pf_vector_zero();
1490  pf_init_pose_mean.v[0] = pose_new.getOrigin().x();
1491  pf_init_pose_mean.v[1] = pose_new.getOrigin().y();
1492  pf_init_pose_mean.v[2] = getYaw(pose_new);
1493  pf_matrix_t pf_init_pose_cov = pf_matrix_zero();
1494  // Copy in the covariance, converting from 6-D to 3-D
1495  for(int i=0; i<2; i++)
1496  {
1497  for(int j=0; j<2; j++)
1498  {
1499  pf_init_pose_cov.m[i][j] = msg.pose.covariance[6*i+j];
1500  }
1501  }
1502  pf_init_pose_cov.m[2][2] = msg.pose.covariance[6*5+5];
1503 
1504  delete initial_pose_hyp_;
1505  initial_pose_hyp_ = new amcl_hyp_t();
1506  initial_pose_hyp_->pf_pose_mean = pf_init_pose_mean;
1507  initial_pose_hyp_->pf_pose_cov = pf_init_pose_cov;
1508  applyInitialPose();
1509 }
1510 
1516 void
1518 {
1519  boost::recursive_mutex::scoped_lock cfl(configuration_mutex_);
1520  if( initial_pose_hyp_ != NULL && map_ != NULL ) {
1522  pf_init_ = false;
1523 
1524  delete initial_pose_hyp_;
1525  initial_pose_hyp_ = NULL;
1526  }
1527 }
d
ros::ServiceServer set_map_srv_
Definition: amcl_node.cpp:238
bool globalLocalizationCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: amcl_node.cpp:1008
bool tf_broadcast_
Definition: amcl_node.cpp:263
#define MAP_GXWX(map, x)
Definition: map.h:137
double beam_skip_distance_
Definition: amcl_node.cpp:257
static pf_vector_t uniformPoseGenerator(void *arg)
Definition: amcl_node.cpp:970
ros::Time last_laser_received_ts_
Definition: amcl_node.cpp:267
int min_particles_
Definition: amcl_node.cpp:251
ros::Publisher pose_pub_
Definition: amcl_node.cpp:234
double beam_skip_error_threshold_
Definition: amcl_node.cpp:257
boost::shared_ptr< AmclNode > amcl_node_ptr
Definition: amcl_node.cpp:276
static void poseMsgToTF(const geometry_msgs::Pose &msg, Pose &bt)
double pop_err
Definition: pf.h:117
bool first_map_only_
Definition: amcl_node.cpp:178
double v[3]
Definition: pf_vector.h:40
void publish(const boost::shared_ptr< M > &message) const
std::string global_frame_id_
Definition: amcl_node.cpp:175
dynamic_reconfigure::Server< amcl::AMCLConfig > * dsrv_
Definition: amcl_node.cpp:247
void applyInitialPose()
Definition: amcl_node.cpp:1517
void open(std::string const &filename, uint32_t mode=bagmode::Read)
ros::Subscriber initial_pose_sub_
Definition: amcl_node.cpp:193
std::map< std::string, int > frame_to_laser_
Definition: amcl_node.cpp:196
Definition: pf.h:111
#define MAP_VALID(map, i, j)
Definition: map.h:141
map_cell_t * cells
Definition: map.h:73
double pf_err_
Definition: amcl_node.cpp:200
bool setTransform(const geometry_msgs::TransformStamped &transform, const std::string &authority, bool is_static=false)
ros::Publisher particlecloud_pub_
Definition: amcl_node.cpp:235
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
double laser_max_range_
Definition: amcl_node.cpp:207
pf_vector_t(* pf_init_model_fn_t)(void *init_data)
Definition: pf.h:45
int resample_count_
Definition: amcl_node.cpp:205
void getEulerYPR(tfScalar &yaw, tfScalar &pitch, tfScalar &roll, unsigned int solution_number=1) const
TFSIMD_FORCE_INLINE Matrix3x3 & getBasis()
void add(const MEvent &evt)
static double getYaw(const Quaternion &bt_q)
Definition: map.h:46
void checkLaserReceived(const ros::TimerEvent &event)
Definition: amcl_node.cpp:755
bool call(const std::string &service_name, MReq &req, MRes &res)
std::string base_frame_id_
Definition: amcl_node.cpp:174
bool sleep() const
static double normalize(double z)
Definition: amcl_node.cpp:88
void mapReceived(const nav_msgs::OccupancyGridConstPtr &msg)
Definition: amcl_node.cpp:785
pf_vector_t pf_vector_zero()
Definition: pf_vector.c:38
double beam_skip_threshold_
Definition: amcl_node.cpp:257
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
pf_t * pf_alloc(int min_samples, int max_samples, double alpha_slow, double alpha_fast, pf_init_model_fn_t random_pose_fn, void *random_pose_data)
Definition: pf.c:45
tf::TransformBroadcaster * tfb_
Definition: amcl_node.cpp:125
int size_y
Definition: map.h:70
int max_particles_
Definition: amcl_node.cpp:251
laser_model_t
Definition: amcl_laser.h:38
#define MAP_INDEX(map, i, j)
Definition: map.h:144
double origin_x
Definition: map.h:64
double z_max_
Definition: amcl_node.cpp:254
double alpha4_
Definition: amcl_node.cpp:252
ROSCPP_DECL std::string resolve(const std::string &name, bool remap=true)
double z_short_
Definition: amcl_node.cpp:254
ros::Time last_cloud_pub_time
Definition: amcl_node.cpp:216
#define MAP_WXGX(map, i)
Definition: map.h:133
int resample_interval_
Definition: amcl_node.cpp:204
void updatePoseFromServer()
Definition: amcl_node.cpp:712
int main(int argc, char **argv)
Definition: amcl_node.cpp:286
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
double scale
Definition: map.h:67
std::string resolve(const std::string &frame_name)
#define MAP_GYWY(map, y)
Definition: map.h:138
void sigintHandler(int sig)
Definition: amcl_node.cpp:278
void SetModelBeam(double z_hit, double z_short, double z_max, double z_rand, double sigma_hit, double labda_short, double chi_outlier)
Definition: amcl_laser.cpp:65
virtual bool UpdateAction(pf_t *pf, AMCLSensorData *data)
Definition: amcl_odom.cpp:113
odom_model_t odom_model_type_
Definition: amcl_node.cpp:259
#define ROS_WARN(...)
void savePoseToServer()
Definition: amcl_node.cpp:690
void runFromBag(const std::string &in_bag_fn)
Uses TF and LaserScan messages from bag file to drive AMCL instead.
Definition: amcl_node.cpp:603
static tf::Quaternion createIdentityQuaternion()
void close()
double alpha3_
Definition: amcl_node.cpp:252
#define MAP_WYGY(map, j)
Definition: map.h:134
TransformListenerWrapper * tf_
Definition: amcl_node.cpp:133
double alpha1_
Definition: amcl_node.cpp:252
int size_x
Definition: map.h:70
double init_pose_[3]
Definition: amcl_node.cpp:260
tf::MessageFilter< sensor_msgs::LaserScan > * laser_scan_filter_
Definition: amcl_node.cpp:192
ROSCPP_DECL void spin(Spinner &spinner)
void SetModel(odom_model_t type, double alpha1, double alpha2, double alpha3, double alpha4, double alpha5=0)
Definition: amcl_odom.cpp:96
void setIdentity()
void pf_init(pf_t *pf, pf_vector_t mean, pf_matrix_t cov)
Definition: pf.c:130
void update(const std::string &key, const XmlRpc::XmlRpcValue &v)
std::vector< AMCLLaser * > lasers_
Definition: amcl_node.cpp:194
int pf_get_cluster_stats(pf_t *pf, int cluster, double *weight, pf_vector_t *mean, pf_matrix_t *cov)
Definition: pf.c:641
bool waitForTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration &timeout, const ros::Duration &polling_sleep_duration=ros::Duration(0.01), std::string *error_msg=NULL) const
ROSCPP_DECL CallbackQueue * getGlobalCallbackQueue()
TFSIMD_FORCE_INLINE const tfScalar & x() const
pf_vector_t pf_pose_mean
Definition: amcl_node.cpp:80
AMCLLaser * laser_
Definition: amcl_node.cpp:213
ros::Subscriber initial_pose_sub_old_
Definition: amcl_node.cpp:239
ROSCPP_DECL void set(const std::string &key, const XmlRpc::XmlRpcValue &v)
double origin_y
Definition: map.h:64
ros::ServiceServer nomotion_update_srv_
Definition: amcl_node.cpp:237
double getYaw(tf::Pose &t)
Definition: amcl_node.cpp:1421
int occ_state
Definition: map.h:49
std::string odom_frame_id_
Definition: amcl_node.cpp:168
void transformQuaternion(const std::string &target_frame, const geometry_msgs::QuaternionStamped &stamped_in, geometry_msgs::QuaternionStamped &stamped_out) const
bool sleep() const
double z_hit_
Definition: amcl_node.cpp:254
double pop_z
Definition: pf.h:117
bool first_reconfigure_call_
Definition: amcl_node.cpp:244
static Quaternion createQuaternionFromYaw(double yaw)
Definition: map.h:61
bool getOdomPose(tf::Stamped< tf::Pose > &pose, double &x, double &y, double &yaw, const ros::Time &t, const std::string &f)
Definition: amcl_node.cpp:944
void requestMap()
Definition: amcl_node.cpp:767
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)
Duration & fromSec(double t)
void handleMapMessage(const nav_msgs::OccupancyGrid &msg)
Definition: amcl_node.cpp:797
int current_set
Definition: pf.h:121
std::vector< bool > lasers_update_
Definition: amcl_node.cpp:195
double alpha2_
Definition: amcl_node.cpp:252
AMCLSensor * sensor
Definition: amcl_sensor.h:88
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
double alpha5_
Definition: amcl_node.cpp:252
static double angle_diff(double a, double b)
Definition: amcl_node.cpp:93
static std::vector< std::pair< int, int > > free_space_indices
Definition: amcl_node.cpp:144
double m[3][3]
Definition: pf_vector.h:47
ros::Duration cloud_pub_interval
Definition: amcl_node.cpp:215
static void quaternionTFToMsg(const Quaternion &bt, geometry_msgs::Quaternion &msg)
boost::shared_ptr< T > instantiate() const
double(* ranges)[2]
Definition: amcl_laser.h:54
double sigma_hit_
Definition: amcl_node.cpp:254
pf_matrix_t pf_matrix_zero()
Definition: pf_vector.c:134
ROSCPP_DECL bool ok()
TFSIMD_FORCE_INLINE const tfScalar & y() const
pf_matrix_t pf_pose_cov
Definition: amcl_node.cpp:83
void sendTransform(const StampedTransform &transform)
void laserReceived(const sensor_msgs::LaserScanConstPtr &laser_scan)
Definition: amcl_node.cpp:1044
ros::Subscriber map_sub_
Definition: amcl_node.cpp:240
bool m_force_update
Definition: amcl_node.cpp:210
AMCLOdom * odom_
Definition: amcl_node.cpp:212
amcl_hyp_t * initial_pose_hyp_
Definition: amcl_node.cpp:242
pf_vector_t pose
Definition: amcl_odom.h:50
ros::Duration transform_tolerance_
Definition: amcl_node.cpp:230
ros::Time save_pose_last_time
Definition: amcl_node.cpp:181
double getYaw(const tf2::Quaternion &q)
Transform inverse() const
map_t * convertMap(const nav_msgs::OccupancyGrid &map_msg)
Definition: amcl_node.cpp:906
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void SetModelLikelihoodField(double z_hit, double z_rand, double sigma_hit, double max_occ_dist)
Definition: amcl_laser.cpp:84
bool sent_first_transform_
Definition: amcl_node.cpp:135
void pf_init_model(pf_t *pf, pf_init_model_fn_t init_fn, void *init_data)
Definition: pf.c:172
ros::WallDuration bag_scan_period_
Definition: amcl_node.cpp:219
static const std::string scan_topic_
Definition: amcl_node.cpp:108
#define ROS_WARN_STREAM(args)
tf::Transform latest_tf_
Definition: amcl_node.cpp:137
bool first_map_received_
Definition: amcl_node.cpp:243
TFSIMD_FORCE_INLINE Vector3 & getOrigin()
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
double alpha_slow_
Definition: amcl_node.cpp:253
map_t * map_
Definition: amcl_node.cpp:186
ros::NodeHandle nh_
Definition: amcl_node.cpp:232
ros::ServiceServer global_loc_srv_
Definition: amcl_node.cpp:236
char * mapdata
Definition: amcl_node.cpp:187
ros::Timer check_laser_timer_
Definition: amcl_node.cpp:249
geometry_msgs::PoseWithCovarianceStamped last_published_pose
Definition: amcl_node.cpp:184
bool use_map_topic_
Definition: amcl_node.cpp:177
double lambda_short_
Definition: amcl_node.cpp:254
boost::recursive_mutex configuration_mutex_
Definition: amcl_node.cpp:246
static void poseTFToMsg(const Pose &bt, geometry_msgs::Pose &msg)
void subscribe(ros::NodeHandle &nh, const std::string &topic, uint32_t queue_size, const ros::TransportHints &transport_hints=ros::TransportHints(), ros::CallbackQueueInterface *callback_queue=0)
static WallTime now()
void pf_update_resample(pf_t *pf)
Definition: pf.c:312
void map_free(map_t *map)
Definition: map.c:61
void transformPose(const std::string &target_frame, const geometry_msgs::PoseStamped &stamped_in, geometry_msgs::PoseStamped &stamped_out) const
pf_t * pf_
Definition: amcl_node.cpp:199
void freeMapDependentMemory()
Definition: amcl_node.cpp:885
ros::Duration gui_publish_period
Definition: amcl_node.cpp:180
std::string const & getTopic() const
laser_model_t laser_model_type_
Definition: amcl_node.cpp:262
amcl::AMCLConfig default_config_
Definition: amcl_node.cpp:248
ros::Duration save_pose_period
Definition: amcl_node.cpp:182
double weight
Definition: amcl_node.cpp:77
bool nomotionUpdateCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
Definition: amcl_node.cpp:1025
odom_model_t
Definition: amcl_odom.h:38
static Time now()
bool do_beamskip_
Definition: amcl_node.cpp:256
double d_thresh_
Definition: amcl_node.cpp:203
ROSCPP_DECL void shutdown()
void reconfigureCB(amcl::AMCLConfig &config, uint32_t level)
Definition: amcl_node.cpp:458
double pf_z_
Definition: amcl_node.cpp:200
ros::NodeHandle private_nh_
Definition: amcl_node.cpp:233
map_t * map_alloc(void)
Definition: map.c:38
bool pf_init_
Definition: amcl_node.cpp:201
message_filters::Subscriber< sensor_msgs::LaserScan > * laser_scan_sub_
Definition: amcl_node.cpp:191
void handleInitialPoseMessage(const geometry_msgs::PoseWithCovarianceStamped &msg)
Definition: amcl_node.cpp:1435
#define ROS_ASSERT(cond)
pf_sample_set_t sets[2]
Definition: pf.h:122
void pf_free(pf_t *pf)
Definition: pf.c:114
bool latest_tf_valid_
Definition: amcl_node.cpp:138
ros::Duration laser_check_interval_
Definition: amcl_node.cpp:268
int cluster_count
Definition: pf.h:100
tf::Stamped< tf::Pose > latest_odom_pose_
Definition: amcl_node.cpp:171
double resolution
Definition: amcl_node.cpp:189
#define ROS_ERROR(...)
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
void SetModelLikelihoodFieldProb(double z_hit, double z_rand, double sigma_hit, double max_occ_dist, bool do_beamskip, double beam_skip_distance, double beam_skip_threshold, double beam_skip_error_threshold)
Definition: amcl_laser.cpp:98
double laser_min_range_
Definition: amcl_node.cpp:206
double laser_likelihood_max_dist_
Definition: amcl_node.cpp:258
pf_vector_t delta
Definition: amcl_odom.h:53
pf_vector_t pf_odom_pose_
Definition: amcl_node.cpp:202
double alpha_fast_
Definition: amcl_node.cpp:253
int max_beams_
Definition: amcl_node.cpp:251
bool setMapCallback(nav_msgs::SetMap::Request &req, nav_msgs::SetMap::Response &res)
Definition: amcl_node.cpp:1034
double a_thresh_
Definition: amcl_node.cpp:203
void initialPoseReceived(const geometry_msgs::PoseWithCovarianceStampedConstPtr &msg)
Definition: amcl_node.cpp:1429
double init_cov_[3]
Definition: amcl_node.cpp:261
Connection registerCallback(const C &callback)
#define ROS_DEBUG(...)
double z_rand_
Definition: amcl_node.cpp:254


amcl
Author(s): Brian P. Gerkey, contradict@gmail.com
autogenerated on Sun Mar 3 2019 03:44:09