Test trees offline¶
You can run a behaviour tree with XPARO’s engine from a Python script, without
starting xparo_ros and without connecting to the server. It is a quick way
to check a tree’s logic, or to test a custom node, on your own computer.
It still needs ROS 2: the engine imports rclpy, so install and build the
package as in Install and run and source your workspace. Without ROS
2 sourced, the import fails with ModuleNotFoundError: No module named
'rclpy'.
Run a tree¶
from xparo.engine import Engine
from xparo.bt_engine.executor import BehaviorTreeExecutor
# An offline Engine: no server connection, nothing is sent anywhere.
engine = Engine("unused", "local-test", connection_type="offline")
engine.transport.send = lambda message, command_for=None: None
executor = BehaviorTreeExecutor(node=None, engine=engine)
tree = """
<Sequence name="deliver_medicine">
<ScriptCondition name="battery_ok" code="battery > 20" />
<Script name="pick_room" code="room := destination" />
<Wait name="wait_at_door" seconds="1" />
</Sequence>
"""
report = executor.run_with_trace(tree, blackboard={"battery": "55", "destination": "ward_3"}, timeout_s=30)
print(report["outcome"], "-", report["explanation"])
print("blackboard after:", report["blackboard"])
source /opt/ros/jazzy/setup.bash
source ~/xparo_ws/install/setup.bash
python3 try_tree.py
After a few start-up lines it prints:
success - The tree finished with SUCCESS.
blackboard after: {'battery': '55', 'destination': 'ward_3', 'room': 'ward_3'}
Change "battery": "55" to "10" and the result is failed with
the reason: The tree finished with FAILURE at battery_ok (ScriptCondition):
'battery > 20' is False.
run_with_trace takes the tree (the part inside <BehaviorTree>, as the
Behaviour editor saves it), the starting blackboard and a time limit, and
returns the same report a task run produces on a robot: outcome,
explanation, failed_node, blackboard, stats and a timeline of
every node’s status changes. The node rules, the expression language and the
outcomes are in Behaviour trees on the robot.
What works offline¶
All control, decorator and condition nodes,
Script,ScriptCondition,WaitandSubTree(pass the other trees assubtrees={"name": "<xml>"}).The placeholder XPARO nodes (
NavigateTo,SpeakText…), which only log what they would do, as they do on a robot.ParamSetdoes not set anything without a ROS 2 node: it reports what it would have set and continues. Pass your ownrclpynode asBehaviorTreeExecutor(node=my_node, engine=engine)to really set parameters.
Why the robot needs its ROS 2 node¶
On a robot, tasks only run inside xparo_ros. An XPARO process started
without its node answers every RUN_TASK with:
{"TASK_RESULT": {"task_id": "...", "run_id": "...", "success": false, "duration_s": 0.0,
"outcome": "no_executor", "retryable": false,
"error": "This robot's XPARO process is running without its ROS 2 node, so it can't run behaviour trees. Start XPARO on the robot with its ROS 2 launch file (ros2 launch xparo xparo_launch.py).",
"explanation": ""}}
retryable is false, so Restart on Failure doesn’t loop on it.