1003 字
5 分钟
Decorators (二) - ForceSuccess & ForceFailure
一、ForceSuccess & ForceFailure 核心解析
这两个节点同样是装饰器节点(仅包含一个子节点),核心逻辑比 Inverter 更简单:强制修改子节点的最终返回状态,具体规则如下:
| 节点类型 | 核心功能 |
|---|---|
ForceSuccess | 执行子节点一次,无论子节点返回 FAILURE/SUCCESS, 最终都返回 SUCCESS;若子节点返回 RUNNING, 则自身也返回 RUNNING。 |
ForceFailure | 执行子节点一次,无论子节点返回 FAILURE/SUCCESS, 最终都返回 FAILURE;若子节点返回 RUNNING, 则自身也返回 RUNNING。 |
适用场景
- ForceSuccess:即使某个子节点执行失败,也不想让整个分支中断(比如“尝试发送消息失败,但不影响后续逻辑”)。
- ForceFailure:即使某个子节点执行成功,也需要强制让分支判定为失败(比如“检测到目标但权限不足,强制终止任务”)。
二、ROS2 + BehaviorTree4.x 实战示例
下面基于你熟悉的代码结构,展示这两个节点的使用(兼容 ROS2 Humble + BehaviorTree4.x)。
1. 完整代码示例
#include "behaviortree_cpp/bt_factory.h"#include "rclcpp/rclcpp.hpp"
// 自定义测试节点:可通过参数控制返回状态class ControllableNode : public BT::SyncActionNode{public: // 构造函数:接收节点名称 + 参数(返回SUCCESS/FAILURE) ControllableNode(const std::string& name, const BT::NodeConfig& config) : BT::SyncActionNode(name, config) {}
// 定义输入参数(控制返回状态) static BT::PortsList providedPorts() { return { BT::InputPort<std::string>("return_status", "SUCCESS or FAILURE") }; }
// 核心执行逻辑:根据参数返回指定状态 BT::NodeStatus tick() override { std::string status_str; // 获取输入参数 if (!getInput("return_status", status_str)) { RCLCPP_ERROR(rclcpp::get_logger("ControllableNode"), "未设置return_status参数"); return BT::NodeStatus::FAILURE; }
// 根据参数返回状态 if (status_str == "SUCCESS") { RCLCPP_INFO(rclcpp::get_logger("ControllableNode"), "执行ControllableNode,返回SUCCESS"); return BT::NodeStatus::SUCCESS; } else if (status_str == "FAILURE") { RCLCPP_INFO(rclcpp::get_logger("ControllableNode"), "执行ControllableNode,返回FAILURE"); return BT::NodeStatus::FAILURE; } else { RCLCPP_WARN(rclcpp::get_logger("ControllableNode"), "参数无效,默认返回FAILURE"); return BT::NodeStatus::FAILURE; } }};
int main(int argc, char** argv){ // 初始化ROS2节点 rclcpp::init(argc, argv); auto node = rclcpp::Node::make_shared("force_nodes_example_node");
// 1. 创建行为树工厂 BT::BehaviorTreeFactory factory;
// 2. 注册自定义节点 factory.registerNodeType<ControllableNode>("ControllableNode");
// 3. 定义行为树结构:测试ForceSuccess和ForceFailure std::string xml_text = R"( <root BTCPP_format="4"> <BehaviorTree ID="ForceNodesExample"> <Sequence> <!-- 测试1:ForceSuccess包裹返回FAILURE的节点 → 最终返回SUCCESS --> <ForceSuccess> <ControllableNode return_status="FAILURE"/> </ForceSuccess> <!-- 测试2:ForceFailure包裹返回SUCCESS的节点 → 最终返回FAILURE --> <ForceFailure> <ControllableNode return_status="SUCCESS"/> </ForceFailure> <!-- 测试3:ForceSuccess包裹返回SUCCESS的节点 → 仍返回SUCCESS --> <ForceSuccess> <ControllableNode return_status="SUCCESS"/> </ForceSuccess> </Sequence> </BehaviorTree> </root> )";
// 4. 创建行为树 auto tree = factory.createTreeFromText(xml_text);
// 5. 执行行为树 RCLCPP_INFO(node->get_logger(), "开始执行行为树..."); BT::NodeStatus status = tree.tickWhileRunning();
// 6. 输出最终结果 RCLCPP_INFO(node->get_logger(), "行为树执行完成,最终状态:%s", BT::toStr(status).c_str());
rclcpp::shutdown(); return 0;}2. 代码核心解释
ControllableNode:可通过输入参数return_status控制返回 SUCCESS 或 FAILURE,比固定返回的节点更灵活,能全面测试 Force 系列节点的效果。- 行为树结构:用
Sequence串联 3 个测试用例:ForceSuccess+ 返回 FAILURE 的子节点 → 最终返回 SUCCESSForceFailure+ 返回 SUCCESS 的子节点 → 最终返回 FAILUREForceSuccess+ 返回 SUCCESS 的子节点 → 仍返回 SUCCESS(验证“强制成功”对成功状态无影响)
- 参数传递:通过 XML 属性
return_status="FAILURE"给自定义节点传参,这是 ROS2 行为树中传递参数的标准方式。
3. 预期输出
运行代码后终端输出如下(重点看 Force 节点对结果的覆盖效果):
[INFO] [ControllableNode]: 执行ControllableNode,返回FAILURE[INFO] [ControllableNode]: 执行ControllableNode,返回SUCCESS[INFO] [ControllableNode]: 执行ControllableNode,返回SUCCESS[INFO] [force_nodes_example_node]: 行为树执行完成,最终状态:FAILURE注:Sequence 节点第二个子节点(ForceFailure)返回 FAILURE,因此整个 Sequence 最终状态为 FAILURE,符合预期。
三、XML 文件单独定义(ROS2 常用方式)
<root BTCPP_format="4"> <BehaviorTree ID="ForceNodesTest"> <!-- 场景1:即使传感器检测失败,也强制判定为成功,继续执行后续逻辑 --> <ForceSuccess name="ForceSensorSuccess"> <SensorCheck/> <!-- 自定义传感器检测节点 --> </ForceSuccess>
<!-- 场景2:即使任务执行成功,也强制判定为失败,终止当前分支 --> <ForceFailure name="ForceTaskFailure"> <TaskExecute/> <!-- 自定义任务执行节点 --> </ForceFailure> </BehaviorTree></root> 分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Decorators (二) - ForceSuccess & ForceFailure
https://github.com/qingfeng3374-lab 部分信息可能已经过时









