ROS2 的行为树 — 第 1 部分:解锁高级机器人决策和控制

news/2024/5/14 11:21:12/文章来源:https://blog.csdn.net/gongdiwudu/article/details/133064536

一、说明

        在复杂而迷人的机器人世界中,行为树(BT)已成为决策过程中不可或缺的一部分。它们提供了一种结构化模块化高效的方法来对机器人的行为进行编程。BT起源于视频游戏行业,用于控制非玩家角色,他们在机器人领域找到了归宿,他们擅长管理无数的任务和条件。

        用于机器人导航的Nav2和操作框架MoveIt等机器人软件使用行为树来处理复杂的动作和条件。

        在这篇文章中,我们将探索行为树以彻底理解它们。我们将首先分解行为树的基本部分,并清楚地了解它们的工作原理。然后,我们将进入实际领域,编写代码来创建和使用行为树,独立于任何特定的平台或框架。

但我们不会止步于此。一旦我们掌握了基础知识,我们将更进一步,将我们的行为树与ROS2(机器人操作系统2)集成,ROS<>是一个用于编写机器人软件的灵活框架。这将展示如何在现实世界的机器人环境中使用行为树,增强我们自主系统的决策能力。

二、行为树的基本概念 

        将行为树 (BT) 视为视频游戏角色、机器人或任何其他需要决定下一步操作的自主代理的决策图。

        想象一下,你正在导演一部戏剧,但你的演员是机器人。作为导演,你需要一种方法来指导你的演员,告诉他们该做什么以及什么时候做。行为树(BT)就像你的脚本,详细说明你的机器人演员需要做出的每一个动作。就像在真实的戏剧中一样,当导演叫“动作”(或者,在这种情况下,“滴答”)时,节目(或任务)就开始了。

        那么,什么是“刻度”?在BT的上下文中,tick是从树的根节点(或起点)到其子节点的信号,敦促它们执行任务。节点仅在收到即时报价时“采取行动”。

        现在,这个系统的美妙之处在于它的反馈机制。节点开始执行其任务后,它会使用以下三种状态之一与控制器(其父节点)通信其进度:正在运行成功失败

正在运行:这种状态有点像在说,“我在上面,但我还没有完成。
成功:这相当于,“我已经尽了自己的一份力量,而且进展顺利。
失败:这就像说,“我试过了,但我做不到。

        根据这些状态,导演决定将下一个即时报价发送到何处。这是一个持续到任务完成或不再有效的循环。

        行为树由两种主要类型的节点组成:控制流节点和执行节点。让我们更深入地了解它们。

        控制流节点就像导演的助手,他们帮助决定演员下一步应该做什么。主要有四种类型:

        序列(→)节点:这就像一个严格的助手,他要求每个任务都必须完美地完成,顺序,然后才能继续下一个任务。如果任何任务失败,序列将停止并报告失败。

        回退 (?节点(也称为选择器):这是一个更灵活的助手,他有一个任务列表并逐个尝试,直到一个成功。如果所有任务都失败,则回退报告失败。

        并行 (⇒)节点: 这是一个可以同时处理多项任务的助手,指导多个演员同时执行他们的任务。并行节点根据一组必须成功的任务来定义其成功。

        装饰器节点:这个助手有点特别,因为它只处理一个演员,但可以通过各种方式修改演员的行为。有不同种类的装饰器,每种装饰器都为任务提供了独特的转折。

执行节点是参与者,即执行任务(操作)或评估某些条件(条件)的参与者。

        操作节点: 当此参与者收到勾号时,它会启动其任务,使控制器保持“正在运行”状态的更新,最后报告“成功”或“失败”。

        条件节点: 这个演员更像是一个抽查者。它评估是否满足某些条件,如果条件为真,则立即报告“成功”,如果条件为假,则立即报告“失败”。

        现在您已经了解了基础知识,您可以使用行为树指导您的机器人游戏。请记住,此框架旨在提高灵活性和适应性,使您的机器人参与者能够快速响应变化并执行复杂、细致入微的任务。

三、BT 的节点类型

        让我们考虑一个机器人手臂上下文中的行为树,它可以捡起球并将其放置在球门位置。

高级BT执行一项任务,包括首先找到,然后挑选并最终放置球

  1. BT 以序列节点作为主控制器开始。该节点对机器人有两个主要任务:“查找球”和“放置球”。
  2. 第一个任务“找球”涉及一个机器人,该机器人被分配来定位球。
  3. 第二个任务“放置一个球”更为复杂。此任务由另一个“序列”节点管理,该节点可确保按顺序执行一系列操作。此序列涉及任务“挑选球”。
  4. “拾球”任务由两个回退节点管理。这些节点中的每一个都有不同的方法来引导机器人。
  • 第一个回退节点确保机器人检查“球是否接近”,如果是,则指示机器人“接近球”。
  • 第二个回退节点负责检查“球是否被抓住”,如果没有,则指示机器人“抓住球”。

        请记住,在BT中,节点仅在收到信号或“滴答”时才起作用。一旦任务启动,机器人就会将其状态传达回其父节点。循环一直持续到所有任务完成或无法完成。

        到目前为止,我们已经详细讨论了行为树的概念和机制。现在,是时候将这些想法付诸行动了。

        在深入研究实际编码之前,我们需要设置行为树包。在以下各节中,我们将引导您完成设置此包的过程,之后我们将探索将行为树变为现实的代码。

        要在 Ubuntu 20.04 上设置并运行我们的第一个 BehaviorTree.CPP 示例,请执行以下步骤:

# Install the required dependencies:
# Open a terminal and run the following commands to install the necessary 
# dependencies:
sudo apt-get update
sudo apt-get install -y libzmq3-dev libboost-dev libboost-system-dev libboost-filesystem-dev libboost-thread-dev libprotobuf-dev protobuf-compiler libmsgsl-dev libgtest-dev cmake# Build and install BehaviorTree.CPP:
# Clone the BehaviorTree.CPP repository, build, and install the library:
git clone https://github.com/BehaviorTree/BehaviorTree.CPP.git
cd BehaviorTree.CPP
mkdir build
cd build
cmake ..
make -j$(nproc)
sudo make install

让我们从使用 BehaviorTree 的简单示例开始.CPP将帮助您了解基础知识并熟悉语法。

mkdir ~/example1
cd ~/example1
touch main.cpp && touch CMakeLists.txt
// main.cpp#include <behaviortree_cpp/bt_factory.h>
#include <behaviortree_cpp/behavior_tree.h>using namespace BT;class SaySomething : public SyncActionNode
{
public:SaySomething(const std::string& name, const NodeConfiguration& config): SyncActionNode(name, config){}static PortsList providedPorts(){return { InputPort<std::string>("message") };}NodeStatus tick() override{std::string message;getInput("message", message);std::cout << "Robot says: " << message << std::endl;return NodeStatus::SUCCESS;}
};static const char* xml_text = R"(
<root><BehaviorTree><SaySomething message="Hello, World!" /></BehaviorTree>
</root>
)";int main()
{BehaviorTreeFactory factory;factory.registerNodeType<SaySomething>("SaySomething");auto tree = factory.createTreeFromText(xml_text);tree.tickWhileRunning();return 0;
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(bt_example)set(CMAKE_CXX_STANDARD 17)find_package(behaviortree_cpp REQUIRED)add_executable(bt_example main.cpp)
target_link_libraries(bt_example BT::behaviortree_cpp)
# Now, build and run the example:
mkdir build
cd build
cmake ..
make
./bt_example

        太棒了,您已经获得了第一个BehaviorTree.CPP 代码片段!该脚本代表了一个基本的行为树,其中机器人(您的演员)有一个简单的任务:说些什么。让我们来分解一下:

        该类扩展了该类,该类是 BehaviorTree.CPP 提供的执行节点类型之一。这是一个同步操作节点,这意味着它不返回“正在运行”状态,而只返回“成功”或“失败”。在我们的例子中,它将始终返回“成功”。SaySomethingSyncActionNodeSyncActionNode

        该方法是在勾选此节点时调用的主要方法。在这里,它检索输入消息并将其输出到控制台。由于它每次都成功执行其任务,因此它会返回 .tick()NodeStatus::SUCCESS

        定义为 的 XML 文本表示行为树的结构。它包含一个节点,带有消息“Hello, World!xml_textSaySomething

        最后,该函数创建一个 ,注册节点类型,从 XML 文本创建树,并在树运行时勾选树。这让机器人说“你好,世界!mainBehaviorTreeFactorySaySomething

        现在,有了基础知识,您就可以转向更复杂的行为树,例如拾取和放置树。在选取和放置树中,您将引入更多控制流节点和执行节点,将它们交织在一起以实现所需的行为。此处提供了此示例的完整代码。

#include <iostream>#include <behaviortree_cpp/bt_factory.h>
#include <behaviortree_cpp/behavior_tree.h>using namespace BT;// Define FindBall action node
class FindBall : public BT::SyncActionNode 
{public:FindBall(const std::string& name) : BT::SyncActionNode(name, {}){}// Define the tick() function for the FindBall nodeNodeStatus tick() override{std::cout << "[⚓ FindBall ] => \t" << this->name() << std::endl; return BT::NodeStatus::SUCCESS;}
};// Define PickBall action node
class PickBall : public BT::SyncActionNode
{public:PickBall(const std::string& name) : BT::SyncActionNode(name, {}){}// Define the tick() function for the PickBall nodeNodeStatus tick() override{std::cout << "[⚓ PickBall ] => \t" << this->name() << std::endl;return BT::NodeStatus::SUCCESS;}
};// Define PlaceBall action node
class PlaceBall : public BT::SyncActionNode
{public:PlaceBall(const std::string& name) : BT::SyncActionNode(name, {}){}// Define the tick() function for the PlaceBall nodeNodeStatus tick() override{std::cout << "[⚓ PlaceBall ] => \t" << this->name() << std::endl;return BT::NodeStatus::SUCCESS;}
};// Define GripperInterface class for interacting with the gripper
class GripperInterface
{private:bool _opened;public:GripperInterface() : _opened(true){}NodeStatus open(){_opened = true;std::cout << "GripperInterface::open" << std::endl;return BT::NodeStatus::SUCCESS;}NodeStatus close(){std::cout << "GripperInterface::close" << std::endl;_opened = false;return BT::NodeStatus::SUCCESS;}
};// Define BallClose condition function
BT::NodeStatus BallClose()
{std::cout << "[ Close to ball: NO ]" << std::endl;return BT::NodeStatus::FAILURE;
}// Define BallGrasped condition function
BT::NodeStatus BallGrasped()
{std::cout << "[ Grasped: NO ]" << std::endl;return BT::NodeStatus::FAILURE;
}// Define the behavior tree structure in XML format
static const char* xml_text = R"(<root main_tree_to_execute = "MainTree" ><BehaviorTree ID="MainTree"><Sequence name="root_sequence"><FindBall   name="found_ok"/><Sequence><Fallback><BallClose   name="no_ball"/><PickBall    name="approach_ball"/></Fallback><Fallback><BallGrasped   name="no_grasp"/><GraspBall  name="grasp_ball"/></Fallback></Sequence><PlaceBall   name="ball_placed"/></Sequence></BehaviorTree></root>)";int main()
{    BehaviorTreeFactory factory;// Register custom action nodes with the factoryfactory.registerNodeType<FindBall>("FindBall");factory.registerNodeType<PickBall>("PickBall");factory.registerNodeType<PlaceBall>("PlaceBall");// Register custom condition nodes with the factoryfactory.registerSimpleCondition("BallClose", std::bind(BallClose));factory.registerSimpleCondition("BallGrasped", std::bind(BallGrasped));// Create an instance of GripperInterfaceGripperInterface gripper;// Register a simple action node using the GripperInterface instancefactory.registerSimpleAction("GraspBall", std::bind(&GripperInterface::close, &gripper));// Create the behavior tree using the XML descriptionauto tree = factory.createTreeFromText(xml_text);// Run the behavior tree until it finishestree.tickWhileRunning();return 0;
}
# Output
[⚓ FindBall ] =>       found_ok
[ Close to ball: NO ]
[⚓ PickBall ] =>       approach_ball
[ Grasped: NO ]
GripperInterface::close
[⚓ PlaceBall ] =>      cube_placed

        太好了,您创建了一个更复杂的行为树!此脚本表示机器人的拾取和放置操作,由查找、拾取和放置球组成。让我们剖析一下:

  1. 您已经创建了三个操作节点:、 和 。这些类中的每一个都扩展并实现函数,该函数记录操作的名称并返回 .FindBallPickBallPlaceBallSyncActionNodetick()NodeStatus::SUCCESS
  2. 您已经定义了一个类,该类表示机器人的抓手。它可以打开和关闭夹持器,两个操作返回。GripperInterfaceNodeStatus::SUCCESS
  3. 您已经定义了两个条件函数:和 。这些功能表示机器人在捡球之前需要进行的检查。他们目前总是返回,模拟球没有接近并且机器人还没有抓住球的场景。BallCloseBallGraspedNodeStatus::FAILURE
  4. XML 字符串定义行为树。它从一个序列节点开始,该节点首先尝试找到球 ()。找到球后,它会尝试拾取球,这是由两个回退节点组成的另一个序列节点。第一个回退节点检查球是否接近 (),如果没有,机器人将接近球 ()。第二个回退节点检查球是否被抓住(),如果没有,机器人会抓住球()。一旦球被捡起,机器人就会放置球()。xml_textFindBallBallClosePickBallBallGraspedGraspBallPlaceBall
  5. 最后,该函数注册自定义操作和条件节点,创建 的实例,使用 注册操作,从 XML 文本创建树,并在树运行时勾选树。mainGripperInterfaceGraspBallGripperInterface

        此代码提供了机器人如何使用行为树执行一系列任务的实际演示,并在此过程中进行检查。但是,请注意,当前条件始终返回 。为了使此示例更加逼真,您可能需要根据机器人的实际状态及其环境更新这些条件。NodeStatus::FAILURE

        这是这篇文章的总结!您已经了解了行为树、其结构和组件,甚至使用拾取和放置示例实现了复杂的树。

        请继续关注我们的下一篇文章,我们将把事情提升一个档次。我们将介绍 ROS2(机器人操作系统 2)与行为树的集成,为您的机器人应用程序创建复杂、健壮和自适应行为开辟更多可能性。下一篇文章见!

        我希望这些信息对您有所帮助,并且您发现它很有用。如果您有任何问题或意见,请随时告诉我。感谢您的反馈,并很乐意帮助回答您可能遇到的任何问题。感谢您抽出宝贵时间阅读本文。

        我总是在LinkedIn上分享有趣的文章和更新,所以如果您想随时了解情况,请随时在平台上关注我。杰加特桑·尚穆甘

参考资料:
1.行为树官方文档
2.机器人和人工智能中的行为树:简介
3.导航2行为树

Nav2 Behavior Trees — Nav2 1.0.0 documentation (ros.org) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_173541.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云原生的简单理解

一、何谓云原生&#xff1f; 一种构建和运行应用软件的方法 应用程序从设计之初即考虑到云的环境&#xff0c;原生为云而设计&#xff0c;在云上以最佳姿势运行&#xff0c;充分利用和发挥云平台的弹性分布式优势。 二、包括以下四个要素 采用容器化部署&#xff1a;实现云平…

机器学习(17)---支持向量机(SVM)

支持向量机 一、概述1.1 介绍1.2 工作原理1.3 三层理解 二、sklearn.svm.SVC2.1 查看数据集2.2 contour函数2.3 画决策边界&#xff1a;制作网格2.4 建模画图 三、非线性情况推广3.1 查看数据集3.2 线性画图3.3 为非线性数据增加维度并绘制3D图像 四、核函数 一、概述 1.1 介绍…

hadoop测试环境sqoop使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Sqoop看这篇文章就够了_must contain $conditions in where clause._SoWhat1412的博客-CSDN博客 大数据环境 C:\Windows\System32\drivers\etc 修改ip和hostname的对应关系 1…

记一次hyperf框架封装swoole自定义进程

背景 公司准备引入swoole和rabbitmq来处理公司业务。因此&#xff0c;我引入hyperf框架&#xff0c;想用swoole的多进程来实现。 自定义启动服务封装 <?php /*** 进程启动服务【manager】*/ declare(strict_types1);namespace App\Command;use Swoole; use Swoole\Proce…

StarRocks 社区:从初生到两周年的进化之路

2021 年 9 月 8 日&#xff0c;StarRocks 开源社区诞生。从第一天开始&#xff0c;我们怀揣着“打造世界一流的数据分析产品”的梦想&#xff0c;踏上了星辰大海的征途。 两年间&#xff0c;StarRocks 在 GitHub 上收获了 5.4K Stars&#xff0c;产品共迭代发布了 90 余个版本&…

Java下打印九九乘法表

这个算法是基于打直角三角型演变而来&#xff0c;代码如下&#xff1a; public class MyWork {public static void main(String[] args) {for (int i 1; i < 10; i) {for (int j 1; j < i; j) {System.out.print(j "x" i "" i*j "\t&qu…

以太网媒体接口MII/RMII/SMII/GMII/RGMII/SGMII

以太网媒体接口MII/RMII/SMII/GMII/RGMII/SGMII GMAC系统框架&#xff08;EMAC是百兆mac&#xff0c; GMAC是千兆mac&#xff09;网卡网卡系统框架结构 PHY&#xff08;Physical Layer&#xff0c;物理层&#xff09;MAC(Media Access Control、媒体访问控制器)以太网结构大框架…

HTTPS 证书生成脚本详细讲解

前言 HTTPS证书的作用是用于保障网站的安全性。在HTTPS协议中&#xff0c;通过使用证书来实现客户端与服务器之间的认证和数据加密&#xff0c;防止中间人攻击、信息泄漏等安全问题的发生。https证书也就是SSL证书&#xff0c;我们首先要确定好需要 https 安全连接的域名&…

Springboot整合jdbc和Mybatis

目录 整合jdbc 1. 新建项目 2. 编写yaml配置文件连接数据库 3. 测试类 使用原生的jdbcTemplate进行访问测试 使用Druid连接池 1. 添加类型 2. 初始化连接池 3. 编写config类 配置Druid数据源监视 整合Mybatis 1. 导入依赖 2. 编写mapper接口 3. 编写实体类 4. 编…

【LeetCode热题100】--560.和为K的子数组

560.和为K的子数组 示例2的结果&#xff1a; 输入&#xff1a;nums [1,2,3] ,k3的时候 连续子数组有[1,2],[3]&#xff0c;一共有2个 利用枚举法&#xff1a; 枚举[0,…i]里所有的下标j来判断是否符合条件 class Solution {public int subarraySum(int[] nums, int k) {i…

HiEV独家 | 接棒余承东,华为光产品线总裁靳玉志出任车BU CEO

作者 | 德新 编辑 | 王博 HiEV从多个信息源获悉&#xff0c;华为光产品线总裁靳玉志已于近期接任智能汽车解决方案BU CEO一职&#xff0c;而余承东担任智能汽车解决方案BU&#xff08;以下简称「车BU」&#xff09;董事长一职。 华为光产品线又称华为光传输与接入产品线&#…

极光笔记 | 大语言模型插件

在人工智能领域&#xff0c;大语言模型&#xff08;LLMs&#xff09;是根据预训练数据集进行”学习“&#xff0c;获取可以拟合结果的参数&#xff0c;虽然随着参数的增加&#xff0c;模型的功能也会随之增强。但无论专业领域的小模型&#xff0c;还是当下最火、效果最好的大模…

rtsp转webrtc的其他几个项目

1&#xff09; mpromonet/webrtc-streamer &#xff08;c开发&#xff09; 把rtsp转webrtc&#xff0c; 通过 load urls from JSON config file ./webrtc-streamer -C config.json 通过exe文件和docker项目实际测试可以显示&#xff0c;但不太稳定加载慢,有时候出错后很难…

Unity制作曲线进度条

unity制作曲线进度条 大家好&#xff0c;我是阿赵。   在使用Unity引擎做进度条的时候&#xff0c;有时会遇到一个问题&#xff0c;如果进度条不是简单的横向、纵向或者圆形&#xff0c;而是任意的不规则形状&#xff0c;那该怎么办呢&#xff1f;比如这样的&#xff1a; 一…

基于Xml方法的Bean的配置-实例化Bean的方法-构造方法

SpringBean的配置详解 Bean的实例化配置 Spring的实例化方法主要由以下两种 构造方法实例化 底层通过构造方法对bean进行实例化 构造方法实例化bean又分为无参方法实例化和有参方法实例化&#xff0c;在Spring中配置的<bean>几乎都是无参构造该方式&#xff0c;默认是无…

DevSecOps内置安全保护

前言 随着DevOps的发展&#xff0c;DevOps大幅提升了企业应用迭代的速度。但同时&#xff0c;安全如果不能跟上步伐&#xff0c;不仅会抵消DevOps变革带来的提升&#xff0c;拖慢企业数字化转型进程&#xff0c;还会导致漏洞与风险不约而至。所以安全能力在全球范围内受到的重…

配置HBase和zookeeper

一、上传文件 二、解压 tar -zxf ./zookeeper-3.4.5-cdh5.14.2.tar.gz -C /opt/soft/ tar -zxf ./hbase-2.3.5-bin.tar.gz -C ../soft/ 三、改名字 mv ./zookeeper-3.4.5-cdh5.14.2/ zk345 mv ./hbase-2.3.5/ hbase235 四、配置映射 vim /etc/profile#ZK export ZOOKEEPE…

1999-2018年地级市一般公共预算收入、支出(教育事业费、科技支出)

1999-2018年地级市一般公共预算收入、支出&#xff08;教育事业费、科技支出&#xff09; 1、时间&#xff1a;1999-2018年 2、来源&#xff1a;城市年鉴 3、指标&#xff1a;行政区划代码、城市、年份、地方一般公共预算收入_市辖区_万元、地方一般公共预算支出_市辖区_万元…

山石网科国产化防火墙,打造全方位边界安全解决方案

互联网的快速发展促进了各行各业的信息化建设&#xff0c;但也随之带来了诸多网络安全风险。大部分组织机构采用统一互联网接入方案&#xff0c;互联网出口承担着内部用户访问互联网的统一出口和对外信息服务的入口&#xff0c;因此在该区域部署相匹配的安全防护手段必不可少。…

iOS加固保护技术:保护你的iOS应用免受恶意篡改

目录 转载&#xff1a;开始使用ipaguard 前言 下载ipa代码混淆保护工具 获取ipaguard登录码 代码混淆 文件混淆 IPA重签名与安装测试 转载&#xff1a;开始使用ipaguard 前言 iOS加固保护是直接针对ios ipa二进制文件的保护技术&#xff0c;可以对iOS APP中的可执行文件…