Files
PythonRobotics/MissionPlanning/BehaviorTree/robot_behavior_case.py
Aglargil fc160179c0 feat: add behavior tree (#1177)
* feat: add behavior tree

* feat: add behavior tree test

* feat: add behavior tree doc

* feat: add behavior tree update
2025-03-08 19:26:23 +09:00

248 lines
6.7 KiB
Python

"""
Robot Behavior Tree Case
This file demonstrates how to use a behavior tree to control robot behavior.
"""
from behavior_tree import (
BehaviorTreeFactory,
Status,
ActionNode,
)
import time
import random
import os
class CheckBatteryNode(ActionNode):
"""
Node to check robot battery level
If battery level is below threshold, returns FAILURE, otherwise returns SUCCESS
"""
def __init__(self, name, threshold=20):
super().__init__(name)
self.threshold = threshold
self.battery_level = 100 # Initial battery level is 100%
def tick(self):
# Simulate battery level decreasing
self.battery_level -= random.randint(1, 5)
print(f"Current battery level: {self.battery_level}%")
if self.battery_level <= self.threshold:
return Status.FAILURE
return Status.SUCCESS
class ChargeBatteryNode(ActionNode):
"""
Node to charge the robot's battery
"""
def __init__(self, name, charge_rate=10):
super().__init__(name)
self.charge_rate = charge_rate
self.charging_time = 0
def tick(self):
# Simulate charging process
if self.charging_time == 0:
print("Starting to charge...")
self.charging_time += 1
charge_amount = self.charge_rate * self.charging_time
if charge_amount >= 100:
print("Charging complete! Battery level: 100%")
self.charging_time = 0
return Status.SUCCESS
else:
print(f"Charging in progress... Battery level: {min(charge_amount, 100)}%")
return Status.RUNNING
class MoveToPositionNode(ActionNode):
"""
Node to move to a specified position
"""
def __init__(self, name, position, move_duration=2):
super().__init__(name)
self.position = position
self.move_duration = move_duration
self.start_time = None
def tick(self):
if self.start_time is None:
self.start_time = time.time()
print(f"Starting movement to position {self.position}")
elapsed_time = time.time() - self.start_time
if elapsed_time >= self.move_duration:
print(f"Arrived at position {self.position}")
self.start_time = None
return Status.SUCCESS
else:
print(
f"Moving to position {self.position}... {int(elapsed_time / self.move_duration * 100)}% complete"
)
return Status.RUNNING
class DetectObstacleNode(ActionNode):
"""
Node to detect obstacles
"""
def __init__(self, name, obstacle_probability=0.3):
super().__init__(name)
self.obstacle_probability = obstacle_probability
def tick(self):
# Use random probability to simulate obstacle detection
if random.random() < self.obstacle_probability:
print("Obstacle detected!")
return Status.SUCCESS
else:
print("No obstacle detected")
return Status.FAILURE
class AvoidObstacleNode(ActionNode):
"""
Node to avoid obstacles
"""
def __init__(self, name, avoid_duration=1.5):
super().__init__(name)
self.avoid_duration = avoid_duration
self.start_time = None
def tick(self):
if self.start_time is None:
self.start_time = time.time()
print("Starting obstacle avoidance...")
elapsed_time = time.time() - self.start_time
if elapsed_time >= self.avoid_duration:
print("Obstacle avoidance complete")
self.start_time = None
return Status.SUCCESS
else:
print("Avoiding obstacle...")
return Status.RUNNING
class PerformTaskNode(ActionNode):
"""
Node to perform a specific task
"""
def __init__(self, name, task_name, task_duration=3):
super().__init__(name)
self.task_name = task_name
self.task_duration = task_duration
self.start_time = None
def tick(self):
if self.start_time is None:
self.start_time = time.time()
print(f"Starting task: {self.task_name}")
elapsed_time = time.time() - self.start_time
if elapsed_time >= self.task_duration:
print(f"Task complete: {self.task_name}")
self.start_time = None
return Status.SUCCESS
else:
print(
f"Performing task: {self.task_name}... {int(elapsed_time / self.task_duration * 100)}% complete"
)
return Status.RUNNING
def create_robot_behavior_tree():
"""
Create robot behavior tree
"""
factory = BehaviorTreeFactory()
# Register custom nodes
factory.register_node_builder(
"CheckBattery",
lambda node: CheckBatteryNode(
node.attrib.get("name", "CheckBattery"),
int(node.attrib.get("threshold", "20")),
),
)
factory.register_node_builder(
"ChargeBattery",
lambda node: ChargeBatteryNode(
node.attrib.get("name", "ChargeBattery"),
int(node.attrib.get("charge_rate", "10")),
),
)
factory.register_node_builder(
"MoveToPosition",
lambda node: MoveToPositionNode(
node.attrib.get("name", "MoveToPosition"),
node.attrib.get("position", "Unknown Position"),
float(node.attrib.get("move_duration", "2")),
),
)
factory.register_node_builder(
"DetectObstacle",
lambda node: DetectObstacleNode(
node.attrib.get("name", "DetectObstacle"),
float(node.attrib.get("obstacle_probability", "0.3")),
),
)
factory.register_node_builder(
"AvoidObstacle",
lambda node: AvoidObstacleNode(
node.attrib.get("name", "AvoidObstacle"),
float(node.attrib.get("avoid_duration", "1.5")),
),
)
factory.register_node_builder(
"PerformTask",
lambda node: PerformTaskNode(
node.attrib.get("name", "PerformTask"),
node.attrib.get("task_name", "Unknown Task"),
float(node.attrib.get("task_duration", "3")),
),
)
# Read XML from file
xml_path = os.path.join(os.path.dirname(__file__), "robot_behavior_tree.xml")
return factory.build_tree_from_file(xml_path)
def main():
"""
Main function: Create and run the robot behavior tree
"""
print("Creating robot behavior tree...")
tree = create_robot_behavior_tree()
print("\nStarting robot behavior tree execution...\n")
# Run for a period of time or until completion
tree.tick_while_running(interval=0.01)
print("\nBehavior tree execution complete!")
if __name__ == "__main__":
main()