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" 42 #include "sensor_msgs/PointCloud2.h" 44 #include "visualization_msgs/MarkerArray.h" 50 cartographer_ros_msgs::SensorTopics DefaultSensorTopics() {
51 cartographer_ros_msgs::SensorTopics topics;
64 template <
typename MessageType>
66 void (Node::*handler)(
int,
const std::string&,
67 const typename MessageType::ConstPtr&),
68 const int trajectory_id,
const std::string&
topic,
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);
81 namespace carto = ::cartographer;
83 using carto::transform::Rigid3d;
87 std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
89 : node_options_(node_options),
90 map_builder_bridge_(node_options_,
std::
move(map_builder), tf_buffer) {
91 carto::common::MutexLocker lock(&
mutex_);
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);
147 carto::common::MutexLocker lock(&
mutex_);
153 constexpr
double kExtrapolationEstimationTimeSec = 0.001;
155 const double gravity_time_constant =
158 .imu_gravity_time_constant()
160 .imu_gravity_time_constant();
162 std::piecewise_construct, std::forward_as_tuple(trajectory_id),
163 std::forward_as_tuple(
165 gravity_time_constant));
172 std::piecewise_construct, std::forward_as_tuple(trajectory_id),
173 std::forward_as_tuple(
180 carto::common::MutexLocker lock(&
mutex_);
181 for (
const auto& entry : map_builder_bridge_.GetTrajectoryStates()) {
182 const auto& trajectory_state = entry.second;
187 if (trajectory_state.local_slam_data->time !=
188 extrapolator.GetLastPoseTime()) {
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);
202 carto::common::ToUniversal(trajectory_state.local_slam_data->time),
204 carto::sensor::TransformTimedPointCloud(
205 point_cloud, trajectory_state.local_to_map.cast<
float>())));
207 extrapolator.AddPose(trajectory_state.local_slam_data->time,
208 trajectory_state.local_slam_data->local_pose);
211 geometry_msgs::TransformStamped stamped_transform;
216 const ::cartographer::common::Time now = std::max(
218 stamped_transform.header.stamp =
ToRos(now);
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)));
225 return extrapolator.ExtrapolatePose(now);
228 const Rigid3d tracking_to_map =
229 trajectory_state.local_to_map * tracking_to_local;
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;
236 stamped_transform.child_frame_id =
237 trajectory_state.trajectory_options.odom_frame;
238 stamped_transform.transform =
240 stamped_transforms.push_back(stamped_transform);
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;
247 tracking_to_local * (*trajectory_state.published_to_tracking));
248 stamped_transforms.push_back(stamped_transform);
253 stamped_transform.child_frame_id =
254 trajectory_state.trajectory_options.published_frame;
256 tracking_to_map * (*trajectory_state.published_to_tracking));
264 const ::ros::WallTimerEvent& unused_timer_event) {
266 carto::common::MutexLocker lock(&
mutex_);
268 map_builder_bridge_.GetTrajectoryNodeList());
273 const ::ros::WallTimerEvent& unused_timer_event) {
275 carto::common::MutexLocker lock(&
mutex_);
277 map_builder_bridge_.GetLandmarkPosesList());
282 const ::ros::WallTimerEvent& unused_timer_event) {
284 carto::common::MutexLocker lock(&
mutex_);
289 std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>
292 const cartographer_ros_msgs::SensorTopics& topics)
const {
294 using SensorType = SensorId::SensorType;
295 std::set<SensorId> expected_topics;
301 for (
const std::string&
topic :
316 expected_topics.insert(
SensorId{SensorType::IMU, topics.imu_topic});
320 expected_topics.insert(
321 SensorId{SensorType::ODOMETRY, topics.odometry_topic});
325 expected_topics.insert(
326 SensorId{SensorType::FIXED_FRAME_POSE, topics.nav_sat_fix_topic});
332 return expected_topics;
336 const cartographer_ros_msgs::SensorTopics& topics) {
337 const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>
339 const int trajectory_id =
340 map_builder_bridge_.AddTrajectory(expected_sensor_ids, options);
344 is_active_trajectory_[trajectory_id] =
true;
345 for (
const auto& sensor_id : expected_sensor_ids) {
348 return trajectory_id;
352 const cartographer_ros_msgs::SensorTopics& topics,
353 const int trajectory_id) {
357 {SubscribeWithHandler<sensor_msgs::LaserScan>(
362 for (
const std::string&
topic :
366 {SubscribeWithHandler<sensor_msgs::MultiEchoLaserScan>(
374 {SubscribeWithHandler<sensor_msgs::PointCloud2>(
386 std::string
topic = topics.imu_topic;
389 trajectory_id,
topic,
395 std::string
topic = topics.odometry_topic;
398 trajectory_id,
topic,
403 std::string
topic = topics.nav_sat_fix_topic;
405 {SubscribeWithHandler<sensor_msgs::NavSatFix>(
411 std::string
topic = topics.landmark_topic;
413 {SubscribeWithHandler<cartographer_ros_msgs::LandmarkList>(
423 .has_trajectory_builder_2d_options();
427 .has_trajectory_builder_3d_options();
433 const ::cartographer_ros_msgs::SensorTopics& topics,
436 const std::string&
topic = sensor_id.id;
438 LOG(ERROR) <<
"Topic name [" << topic <<
"] is already used.";
446 const int trajectory_id) {
447 cartographer_ros_msgs::StatusResponse status_response;
450 if (map_builder_bridge_.GetFrozenTrajectoryIds().count(trajectory_id)) {
451 const std::string error =
452 "Trajectory " + std::to_string(trajectory_id) +
" is frozen.";
454 status_response.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
455 status_response.message = error;
456 return status_response;
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.";
462 status_response.code = cartographer_ros_msgs::StatusCode::NOT_FOUND;
463 status_response.message = error;
464 return status_response;
466 if (!is_active_trajectory_[trajectory_id]) {
467 const std::string error =
"Trajectory " + std::to_string(trajectory_id) +
468 " has already been finished.";
470 status_response.code =
471 cartographer_ros_msgs::StatusCode::RESOURCE_EXHAUSTED;
472 status_response.message = error;
473 return status_response;
478 entry.subscriber.shutdown();
480 LOG(INFO) <<
"Shutdown the subscriber of [" << entry.topic <<
"]";
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;
494 ::cartographer_ros_msgs::StartTrajectory::Request& request,
495 ::cartographer_ros_msgs::StartTrajectory::Response& response) {
496 carto::common::MutexLocker lock(&
mutex_);
500 const std::string error =
"Invalid trajectory options.";
502 response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
503 response.status.message = error;
505 const std::string error =
"Invalid topics.";
507 response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
508 response.status.message = error;
510 response.trajectory_id =
AddTrajectory(options, request.topics);
511 response.status.code = cartographer_ros_msgs::StatusCode::OK;
512 response.status.message =
"Success.";
518 carto::common::MutexLocker lock(&
mutex_);
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) {
531 if (bags_options.size() > 1) {
532 prefix =
"bag_" + std::to_string(i + 1) +
"_";
534 std::set<SensorId> unique_sensor_ids;
535 for (
const auto& sensor_id :
537 unique_sensor_ids.insert(
SensorId{sensor_id.type, prefix + sensor_id.id});
539 bags_sensor_ids.push_back(unique_sensor_ids);
541 return bags_sensor_ids;
545 const std::set<cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
548 carto::common::MutexLocker lock(&
mutex_);
549 const int trajectory_id =
550 map_builder_bridge_.AddTrajectory(expected_sensor_ids, options);
553 is_active_trajectory_[trajectory_id] =
true;
554 return trajectory_id;
558 ::cartographer_ros_msgs::FinishTrajectory::Request& request,
559 ::cartographer_ros_msgs::FinishTrajectory::Response& response) {
560 carto::common::MutexLocker lock(&
mutex_);
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 +
"'.";
573 response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
574 response.status.message =
"Failed to write '" + request.filename +
"'.";
580 carto::common::MutexLocker lock(&
mutex_);
581 for (
auto& entry : is_active_trajectory_) {
582 const int trajectory_id = entry.first;
585 cartographer_ros_msgs::StatusCode::OK);
591 carto::common::MutexLocker lock(&
mutex_);
593 cartographer_ros_msgs::StatusCode::OK;
598 carto::common::MutexLocker lock(&
mutex_);
599 for (
const auto& entry : is_active_trajectory_) {
600 CHECK(!entry.second);
605 map_builder_bridge_.RunFinalOptimization();
609 const std::string& sensor_id,
610 const nav_msgs::Odometry::ConstPtr& msg) {
611 carto::common::MutexLocker lock(&
mutex_);
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);
620 sensor_bridge_ptr->HandleOdometryMessage(sensor_id, msg);
624 const std::string& sensor_id,
625 const sensor_msgs::NavSatFix::ConstPtr& msg) {
626 carto::common::MutexLocker lock(&
mutex_);
630 map_builder_bridge_.sensor_bridge(trajectory_id)
631 ->HandleNavSatFixMessage(sensor_id, msg);
635 const int trajectory_id,
const std::string& sensor_id,
636 const cartographer_ros_msgs::LandmarkList::ConstPtr& msg) {
637 carto::common::MutexLocker lock(&
mutex_);
641 map_builder_bridge_.sensor_bridge(trajectory_id)
642 ->HandleLandmarkMessage(sensor_id, msg);
646 const std::string& sensor_id,
647 const sensor_msgs::Imu::ConstPtr& msg) {
648 carto::common::MutexLocker lock(&
mutex_);
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) {
657 sensor_bridge_ptr->HandleImuMessage(sensor_id, msg);
661 const std::string& sensor_id,
662 const sensor_msgs::LaserScan::ConstPtr& msg) {
663 carto::common::MutexLocker lock(&
mutex_);
667 map_builder_bridge_.sensor_bridge(trajectory_id)
668 ->HandleLaserScanMessage(sensor_id, msg);
672 const int trajectory_id,
const std::string& sensor_id,
673 const sensor_msgs::MultiEchoLaserScan::ConstPtr& msg) {
674 carto::common::MutexLocker lock(&
mutex_);
678 map_builder_bridge_.sensor_bridge(trajectory_id)
679 ->HandleMultiEchoLaserScanMessage(sensor_id, msg);
683 const int trajectory_id,
const std::string& sensor_id,
684 const sensor_msgs::PointCloud2::ConstPtr& msg) {
685 carto::common::MutexLocker lock(&
mutex_);
689 map_builder_bridge_.sensor_bridge(trajectory_id)
690 ->HandlePointCloud2Message(sensor_id, msg);
694 carto::common::MutexLocker lock(&
mutex_);
695 CHECK(map_builder_bridge_.SerializeState(filename))
696 <<
"Could not write state.";
700 const bool load_frozen_state) {
701 carto::common::MutexLocker lock(&
mutex_);
702 map_builder_bridge_.LoadState(state_filename, load_frozen_state);
bool FinishTrajectory(int trajectory_id)
double imu_sampling_ratio
::ros::Publisher trajectory_node_list_publisher_
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)
constexpr char kLandmarkTopic[]
::cartographer::mapping::proto::MapBuilderOptions map_builder_options
std::vector<::ros::ServiceServer > service_servers_
void FinishAllTrajectories()
double odometry_sampling_ratio
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
::ros::Publisher landmark_poses_list_publisher_
void HandleMultiEchoLaserScanMessage(int trajectory_id, const std::string &sensor_id, const sensor_msgs::MultiEchoLaserScan::ConstPtr &msg)
bool ValidateTrajectoryOptions(const TrajectoryOptions &options)
std::unordered_map< int, TrajectorySensorSamplers > sensor_samplers_
constexpr int kLatestOnlyPublisherQueueSize
void PublishSubmapList(const ::ros::WallTimerEvent &timer_event)
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)
constexpr char kImuTopic[]
Node(const NodeOptions &node_options, std::unique_ptr< cartographer::mapping::MapBuilderInterface > map_builder, tf2_ros::Buffer *tf_buffer)
cartographer::common::Mutex mutex_
const NodeOptions node_options_
constexpr char kLaserScanTopic[]
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
tf2_ros::TransformBroadcaster tf_broadcaster_
void AddExtrapolator(int trajectory_id, const TrajectoryOptions &options)
bool HandleStartTrajectory(cartographer_ros_msgs::StartTrajectory::Request &request, cartographer_ros_msgs::StartTrajectory::Response &response)
::ros::Publisher scan_matched_point_cloud_publisher_
void PublishTrajectoryNodeList(const ::ros::WallTimerEvent &timer_event)
std::vector< std::string > ComputeRepeatedTopicNames(const std::string &topic, const int num_topics)
void RunFinalOptimization()
double fixed_frame_pose_sampling_ratio
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
::ros::Publisher submap_list_publisher_
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)
cartographer_ros_msgs::StatusResponse FinishTrajectoryUnderLock(int trajectory_id) REQUIRES(mutex_)
Duration FromSeconds(const double seconds)
void HandleOdometryMessage(int trajectory_id, const std::string &sensor_id, const nav_msgs::Odometry::ConstPtr &msg)
double landmarks_sampling_ratio
void HandleImuMessage(int trajectory_id, const std::string &sensor_id, const sensor_msgs::Imu::ConstPtr &msg)
void HandleLaserScanMessage(int trajectory_id, const std::string &sensor_id, const sensor_msgs::LaserScan::ConstPtr &msg)
::ros::Publisher constraint_list_publisher_
::ros::NodeHandle node_handle_
constexpr double kConstraintPublishPeriodSec
std::vector<::ros::WallTimer > wall_timers_
int AddTrajectory(const TrajectoryOptions &options, const cartographer_ros_msgs::SensorTopics &topics)
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)
void PublishConstraintList(const ::ros::WallTimerEvent &timer_event)
constexpr char kWriteStateServiceName[]
constexpr char kOdometryTopic[]
::cartographer::mapping::proto::TrajectoryBuilderOptions trajectory_builder_options
void LoadState(const std::string &state_filename, bool load_frozen_state)
std::unordered_set< std::string > subscribed_topics_
double trajectory_publish_period_sec
::cartographer::common::Time FromRos(const ::ros::Time &time)
int num_multi_echo_laser_scans
double pose_publish_period_sec
void AddSensorSamplers(int trajectory_id, const TrajectoryOptions &options)
bool FromRosMessage(const cartographer_ros_msgs::TrajectoryOptions &msg, TrajectoryOptions *options)
::ros::NodeHandle * node_handle()
bool HandleFinishTrajectory(cartographer_ros_msgs::FinishTrajectory::Request &request, cartographer_ros_msgs::FinishTrajectory::Response &response)
void StartTrajectoryWithDefaultTopics(const TrajectoryOptions &options)
constexpr char kMultiEchoLaserScanTopic[]
constexpr char kTrajectoryNodeListTopic[]
constexpr char kSubmapQueryServiceName[]
std::unordered_map< int, std::vector< Subscriber > > subscribers_
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)
double rangefinder_sampling_ratio
constexpr char kPointCloud2Topic[]
std::map< int, ::cartographer::mapping::PoseExtrapolator > extrapolators_
constexpr char kSubmapListTopic[]
void HandleLandmarkMessage(int trajectory_id, const std::string &sensor_id, const cartographer_ros_msgs::LandmarkList::ConstPtr &msg)
constexpr int kInfiniteSubscriberQueueSize
bool HandleSubmapQuery(cartographer_ros_msgs::SubmapQuery::Request &request, cartographer_ros_msgs::SubmapQuery::Response &response)
void LaunchSubscribers(const TrajectoryOptions &options, const cartographer_ros_msgs::SensorTopics &topics, int trajectory_id)
bool ValidateTopicNames(const ::cartographer_ros_msgs::SensorTopics &topics, const TrajectoryOptions &options)
::ros::Time ToRos(::cartographer::common::Time time)
uint32_t getNumSubscribers() const
void PublishTrajectoryStates(const ::ros::WallTimerEvent &timer_event)
void PublishLandmarkPosesList(const ::ros::WallTimerEvent &timer_event)
constexpr char kNavSatFixTopic[]
::cartographer::mapping::TrajectoryBuilderInterface::SensorId SensorId
constexpr char kConstraintListTopic[]
double submap_publish_period_sec
std::set<::cartographer::mapping::TrajectoryBuilderInterface::SensorId > ComputeExpectedSensorIds(const TrajectoryOptions &options, const cartographer_ros_msgs::SensorTopics &topics) const