15#include "auto_apms_px4/behavior_mode_executor.hpp"
21#include "auto_apms_behavior_tree/executor/options.hpp"
22#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
23#include "auto_apms_px4/behavior_mode_executor_params.hpp"
24#include "px4_msgs/msg/vehicle_command.hpp"
33BehaviorOwnedMode::BehaviorOwnedMode(rclcpp::Node & node,
const px4_ros2::ModeBase::Settings & settings)
34: px4_ros2::ModeBase(node, settings)
36 actuator_setpoint_ptr_ = std::make_shared<px4_ros2::DirectActuatorsSetpointType>(*
this);
39void BehaviorOwnedMode::updateSetpoint(
float )
51 BehaviorOwnedMode & owned_mode,
const px4_ros2::ModeExecutorBase::Settings & settings,
53: px4_ros2::ModeExecutorBase(settings, owned_mode),
54 node_(owned_mode.node()),
55 owned_mode_(owned_mode),
56 behavior_executor_(engine),
57 config_provider_(std::move(config_provider)),
58 config_(config_provider_())
64 RCLCPP_INFO(node_.get_logger(),
"Behavior execution result: %s.", auto_apms_behavior_tree::toStr(result).c_str());
68 RCLCPP_INFO(node_.get_logger(),
"No longer in charge. Skipping completion reaction");
73 result == ExecutionResult::TREE_SUCCEEDED ? config_.on_completion : config_.on_failure;
74 performReaction(reaction, result);
85 throw std::invalid_argument(
86 "Invalid completion reaction '" + str +
"' (expected one of: hold, rtl, land, disarm, complete, none)");
89void BehaviorModeExecutor::onActivate()
94 config_ = config_provider_();
97 RCLCPP_ERROR(node_.get_logger(),
"Cannot start behavior: parameter 'behavior.build_request' must not be empty");
103 node_.get_logger(),
"Behavior executor put in charge. Starting behavior '%s'", config_.spec.
build_request.c_str());
105 if (config_.defer_failsafes) {
106 if (deferFailsafesSync(
true)) {
107 RCLCPP_INFO(node_.get_logger(),
"Failsafes are now being deferred while the behavior is running");
109 RCLCPP_WARN(node_.get_logger(),
"Failed to enable failsafe deferral");
117 const int source_component =
static_cast<int>(px4_msgs::msg::VehicleCommand::COMPONENT_MODE_EXECUTOR_START) +
id();
118 behavior_executor_.getGlobalBlackboardPtr()->set(AUTO_APMS_PX4_SOURCE_COMPONENT_GLOBAL_KEY, source_component);
122 behavior_executor_.getGlobalBlackboardPtr()->set(AUTO_APMS_PX4_MODE_EXECUTOR_ACTIVE_GLOBAL_KEY,
true);
124 auto_apms_behavior_tree::core::NodeManifest node_manifest;
125 if (!config_.spec.node_manifest.empty()) {
126 node_manifest = auto_apms_behavior_tree::core::NodeManifest::decode(config_.spec.node_manifest);
130 behavior_executor_.startExecution(config_.spec.build_request, config_.spec.entry_point, node_manifest);
131 }
catch (
const std::exception & e) {
132 RCLCPP_ERROR(node_.get_logger(),
"Failed to start behavior: %s", e.what());
137void BehaviorModeExecutor::onDeactivate(DeactivateReason reason)
139 const char * reason_str = reason == DeactivateReason::FailsafeActivated ?
"failsafe activated" :
"other";
140 RCLCPP_INFO(node_.get_logger(),
"Behavior executor deactivating (reason: %s)", reason_str);
143 if (behavior_executor_.isBusy()) {
144 RCLCPP_INFO(node_.get_logger(),
"Behavior is still running. Terminating it now...");
148 if (config_.defer_failsafes) {
149 deferFailsafesSync(
false);
153void BehaviorModeExecutor::performReaction(CompletionReaction reaction, ExecutionResult result)
155 px4_ros2::Result px4_result = px4_ros2::Result::Success;
157 case ExecutionResult::TREE_SUCCEEDED:
158 px4_result = px4_ros2::Result::Success;
160 case ExecutionResult::TERMINATED_PREMATURELY:
161 px4_result = px4_ros2::Result::Deactivated;
163 case ExecutionResult::TREE_FAILED:
164 case ExecutionResult::ERROR:
166 px4_result = px4_ros2::Result::ModeFailureOther;
170 const auto log_done = [
this](px4_ros2::Result r) {
171 RCLCPP_INFO(node_.get_logger(),
"Completion reaction finished (%s)", px4_ros2::resultToString(r));
176 RCLCPP_INFO(node_.get_logger(),
"Completion reaction: HOLD");
180 RCLCPP_INFO(node_.get_logger(),
"Completion reaction: RTL");
184 RCLCPP_INFO(node_.get_logger(),
"Completion reaction: LAND");
188 RCLCPP_INFO(node_.get_logger(),
"Completion reaction: DISARM");
192 RCLCPP_INFO(node_.get_logger(),
"Completion reaction: COMPLETE (reporting owned mode completion)");
193 owned_mode_.finish(px4_result);
196 RCLCPP_INFO(node_.get_logger(),
"Completion reaction: NONE");
201void BehaviorModeExecutor::scheduleLoiter()
203 scheduleMode(px4_ros2::ModeBase::kModeIDLoiter, [](px4_ros2::Result) {
212px4_ros2::ModeExecutorBase::Settings::Activation BehaviorModeExecutorNode::activationFromString(
const std::string & str)
214 using Activation = px4_ros2::ModeExecutorBase::Settings::Activation;
215 if (str ==
"armed")
return Activation::ActivateOnlyWhenArmed;
216 if (str ==
"always")
return Activation::ActivateAlways;
217 if (str ==
"immediately")
return Activation::ActivateImmediately;
218 throw std::invalid_argument(
"Invalid activation '" + str +
"' (expected one of: armed, always, immediately)");
221BehaviorModeExecutorNode::BehaviorModeExecutorNode(
const rclcpp::NodeOptions & options)
222: GenericTreeExecutorNode(
223 "behavior_mode_executor",
224 auto_apms_behavior_tree::TreeExecutorNodeOptions(options).enableStrictUnkownParameterRemoval(false)),
225 registration_handler_(getNodePtr())
233 const auto param_listener_ptr = std::make_shared<behavior_mode_executor_params::ParamListener>(getNodePtr());
234 const behavior_mode_executor_params::Params params = param_listener_ptr->get_params();
236 if (params.behavior.build_request.empty()) {
237 throw std::invalid_argument(
"Parameter 'behavior.build_request' must not be empty.");
243 auto config_provider = [param_listener_ptr]() -> BehaviorModeExecutor::Config {
244 const behavior_mode_executor_params::Params p = param_listener_ptr->get_params();
245 BehaviorModeExecutor::Config config;
246 config.spec.build_request = p.behavior.build_request;
247 config.spec.entry_point = p.behavior.entry_point;
248 config.spec.node_manifest = p.behavior.node_manifest;
251 config.defer_failsafes = p.defer_failsafes;
255 const px4_ros2::ModeExecutorBase::Settings settings{activationFromString(params.activation)};
257 owned_mode_ptr_ = std::make_unique<BehaviorOwnedMode>(*getNodePtr(), px4_ros2::ModeBase::Settings{params.mode_name});
259 executor_ptr_ = std::make_unique<BehaviorModeExecutor>(*owned_mode_ptr_, settings, std::move(config_provider), *
this);
262 registration_handler_.registerMode(*executor_ptr_, params.mode_name);
265void BehaviorModeExecutorNode::onTermination(
const ExecutionResult & result)
267 executor_ptr_->onExecutionResult(result);
272#include "rclcpp_components/register_node_macro.hpp"
Flexible and configurable ROS 2 behavior tree executor node.
@ TERMINATE
Halt the currently executing tree and terminate the execution routine.
ROS 2 component that hosts a BehaviorModeExecutor and its owned mode on an in-process behavior tree e...
static CompletionReaction reactionFromString(const std::string &str)
Parse a string into a CompletionReaction.
CompletionReaction
Reaction performed when a behavior terminates or fails, using the in-charge executor API.
@ HOLD
Schedule the owned mode (hold position) and stay in charge.
@ DISARM
Disarm the vehicle.
@ COMPLETE
Report the owned mode as completed to the FMU (relinquish charge).
@ LAND
Land at the current position.
@ NONE
Do nothing and stay in charge.
void onExecutionResult(ExecutionResult result)
Handle the termination of the behavior running on the in-process executor.
BehaviorModeExecutor(BehaviorOwnedMode &owned_mode, const px4_ros2::ModeExecutorBase::Settings &settings, std::function< Config()> config_provider, auto_apms_behavior_tree::GenericTreeExecutorNode &engine)
Constructor.
Registration placeholder PX4 mode owned by a BehaviorModeExecutor.
Implementation of PX4 mode peers offered by px4_ros2_cpp enabling integration with AutoAPMS.
std::string build_request
Behavior build request (e.g. a registered behavior resource identity or XML).