|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +""" |
| 4 | +Demonstration of stateful action nodes. |
| 5 | +
|
| 6 | +To run, ensure that the `btpy_cpp` Python extension is on your `PYTHONPATH` |
| 7 | +variable. It is probably located in your build directory if you're building from |
| 8 | +source. |
| 9 | +""" |
| 10 | + |
| 11 | +import rclpy |
| 12 | +from rclpy.node import Node |
| 13 | +from tf2_ros.buffer import Buffer |
| 14 | +from tf2_ros.transform_listener import TransformListener |
| 15 | + |
| 16 | +from btpy import ( |
| 17 | + BehaviorTreeFactory, |
| 18 | + StatefulActionNode, |
| 19 | + SyncActionNode, |
| 20 | + NodeStatus, |
| 21 | + ports, |
| 22 | +) |
| 23 | + |
| 24 | + |
| 25 | +xml_text = """ |
| 26 | + <root BTCPP_format="4" > |
| 27 | +
|
| 28 | + <BehaviorTree ID="MainTree"> |
| 29 | + <Sequence> |
| 30 | + <ReactiveSequence name="root"> |
| 31 | + <Print value="{tf}" /> |
| 32 | + <GetRosTransform frame_id="odom" child_frame_id="base_link" tf="{tf}" /> |
| 33 | + </ReactiveSequence> |
| 34 | + </Sequence> |
| 35 | + </BehaviorTree> |
| 36 | +
|
| 37 | + </root> |
| 38 | +""" |
| 39 | + |
| 40 | + |
| 41 | +@ports(inputs=["frame_id", "child_frame_id"], outputs=["tf"]) |
| 42 | +class GetRosTransform(StatefulActionNode): |
| 43 | + def __init__(self, name, config, node): |
| 44 | + super().__init__(name, config) |
| 45 | + |
| 46 | + self.node = node |
| 47 | + self.tf_buffer = Buffer() |
| 48 | + self.tf_listener = TransformListener(self.tf_buffer, self.node) |
| 49 | + |
| 50 | + def on_start(self): |
| 51 | + return NodeStatus.RUNNING |
| 52 | + |
| 53 | + def on_running(self): |
| 54 | + frame_id = self.get_input("frame_id") |
| 55 | + child_frame_id = self.get_input("child_frame_id") |
| 56 | + |
| 57 | + time = self.node.get_clock().now() |
| 58 | + if self.tf_buffer.can_transform(frame_id, child_frame_id, time): |
| 59 | + tf = self.tf_buffer.lookup_transform(frame_id, child_frame_id, time) |
| 60 | + self.set_output("tf", tf) |
| 61 | + |
| 62 | + return NodeStatus.RUNNING |
| 63 | + |
| 64 | + def on_halted(self): |
| 65 | + pass |
| 66 | + |
| 67 | + |
| 68 | +@ports(inputs=["value"]) |
| 69 | +class Print(SyncActionNode): |
| 70 | + def tick(self): |
| 71 | + value = self.get_input("value") |
| 72 | + if value is not None: |
| 73 | + print(value) |
| 74 | + return NodeStatus.SUCCESS |
| 75 | + |
| 76 | + |
| 77 | +rclpy.init() |
| 78 | +node = Node("ex04_ros_interopt") |
| 79 | + |
| 80 | +factory = BehaviorTreeFactory() |
| 81 | +factory.register(GetRosTransform, node) |
| 82 | +factory.register(Print) |
| 83 | + |
| 84 | +tree = factory.create_tree_from_text(xml_text) |
| 85 | + |
| 86 | +node.create_timer(0.01, lambda: tree.tick_once()) |
| 87 | +rclpy.spin(node) |
0 commit comments