Skip to main content

Nav2 behavior tree nodes for the BTEng engine

Project description

bteng-nav2

Nav2 behavior tree nodes for the BTEng engine.

A pure Python pip library — no ROS 2 workspace, no colcon, no XML behavior trees required. Every Nav2 action server, service, and common condition is available as a composable BTEng node.

Install

source /opt/ros/humble/setup.bash   # or iron / jazzy
pip install bteng-nav2

bteng and bteng-ros2 are pulled in automatically.


What's included

Actions → RosActionNode

Node Nav2 server Ports IN Ports OUT
NavigateToPoseNode /navigate_to_pose goal_pose, behavior_tree="" result
NavigateThroughPosesNode /navigate_through_poses poses, behavior_tree="" result
ComputePathToPoseNode /compute_path_to_pose goal, start=None, planner_id="" path
ComputePathThroughPosesNode /compute_path_through_poses goals, start=None, planner_id="" path
FollowPathNode /follow_path path, controller_id="", goal_checker_id=""
SmoothPathNode /smooth_path path, smoother_id="", max_smoothing_duration=10.0 smoothed_path
SpinNode /spin target_yaw, time_allowance=10.0
BackUpNode /back_up backup_dist=0.15, backup_speed=0.025, time_allowance=10.0
DriveOnHeadingNode /drive_on_heading dist_to_travel, speed, time_allowance=10.0
WaitNode /wait wait_duration=1
AssistedTeleopNode /assisted_teleop time_allowance=30.0
DockRobotNode /dock_robot dock_id, dock_type="" success
UndockRobotNode /undock_robot dock_type=""

Services → RosServiceNode

Node Nav2 server Ports IN Ports OUT
ClearGlobalCostmapNode /clear_costmap_global_srv
ClearLocalCostmapNode /clear_costmap_local_srv
ClearGlobalCostmapAroundRobotNode /clear_global_costmap_around_robot reset_distance=1.0
ClearLocalCostmapAroundRobotNode /clear_local_costmap_around_robot reset_distance=1.0
GetGlobalCostmapNode /get_costmap_global costmap
GetLocalCostmapNode /get_costmap_local costmap
IsPathValidNode /is_path_valid path — (SUCCESS/FAILURE)
LoadMapNode /map_server/load_map map_url result_code

Conditions → RosConditionNode

Node Source Logic
IsRobotNearGoalCondition /amcl_pose Euclidean distance to goal_pose < tolerance=0.5
IsLocalizationActiveCondition /amcl_pose Message received within timeout=2.0 s
IsObstacleNearCondition /scan min(ranges) < min_distance=0.5
IsStuckCondition /odom Velocity ≈ 0 for > stuck_timeout=3.0 s
IsGoalUpdatedCondition Blackboard goal_pose key changed since last tick
IsNavigationActiveCondition Action server /navigate_to_pose server is available

Publishers → RosTopicMixin

Node Topic Message
PublishGoalPoseNode /goal_pose geometry_msgs/PoseStamped
SetInitialPoseNode /initialpose geometry_msgs/PoseWithCovarianceStamped

Usage

Navigate to a pose

import rclpy
from bteng import Tree, Blackboard, NodeConfig
from bteng_ros2 import RosBTExecutor
from bteng_nav2 import NavigateToPoseNode
from geometry_msgs.msg import PoseStamped

rclpy.init()
ros_node = rclpy.create_node("bt_nav")

bb = Blackboard()
bb.set("goal_pose", make_pose(x=2.0, y=1.5))

config = NodeConfig(blackboard=bb, input_ports={"goal_pose": "goal_pose"})
root = NavigateToPoseNode("navigate", config=config)

tree = Tree(root=root)
executor = RosBTExecutor(tree, ros_node=ros_node)
executor.run()

rclpy.shutdown()

Compute path then follow it

Wire the output of one node to the input of another through the blackboard:

from bteng import SequenceNode, NodeConfig, Blackboard
from bteng_nav2 import ComputePathToPoseNode, FollowPathNode

bb = Blackboard()
bb.set("goal", goal_pose)

compute_cfg = NodeConfig(
    blackboard=bb,
    input_ports={"goal": "goal"},
    output_ports={"path": "path"},
)
follow_cfg = NodeConfig(
    blackboard=bb,
    input_ports={"path": "path"},
)

root = SequenceNode("root", children=[
    ComputePathToPoseNode("compute", config=compute_cfg),
    FollowPathNode("follow", config=follow_cfg),
])

Recovery tree

from bteng import FallbackNode, SequenceNode
from bteng_nav2 import (
    NavigateToPoseNode, ClearGlobalCostmapNode, BackUpNode, SpinNode
)

root = FallbackNode("root", children=[
    NavigateToPoseNode("navigate", config=nav_cfg),
    SequenceNode("recovery", children=[
        ClearGlobalCostmapNode("clear", config=cfg),
        BackUpNode("back_up", config=cfg),
        SpinNode("spin", config=cfg),
        NavigateToPoseNode("retry", config=nav_cfg),
    ]),
])

Full autonomy with conditions

from bteng import FallbackNode, SequenceNode
from bteng_nav2 import (
    IsLocalizationActiveCondition,
    IsRobotNearGoalCondition,
    IsNavigationActiveCondition,
    NavigateToPoseNode,
    ClearGlobalCostmapNode,
    SpinNode,
)

root = FallbackNode("root", children=[
    SequenceNode("pre_checks", children=[
        IsLocalizationActiveCondition("localized", config=cfg),
        IsRobotNearGoalCondition("near_goal", config=cfg),  # already there
    ]),
    SequenceNode("navigate", children=[
        IsNavigationActiveCondition("nav_ready", config=cfg),
        NavigateToPoseNode("go", config=cfg),
    ]),
    SequenceNode("recover", children=[
        ClearGlobalCostmapNode("clear", config=cfg),
        SpinNode("spin", config=cfg),
    ]),
])

Design

bteng-nav2 follows the same mixin pattern as bteng-ros2:

  • Action nodes subclass RosActionNode and implement make_goal(). All nav2 action lifecycle (send, poll, cancel) is handled.
  • Service nodes subclass RosServiceNode and implement make_request(). Response handling goes in on_response().
  • Condition nodes subclass RosConditionNode and implement evaluate(msg). Subscriptions are created lazily on the first tick.
  • Publisher nodes mix RosTopicMixin with ActionNode. Publishers are created lazily and reused.

All ROS message imports are lazy (inside methods), so the package imports cleanly without a ROS installation — enabling unit testing via standard pytest.


Testing without ROS 2

The test suite runs fully offline:

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest

test/conftest.py stubs all ROS 2 and Nav2 message types so no ROS installation is needed.


Examples

File Demonstrates
examples/01_navigate_to_pose.py Single goal navigation
examples/02_compute_and_follow.py Path planning + path following pipeline
examples/03_patrol_loop.py Multi-waypoint patrol loop
examples/04_recovery_tree.py Navigation with costmap clear + backup fallback
examples/05_full_autonomy.py Localization check, goal check, navigation, recovery

Run any example after sourcing ROS 2:

source /opt/ros/humble/setup.bash
python examples/01_navigate_to_pose.py

Requirements

  • Python ≥ 3.10
  • ROS 2 Humble / Iron / Jazzy
  • bteng >= 0.2.0
  • bteng-ros2 >= 0.1.0
  • Nav2 (nav2_msgs, nav_msgs, sensor_msgs, geometry_msgs)

License

Apache 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bteng_nav2-0.1.0.tar.gz (28.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bteng_nav2-0.1.0-py3-none-any.whl (24.7 kB view details)

Uploaded Python 3

File details

Details for the file bteng_nav2-0.1.0.tar.gz.

File metadata

  • Download URL: bteng_nav2-0.1.0.tar.gz
  • Upload date:
  • Size: 28.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for bteng_nav2-0.1.0.tar.gz
Algorithm Hash digest
SHA256 ddac2e581eb89725c5e2ac03b2ccd459f075c4e1bc0e642e8605e71462e46e5a
MD5 3133bbce04bb9e5997d927e67e1e7282
BLAKE2b-256 810cef9a403133d9723d4af914f6e5cbdccbc781c36b2c3ce3b245c98f6c5062

See more details on using hashes here.

File details

Details for the file bteng_nav2-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: bteng_nav2-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for bteng_nav2-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 370aaa9b9eaa8640763913f7dc0918d6e9e9d6ff7548a6b6b6beff0a52e8726f
MD5 62ae70525cc6b6d779db9ecaa28daa64
BLAKE2b-256 9bc2a53414e6456c93236a400968e10afcb9716c23c81b719580ffa734a2362e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page