尽量不要用行为树,除非公司里有个人,本来就很擅长行为树,那么可以交给他,其他人没必要参与了。行为树入门难,原因不是它本身多么复杂,而是网上的资料太少,尤其groot的资料更少,全靠自己摸索,一个并不复杂的问题,摸索一整天。有不少资料是游戏设计方面的,用于机器人领域的开源方案目前只有ROS2。资料这么少,肯定是有原因的。
最近从行为树版本3切换到版本4,发现有一些变化,又走了一遍坑之后,我还是认为最好不要用行为树。
准确地说,是BehaviorTree.CPP
和Groot
太垃圾,行为树本身在游戏行业已经用了很多年,不需要讨论其可用性。
行为树的缺点
网上找不到修饰节点Timeout
的使用方法,从API里找到了说明:The TimeoutNode will halt() a running child if the latter has been RUNNING for more than a give time. The timeout is in milliseconds and it is passed using the port “msec”.
但是我反复试验,发现这个节点总不生效,它修饰的节点运行时间早就超过Timeout
规定时间了,但是不会停止
安装 安装依赖项,然后去github的release里下载最新的版本1 2 3 4 5 sudo apt-get sqlite3 sudo apt-get install libzmq3-dev libboost-dev sudo apt-get install libboost-coroutine-dev sudo apt-get install qtbase5-dev libqt5svg5-dev libzmq3-dev libdw-dev
cmake老三样编译安装。
普通的cmake设置如下1 2 3 4 5 6 7 8 9 10 cmake_minimum_required(VERSION 3.10.2) project(simple_bt) set (CMAKE_CXX_SaTANDARD 17)set (CMAKE_CXX_STANDARD_REQUIRED ON)find_package(behaviortree_cpp) add_executable(${PROJECT_NAME} "simple_bt.cpp" ) target_link_libraries(${PROJECT_NAME} BT::behaviortree_cpp)
ROS2环境的设置如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 cmake_minimum_required(VERSION 3.8 ) project(test_node) if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) add_compile_options(-Wall -Wextra -Wpedantic) endif() set(CMAKE_CXX_STANDARD 17 ) add_compile_options(-Wextra -Wpedantic -Wno-unused-parameter -g) find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED) find_package(ament_index_cpp) find_package(behaviortree_cpp) INCLUDE_DIRECTORIES(/home/us er/catkin_ws/src/test_node/include) add_executable(test_node src/test.cpp) ament_target_dependencies(test_node rclcpp behaviortree_cpp ${BTCPP_LIBRARY} ) install(TARGETS test_node DESTINATION lib/${PROJECT_NAME} ) ament_package()
package.xml
如下:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?xml version="1.0"?> <?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> <package format ="3" > <name > test_node</name > <version > 0.0.0</version > <description > TODO: Package description</description > <maintainer email ="user@todo.todo" > zzp</maintainer > <license > TODO: License declaration</license > <buildtool_depend > ament_cmake</buildtool_depend > <depend > rclcpp</depend > <depend > std_msgs</depend > <depend > behaviortree_cpp</depend > <test_depend > ament_lint_auto</test_depend > <test_depend > ament_lint_common</test_depend > <export > <build_type > ament_cmake</build_type > </export > </package >
行为树的优点:
使用groot编辑,直观容易理解
行为逻辑和状态数据分离(减少了耦合),任何节点写好以后可以反复利用
重用性高,可用通过重组不同的节点来实现不同的行为树
线性的方式扩展,所以扩展性好
黑板变量用起来很灵活
缺点:
任何一个简单的操作都需要使用节点
每次从根节点开始逻辑,占用CPU更多
行为树本身并不具体实现机器人的执行内容,它只负责将执行内容进行编排。以Navigation2为例,具体的执行内容实现是放在各个server中的。行为树上的节点与server进行通信,请求具体的执行内容,然后获得反馈。根据反馈结果又可以请求另外的执行内容。这些不同执行内容间的跳转就是由行为树控制的。
另一种比较常见的组织机器人行为的方式是状态机。ROS1中的move_base就是基于状态机的。它与行为树最显著的区别是状态与执行内容是绑定在一起的。当执行内容需要在多个状态中执行时,各个状态下都需要放置执行内容的逻辑。当业务逻辑代码分散在各处时就不太好维护了
ROS2行为树动态库默认安装在/opt/ros/galactic/lib/libbehaviortree_cpp_v3.so
,头文件在/opt/ros/foxy/include/behaviortree_cpp_v3
xml 文件 xml格式有以下几个要点
root这个tag是必须的,而且它需要有main_tree_to_execute
的属性,表示执行哪颗树
root的子元素必须有BehaviorTree,BehaviorTree必须有ID属性
如果root拥有多个BehaviorTree,那么BehaviorTree
的ID的属性值必须是不同的,此时必须指定main_tree_to_execute
标签
如果root只有一个BehaviorTree,那么main_tree_to_execute
属性可有可无
BehaviorTree的子元素就是树节点(tree nodes)
TreeNodesModel
标签,主要用于Groot可视化。对于C++程序来说,可以没有。
createTreeFromFile
的文件路径错误时,会报错 what(): Internal error in realpath(): No such file or directory
调试 行为树的各种调试工具
Groot1的日志工具很不好用,在fbl
文件比较大的时候,很容易卡死。如果总的行为树很大,需要放大才能观看流程,十分不方便。Groot2的日志工具据说很好用,但是收费。
拆分行为树后,在Groot里不方便直接打开子树,只能再开一个Groot打开子树的xml文件. 后来Groot2解决了这个问题,在设置的Editor标签里还可设置是否每次都加载<include>
标签对应的文件。