Skip to content

Commit 51a4ade

Browse files
committed
Initial commit
0 parents  commit 51a4ade

File tree

7 files changed

+412
-0
lines changed

7 files changed

+412
-0
lines changed

CMakeLists.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
project(behaviortree_py)
3+
4+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
5+
6+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
7+
add_compile_options(-Wall -Wextra -Wpedantic)
8+
endif()
9+
10+
find_package(ament_cmake REQUIRED)
11+
find_package(behaviortree_cpp REQUIRED)
12+
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
13+
find_package(pybind11_vendor REQUIRED)
14+
find_package(pybind11 REQUIRED)
15+
16+
ament_python_install_package(behaviortree_py PACKAGE_DIR behaviortree_py)
17+
18+
pybind11_add_module(behaviortree_py src/behaviortree_py.cpp)
19+
target_compile_features(behaviortree_py PRIVATE cxx_std_20)
20+
target_link_libraries(behaviortree_py
21+
PRIVATE behaviortree_cpp::behaviortree_cpp)
22+
23+
add_custom_command(
24+
TARGET behaviortree_py
25+
POST_BUILD
26+
COMMAND stubgen --output $<TARGET_FILE_DIR:behaviortree_py> -p behaviortree_py
27+
-v --verbose
28+
WORKING_DIRECTORY $<TARGET_FILE_DIR:behaviortree_py>
29+
USES_TERMINAL)
30+
31+
install(TARGETS behaviortree_py
32+
LIBRARY DESTINATION ${PYTHON_INSTALL_DIR}/behaviortree_py)
33+
install(
34+
FILES
35+
$<TARGET_FILE_DIR:behaviortree_py>/$<TARGET_FILE_BASE_NAME:behaviortree_py>.pyi
36+
COMPONENT python
37+
DESTINATION ${PYTHON_INSTALL_DIR}/$<TARGET_FILE_BASE_NAME:behaviortree_py>)
38+
39+
ament_package()

behaviortree_py/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from behaviortree_py.behaviortree_py import *

behaviortree_py/py.typed

Whitespace-only changes.

examples/bt_example.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import behaviortree_py
2+
import time
3+
4+
xml_text = """
5+
<root BTCPP_format="4">
6+
7+
<BehaviorTree ID="MainTree">
8+
<Sequence>
9+
<Fallback>
10+
<Inverter>
11+
<IsDoorClosed/>
12+
</Inverter>
13+
<SubTree ID="DoorClosed"/>
14+
</Fallback>
15+
<PassThroughDoor/>
16+
</Sequence>
17+
</BehaviorTree>
18+
19+
<BehaviorTree ID="DoorClosed">
20+
<Fallback>
21+
<OpenDoor/>
22+
<RetryUntilSuccessful num_attempts="5">
23+
<PickLock/>
24+
</RetryUntilSuccessful>
25+
<SmashDoor/>
26+
</Fallback>
27+
</BehaviorTree>
28+
29+
</root>
30+
"""
31+
32+
33+
class CrossDoor:
34+
35+
def __init__(self):
36+
self.door_open = False
37+
self.door_locked = True
38+
self.pick_attempts = 0
39+
40+
def register_nodes(self, factory: behaviortree_py.BehaviorTreeFactory):
41+
factory.register_simple_condition("IsDoorClosed", self.is_door_closed)
42+
factory.register_simple_action("PassThroughDoor", self.pass_through_door)
43+
factory.register_simple_action("OpenDoor", self.open_door)
44+
factory.register_simple_action("PickLock", self.pick_lock)
45+
factory.register_simple_action("SmashDoor", self.smash_door)
46+
47+
def is_door_closed(
48+
self, tree_node: behaviortree_py.TreeNode
49+
) -> behaviortree_py.NodeStatus:
50+
time.sleep(0.2)
51+
return (
52+
behaviortree_py.NodeStatus.SUCCESS
53+
if not self.door_open
54+
else behaviortree_py.NodeStatus.FAILURE
55+
)
56+
57+
def pass_through_door(
58+
self, tree_node: behaviortree_py.TreeNode
59+
) -> behaviortree_py.NodeStatus:
60+
time.sleep(0.5)
61+
return (
62+
behaviortree_py.NodeStatus.SUCCESS
63+
if self.door_open
64+
else behaviortree_py.NodeStatus.FAILURE
65+
)
66+
67+
def open_door(
68+
self, tree_node: behaviortree_py.TreeNode
69+
) -> behaviortree_py.NodeStatus:
70+
time.sleep(0.5)
71+
if self.door_locked:
72+
return behaviortree_py.NodeStatus.FAILURE
73+
self.door_open = True
74+
return behaviortree_py.NodeStatus.SUCCESS
75+
76+
def pick_lock(
77+
self, tree_node: behaviortree_py.TreeNode
78+
) -> behaviortree_py.NodeStatus:
79+
time.sleep(0.5)
80+
self.pick_attempts += 1
81+
if self.pick_attempts > 3:
82+
self.door_locked = False
83+
self.door_open = True
84+
return (
85+
behaviortree_py.NodeStatus.SUCCESS
86+
if self.door_open
87+
else behaviortree_py.NodeStatus.FAILURE
88+
)
89+
90+
def smash_door(self) -> behaviortree_py.NodeStatus:
91+
self.door_locked = False
92+
self.door_open = True
93+
return behaviortree_py.NodeStatus.SUCCESS
94+
95+
96+
factory = behaviortree_py.BehaviorTreeFactory()
97+
98+
cross_door = CrossDoor()
99+
cross_door.register_nodes(factory)
100+
101+
factory.register_behavior_tree_from_text(xml_text)
102+
103+
tree = factory.create_tree("MainTree")
104+
105+
logger = behaviortree_py.StdCoutLogger(tree)
106+
# logger = behaviortree_py.Groot2Publisher(tree)
107+
108+
print(behaviortree_py.get_tree_recursively(tree.root_node()))
109+
110+
tree.tick_while_running()

examples/scripting.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import behaviortree_py as bt
2+
3+
xml_text = """
4+
<root BTCPP_format="4">
5+
<BehaviorTree>
6+
<Sequence>
7+
<Script code=" msg:='hello world' " />
8+
<Script code=" A:=THE_ANSWER; B:=3.14; color:=RED " />
9+
<Precondition if="A>B && color != BLUE" else="FAILURE">
10+
<Sequence>
11+
<SetValue value="{double_value}"/>
12+
<SaySomething message="{A}"/>
13+
<SaySomething message="{B}"/>
14+
<SaySomething message="{msg}"/>
15+
<SaySomething message="{color}"/>
16+
<SaySomethingDouble message="{double_value}"/>
17+
</Sequence>
18+
</Precondition>
19+
</Sequence>
20+
</BehaviorTree>
21+
</root>
22+
"""
23+
24+
25+
def say_something_double(
26+
tree_node: bt.TreeNode,
27+
) -> bt.NodeStatus:
28+
print(tree_node.get_input_double("message"))
29+
return bt.NodeStatus.SUCCESS
30+
31+
32+
def say_something(tree_node: bt.TreeNode) -> bt.NodeStatus:
33+
print(tree_node.get_input_string("message"))
34+
return bt.NodeStatus.SUCCESS
35+
36+
37+
def set_value(tree_node: bt.TreeNode) -> bt.NodeStatus:
38+
if not (result := tree_node.set_output("value", 24.9)):
39+
return bt.NodeStatus.FAILURE
40+
return bt.NodeStatus.SUCCESS
41+
42+
43+
factory = bt.BehaviorTreeFactory()
44+
factory.register_simple_action(
45+
"SetValue", set_value, dict([bt.output_port_double("value")])
46+
)
47+
factory.register_simple_action(
48+
"SaySomething", say_something, dict([bt.input_port_string("message")])
49+
)
50+
factory.register_simple_action(
51+
"SaySomethingDouble", say_something_double, dict([bt.input_port_double("message")])
52+
)
53+
factory.register_scripting_enum("RED", 1)
54+
factory.register_scripting_enum("BLUE", 2)
55+
factory.register_scripting_enum("GREEN", 3)
56+
factory.register_scripting_enum("THE_ANSWER", 42)
57+
tree = factory.create_tree_from_text(xml_text)
58+
logger = bt.StdCoutLogger(tree)
59+
60+
print(bt.get_tree_recursively(tree.root_node()))
61+
62+
tree.tick_while_running()

package.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0"?>
2+
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
3+
<package format="3">
4+
<name>behaviortree_py</name>
5+
<version>0.0.0</version>
6+
<description>TODO: Package description</description>
7+
<maintainer email="[email protected]">Jafar Uruc</maintainer>
8+
<license>TODO: License declaration</license>
9+
10+
<buildtool_depend>ament_cmake</buildtool_depend>
11+
12+
<depend>behaviortree_cpp</depend>
13+
14+
<export>
15+
<build_type>ament_cmake</build_type>
16+
</export>
17+
</package>

0 commit comments

Comments
 (0)