MoveIt2 behavior tree nodes for the BTEng engine
Project description
bteng-moveit
MoveIt2 behavior tree nodes for the BTEng engine.
bteng-moveit provides a collection of plug-and-play behavior tree nodes that wrap the MoveIt2 ROS 2 interfaces — action servers, services, and topics — so that robot manipulation pipelines can be composed entirely from a behavior tree without writing any ROS 2 boilerplate.
Install
pip install bteng-moveit
The package depends on bteng and bteng-ros2. MoveIt2 message packages (moveit_msgs, shape_msgs, etc.) must be available in the active ROS 2 environment.
Design
Lazy ROS 2 imports
Every node defers all ROS 2 and MoveIt2 message imports to the first tick or service call (on_start, make_goal, make_request, tick). This means the package can be imported in any Python process — even one that has not sourced a ROS 2 workspace — without raising ImportError. The ROS 2 environment is only required at runtime when a node actually executes.
MoveItErrorCodes check
Action nodes inherit from MoveItActionNode, a thin subclass of RosActionNode. When a MoveIt2 action completes, on_running inspects action_result.error_code.val. If the value is not 1 (MoveItErrorCodes.SUCCESS), the node transitions to FAILURE immediately, even though the ROS 2 action itself succeeded. This maps MoveIt2-level planning or execution failures onto the behavior tree status without any extra error-handling code in each node.
Composable node architecture
Each node exposes its interface purely through provided_ports(). Input and output values are passed through the blackboard, so any node in the tree can feed data to any other. The three plan-only nodes (PlanToPoseNode, PlanToJointValuesNode, ComputeCartesianPathNode) write their trajectory to an output port so that ExecuteTrajectoryNode can consume it separately, enabling plan-then-inspect-then-execute workflows. MoveGroupNode combines planning and execution in a single step when that split is not needed.
Nodes
| Class | Type | Description |
|---|---|---|
PlanToPoseNode |
Action | Plan to Cartesian pose (plan only) |
PlanToJointValuesNode |
Action | Plan to joint target (plan only) |
ExecuteTrajectoryNode |
Action | Execute a pre-planned trajectory |
MoveGroupNode |
Action | Plan and execute in one step |
ComputeCartesianPathNode |
Service | Compute Cartesian path through waypoints |
ComputeIKNode |
Service | Compute inverse kinematics |
ComputeFKNode |
Service | Compute forward kinematics |
GetPlanningSceneNode |
Service | Query the MoveIt planning scene |
ApplyPlanningSceneNode |
Service | Apply a planning scene update |
AddCollisionObjectNode |
Publisher | Add collision object to scene |
RemoveCollisionObjectNode |
Publisher | Remove collision object by ID |
IsMoveGroupReadyCondition |
Condition | Check move_group action server is ready |
IsAtJointTargetCondition |
Condition | Check joints are at target positions |
Usage
Plan to a Cartesian pose, then execute
PlanToPoseNode sets plan_only = True and writes the resulting trajectory to the trajectory output port. Pass that port directly into ExecuteTrajectoryNode.
import bteng as bt
from bteng_moveit import PlanToPoseNode, ExecuteTrajectoryNode
tree = bt.Sequence(
children=[
PlanToPoseNode(
name="Plan",
ports={
"pose": bt.Blackboard.entry("target_pose"),
"planning_group": "arm",
"link_name": "tool0",
"trajectory": bt.Blackboard.entry("planned_traj"),
},
),
ExecuteTrajectoryNode(
name="Execute",
ports={
"trajectory": bt.Blackboard.entry("planned_traj"),
},
),
]
)
Plan to joint values, then execute
from bteng_moveit import PlanToJointValuesNode, ExecuteTrajectoryNode
tree = bt.Sequence(
children=[
PlanToJointValuesNode(
name="PlanJoints",
ports={
"planning_group": "arm",
"joint_names": ["joint_1", "joint_2", "joint_3"],
"joint_values": [0.0, -1.57, 1.57],
"trajectory": bt.Blackboard.entry("planned_traj"),
},
),
ExecuteTrajectoryNode(
name="Execute",
ports={
"trajectory": bt.Blackboard.entry("planned_traj"),
},
),
]
)
Compute IK before planning
from bteng_moveit import ComputeIKNode
tree = bt.Sequence(
children=[
ComputeIKNode(
name="IK",
ports={
"planning_group": "arm",
"link_name": "tool0",
"pose": bt.Blackboard.entry("target_pose"),
"joint_state": bt.Blackboard.entry("ik_solution"),
},
),
# use ik_solution downstream ...
]
)
Guard with readiness and position checks
Wrap motion subtrees with IsMoveGroupReadyCondition to avoid sending goals before the action server is up, and use IsAtJointTargetCondition to skip redundant moves.
from bteng_moveit import IsMoveGroupReadyCondition, IsAtJointTargetCondition, PlanToJointValuesNode
tree = bt.Sequence(
children=[
IsMoveGroupReadyCondition(name="ServerReady"),
bt.Fallback(
children=[
IsAtJointTargetCondition(
name="AlreadyAtHome",
ports={
"joint_names": ["joint_1", "joint_2"],
"joint_values": [0.0, 0.0],
"tolerance": 0.01,
},
),
# motion subtree executed only when not already at target
PlanToJointValuesNode(...),
]
),
]
)
License
Apache-2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bteng_moveit-0.1.0.tar.gz.
File metadata
- Download URL: bteng_moveit-0.1.0.tar.gz
- Upload date:
- Size: 19.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66cd72ff727a4769a8a3f6427b5502c8dd07adf033ebf65be597505673826eb8
|
|
| MD5 |
168ab56a1e2037ebb45123befbbb3747
|
|
| BLAKE2b-256 |
19f35f7bfdd57d4752281ca13760d31816c733e3ead59283d3bd690cefebcbb3
|
File details
Details for the file bteng_moveit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: bteng_moveit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ad764895faae3888d02ae30e7eec6d9c8129b6ba4a31f0283922f6a6e57c68b
|
|
| MD5 |
e6e4c71a7a001656157787a1f78bba9e
|
|
| BLAKE2b-256 |
75ad22c0c71a94ad7981a079d3dbcd06af5ecea7776ad37caf96c5244362e623
|