3 #define MAP_FRAME_ID(id) "robot" + std::to_string(id) + "_map"
4 #define CURRENT_FRAME_ID(id) "robot" + std::to_string(id) + "_current_pose"
5 #define LATEST_OPTIMIZED_FRAME_ID(id) "robot" + std::to_string(id) + "_latest_optimized_pose"
10 : node_(
node), max_waiting_time_sec_(60, 0)
12 node_->get_parameter(
"max_nb_robots", max_nb_robots_);
13 node_->get_parameter(
"robot_id", robot_id_);
14 node_->get_parameter(
"backend.pose_graph_optimization_start_period_ms",
15 pose_graph_optimization_start_period_ms_);
16 node_->get_parameter(
"backend.pose_graph_optimization_loop_period_ms",
17 pose_graph_optimization_loop_period_ms_);
18 node_->get_parameter(
"backend.enable_broadcast_tf_frames",
19 enable_broadcast_tf_frames_);
20 node_->get_parameter(
"neighbor_management.heartbeat_period_sec", heartbeat_period_sec_);
21 node->get_parameter(
"evaluation.enable_logs",
23 node->get_parameter(
"evaluation.log_folder",
25 node->get_parameter(
"evaluation.enable_gps_recording",
26 enable_gps_recording_);
27 node->get_parameter(
"evaluation.enable_simulated_rendezvous", enable_simulated_rendezvous_);
28 std::string rendezvous_schedule_file;
29 node->get_parameter(
"evaluation.rendezvous_schedule_file", rendezvous_schedule_file);
30 node->get_parameter(
"evaluation.enable_pose_timestamps_recording", enable_pose_timestamps_recording_);
31 node_->get_parameter(
"visualization.enable",
32 enable_visualization_);
33 node_->get_parameter(
"visualization.publishing_period_ms",
34 visualization_period_ms_);
36 int max_waiting_param;
37 node_->get_parameter(
"backend.max_waiting_time_sec", max_waiting_param);
38 max_waiting_time_sec_ = rclcpp::Duration(max_waiting_param, 0);
40 odometry_subscriber_ =
41 node->create_subscription<cslam_common_interfaces::msg::KeyframeOdom>(
42 "cslam/keyframe_odom", 1000,
44 std::placeholders::_1));
46 intra_robot_loop_closure_subscriber_ =
node->create_subscription<
47 cslam_common_interfaces::msg::IntraRobotLoopClosure>(
48 "cslam/intra_robot_loop_closure", 1000,
50 std::placeholders::_1));
52 inter_robot_loop_closure_subscriber_ =
node->create_subscription<
53 cslam_common_interfaces::msg::InterRobotLoopClosure>(
54 "/cslam/inter_robot_loop_closure", 1000,
56 std::placeholders::_1));
58 write_current_estimates_subscriber_ =
59 node->create_subscription<std_msgs::msg::String>(
60 "cslam/print_current_estimates", 100,
62 std::placeholders::_1));
64 rotation_default_noise_std_ = 0.01;
65 translation_default_noise_std_ = 0.1;
66 Eigen::VectorXd sigmas(6);
67 sigmas << rotation_default_noise_std_, rotation_default_noise_std_,
68 rotation_default_noise_std_, translation_default_noise_std_,
69 translation_default_noise_std_, translation_default_noise_std_;
70 default_noise_model_ = gtsam::noiseModel::Diagonal::Sigmas(sigmas);
71 pose_graph_ = boost::make_shared<gtsam::NonlinearFactorGraph>();
72 current_pose_estimates_ = boost::make_shared<gtsam::Values>();
73 odometry_pose_estimates_ = boost::make_shared<gtsam::Values>();
76 optimization_timer_ = node_->create_wall_timer(
77 std::chrono::milliseconds(pose_graph_optimization_start_period_ms_),
80 optimization_loop_timer_ = node_->create_wall_timer(
81 std::chrono::milliseconds(pose_graph_optimization_loop_period_ms_),
84 if (enable_visualization_)
86 RCLCPP_INFO(node_->get_logger(),
"Visualization enabled.");
87 visualization_timer_ = node_->create_wall_timer(
88 std::chrono::milliseconds(visualization_period_ms_),
93 RCLCPP_INFO(node_->get_logger(),
"Visualization disabled.");
97 debug_optimization_result_publisher_ =
98 node_->create_publisher<cslam_common_interfaces::msg::OptimizationResult>(
99 "cslam/debug_optimization_result", 100);
101 for (
unsigned int i = 0; i < max_nb_robots_; i++)
103 optimized_estimates_publishers_.insert(
104 {i,
node->create_publisher<
105 cslam_common_interfaces::msg::OptimizationResult>(
106 "/r" + std::to_string(i) +
"/cslam/optimized_estimates", 100)});
109 optimized_estimates_subscriber_ =
node->create_subscription<
110 cslam_common_interfaces::msg::OptimizationResult>(
111 "cslam/optimized_estimates", 100,
113 std::placeholders::_1));
115 optimized_pose_estimate_publisher_ =
node->create_publisher<
116 geometry_msgs::msg::PoseStamped>(
117 "/r" + std::to_string(robot_id_) +
"/cslam/current_pose_estimate", 100);
119 optimizer_state_publisher_ =
121 "cslam/optimizer_state", 100);
124 for (
unsigned int i = 0; i < max_nb_robots_; i++)
126 for (
unsigned int j = i + 1; j < max_nb_robots_; j++)
128 inter_robot_loop_closures_.insert(
129 {{i, j}, std::vector<gtsam::BetweenFactor<gtsam::Pose3>>()});
134 get_current_neighbors_publisher_ =
135 node->create_publisher<std_msgs::msg::String>(
"cslam/get_current_neighbors",
138 current_neighbors_subscriber_ =
node->create_subscription<
139 cslam_common_interfaces::msg::RobotIdsAndOrigin>(
140 "cslam/current_neighbors", 100,
142 std::placeholders::_1));
145 for (
unsigned int i = 0; i < max_nb_robots_; i++)
147 get_pose_graph_publishers_.insert(
148 {i,
node->create_publisher<cslam_common_interfaces::msg::RobotIds>(
149 "/r" + std::to_string(i) +
"/cslam/get_pose_graph", 100)});
150 received_pose_graphs_.insert({i,
false});
153 get_pose_graph_subscriber_ =
154 node->create_subscription<cslam_common_interfaces::msg::RobotIds>(
155 "cslam/get_pose_graph", 100,
157 std::placeholders::_1));
159 pose_graph_publisher_ =
160 node->create_publisher<cslam_common_interfaces::msg::PoseGraph>(
161 "/cslam/pose_graph", 100);
163 pose_graph_subscriber_ =
164 node->create_subscription<cslam_common_interfaces::msg::PoseGraph>(
165 "/cslam/pose_graph", 100,
167 std::placeholders::_1));
169 visualization_pose_graph_publisher_ =
170 node->create_publisher<cslam_common_interfaces::msg::PoseGraph>(
171 "/cslam/viz/pose_graph", 100);
176 optimization_count_ = 0;
179 tf_broadcaster_ = std::make_unique<tf2_ros::TransformBroadcaster>(*node_);
181 if (enable_broadcast_tf_frames_)
183 tf_broadcaster_timer_ = node_->create_wall_timer(
184 std::chrono::milliseconds(pose_graph_optimization_loop_period_ms_),
188 heartbeat_publisher_ =
189 node_->create_publisher<std_msgs::msg::UInt32>(
"cslam/heartbeat", 10);
190 heartbeat_timer_ = node_->create_wall_timer(
191 std::chrono::milliseconds((
unsigned int)heartbeat_period_sec_ * 1000),
194 reference_frame_per_robot_publisher_ =
195 node_->create_publisher<cslam_common_interfaces::msg::ReferenceFrames>(
196 "cslam/reference_frames", rclcpp::QoS(1).transient_local());
198 origin_robot_id_ = robot_id_;
202 logger_ = std::make_shared<Logger>(node_, robot_id_, max_nb_robots_, log_folder_);
205 if (enable_simulated_rendezvous_)
207 sim_rdv_ = std::make_shared<SimulatedRendezVous>(node_, rendezvous_schedule_file, robot_id_);
210 RCLCPP_INFO(node_->get_logger(),
"Initialization done.");
215 for (
unsigned int i = 0; i < max_nb_robots_; i++)
217 received_pose_graphs_[i] =
false;
219 other_robots_graph_and_estimates_.clear();
220 received_pose_graphs_connectivity_.clear();
225 bool received_all =
true;
226 for (
auto id : current_neighbors_ids_.robots.ids)
228 received_all &= received_pose_graphs_[id];
234 const cslam_common_interfaces::msg::KeyframeOdom::ConstSharedPtr msg)
239 odometry_pose_estimates_->insert(symbol, current_estimate);
242 current_pose_estimates_->insert(symbol, current_estimate);
245 if (latest_local_symbol_ != gtsam::LabeledSymbol())
247 gtsam::Pose3 odom_diff = latest_local_pose_.inverse() * current_estimate;
248 gtsam::BetweenFactor<gtsam::Pose3> factor(latest_local_symbol_, symbol,
249 odom_diff, default_noise_model_);
250 pose_graph_->push_back(factor);
253 if (enable_gps_recording_)
255 gps_data_.insert({msg->id, msg->gps});
259 latest_local_pose_ = current_estimate;
260 latest_local_symbol_ = symbol;
262 if (enable_pose_timestamps_recording_)
264 logger_->log_pose_timestamp(symbol, msg->odom.header.stamp.sec, msg->odom.header.stamp.nanosec);
269 const cslam_common_interfaces::msg::IntraRobotLoopClosure::
281 gtsam::BetweenFactor<gtsam::Pose3> factor =
282 gtsam::BetweenFactor<gtsam::Pose3>(symbol_from, symbol_to, measurement,
283 default_noise_model_);
285 pose_graph_->push_back(factor);
286 RCLCPP_INFO(node_->get_logger(),
"New intra-robot loop closure (%d, %d).", msg->keyframe0_id, msg->keyframe1_id);
291 const cslam_common_interfaces::msg::InterRobotLoopClosure::
298 unsigned char robot0_c =
ROBOT_LABEL(msg->robot0_id);
299 gtsam::LabeledSymbol symbol_from(
GRAPH_LABEL, robot0_c,
300 msg->robot0_keyframe_id);
301 unsigned char robot1_c =
ROBOT_LABEL(msg->robot1_id);
302 gtsam::LabeledSymbol symbol_to(
GRAPH_LABEL, robot1_c, msg->robot1_keyframe_id);
304 gtsam::BetweenFactor<gtsam::Pose3> factor =
305 gtsam::BetweenFactor<gtsam::Pose3>(symbol_from, symbol_to, measurement,
306 default_noise_model_);
308 inter_robot_loop_closures_[{std::min(msg->robot0_id, msg->robot1_id),
309 std::max(msg->robot0_id, msg->robot1_id)}]
311 if (msg->robot0_id == robot_id_)
313 connected_robots_.insert(msg->robot1_id);
315 else if (msg->robot1_id == robot_id_)
317 connected_robots_.insert(msg->robot0_id);
323 const std_msgs::msg::String::ConstSharedPtr msg)
326 gtsam::writeG2o(*pose_graph_, *current_pose_estimates_, msg->data);
327 }
catch (
const std::exception &e) {
328 RCLCPP_ERROR(node_->get_logger(),
"Error while writing estimates: %s", e.what());
333 const cslam_common_interfaces::msg::RobotIdsAndOrigin::ConstSharedPtr msg)
335 current_neighbors_ids_ = *msg;
351 for (
unsigned int i = 0; i < current_neighbors_ids_.origins.ids.size(); i++)
353 if (origin_robot_id_ > current_neighbors_ids_.origins.ids[i])
357 else if (origin_robot_id_ == current_neighbors_ids_.origins.ids[i] &&
358 robot_id_ > current_neighbors_ids_.robots.ids[i])
363 if (odometry_pose_estimates_->size() == 0)
371 auto current_robots_ids = current_neighbors_ids_;
372 current_robots_ids.robots.ids.push_back(robot_id_);
377 cslam_common_interfaces::msg::PoseGraph out_msg;
378 out_msg.robot_id = robot_id_;
380 auto graph = boost::make_shared<gtsam::NonlinearFactorGraph>();
381 graph->push_back(pose_graph_->begin(), pose_graph_->end());
383 std::set<unsigned int> connected_robots;
385 for (
unsigned int i = 0; i < msg.ids.size(); i++)
387 for (
unsigned int j = i + 1; j < msg.ids.size(); j++)
389 unsigned int min_robot_id = std::min(msg.ids[i], msg.ids[j]);
390 unsigned int max_robot_id = std::max(msg.ids[i], msg.ids[j]);
391 if (inter_robot_loop_closures_[{min_robot_id, max_robot_id}].size() > 0 &&
392 (min_robot_id == robot_id_ || max_robot_id == robot_id_))
394 connected_robots.insert(min_robot_id);
395 connected_robots.insert(max_robot_id);
396 if (min_robot_id == robot_id_)
399 inter_robot_loop_closures_[{min_robot_id, max_robot_id}].begin(),
400 inter_robot_loop_closures_[{min_robot_id, max_robot_id}].end());
407 for (
auto id : connected_robots)
411 out_msg.connected_robots.ids.push_back(
id);
415 if (enable_gps_recording_) {
416 for (
auto gps : gps_data_) {
417 out_msg.gps_values_idx.push_back(gps.first);
418 out_msg.gps_values.push_back(gps.second);
424 logger_->fill_msg(out_msg);
431 const cslam_common_interfaces::msg::RobotIds::ConstSharedPtr msg)
434 pose_graph_publisher_->publish(out_msg);
435 tentative_local_pose_at_latest_optimization_ = latest_local_pose_;
439 const cslam_common_interfaces::msg::PoseGraph::ConstSharedPtr msg)
443 other_robots_graph_and_estimates_.insert(
446 received_pose_graphs_[msg->robot_id] =
true;
447 received_pose_graphs_connectivity_.insert(
448 {msg->robot_id, msg->connected_robots.ids});
451 logger_->add_pose_graph_log_info(*msg);
466 if (connected_robots_.size() > 0)
468 std::vector<unsigned int> v(connected_robots_.begin(),
469 connected_robots_.end());
470 received_pose_graphs_connectivity_.insert({robot_id_, v});
473 std::map<unsigned int, bool> is_robot_connected;
474 is_robot_connected.insert({robot_id_,
true});
475 for (
auto id : current_neighbors_ids_.robots.ids)
477 is_robot_connected.insert({id,
false});
481 bool *visited =
new bool[current_neighbors_ids_.robots.ids.size()];
482 for (
unsigned int i = 0; i < current_neighbors_ids_.robots.ids.size(); i++)
485 std::list<unsigned int> queue;
487 unsigned int current_id = robot_id_;
488 visited[current_id] =
true;
489 queue.push_back(current_id);
491 while (!queue.empty())
493 current_id = queue.front();
496 for (
auto id : received_pose_graphs_connectivity_[current_id])
498 is_robot_connected[id] =
true;
507 return is_robot_connected;
512 get_current_neighbors_publisher_->publish(std_msgs::msg::String());
526 start_waiting_time_ = node_->now();
535 if ((node_->now() - start_waiting_time_) > max_waiting_time_sec_)
539 RCLCPP_INFO(node_->get_logger(),
"Timeout: (%d)", robot_id_);
547 odometry_pose_estimates_->size() > 0)
555 std::pair<gtsam::NonlinearFactorGraph::shared_ptr, gtsam::Values::shared_ptr>
561 auto graph = boost::make_shared<gtsam::NonlinearFactorGraph>();
562 auto estimates = boost::make_shared<gtsam::Values>();
564 graph->push_back(pose_graph_->begin(), pose_graph_->end());
565 estimates->insert(*odometry_pose_estimates_);
566 tentative_local_pose_at_latest_optimization_ = latest_local_pose_;
569 for (
auto id : current_neighbors_ids_.robots.ids)
571 if (is_pose_graph_connected[
id])
573 estimates->insert(*other_robots_graph_and_estimates_[
id].second);
577 std::set<std::pair<gtsam::Key, gtsam::Key>> added_loop_closures;
579 auto included_robots_ids = current_neighbors_ids_;
580 included_robots_ids.robots.ids.push_back(robot_id_);
581 for (
unsigned int i = 0; i < included_robots_ids.robots.ids.size(); i++)
583 for (
unsigned int j = i + 1; j < included_robots_ids.robots.ids.size();
586 if (is_pose_graph_connected[included_robots_ids.robots.ids[i]] &&
587 is_pose_graph_connected[included_robots_ids.robots.ids[j]])
589 unsigned int min_id = std::min(included_robots_ids.robots.ids[i],
590 included_robots_ids.robots.ids[j]);
591 unsigned int max_id = std::max(included_robots_ids.robots.ids[i],
592 included_robots_ids.robots.ids[j]);
593 for (
const auto &factor :
594 inter_robot_loop_closures_[{min_id, max_id}])
596 if (estimates->exists(factor.key1()) &&
597 estimates->exists(factor.key2()) &&
598 added_loop_closures.count({factor.key1(), factor.key2()}) == 0)
600 graph->push_back(factor);
601 added_loop_closures.insert({factor.key1(), factor.key2()});
608 for (
auto id : current_neighbors_ids_.robots.ids)
611 for (
const auto &factor_ : *other_robots_graph_and_estimates_[
id].first)
614 boost::dynamic_pointer_cast<gtsam::BetweenFactor<gtsam::Pose3>>(
616 unsigned int robot0_id =
617 ROBOT_ID(gtsam::LabeledSymbol(factor->key1()).label());
618 unsigned int robot1_id =
619 ROBOT_ID(gtsam::LabeledSymbol(factor->key2()).label());
620 if (is_pose_graph_connected[robot0_id] &&
621 is_pose_graph_connected[robot1_id])
623 if (estimates->exists(factor->key1()) &&
624 estimates->exists(factor->key2()) &&
625 added_loop_closures.count({factor->key1(), factor->key2()}) == 0)
627 graph->push_back(factor);
628 added_loop_closures.insert({factor->key1(), factor->key2()});
633 return {graph, estimates};
637 const cslam_common_interfaces::msg::OptimizationResult::ConstSharedPtr
640 if (odometry_pose_estimates_->size() > 0 && msg->estimates.size() > 0)
643 origin_robot_id_ = msg->origin_robot_id;
646 gtsam::Pose3 first_pose;
647 if (current_pose_estimates_->exists(first_symbol))
649 first_pose = current_pose_estimates_->at<gtsam::Pose3>(first_symbol);
655 logger_->write_logs();
657 catch (
const std::exception &e)
659 RCLCPP_ERROR(node_->get_logger(),
"Writing logs failed: %s", e.what());
666 const gtsam::Values &estimates)
668 auto included_robots_ids = current_neighbors_ids_;
669 included_robots_ids.robots.ids.push_back(robot_id_);
670 for (
unsigned int i = 0; i < included_robots_ids.robots.ids.size(); i++)
672 cslam_common_interfaces::msg::OptimizationResult msg;
674 msg.origin_robot_id = origin_robot_id_;
678 optimized_estimates_publishers_[included_robots_ids.robots.ids[i]]->publish(
685 if (enable_simulated_rendezvous_)
687 if (!sim_rdv_->is_alive()) {
691 std_msgs::msg::UInt32 msg;
692 msg.data = origin_robot_id_;
693 heartbeat_publisher_->publish(msg);
698 if (visualization_pose_graph_publisher_->get_subscription_count() > 0)
700 cslam_common_interfaces::msg::PoseGraph out_msg;
701 out_msg.robot_id = robot_id_;
702 out_msg.origin_robot_id = origin_robot_id_;
704 auto graph = boost::make_shared<gtsam::NonlinearFactorGraph>();
705 graph->push_back(pose_graph_->begin(), pose_graph_->end());
707 for (
unsigned int i = 0; i < max_nb_robots_; i++)
709 for (
unsigned int j = i + 1; j < max_nb_robots_; j++)
711 unsigned int min_robot_id = std::min(i, j);
712 unsigned int max_robot_id = std::max(i, j);
713 if (inter_robot_loop_closures_[{min_robot_id, max_robot_id}].size() > 0 &&
714 (min_robot_id == robot_id_ || max_robot_id == robot_id_))
716 if (min_robot_id == robot_id_)
719 inter_robot_loop_closures_[{min_robot_id, max_robot_id}].begin(),
720 inter_robot_loop_closures_[{min_robot_id, max_robot_id}].end());
727 visualization_pose_graph_publisher_->publish(out_msg);
733 rclcpp::Time now = node_->get_clock()->now();
734 origin_to_first_pose_.header.stamp = now;
735 origin_to_first_pose_.header.frame_id =
MAP_FRAME_ID(origin_robot_id_);
736 origin_to_first_pose_.child_frame_id =
MAP_FRAME_ID(robot_id_);
743 if (reference_frame_per_robot_publisher_->get_subscription_count() > 0)
745 cslam_common_interfaces::msg::ReferenceFrames msg;
746 msg.robot_id = robot_id_;
747 msg.origin_to_local = origin_to_first_pose_;
748 reference_frame_per_robot_publisher_->publish(msg);
751 local_pose_at_latest_optimization_ = tentative_local_pose_at_latest_optimization_;
752 latest_optimized_pose_ = current_pose_estimates_->at<gtsam::Pose3>(current_pose_estimates_->keys().back());
762 rclcpp::Time now = node_->get_clock()->now();
763 origin_to_first_pose_.header.stamp = now;
764 if (origin_to_first_pose_.header.frame_id !=
765 origin_to_first_pose_.child_frame_id)
767 tf_broadcaster_->sendTransform(origin_to_first_pose_);
771 geometry_msgs::msg::TransformStamped latest_optimized_pose_msg;
772 latest_optimized_pose_msg.header.stamp = now;
773 latest_optimized_pose_msg.header.frame_id =
MAP_FRAME_ID(origin_robot_id_);
776 latest_optimized_pose_);
777 tf_broadcaster_->sendTransform(latest_optimized_pose_msg);
780 geometry_msgs::msg::TransformStamped current_transform_msg;
781 current_transform_msg.header.stamp = now;
784 gtsam::Pose3 current_pose_diff = local_pose_at_latest_optimization_.inverse() * latest_local_pose_;
786 tf_broadcaster_->sendTransform(current_transform_msg);
789 geometry_msgs::msg::PoseStamped pose_msg;
790 pose_msg.header.stamp = now;
791 pose_msg.header.frame_id =
MAP_FRAME_ID(origin_robot_id_);
793 optimized_pose_estimate_publisher_->publish(pose_msg);
798 const gtsam::Values::shared_ptr &initial)
800 gtsam::Values result;
802 logger_->start_timer();
805 gtsam::GncParams<gtsam::LevenbergMarquardtParams>
params;
806 gtsam::GncOptimizer<gtsam::GncParams<gtsam::LevenbergMarquardtParams>>
807 optimizer(*graph, *initial,
params);
808 result = optimizer.optimize();
810 catch (
const std::exception &e)
812 RCLCPP_ERROR(node_->get_logger(),
"Optimization failed: %s", e.what());
816 logger_->stop_timer();
818 logger_->log_optimized_global_pose_graph(graph, result, robot_id_);
820 catch (
const std::exception &e)
822 RCLCPP_ERROR(node_->get_logger(),
"Logging failed: %s", e.what());
838 if (!current_pose_estimates_->exists(first_symbol))
843 aggregate_pose_graph_.first->addPrior(
844 first_symbol, current_pose_estimates_->at<gtsam::Pose3>(first_symbol),
845 default_noise_model_);
848 logger_->log_initial_global_pose_graph(aggregate_pose_graph_.first, aggregate_pose_graph_.second);
852 optimization_result_ =
854 aggregate_pose_graph_.second);
860 auto status = optimization_result_.wait_for(std::chrono::milliseconds(0));
862 if (status == std::future_status::ready)
864 RCLCPP_DEBUG(node_->get_logger(),
"Pose Graph Optimization completed.");
865 auto result = optimization_result_.get();
866 optimization_count_++;
873 if (debug_optimization_result_publisher_->get_subscription_count() > 0)
875 cslam_common_interfaces::msg::OptimizationResult msg;
879 debug_optimization_result_publisher_->publish(msg);
886 if (!odometry_pose_estimates_->empty())
888 if (optimizer_state_ ==
891 if (current_neighbors_ids_.robots.ids.size() > 0)
893 for (
auto id : current_neighbors_ids_.robots.ids)
895 auto current_robots_ids = current_neighbors_ids_;
896 current_robots_ids.robots.ids.push_back(robot_id_);
897 get_pose_graph_publishers_[id]->publish(current_robots_ids.robots);
920 if (optimizer_state_publisher_->get_subscription_count() > 0)
923 state_msg.state = optimizer_state_;
924 optimizer_state_publisher_->publish(state_msg);
void write_current_estimates_callback(const std_msgs::msg::String::ConstSharedPtr msg)
Prints current estimates.
void pose_graph_callback(const cslam_common_interfaces::msg::PoseGraph::ConstSharedPtr msg)
Receives pose graph.
bool is_optimizer()
Check if the local robot is the optimizer according to the specified priority rule Default priority r...
void check_result_and_finish_optimization()
Check if the optimization is finished.
void optimized_estimates_callback(const cslam_common_interfaces::msg::OptimizationResult::ConstSharedPtr msg)
Receives estimates from the optimizer.
void end_waiting()
End waiting.
void heartbeat_timer_callback()
Publish heartbeat message periodically.
void optimization_callback()
Starts pose graph optimization process every X ms (defined in config)
void inter_robot_loop_closure_callback(const cslam_common_interfaces::msg::InterRobotLoopClosure::ConstSharedPtr msg)
Receives inter-robot loop closures.
void visualization_callback()
Publish heartbeat message periodically.
bool is_waiting()
Check if waiting.
void start_optimization()
Performs pose graph optimization.
cslam_common_interfaces::msg::PoseGraph fill_pose_graph_msg()
Fill a PoseGraph message with the local data.
void optimization_loop_callback()
Step execution of the optimization State Machine.
void get_pose_graph_callback(const cslam_common_interfaces::msg::RobotIds::ConstSharedPtr msg)
Receives request for pose graph.
void odometry_callback(const cslam_common_interfaces::msg::KeyframeOdom::ConstSharedPtr msg)
Receives odometry msg + keyframe id.
void resquest_current_neighbors()
Request to check the current neighbors.
bool check_waiting_timeout()
Check waiting timeout.
bool check_received_pose_graphs()
Check if received all pose graphs.
void intra_robot_loop_closure_callback(const cslam_common_interfaces::msg::IntraRobotLoopClosure::ConstSharedPtr msg)
Receives intra-robot loop closures.
void share_optimized_estimates(const gtsam::Values &estimates)
Shares optimizes estimates with the robots concerned.
std::map< unsigned int, bool > connected_robot_pose_graph()
Breadth First Seach to check connectivity.
std::pair< gtsam::NonlinearFactorGraph::shared_ptr, gtsam::Values::shared_ptr > aggregate_pose_graphs()
Put all connected pose graphs into one.
void reinitialize_received_pose_graphs()
Sets received pose graphs to false.
DecentralizedPGO(std::shared_ptr< rclcpp::Node > &node)
Initialization of parameters and ROS 2 objects.
void update_transform_to_origin(const gtsam::Pose3 &pose)
Update transform to origin.
void start_waiting()
Start waiting.
gtsam::Values optimize(const gtsam::NonlinearFactorGraph::shared_ptr &graph, const gtsam::Values::shared_ptr &initial)
Pose graph optimization function.
void current_neighbors_callback(const cslam_common_interfaces::msg::RobotIdsAndOrigin::ConstSharedPtr msg)
Receives current neighbors.
void broadcast_tf_callback()
Broadcast tf to current origin point.
#define LATEST_OPTIMIZED_FRAME_ID(id)
#define CURRENT_FRAME_ID(id)
gtsam::NonlinearFactorGraph::shared_ptr edges_msg_to_gtsam(const std::vector< cslam_common_interfaces::msg::PoseGraphEdge > &edges)
Converts from ROS 2 message to GTSAM.
gtsam::Pose3 odometry_msg_to_pose3(const nav_msgs::msg::Odometry &odom_msg)
Converts odometry message to gtsam::Pose3.
std::vector< cslam_common_interfaces::msg::PoseGraphValue > gtsam_values_to_msg(const gtsam::Values::shared_ptr values)
Converts from GTSAM to ROS 2 message.
gtsam::Values::shared_ptr values_msg_to_gtsam(const std::vector< cslam_common_interfaces::msg::PoseGraphValue > &values)
Converts from ROS 2 message to GTSAM.
gtsam::Pose3 transform_msg_to_pose3(const geometry_msgs::msg::Transform &msg)
Converts a transform msg into a gtsam::Pose3.
geometry_msgs::msg::Pose gtsam_pose_to_msg(const gtsam::Pose3 &pose)
Converts from GTSAM to ROS 2 message.
std::vector< cslam_common_interfaces::msg::PoseGraphEdge > gtsam_factors_to_msg(const gtsam::NonlinearFactorGraph::shared_ptr factors)
Converts from GTSAM to ROS 2 message.
geometry_msgs::msg::Transform gtsam_pose_to_transform_msg(const gtsam::Pose3 &pose)
Converts from GTSAM to ROS 2 message.
OptimizerState
State of the Pose Graph Optimization node.
@ WAITING_FOR_NEIGHBORS_INFO
@ WAITING_FOR_NEIGHBORS_POSEGRAPHS