node.cc
Go to the documentation of this file.
1 /*
2  * Copyright 2016 The Cartographer Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "cartographer_ros/node.h"
18 
19 #include <chrono>
20 #include <string>
21 #include <vector>
22 
23 #include "Eigen/Core"
29 #include "cartographer/mapping/proto/submap_visualization.pb.h"
37 #include "cartographer_ros_msgs/StatusCode.h"
38 #include "cartographer_ros_msgs/StatusResponse.h"
39 #include "glog/logging.h"
40 #include "nav_msgs/Odometry.h"
41 #include "ros/serialization.h"
42 #include "sensor_msgs/PointCloud2.h"
43 #include "tf2_eigen/tf2_eigen.h"
44 #include "visualization_msgs/MarkerArray.h"
45 
46 namespace cartographer_ros {
47 
48 namespace {
49 
50 cartographer_ros_msgs::SensorTopics DefaultSensorTopics() {
51  cartographer_ros_msgs::SensorTopics topics;
52  topics.laser_scan_topic = kLaserScanTopic;
53  topics.multi_echo_laser_scan_topic = kMultiEchoLaserScanTopic;
54  topics.point_cloud2_topic = kPointCloud2Topic;
55  topics.imu_topic = kImuTopic;
56  topics.odometry_topic = kOdometryTopic;
57  topics.nav_sat_fix_topic = kNavSatFixTopic;
58  topics.landmark_topic = kLandmarkTopic;
59  return topics;
60 }
61 
62 // Subscribes to the 'topic' for 'trajectory_id' using the 'node_handle' and
63 // calls 'handler' on the 'node' to handle messages. Returns the subscriber.
64 template <typename MessageType>
65 ::ros::Subscriber SubscribeWithHandler(
66  void (Node::*handler)(int, const std::string&,
67  const typename MessageType::ConstPtr&),
68  const int trajectory_id, const std::string& topic,
69  ::ros::NodeHandle* const node_handle, Node* const node) {
70  return node_handle->subscribe<MessageType>(
72  boost::function<void(const typename MessageType::ConstPtr&)>(
73  [node, handler, trajectory_id,
74  topic](const typename MessageType::ConstPtr& msg) {
75  (node->*handler)(trajectory_id, topic, msg);
76  }));
77 }
78 
79 } // namespace
80 
81 namespace carto = ::cartographer;
82 
83 using carto::transform::Rigid3d;
84 
86  const NodeOptions& node_options,
87  std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
88  tf2_ros::Buffer* const tf_buffer)
89  : node_options_(node_options),
90  map_builder_bridge_(node_options_, std::move(map_builder), tf_buffer) {
91  carto::common::MutexLocker lock(&mutex_);
93  node_handle_.advertise<::cartographer_ros_msgs::SubmapList>(
96  node_handle_.advertise<::visualization_msgs::MarkerArray>(
99  node_handle_.advertise<::visualization_msgs::MarkerArray>(
102  node_handle_.advertise<::visualization_msgs::MarkerArray>(
112 
114  node_handle_.advertise<sensor_msgs::PointCloud2>(
116 
119  &Node::PublishSubmapList, this));
132 }
133 
135 
137 
139  ::cartographer_ros_msgs::SubmapQuery::Request& request,
140  ::cartographer_ros_msgs::SubmapQuery::Response& response) {
141  carto::common::MutexLocker lock(&mutex_);
142  map_builder_bridge_.HandleSubmapQuery(request, response);
143  return true;
144 }
145 
146 void Node::PublishSubmapList(const ::ros::WallTimerEvent& unused_timer_event) {
147  carto::common::MutexLocker lock(&mutex_);
148  submap_list_publisher_.publish(map_builder_bridge_.GetSubmapList());
149 }
150 
151 void Node::AddExtrapolator(const int trajectory_id,
152  const TrajectoryOptions& options) {
153  constexpr double kExtrapolationEstimationTimeSec = 0.001; // 1 ms
154  CHECK(extrapolators_.count(trajectory_id) == 0);
155  const double gravity_time_constant =
156  node_options_.map_builder_options.use_trajectory_builder_3d()
157  ? options.trajectory_builder_options.trajectory_builder_3d_options()
158  .imu_gravity_time_constant()
159  : options.trajectory_builder_options.trajectory_builder_2d_options()
160  .imu_gravity_time_constant();
161  extrapolators_.emplace(
162  std::piecewise_construct, std::forward_as_tuple(trajectory_id),
163  std::forward_as_tuple(
164  ::cartographer::common::FromSeconds(kExtrapolationEstimationTimeSec),
165  gravity_time_constant));
166 }
167 
168 void Node::AddSensorSamplers(const int trajectory_id,
169  const TrajectoryOptions& options) {
170  CHECK(sensor_samplers_.count(trajectory_id) == 0);
171  sensor_samplers_.emplace(
172  std::piecewise_construct, std::forward_as_tuple(trajectory_id),
173  std::forward_as_tuple(
176  options.landmarks_sampling_ratio));
177 }
178 
179 void Node::PublishTrajectoryStates(const ::ros::WallTimerEvent& timer_event) {
180  carto::common::MutexLocker lock(&mutex_);
181  for (const auto& entry : map_builder_bridge_.GetTrajectoryStates()) {
182  const auto& trajectory_state = entry.second;
183 
184  auto& extrapolator = extrapolators_.at(entry.first);
185  // We only publish a point cloud if it has changed. It is not needed at high
186  // frequency, and republishing it would be computationally wasteful.
187  if (trajectory_state.local_slam_data->time !=
188  extrapolator.GetLastPoseTime()) {
190  // TODO(gaschler): Consider using other message without time
191  // information.
192  carto::sensor::TimedPointCloud point_cloud;
193  point_cloud.reserve(trajectory_state.local_slam_data
194  ->range_data_in_local.returns.size());
195  for (const Eigen::Vector3f point :
196  trajectory_state.local_slam_data->range_data_in_local.returns) {
197  Eigen::Vector4f point_time;
198  point_time << point, 0.f;
199  point_cloud.push_back(point_time);
200  }
202  carto::common::ToUniversal(trajectory_state.local_slam_data->time),
204  carto::sensor::TransformTimedPointCloud(
205  point_cloud, trajectory_state.local_to_map.cast<float>())));
206  }
207  extrapolator.AddPose(trajectory_state.local_slam_data->time,
208  trajectory_state.local_slam_data->local_pose);
209  }
210 
211  geometry_msgs::TransformStamped stamped_transform;
212  // If we do not publish a new point cloud, we still allow time of the
213  // published poses to advance. If we already know a newer pose, we use its
214  // time instead. Since tf knows how to interpolate, providing newer
215  // information is better.
216  const ::cartographer::common::Time now = std::max(
217  FromRos(ros::Time::now()), extrapolator.GetLastExtrapolatedTime());
218  stamped_transform.header.stamp = ToRos(now);
219 
220  const Rigid3d tracking_to_local = [&] {
221  if (trajectory_state.trajectory_options.publish_frame_projected_to_2d) {
222  return carto::transform::Embed3D(
223  carto::transform::Project2D(extrapolator.ExtrapolatePose(now)));
224  }
225  return extrapolator.ExtrapolatePose(now);
226  }();
227 
228  const Rigid3d tracking_to_map =
229  trajectory_state.local_to_map * tracking_to_local;
230 
231  if (trajectory_state.published_to_tracking != nullptr) {
232  if (trajectory_state.trajectory_options.provide_odom_frame) {
233  std::vector<geometry_msgs::TransformStamped> stamped_transforms;
234 
235  stamped_transform.header.frame_id = node_options_.map_frame;
236  stamped_transform.child_frame_id =
237  trajectory_state.trajectory_options.odom_frame;
238  stamped_transform.transform =
239  ToGeometryMsgTransform(trajectory_state.local_to_map);
240  stamped_transforms.push_back(stamped_transform);
241 
242  stamped_transform.header.frame_id =
243  trajectory_state.trajectory_options.odom_frame;
244  stamped_transform.child_frame_id =
245  trajectory_state.trajectory_options.published_frame;
246  stamped_transform.transform = ToGeometryMsgTransform(
247  tracking_to_local * (*trajectory_state.published_to_tracking));
248  stamped_transforms.push_back(stamped_transform);
249 
250  tf_broadcaster_.sendTransform(stamped_transforms);
251  } else {
252  stamped_transform.header.frame_id = node_options_.map_frame;
253  stamped_transform.child_frame_id =
254  trajectory_state.trajectory_options.published_frame;
255  stamped_transform.transform = ToGeometryMsgTransform(
256  tracking_to_map * (*trajectory_state.published_to_tracking));
257  tf_broadcaster_.sendTransform(stamped_transform);
258  }
259  }
260  }
261 }
262 
264  const ::ros::WallTimerEvent& unused_timer_event) {
266  carto::common::MutexLocker lock(&mutex_);
268  map_builder_bridge_.GetTrajectoryNodeList());
269  }
270 }
271 
273  const ::ros::WallTimerEvent& unused_timer_event) {
275  carto::common::MutexLocker lock(&mutex_);
277  map_builder_bridge_.GetLandmarkPosesList());
278  }
279 }
280 
282  const ::ros::WallTimerEvent& unused_timer_event) {
284  carto::common::MutexLocker lock(&mutex_);
285  constraint_list_publisher_.publish(map_builder_bridge_.GetConstraintList());
286  }
287 }
288 
289 std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>
291  const TrajectoryOptions& options,
292  const cartographer_ros_msgs::SensorTopics& topics) const {
294  using SensorType = SensorId::SensorType;
295  std::set<SensorId> expected_topics;
296  // Subscribe to all laser scan, multi echo laser scan, and point cloud topics.
297  for (const std::string& topic : ComputeRepeatedTopicNames(
298  topics.laser_scan_topic, options.num_laser_scans)) {
299  expected_topics.insert(SensorId{SensorType::RANGE, topic});
300  }
301  for (const std::string& topic :
302  ComputeRepeatedTopicNames(topics.multi_echo_laser_scan_topic,
303  options.num_multi_echo_laser_scans)) {
304  expected_topics.insert(SensorId{SensorType::RANGE, topic});
305  }
306  for (const std::string& topic : ComputeRepeatedTopicNames(
307  topics.point_cloud2_topic, options.num_point_clouds)) {
308  expected_topics.insert(SensorId{SensorType::RANGE, topic});
309  }
310  // For 2D SLAM, subscribe to the IMU if we expect it. For 3D SLAM, the IMU is
311  // required.
312  if (node_options_.map_builder_options.use_trajectory_builder_3d() ||
313  (node_options_.map_builder_options.use_trajectory_builder_2d() &&
314  options.trajectory_builder_options.trajectory_builder_2d_options()
315  .use_imu_data())) {
316  expected_topics.insert(SensorId{SensorType::IMU, topics.imu_topic});
317  }
318  // Odometry is optional.
319  if (options.use_odometry) {
320  expected_topics.insert(
321  SensorId{SensorType::ODOMETRY, topics.odometry_topic});
322  }
323  // NavSatFix is optional.
324  if (options.use_nav_sat) {
325  expected_topics.insert(
326  SensorId{SensorType::FIXED_FRAME_POSE, topics.nav_sat_fix_topic});
327  }
328  // Landmark is optional.
329  if (options.use_landmarks) {
330  expected_topics.insert(SensorId{SensorType::LANDMARK, kLandmarkTopic});
331  }
332  return expected_topics;
333 }
334 
336  const cartographer_ros_msgs::SensorTopics& topics) {
337  const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>
338  expected_sensor_ids = ComputeExpectedSensorIds(options, topics);
339  const int trajectory_id =
340  map_builder_bridge_.AddTrajectory(expected_sensor_ids, options);
341  AddExtrapolator(trajectory_id, options);
342  AddSensorSamplers(trajectory_id, options);
343  LaunchSubscribers(options, topics, trajectory_id);
344  is_active_trajectory_[trajectory_id] = true;
345  for (const auto& sensor_id : expected_sensor_ids) {
346  subscribed_topics_.insert(sensor_id.id);
347  }
348  return trajectory_id;
349 }
350 
352  const cartographer_ros_msgs::SensorTopics& topics,
353  const int trajectory_id) {
354  for (const std::string& topic : ComputeRepeatedTopicNames(
355  topics.laser_scan_topic, options.num_laser_scans)) {
356  subscribers_[trajectory_id].push_back(
357  {SubscribeWithHandler<sensor_msgs::LaserScan>(
359  this),
360  topic});
361  }
362  for (const std::string& topic :
363  ComputeRepeatedTopicNames(topics.multi_echo_laser_scan_topic,
364  options.num_multi_echo_laser_scans)) {
365  subscribers_[trajectory_id].push_back(
366  {SubscribeWithHandler<sensor_msgs::MultiEchoLaserScan>(
368  &node_handle_, this),
369  topic});
370  }
371  for (const std::string& topic : ComputeRepeatedTopicNames(
372  topics.point_cloud2_topic, options.num_point_clouds)) {
373  subscribers_[trajectory_id].push_back(
374  {SubscribeWithHandler<sensor_msgs::PointCloud2>(
375  &Node::HandlePointCloud2Message, trajectory_id, topic,
376  &node_handle_, this),
377  topic});
378  }
379 
380  // For 2D SLAM, subscribe to the IMU if we expect it. For 3D SLAM, the IMU is
381  // required.
382  if (node_options_.map_builder_options.use_trajectory_builder_3d() ||
383  (node_options_.map_builder_options.use_trajectory_builder_2d() &&
384  options.trajectory_builder_options.trajectory_builder_2d_options()
385  .use_imu_data())) {
386  std::string topic = topics.imu_topic;
387  subscribers_[trajectory_id].push_back(
388  {SubscribeWithHandler<sensor_msgs::Imu>(&Node::HandleImuMessage,
389  trajectory_id, topic,
390  &node_handle_, this),
391  topic});
392  }
393 
394  if (options.use_odometry) {
395  std::string topic = topics.odometry_topic;
396  subscribers_[trajectory_id].push_back(
397  {SubscribeWithHandler<nav_msgs::Odometry>(&Node::HandleOdometryMessage,
398  trajectory_id, topic,
399  &node_handle_, this),
400  topic});
401  }
402  if (options.use_nav_sat) {
403  std::string topic = topics.nav_sat_fix_topic;
404  subscribers_[trajectory_id].push_back(
405  {SubscribeWithHandler<sensor_msgs::NavSatFix>(
407  this),
408  topic});
409  }
410  if (options.use_landmarks) {
411  std::string topic = topics.landmark_topic;
412  subscribers_[trajectory_id].push_back(
413  {SubscribeWithHandler<cartographer_ros_msgs::LandmarkList>(
415  this),
416  topic});
417  }
418 }
419 
421  if (node_options_.map_builder_options.use_trajectory_builder_2d()) {
422  return options.trajectory_builder_options
423  .has_trajectory_builder_2d_options();
424  }
425  if (node_options_.map_builder_options.use_trajectory_builder_3d()) {
426  return options.trajectory_builder_options
427  .has_trajectory_builder_3d_options();
428  }
429  return false;
430 }
431 
433  const ::cartographer_ros_msgs::SensorTopics& topics,
434  const TrajectoryOptions& options) {
435  for (const auto& sensor_id : ComputeExpectedSensorIds(options, topics)) {
436  const std::string& topic = sensor_id.id;
437  if (subscribed_topics_.count(topic) > 0) {
438  LOG(ERROR) << "Topic name [" << topic << "] is already used.";
439  return false;
440  }
441  }
442  return true;
443 }
444 
445 cartographer_ros_msgs::StatusResponse Node::FinishTrajectoryUnderLock(
446  const int trajectory_id) {
447  cartographer_ros_msgs::StatusResponse status_response;
448 
449  // First, check if we can actually finish the trajectory.
450  if (map_builder_bridge_.GetFrozenTrajectoryIds().count(trajectory_id)) {
451  const std::string error =
452  "Trajectory " + std::to_string(trajectory_id) + " is frozen.";
453  LOG(ERROR) << error;
454  status_response.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
455  status_response.message = error;
456  return status_response;
457  }
458  if (is_active_trajectory_.count(trajectory_id) == 0) {
459  const std::string error =
460  "Trajectory " + std::to_string(trajectory_id) + " is not created yet.";
461  LOG(ERROR) << error;
462  status_response.code = cartographer_ros_msgs::StatusCode::NOT_FOUND;
463  status_response.message = error;
464  return status_response;
465  }
466  if (!is_active_trajectory_[trajectory_id]) {
467  const std::string error = "Trajectory " + std::to_string(trajectory_id) +
468  " has already been finished.";
469  LOG(ERROR) << error;
470  status_response.code =
471  cartographer_ros_msgs::StatusCode::RESOURCE_EXHAUSTED;
472  status_response.message = error;
473  return status_response;
474  }
475 
476  // Shutdown the subscribers of this trajectory.
477  for (auto& entry : subscribers_[trajectory_id]) {
478  entry.subscriber.shutdown();
479  subscribed_topics_.erase(entry.topic);
480  LOG(INFO) << "Shutdown the subscriber of [" << entry.topic << "]";
481  }
482  CHECK_EQ(subscribers_.erase(trajectory_id), 1);
483  CHECK(is_active_trajectory_.at(trajectory_id));
484  map_builder_bridge_.FinishTrajectory(trajectory_id);
485  is_active_trajectory_[trajectory_id] = false;
486  const std::string message =
487  "Finished trajectory " + std::to_string(trajectory_id) + ".";
488  status_response.code = cartographer_ros_msgs::StatusCode::OK;
489  status_response.message = message;
490  return status_response;
491 }
492 
494  ::cartographer_ros_msgs::StartTrajectory::Request& request,
495  ::cartographer_ros_msgs::StartTrajectory::Response& response) {
496  carto::common::MutexLocker lock(&mutex_);
498  if (!FromRosMessage(request.options, &options) ||
499  !ValidateTrajectoryOptions(options)) {
500  const std::string error = "Invalid trajectory options.";
501  LOG(ERROR) << error;
502  response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
503  response.status.message = error;
504  } else if (!ValidateTopicNames(request.topics, options)) {
505  const std::string error = "Invalid topics.";
506  LOG(ERROR) << error;
507  response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
508  response.status.message = error;
509  } else {
510  response.trajectory_id = AddTrajectory(options, request.topics);
511  response.status.code = cartographer_ros_msgs::StatusCode::OK;
512  response.status.message = "Success.";
513  }
514  return true;
515 }
516 
518  carto::common::MutexLocker lock(&mutex_);
519  CHECK(ValidateTrajectoryOptions(options));
520  AddTrajectory(options, DefaultSensorTopics());
521 }
522 
523 std::vector<
524  std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>>
526  const std::vector<TrajectoryOptions>& bags_options) const {
528  std::vector<std::set<SensorId>> bags_sensor_ids;
529  for (size_t i = 0; i < bags_options.size(); ++i) {
530  std::string prefix;
531  if (bags_options.size() > 1) {
532  prefix = "bag_" + std::to_string(i + 1) + "_";
533  }
534  std::set<SensorId> unique_sensor_ids;
535  for (const auto& sensor_id :
536  ComputeExpectedSensorIds(bags_options.at(i), DefaultSensorTopics())) {
537  unique_sensor_ids.insert(SensorId{sensor_id.type, prefix + sensor_id.id});
538  }
539  bags_sensor_ids.push_back(unique_sensor_ids);
540  }
541  return bags_sensor_ids;
542 }
543 
545  const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
546  expected_sensor_ids,
547  const TrajectoryOptions& options) {
548  carto::common::MutexLocker lock(&mutex_);
549  const int trajectory_id =
550  map_builder_bridge_.AddTrajectory(expected_sensor_ids, options);
551  AddExtrapolator(trajectory_id, options);
552  AddSensorSamplers(trajectory_id, options);
553  is_active_trajectory_[trajectory_id] = true;
554  return trajectory_id;
555 }
556 
558  ::cartographer_ros_msgs::FinishTrajectory::Request& request,
559  ::cartographer_ros_msgs::FinishTrajectory::Response& response) {
560  carto::common::MutexLocker lock(&mutex_);
561  response.status = FinishTrajectoryUnderLock(request.trajectory_id);
562  return true;
563 }
564 
566  ::cartographer_ros_msgs::WriteState::Request& request,
567  ::cartographer_ros_msgs::WriteState::Response& response) {
568  carto::common::MutexLocker lock(&mutex_);
569  if (map_builder_bridge_.SerializeState(request.filename)) {
570  response.status.code = cartographer_ros_msgs::StatusCode::OK;
571  response.status.message = "State written to '" + request.filename + "'.";
572  } else {
573  response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
574  response.status.message = "Failed to write '" + request.filename + "'.";
575  }
576  return true;
577 }
578 
580  carto::common::MutexLocker lock(&mutex_);
581  for (auto& entry : is_active_trajectory_) {
582  const int trajectory_id = entry.first;
583  if (entry.second) {
584  CHECK_EQ(FinishTrajectoryUnderLock(trajectory_id).code,
585  cartographer_ros_msgs::StatusCode::OK);
586  }
587  }
588 }
589 
590 bool Node::FinishTrajectory(const int trajectory_id) {
591  carto::common::MutexLocker lock(&mutex_);
592  return FinishTrajectoryUnderLock(trajectory_id).code ==
593  cartographer_ros_msgs::StatusCode::OK;
594 }
595 
597  {
598  carto::common::MutexLocker lock(&mutex_);
599  for (const auto& entry : is_active_trajectory_) {
600  CHECK(!entry.second);
601  }
602  }
603  // Assuming we are not adding new data anymore, the final optimization
604  // can be performed without holding the mutex.
605  map_builder_bridge_.RunFinalOptimization();
606 }
607 
608 void Node::HandleOdometryMessage(const int trajectory_id,
609  const std::string& sensor_id,
610  const nav_msgs::Odometry::ConstPtr& msg) {
611  carto::common::MutexLocker lock(&mutex_);
612  if (!sensor_samplers_.at(trajectory_id).odometry_sampler.Pulse()) {
613  return;
614  }
615  auto sensor_bridge_ptr = map_builder_bridge_.sensor_bridge(trajectory_id);
616  auto odometry_data_ptr = sensor_bridge_ptr->ToOdometryData(msg);
617  if (odometry_data_ptr != nullptr) {
618  extrapolators_.at(trajectory_id).AddOdometryData(*odometry_data_ptr);
619  }
620  sensor_bridge_ptr->HandleOdometryMessage(sensor_id, msg);
621 }
622 
623 void Node::HandleNavSatFixMessage(const int trajectory_id,
624  const std::string& sensor_id,
625  const sensor_msgs::NavSatFix::ConstPtr& msg) {
626  carto::common::MutexLocker lock(&mutex_);
627  if (!sensor_samplers_.at(trajectory_id).fixed_frame_pose_sampler.Pulse()) {
628  return;
629  }
630  map_builder_bridge_.sensor_bridge(trajectory_id)
631  ->HandleNavSatFixMessage(sensor_id, msg);
632 }
633 
635  const int trajectory_id, const std::string& sensor_id,
636  const cartographer_ros_msgs::LandmarkList::ConstPtr& msg) {
637  carto::common::MutexLocker lock(&mutex_);
638  if (!sensor_samplers_.at(trajectory_id).landmark_sampler.Pulse()) {
639  return;
640  }
641  map_builder_bridge_.sensor_bridge(trajectory_id)
642  ->HandleLandmarkMessage(sensor_id, msg);
643 }
644 
645 void Node::HandleImuMessage(const int trajectory_id,
646  const std::string& sensor_id,
647  const sensor_msgs::Imu::ConstPtr& msg) {
648  carto::common::MutexLocker lock(&mutex_);
649  if (!sensor_samplers_.at(trajectory_id).imu_sampler.Pulse()) {
650  return;
651  }
652  auto sensor_bridge_ptr = map_builder_bridge_.sensor_bridge(trajectory_id);
653  auto imu_data_ptr = sensor_bridge_ptr->ToImuData(msg);
654  if (imu_data_ptr != nullptr) {
655  extrapolators_.at(trajectory_id).AddImuData(*imu_data_ptr);
656  }
657  sensor_bridge_ptr->HandleImuMessage(sensor_id, msg);
658 }
659 
660 void Node::HandleLaserScanMessage(const int trajectory_id,
661  const std::string& sensor_id,
662  const sensor_msgs::LaserScan::ConstPtr& msg) {
663  carto::common::MutexLocker lock(&mutex_);
664  if (!sensor_samplers_.at(trajectory_id).rangefinder_sampler.Pulse()) {
665  return;
666  }
667  map_builder_bridge_.sensor_bridge(trajectory_id)
668  ->HandleLaserScanMessage(sensor_id, msg);
669 }
670 
672  const int trajectory_id, const std::string& sensor_id,
673  const sensor_msgs::MultiEchoLaserScan::ConstPtr& msg) {
674  carto::common::MutexLocker lock(&mutex_);
675  if (!sensor_samplers_.at(trajectory_id).rangefinder_sampler.Pulse()) {
676  return;
677  }
678  map_builder_bridge_.sensor_bridge(trajectory_id)
679  ->HandleMultiEchoLaserScanMessage(sensor_id, msg);
680 }
681 
683  const int trajectory_id, const std::string& sensor_id,
684  const sensor_msgs::PointCloud2::ConstPtr& msg) {
685  carto::common::MutexLocker lock(&mutex_);
686  if (!sensor_samplers_.at(trajectory_id).rangefinder_sampler.Pulse()) {
687  return;
688  }
689  map_builder_bridge_.sensor_bridge(trajectory_id)
690  ->HandlePointCloud2Message(sensor_id, msg);
691 }
692 
693 void Node::SerializeState(const std::string& filename) {
694  carto::common::MutexLocker lock(&mutex_);
695  CHECK(map_builder_bridge_.SerializeState(filename))
696  << "Could not write state.";
697 }
698 
699 void Node::LoadState(const std::string& state_filename,
700  const bool load_frozen_state) {
701  carto::common::MutexLocker lock(&mutex_);
702  map_builder_bridge_.LoadState(state_filename, load_frozen_state);
703 }
704 
705 } // namespace cartographer_ros
bool FinishTrajectory(int trajectory_id)
Definition: node.cc:590
::ros::Publisher trajectory_node_list_publisher_
Definition: node.h:175
sensor_msgs::PointCloud2 ToPointCloud2Message(const int64_t timestamp, const std::string &frame_id, const ::cartographer::sensor::TimedPointCloud &point_cloud)
void SerializeState(const std::string &filename)
Definition: node.cc:693
constexpr char kLandmarkTopic[]
::cartographer::mapping::proto::MapBuilderOptions map_builder_options
Definition: node_options.h:32
std::vector<::ros::ServiceServer > service_servers_
Definition: node.h:179
void FinishAllTrajectories()
Definition: node.cc:579
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
std::vector< std::set<::cartographer::mapping::TrajectoryBuilderInterface::SensorId > > ComputeDefaultSensorIdsForMultipleBags(const std::vector< TrajectoryOptions > &bags_options) const
Definition: node.cc:525
::ros::Publisher landmark_poses_list_publisher_
Definition: node.h:176
void HandleMultiEchoLaserScanMessage(int trajectory_id, const std::string &sensor_id, const sensor_msgs::MultiEchoLaserScan::ConstPtr &msg)
Definition: node.cc:671
Rigid3< double > Rigid3d
bool ValidateTrajectoryOptions(const TrajectoryOptions &options)
Definition: node.cc:420
std::unordered_map< int, TrajectorySensorSamplers > sensor_samplers_
Definition: node.h:203
constexpr int kLatestOnlyPublisherQueueSize
void PublishSubmapList(const ::ros::WallTimerEvent &timer_event)
Definition: node.cc:146
constexpr char kFinishTrajectoryServiceName[]
geometry_msgs::Transform ToGeometryMsgTransform(const Rigid3d &rigid3d)
int AddOfflineTrajectory(const std::set< cartographer::mapping::TrajectoryBuilderInterface::SensorId > &expected_sensor_ids, const TrajectoryOptions &options)
Definition: node.cc:544
constexpr char kImuTopic[]
Node(const NodeOptions &node_options, std::unique_ptr< cartographer::mapping::MapBuilderInterface > map_builder, tf2_ros::Buffer *tf_buffer)
Definition: node.cc:85
cartographer::common::Mutex mutex_
Definition: node.h:170
const NodeOptions node_options_
Definition: node.h:166
constexpr char kLaserScanTopic[]
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
tf2_ros::TransformBroadcaster tf_broadcaster_
Definition: node.h:168
void AddExtrapolator(int trajectory_id, const TrajectoryOptions &options)
Definition: node.cc:151
bool HandleStartTrajectory(cartographer_ros_msgs::StartTrajectory::Request &request, cartographer_ros_msgs::StartTrajectory::Response &response)
Definition: node.cc:493
::ros::Publisher scan_matched_point_cloud_publisher_
Definition: node.h:180
void PublishTrajectoryNodeList(const ::ros::WallTimerEvent &timer_event)
Definition: node.cc:263
std::vector< std::string > ComputeRepeatedTopicNames(const std::string &topic, const int num_topics)
void RunFinalOptimization()
Definition: node.cc:596
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
::ros::Publisher submap_list_publisher_
Definition: node.h:174
void publish(const boost::shared_ptr< M > &message) const
void HandlePointCloud2Message(int trajectory_id, const std::string &sensor_id, const sensor_msgs::PointCloud2::ConstPtr &msg)
Definition: node.cc:682
cartographer_ros_msgs::StatusResponse FinishTrajectoryUnderLock(int trajectory_id) REQUIRES(mutex_)
Definition: node.cc:445
Duration FromSeconds(const double seconds)
void HandleOdometryMessage(int trajectory_id, const std::string &sensor_id, const nav_msgs::Odometry::ConstPtr &msg)
Definition: node.cc:608
void HandleImuMessage(int trajectory_id, const std::string &sensor_id, const sensor_msgs::Imu::ConstPtr &msg)
Definition: node.cc:645
options
void HandleLaserScanMessage(int trajectory_id, const std::string &sensor_id, const sensor_msgs::LaserScan::ConstPtr &msg)
Definition: node.cc:660
::ros::Publisher constraint_list_publisher_
Definition: node.h:177
::ros::NodeHandle node_handle_
Definition: node.h:173
constexpr double kConstraintPublishPeriodSec
std::vector<::ros::WallTimer > wall_timers_
Definition: node.h:210
int AddTrajectory(const TrajectoryOptions &options, const cartographer_ros_msgs::SensorTopics &topics)
Definition: node.cc:335
constexpr char kScanMatchedPointCloudTopic[]
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
constexpr char kStartTrajectoryServiceName[]
void HandleNavSatFixMessage(int trajectory_id, const std::string &sensor_id, const sensor_msgs::NavSatFix::ConstPtr &msg)
Definition: node.cc:623
void PublishConstraintList(const ::ros::WallTimerEvent &timer_event)
Definition: node.cc:281
void sendTransform(const geometry_msgs::TransformStamped &transform)
constexpr char kWriteStateServiceName[]
constexpr char kOdometryTopic[]
::cartographer::mapping::proto::TrajectoryBuilderOptions trajectory_builder_options
void LoadState(const std::string &state_filename, bool load_frozen_state)
Definition: node.cc:699
std::unordered_set< std::string > subscribed_topics_
Definition: node.h:205
::cartographer::common::Time FromRos(const ::ros::Time &time)
void AddSensorSamplers(int trajectory_id, const TrajectoryOptions &options)
Definition: node.cc:168
bool FromRosMessage(const cartographer_ros_msgs::TrajectoryOptions &msg, TrajectoryOptions *options)
::ros::NodeHandle * node_handle()
Definition: node.cc:136
bool HandleFinishTrajectory(cartographer_ros_msgs::FinishTrajectory::Request &request, cartographer_ros_msgs::FinishTrajectory::Response &response)
Definition: node.cc:557
void StartTrajectoryWithDefaultTopics(const TrajectoryOptions &options)
Definition: node.cc:517
constexpr char kMultiEchoLaserScanTopic[]
constexpr char kTrajectoryNodeListTopic[]
constexpr char kSubmapQueryServiceName[]
std::unordered_map< int, std::vector< Subscriber > > subscribers_
Definition: node.h:204
void move(std::vector< T > &a, std::vector< T > &b)
constexpr char kLandmarkPosesListTopic[]
bool HandleWriteState(cartographer_ros_msgs::WriteState::Request &request, cartographer_ros_msgs::WriteState::Response &response)
Definition: node.cc:565
constexpr char kPointCloud2Topic[]
std::string topic
std::map< int, ::cartographer::mapping::PoseExtrapolator > extrapolators_
Definition: node.h:202
static Time now()
constexpr char kSubmapListTopic[]
void HandleLandmarkMessage(int trajectory_id, const std::string &sensor_id, const cartographer_ros_msgs::LandmarkList::ConstPtr &msg)
Definition: node.cc:634
constexpr int kInfiniteSubscriberQueueSize
bool HandleSubmapQuery(cartographer_ros_msgs::SubmapQuery::Request &request, cartographer_ros_msgs::SubmapQuery::Response &response)
Definition: node.cc:138
void LaunchSubscribers(const TrajectoryOptions &options, const cartographer_ros_msgs::SensorTopics &topics, int trajectory_id)
Definition: node.cc:351
bool ValidateTopicNames(const ::cartographer_ros_msgs::SensorTopics &topics, const TrajectoryOptions &options)
Definition: node.cc:432
::ros::Time ToRos(::cartographer::common::Time time)
uint32_t getNumSubscribers() const
void PublishTrajectoryStates(const ::ros::WallTimerEvent &timer_event)
Definition: node.cc:179
void PublishLandmarkPosesList(const ::ros::WallTimerEvent &timer_event)
Definition: node.cc:272
constexpr char kNavSatFixTopic[]
::cartographer::mapping::TrajectoryBuilderInterface::SensorId SensorId
constexpr char kConstraintListTopic[]
std::set<::cartographer::mapping::TrajectoryBuilderInterface::SensorId > ComputeExpectedSensorIds(const TrajectoryOptions &options, const cartographer_ros_msgs::SensorTopics &topics) const
Definition: node.cc:290


cartographer_ros
Author(s): The Cartographer Authors
autogenerated on Mon Feb 28 2022 22:06:05