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


amcl
Author(s): Brian P. Gerkey, contradict@gmail.com
autogenerated on Mon Mar 6 2023 03:50:13