上篇中,在编译BehaviorTree.CPP时,使用了Boost,ZeroMQ和Curses库,尤其是Boost,这个库很庞大,本文讲述如何轻量化BehaviorTree.CPP,不依赖Boost,ZeroMQ和ncurse库。
一 修改BehaviorTree.CPP的CMakeLists.txt
下载好BehaviorTree.CPP后,打开里面的CMakeLists.txt,找到Boost的find_package,然后注释掉,
接着找到ZMQ的find_package,也注释掉,
最后是找到Curses的find_package,也注释掉,
以上可以根据自己的需要来进行选择。Boost提供了协程,ZeroMQ会影响PublishedZMQ和bt_recorder的编译,Curses是个图形库,应该是用来写一些界面的。
最后,还有4个配置选项,全部改成OFF,(也可根据需要调整)
二 搭建工程并运行
工程结构如下,
BehaviorTree.CPP是上节下载的源码。
工程目录下的CMakeLists.txt内容如下,
cmake_minimum_required(VERSION 3.5)
project(lite_demo)
# 编译BehaviorTree.CPP
add_subdirectory(BehaviorTree.CPP)
find_package(Threads)
include_directories(BehaviorTree.CPP/include)
include_directories(BehaviorTree.CPP/sample_nodes)
add_executable(main src/main.cpp BehaviorTree.CPP/sample_nodes/dummy_nodes.cpp)
target_link_libraries(main behaviortree_cpp_v3 ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS} )
src下有个main.cpp,内容如下,
#include "behaviortree_cpp_v3/bt_factory.h"
#define MANUAL_STATIC_LINKING
#ifdef MANUAL_STATIC_LINKING
#include "dummy_nodes.h"
#endif
using namespace BT;
/** Behavior Tree are used to create a logic to decide what
* to "do" and when. For this reason, our main building blocks are
* Actions and Conditions.
*
* In this tutorial, we will learn how to create custom ActionNodes.
* It is important to remember that NodeTree are just a way to
* invoke callbacks (called tick() ). These callbacks are implemented by the user.
*/
// clang-format off
static const char* xml_text = R"(
<root main_tree_to_execute = "MainTree" >
<BehaviorTree ID="MainTree">
<Sequence name="root_sequence">
<CheckBattery name="battery_ok"/>
<OpenGripper name="open_gripper"/>
<ApproachObject name="approach_object"/>
<CloseGripper name="close_gripper"/>
</Sequence>
</BehaviorTree>
</root>
)";
// clang-format on
int main()
{
// We use the BehaviorTreeFactory to register our custom nodes
BehaviorTreeFactory factory;
/* There are two ways to register nodes:
* - statically, i.e. registering all the nodes one by one.
* - dynamically, loading the TreeNodes from a shared library (plugin).
* */
#ifdef MANUAL_STATIC_LINKING
// Note: the name used to register should be the same used in the XML.
// Note that the same operations could be done using DummyNodes::RegisterNodes(factory)
using namespace DummyNodes;
// The recommended way to create a Node is through inheritance.
// Even if it requires more boilerplate, it allows you to use more functionalities
// like ports (we will discuss this in future tutorials).
factory.registerNodeType<ApproachObject>("ApproachObject");
// Registering a SimpleActionNode using a function pointer.
// you may also use C++11 lambdas instead of std::bind
factory.registerSimpleCondition("CheckBattery", std::bind(CheckBattery));
//You can also create SimpleActionNodes using methods of a class
GripperInterface gripper;
factory.registerSimpleAction("OpenGripper", std::bind(&GripperInterface::open, &gripper));
factory.registerSimpleAction("CloseGripper", std::bind(&GripperInterface::close, &gripper));
#else
// Load dynamically a plugin and register the TreeNodes it contains
// it automated the registering step.
factory.registerFromPlugin("./libdummy_nodes_dyn.so");
#endif
// Trees are created at deployment-time (i.e. at run-time, but only once at the beginning).
// The currently supported format is XML.
// IMPORTANT: when the object "tree" goes out of scope, all the TreeNodes are destroyed
auto tree = factory.createTreeFromText(xml_text);
// To "execute" a Tree you need to "tick" it.
// The tick is propagated to the children based on the logic of the tree.
// In this case, the entire sequence is executed, because all the children
// of the Sequence return SUCCESS.
tree.tickRoot();
return 0;
}
/* Expected output:
*
[ Battery: OK ]
GripperInterface::open
ApproachObject: approach_object
GripperInterface::close
*/
cd进入build目录,执行下面命令,
cmake .. && make
最后在build目录下生成main,
执行它,
./main
结果如下,
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容