AutoAPMS
Streamlining behaviors in ROS 2
Loading...
Searching...
No Matches
mode_registration.cpp
1// Copyright 2024 Robin Müller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "auto_apms_px4/mode_registration.hpp"
16
17#include <chrono>
18#include <stdexcept>
19
20#include "px4_ros2/components/wait_for_fmu.hpp"
21
22namespace auto_apms_px4
23{
24
25ModeRegistrationHandler::ModeRegistrationHandler(rclcpp::Node::SharedPtr node_ptr) : node_ptr_(node_ptr) {}
26
28{
29 if (registered_mode_pub_) {
31 }
32}
33
34void ModeRegistrationHandler::registerMode(px4_ros2::ModeBase & mode, const std::string & mode_name)
35{
36 waitForFmu();
37
38 if (!mode.doRegister()) {
39 RCLCPP_FATAL(node_ptr_->get_logger(), "Registration of mode with name '%s' failed.", mode_name.c_str());
40 throw std::runtime_error("Mode registration failed");
41 }
42
43 // AFTER (!) registration, the nav_state (mode id) is known and can be announced for discovery by behaviors.
44 announce(mode_name, mode.id());
45
46 RCLCPP_INFO(node_ptr_->get_logger(), "Registered mode '%s' with nav_state %i.", mode_name.c_str(), mode.id());
47}
48
49void ModeRegistrationHandler::registerMode(px4_ros2::ModeExecutorBase & executor, const std::string & mode_name)
50{
51 waitForFmu();
52
53 // Registers the executor together with its owned mode. No announcement: a mode executor cannot be put in charge by
54 // another mode executor, so it is not relevant for native ROS 2 orchestration (which targets modes directly).
55 if (!executor.doRegister()) {
56 RCLCPP_FATAL(
57 node_ptr_->get_logger(), "Registration of mode executor for mode with name '%s' failed.", mode_name.c_str());
58 throw std::runtime_error("Mode executor registration failed");
59 }
60
61 RCLCPP_INFO(node_ptr_->get_logger(), "Registered mode executor owning mode '%s'.", mode_name.c_str());
62}
63
64void ModeRegistrationHandler::waitForFmu()
65{
66 constexpr int max_retries = 5;
67 for (int attempt = 0; attempt < max_retries; ++attempt) {
68 if (px4_ros2::waitForFMU(*node_ptr_, std::chrono::seconds(3))) {
69 RCLCPP_DEBUG(node_ptr_->get_logger(), "FMU availability test successful (attempt %d).", attempt + 1);
70 return;
71 }
72 RCLCPP_WARN(node_ptr_->get_logger(), "No message from FMU (attempt %d/%d). Retrying...", attempt + 1, max_retries);
73 }
74 throw std::runtime_error("No message from FMU after multiple attempts");
75}
76
77void ModeRegistrationHandler::announce(const std::string & mode_name, uint8_t nav_state)
78{
79 registered_mode_msg_.name = mode_name;
80 registered_mode_msg_.nav_state = nav_state;
81
82 // Latched so late-joining subscribers immediately receive the mapping.
83 registered_mode_pub_ = node_ptr_->create_publisher<auto_apms_px4_interfaces::msg::RegisteredMode>(
84 TOPIC_NAME, rclcpp::QoS(1).transient_local());
85 registered_mode_pub_->publish(registered_mode_msg_);
86
87 // Re-announce periodically (availability heartbeat + robust discovery when multiple modes share the topic).
88 announce_timer_ = node_ptr_->create_wall_timer(
89 std::chrono::seconds(1), [this]() { registered_mode_pub_->publish(registered_mode_msg_); });
90}
91
93{
94 // Destroying the publisher retracts the latched announcement for late-joining subscribers.
95 announce_timer_.reset();
96 registered_mode_pub_.reset();
97 RCLCPP_INFO(node_ptr_->get_logger(), "Stopped announcing mode '%s'.", registered_mode_msg_.name.c_str());
98}
99
100} // namespace auto_apms_px4
void registerMode(px4_ros2::ModeBase &mode, const std::string &mode_name)
Wait for the FMU, register mode with it and announce the mode's assigned nav_state.
ModeRegistrationHandler(rclcpp::Node::SharedPtr node_ptr)
Constructor.
~ModeRegistrationHandler()
Stops announcing the mode (see stopModeAnnouncement()) if it was ever announced.
static constexpr auto TOPIC_NAME
Shared topic (relative to the node namespace) on which registered modes are announced.
void stopModeAnnouncement()
Stop announcing the mode registered with registerMode().
Implementation of PX4 mode peers offered by px4_ros2_cpp enabling integration with AutoAPMS.