note : 使用本教程前,建议先弄懂 behaviorTree的使用 ,ros server 的使用, ros action 的使用。
下载参考我提供的demo:demo链接
sudo apt-get install ros-$ROS_DISTRO-behaviortree-cpp-v3
以本教程的 demo 为例子,讲解如何在ROS中使用行为树
库的作者已经给出给出了一个demo ,直接复制就行,参考 官方教程, 可以对照参考我的教程和这份官方教程,理解更深。
步骤:将behaviortree_ros
文件夹复制到 include
目录下,可以看到里面有bt_action_node.h
和 bt_service_node.h
, 这两个头文件就是对 action 和 service 的 封装。
srv
文件夹中创建 服务 do_what.srv
action
文件夹中创建 action Shoot.action
do_what.srv
这个服务的逻辑,通过剩余血量和子弹数量,判断机器人下一步该做什么
int32 blood
int32 remain_bullets
---
int32 dowhat
Shoot.action
这个 action 的逻辑,开枪动作,action过程中反馈正在开第几枪,action 结束后,返回是否打完子弹的结果
# Define the goal
int32 Number_of_shots # 一共打几枪
---
# Define the result
string finish # 打完没
---
# Define a feedback message
int32 Which_shot # 开到第几枪了
复制msg
文件夹进来就行
package.xml
文件
<package format="2">
<name>ros_behaviortree_demoname>
<version>0.0.0version>
<description>The ros_behaviortree_demo packagedescription>
<maintainer email="[email protected]">liaomaintainer>
<license>TODOlicense>
<buildtool_depend>catkinbuildtool_depend>
<build_depend>roscppbuild_depend>
<build_depend>std_msgsbuild_depend>
<build_depend>behaviortree_cpp_v3build_depend>
<build_depend>actionlibbuild_depend>
<build_depend>actionlib_msgsbuild_depend>
<build_depend>message_generationbuild_depend>
<build_depend>genmsgbuild_depend>
<build_export_depend>roscppbuild_export_depend>
<build_export_depend>actionlibbuild_export_depend>
<build_export_depend>actionlib_msgsbuild_export_depend>
<build_export_depend>std_msgsbuild_export_depend>
<build_export_depend>genmsgbuild_export_depend>
<exec_depend>roscppexec_depend>
<exec_depend>std_msgsexec_depend>
<exec_depend>behaviortree_cpp_v3exec_depend>
<exec_depend>actionlibexec_depend>
<exec_depend>actionlib_msgsexec_depend>
<exec_depend>message_generationexec_depend>
<exec_depend>genmsgexec_depend>
<export>
export>
package>
cmakeList.txt
文件,并编译生成相关代码note: 这一步做4件重要的事
cmake_minimum_required(VERSION 3.0.2)
project(ros_behaviortree_demo)
set(CMAKE_CXX_STANDARD 14)
set(ROS_DEPENDENCIES
roscpp std_msgs
behaviortree_cpp_v3
actionlib_msgs
actionlib
message_generation
genmsg
)
# 包含行为树库的路径,同时还包含了创建action 和 service 相关的库
find_package(catkin REQUIRED COMPONENTS ${ROS_DEPENDENCIES})
# 生成与行为树相关的数据类型
add_message_files(
FILES
BehaviorTree.msg
NodeParameter.msg
NodeStatus.msg
StatusChange.msg
StatusChangeLog.msg
TreeNode.msg
)
# 生成 do_whta service 相关代码
add_service_files(
FILES
do_what.srv
)
# 生成 Shoot action 相关代码
add_action_files(
DIRECTORY action
FILES Shoot.action
)
# Generate added messages and services with any dependencies listed here
generate_messages(
DEPENDENCIES
std_msgs # Or other packages containing msgs
actionlib_msgs
)
catkin_package(
INCLUDE_DIRS include
LIBRARIES ros_behaviortree_demo
CATKIN_DEPENDS ${ROS_DEPENDENCIES}
# DEPENDS system_lib
)
include_directories(
include
${catkin_INCLUDE_DIRS}
)
编译
catkin build ros_behaviortree_demo # 如果没有安装catkin tools,那就用catkin_make
note: 这里与普通的ROS 服务端没区别
do_what_service_server
在src文件夹创建 do_what_service_server.cpp
#include
#include
bool DoSomething(ros_behaviortree_demo::do_what::Request &req,
ros_behaviortree_demo::do_what::Response &res)
{
if( (req.blood + req.remain_bullets) < 5){
// 如果子弹数量+血量 < 5 ,就躲避,躲避用1表示
res.dowhat = 1;
ROS_INFO("dowhat = %d", res.dowhat);
}
if( (req.blood + req.remain_bullets) >= 5){
// 如果子弹数量+血量 >= 5 ,就进攻,进攻用2表示
res.dowhat = 2;
ROS_INFO("dowhat = %d", res.dowhat);
}
return true;
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "do_what_server");
ros::NodeHandle n;
ros::ServiceServer service = n.advertiseService("do_what", DoSomething);
ROS_INFO("Ready to do what.");
ros::spin();
return 0;
}
shoot_action_server
在 src
文件夹创建 shoot_action_server.cpp
#include // Note: "Action" is appended
#include
typedef actionlib::SimpleActionServer<ros_behaviortree_demo::ShootAction> Server;
void shoot_action_callback(const ros_behaviortree_demo::ShootGoalConstPtr& goal, Server* server)
{
ros_behaviortree_demo::ShootFeedback feedback;
ros_behaviortree_demo::ShootResult result;
ros::Rate r(2); // 一秒开两枪
bool success = true;
for(int i=1; i <= goal->Number_of_shots; i++)
{
if (server->isPreemptRequested() || !ros::ok())
{
ROS_INFO("shoot is Preempted");
success = false;
break;
}
ROS_INFO("the NO.%d shoot ", i);
feedback.Which_shot = i;
server->publishFeedback(feedback);
r.sleep();
}
if(success)
{
result.finish = "yes";
server->setSucceeded(result);
}
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "shoot_server");
ros::NodeHandle n;
Server server(n, "shoot", boost::bind(&shoot_action_callback, _1, &server), false);
server.start();
ros::spin();
return 0;
}
CmakeLists.txt
添加 do_what_service_server.cpp
和 shoot_action_server.cpp
的 编译规则# 编译 do_what_service_server
add_executable(do_what_service_server src/do_what_service_server.cpp)
add_dependencies(do_what_service_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ros_behaviortree_demo_gencpp)
target_link_libraries(do_what_service_server ${catkin_LIBRARIES} )
# 编译 shoot_action_server
add_executable(shoot_action_server src/shoot_action_server.cpp)
add_dependencies(shoot_action_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} ros_behaviortree_demo_gencpp)
target_link_libraries(shoot_action_server ${catkin_LIBRARIES} )
在include/ros_behaviortree_demo
文件夹创建tree_xml.h
,这里面放行为树的xml文件
// 本行为树的逻辑:整个树是一个序列节点,依次运行以下行为
// 1. 一个简单的printf行为
// 2. 给do_what 服务发送请求,并等待结果
// 3. 给 shoot action 发送请求,并等待结果
#ifndef SRC_TREE_XML_H
#define SRC_TREE_XML_H
static const char* xml_text = R"(
)";
#endif //SRC_TREE_XML_H
tree_node.h
、tree_node.cpp
在 src
文件夹创建 tree_node.cpp
,在include/ros_behaviortree_demo
文件夹创建tree_node.h
。
这两个文件的作用是实现决策树里面叶节点的具体工作。
从上面的决策树逻辑可以看到一共有三个叶节点,分别做出了三种行为,分别是 SaySomething
doWhat
, shoot
。对应的具体行为是SayHelloWorld
, doWhat
,shoot_5_bullets
。
因此,要知道怎么实现具体行为,就必须先在tree_node.cpp
和tree_node.h
文件里面定义该种行为的实现方法。
tree_node.h
: 代码链接
tree_node.cpp
:代码链接
run_bh_tree.cpp
在src
文件夹创建 run_bh_tree.cpp
#include
#include
#include
#include
int main(int argc, char **argv)
{
ros::init(argc, argv, "run_tree");
ros::NodeHandle nh;
BT::BehaviorTreeFactory factory;
// 注册各个叶节点,将行为树的叶节点与实现方式绑定
factory.registerNodeType<TreeNode::SaySomething>("SayHelloWorld");
BT::RegisterRosService<TreeNode::DoWhat>(factory, "doWhat", nh);
BT::RegisterRosAction<TreeNode::Shoot>(factory, "shoot_5_bullets", nh);
auto tree = factory.createTreeFromText(xml_text);
BT::NodeStatus status = BT::NodeStatus::IDLE;
while( ros::ok())
{
ros::spinOnce();
status = tree.tickRoot();
std::cout << status << std::endl;
ros::Duration sleep_time(0.1);
sleep_time.sleep();
}
return 0;
}
CmakeLists.txt
添加 run_bh_tree.cpp
的编译规则# 创建行为树
add_executable(run_bh_tree src/run_bh_tree.cpp src/tree_node.cpp)
add_dependencies(run_bh_tree ${catkin_EXPORTED_TARGETS} ros_behaviortree_demo_gencpp)
target_link_libraries(run_bh_tree ${catkin_LIBRARIES})
catkin build ros_behaviortree_demo
打开三个命令行,分别执行
启动 do_what 服务端
rosrun ros_behaviortree_demo do_what_service_server
启动 shoot 服务端
rosrun ros_behaviortree_demo shoot_action_server
启动 行为树
rosrun ros_behaviortree_demo run_bh_tree