| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -48,6 +48,7 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "cartographer_ros_msgs/TrajectorySubmapList.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "geometry_msgs/Transform.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "geometry_msgs/TransformStamped.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "gflags/gflags.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "glog/log_severity.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "glog/logging.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "pcl/point_cloud.h"
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -67,6 +68,14 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "node_constants.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include "time_conversion.h"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				DEFINE_string(configuration_directory, "",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              "First directory in which configuration files are searched, "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              "second is always the Cartographer installation to allow "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              "including files from there.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				DEFINE_string(configuration_basename, "",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              "Basename, i.e. not containing any directory prefix, of the "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              "configuration file.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				namespace cartographer_ros {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				namespace {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -80,6 +89,12 @@ constexpr int kSubmapPublishPeriodInUts = 300 * 10000ll;  // 300 milliseconds
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr int kPosePublishPeriodInUts = 5 * 10000ll;      // 5 milliseconds
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr double kMaxTransformDelaySeconds = 0.01;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Unique default topic names. Expected to be remapped as needed.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr char kLaserScanTopic[] = "/scan";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr char kMultiEchoLaserScanTopic[] = "/echoes";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr char kPointCloud2Topic[] = "/points2";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr char kImuTopic[] = "/imu";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				Rigid3d ToRigid3d(const geometry_msgs::TransformStamped& transform) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return Rigid3d(Eigen::Vector3d(transform.transform.translation.x,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                 transform.transform.translation.y,
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -153,7 +168,7 @@ class Node {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                        std::unique_ptr<SensorData> sensor_data);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  void ImuMessageCallback(const sensor_msgs::Imu::ConstPtr& msg);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  void LaserScanMessageCallback(const sensor_msgs::LaserScan::ConstPtr& msg);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  void MultiEchoLaserScanCallback(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  void MultiEchoLaserScanMessageCallback(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      const sensor_msgs::MultiEchoLaserScan::ConstPtr& msg);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  void PointCloud2MessageCallback(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      const string& topic, const sensor_msgs::PointCloud2::ConstPtr& msg);
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -163,9 +178,6 @@ class Node {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  void AddLaserFan3D(int64 timestamp, const string& frame_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                     const proto::LaserFan3D& laser_fan_3d);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  template <typename T>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const T GetParamOrDie(const string& name);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Returns a transform for 'frame_id' to 'tracking_frame_' if it exists at
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // 'time' or throws tf2::TransformException if it does not exist.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  Rigid3d LookupToTrackingTransformOrThrow(::cartographer::common::Time time,
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -183,15 +195,15 @@ class Node {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ::cartographer::mapping::SensorCollator<SensorData> sensor_collator_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ros::NodeHandle node_handle_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ros::Subscriber imu_subscriber_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ros::Subscriber laser_2d_subscriber_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  std::vector<ros::Subscriber> laser_3d_subscribers_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ros::Subscriber laser_subscriber_2d_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  std::vector<ros::Subscriber> laser_subscribers_3d_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  string tracking_frame_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  string odom_frame_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  string map_frame_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  bool provide_odom_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  double laser_min_range_m_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  double laser_max_range_m_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  double laser_missing_echo_ray_length_m_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  double laser_min_range_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  double laser_max_range_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  double laser_missing_echo_ray_length_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  tf2_ros::Buffer tf_buffer_;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  tf2_ros::TransformListener tf_;
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -231,7 +243,7 @@ void Node::ImuMessageCallback(const sensor_msgs::Imu::ConstPtr& msg) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  sensor_collator_.AddSensorData(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      kTrajectoryId,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ::cartographer::common::ToUniversal(FromRos(msg->header.stamp)),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      imu_subscriber_.getTopic(), std::move(sensor_data));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      kImuTopic, std::move(sensor_data));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Node::AddImu(const int64 timestamp, const string& frame_id,
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -242,10 +254,9 @@ void Node::AddImu(const int64 timestamp, const string& frame_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const Rigid3d sensor_to_tracking =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        LookupToTrackingTransformOrThrow(time, frame_id);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CHECK(sensor_to_tracking.translation().norm() < 1e-5)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        << "The IMU is not colocated with the tracking frame. This makes it "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				           "hard "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				           "and inprecise to transform its linear accelaration into the "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				           "tracking_frame and will decrease the quality of the SLAM.";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        << "The IMU frame must be colocated with the tracking frame. "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				           "Transforming linear accelaration into the tracking frame will "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				           "otherwise be imprecise.";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    trajectory_builder_->AddImuData(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        time, sensor_to_tracking.rotation() *
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                  ::cartographer::transform::ToEigen(imu.linear_acceleration()),
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -264,7 +275,7 @@ void Node::LaserScanMessageCallback(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  sensor_collator_.AddSensorData(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      kTrajectoryId,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ::cartographer::common::ToUniversal(FromRos(msg->header.stamp)),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      laser_2d_subscriber_.getTopic(), std::move(sensor_data));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      kLaserScanTopic, std::move(sensor_data));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Node::AddHorizontalLaserFan(const int64 timestamp, const string& frame_id,
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -274,11 +285,10 @@ void Node::AddHorizontalLaserFan(const int64 timestamp, const string& frame_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  try {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const Rigid3d sensor_to_tracking =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        LookupToTrackingTransformOrThrow(time, frame_id);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(hrapp): Make things configurable? Through Lua? Through ROS params?
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const ::cartographer::sensor::LaserFan laser_fan =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ::cartographer::sensor::ToLaserFan(laser_scan, laser_min_range_m_,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                           laser_max_range_m_,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                           laser_missing_echo_ray_length_m_);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ::cartographer::sensor::ToLaserFan(laser_scan, laser_min_range_,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                           laser_max_range_,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                           laser_missing_echo_ray_length_);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const auto laser_fan_3d = ::cartographer::sensor::TransformLaserFan3D(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ::cartographer::sensor::ToLaserFan3D(laser_fan),
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -290,14 +300,14 @@ void Node::AddHorizontalLaserFan(const int64 timestamp, const string& frame_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Node::MultiEchoLaserScanCallback(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Node::MultiEchoLaserScanMessageCallback(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const sensor_msgs::MultiEchoLaserScan::ConstPtr& msg) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  auto sensor_data = ::cartographer::common::make_unique<SensorData>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      msg->header.frame_id, ToCartographer(*msg));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  sensor_collator_.AddSensorData(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      kTrajectoryId,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ::cartographer::common::ToUniversal(FromRos(msg->header.stamp)),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      laser_2d_subscriber_.getTopic(), std::move(sensor_data));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      kMultiEchoLaserScanTopic, std::move(sensor_data));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Node::PointCloud2MessageCallback(
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -330,61 +340,59 @@ void Node::AddLaserFan3D(const int64 timestamp, const string& frame_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				template <typename T>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const T Node::GetParamOrDie(const string& name) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  CHECK(node_handle_.hasParam(name)) << "Required parameter '" << name
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                     << "' is unset.";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  T value;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  node_handle_.getParam(name, value);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return value;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void Node::Initialize() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  tracking_frame_ = GetParamOrDie<string>("tracking_frame");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  odom_frame_ = GetParamOrDie<string>("odom_frame");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  map_frame_ = GetParamOrDie<string>("map_frame");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  provide_odom_ = GetParamOrDie<bool>("provide_odom");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  laser_min_range_m_ = GetParamOrDie<double>("laser_min_range_m");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  laser_max_range_m_ = GetParamOrDie<double>("laser_max_range_m");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  laser_missing_echo_ray_length_m_ =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      GetParamOrDie<double>("laser_missing_echo_ray_length_m");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  auto file_resolver = ::cartographer::common::make_unique<
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ::cartographer::common::ConfigurationFileResolver>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      std::vector<string>{FLAGS_configuration_directory});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const string code =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      file_resolver->GetFileContentOrDie(FLAGS_configuration_basename);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ::cartographer::common::LuaParameterDictionary lua_parameter_dictionary(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      code, std::move(file_resolver), nullptr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  tracking_frame_ = lua_parameter_dictionary.GetString("tracking_frame");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  odom_frame_ = lua_parameter_dictionary.GetString("odom_frame");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  map_frame_ = lua_parameter_dictionary.GetString("map_frame");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  provide_odom_ = lua_parameter_dictionary.GetBool("provide_odom");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  laser_min_range_ = lua_parameter_dictionary.GetDouble("laser_min_range");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  laser_max_range_ = lua_parameter_dictionary.GetDouble("laser_max_range");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  laser_missing_echo_ray_length_ =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      lua_parameter_dictionary.GetDouble("laser_missing_echo_ray_length");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Set of all topics we subscribe to. We use the non-remapped default names
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // which are unique.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  std::unordered_set<string> expected_sensor_identifiers;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Subscribe to exactly one laser.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const bool has_laser_scan_2d = node_handle_.hasParam("laser_scan_2d_topic");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const bool has_laser_scan_2d =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      lua_parameter_dictionary.HasKey("use_laser_scan_2d") &&
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      lua_parameter_dictionary.GetBool("use_laser_scan_2d");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const bool has_multi_echo_laser_scan_2d =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      node_handle_.hasParam("multi_echo_laser_scan_2d_topic");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const bool has_laser_scan_3d = node_handle_.hasParam("laser_scan_3d_topics");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      lua_parameter_dictionary.HasKey("use_multi_echo_laser_scan_2d") &&
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      lua_parameter_dictionary.GetBool("use_multi_echo_laser_scan_2d");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const int num_lasers_3d =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      lua_parameter_dictionary.HasKey("num_lasers_3d")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          ? lua_parameter_dictionary.GetNonNegativeInt("num_lasers_3d")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          : 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  CHECK(has_laser_scan_2d + has_multi_echo_laser_scan_2d + has_laser_scan_3d ==
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  CHECK(has_laser_scan_2d + has_multi_echo_laser_scan_2d +
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            (num_lasers_3d > 0) ==
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        1)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      << "Parameters 'laser_scan_2d_topic', 'multi_echo_laser_scan_2d_topic' "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				         "and 'laser_scan_3d_topics' are mutually exclusive, but one is "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				         "required.";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      << "Parameters 'use_laser_scan_2d', 'use_multi_echo_laser_scan_2d' and "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				         "'num_lasers_3d' are mutually exclusive, but one is required.";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (has_laser_scan_2d) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const string topic = GetParamOrDie<string>("laser_scan_2d_topic");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    laser_2d_subscriber_ = node_handle_.subscribe(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        topic, kSubscriberQueueSize, &Node::LaserScanMessageCallback, this);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    expected_sensor_identifiers.insert(topic);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    laser_subscriber_2d_ =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        node_handle_.subscribe(kLaserScanTopic, kSubscriberQueueSize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                               &Node::LaserScanMessageCallback, this);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    expected_sensor_identifiers.insert(kLaserScanTopic);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (has_multi_echo_laser_scan_2d) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const string topic =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        GetParamOrDie<string>("multi_echo_laser_scan_2d_topic");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    laser_2d_subscriber_ = node_handle_.subscribe(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        topic, kSubscriberQueueSize, &Node::MultiEchoLaserScanCallback, this);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    expected_sensor_identifiers.insert(topic);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    laser_subscriber_2d_ =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        node_handle_.subscribe(kMultiEchoLaserScanTopic, kSubscriberQueueSize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                               &Node::MultiEchoLaserScanMessageCallback, this);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    expected_sensor_identifiers.insert(kMultiEchoLaserScanTopic);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  auto file_resolver = ::cartographer::common::make_unique<
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      ::cartographer::common::ConfigurationFileResolver>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      GetParamOrDie<std::vector<string>>("configuration_files_directories"));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  const string code = file_resolver->GetFileContentOrDie(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      GetParamOrDie<string>("mapping_configuration_basename"));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ::cartographer::common::LuaParameterDictionary lua_parameter_dictionary(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      code, std::move(file_resolver), nullptr);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  bool expect_imu_data = true;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (has_laser_scan_2d || has_multi_echo_laser_scan_2d) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    auto sparse_pose_graph_2d = ::cartographer::common::make_unique<
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -402,11 +410,13 @@ void Node::Initialize() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    sparse_pose_graph_ = std::move(sparse_pose_graph_2d);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (has_laser_scan_3d) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const auto topics =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        GetParamOrDie<std::vector<string>>("laser_scan_3d_topics");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for (const auto& topic : topics) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      laser_3d_subscribers_.push_back(node_handle_.subscribe(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (num_lasers_3d > 0) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for (int i = 0; i < num_lasers_3d; ++i) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      string topic = kPointCloud2Topic;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if (num_lasers_3d > 1) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        topic += "_" + std::to_string(i + 1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      laser_subscribers_3d_.push_back(node_handle_.subscribe(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          topic, kSubscriberQueueSize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          boost::function<void(const sensor_msgs::PointCloud2::ConstPtr&)>(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              [this, topic](const sensor_msgs::PointCloud2::ConstPtr& msg) {
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -430,10 +440,9 @@ void Node::Initialize() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // Maybe subscribe to the IMU.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  if (expect_imu_data) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    const string imu_topic = GetParamOrDie<string>("imu_topic");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    imu_subscriber_ = node_handle_.subscribe(imu_topic, kSubscriberQueueSize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    imu_subscriber_ = node_handle_.subscribe(kImuTopic, kSubscriberQueueSize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                             &Node::ImuMessageCallback, this);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    expected_sensor_identifiers.insert(imu_topic);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    expected_sensor_identifiers.insert(kImuTopic);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  // TODO(hrapp): Add odometry subscribers here.
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@ -656,6 +665,12 @@ class ScopedRosLogSink : public google::LogSink {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				int main(int argc, char** argv) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  google::InitGoogleLogging(argv[0]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  google::ParseCommandLineFlags(&argc, &argv, true);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  CHECK(!FLAGS_configuration_directory.empty())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      << "-configuration_directory is missing.";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  CHECK(!FLAGS_configuration_basename.empty())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      << "-configuration_basename is missing.";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ros::init(argc, argv, "cartographer_node");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  ros::start();
 | 
			
		
		
	
	
		
			
				
					| 
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |