3 Commits

Author SHA1 Message Date
b91291b734 更新vllm后端的使用方法 2025-10-13 11:54:02 +08:00
00cde0d2dc 增加区域坐标 2025-09-27 14:11:59 +08:00
bef742db1b 增加简单模式root键 2025-09-25 21:57:32 +08:00
131 changed files with 10073 additions and 1460 deletions

128
README.md
View File

@@ -19,7 +19,6 @@
│ │ │ └── classifier_prompt.txt # 指令简单/复杂分类提示词 │ │ │ └── classifier_prompt.txt # 指令简单/复杂分类提示词
│ │ ├── ... │ │ ├── ...
│ ├── generated_visualizations/ # 存放最新生成的py_tree可视化图像 │ ├── generated_visualizations/ # 存放最新生成的py_tree可视化图像
│ ├── generated_reasoning_content/ # 存放最新推理链Markdown<plan_id>.md
│ └── requirements.txt # 后端服务的Python依赖 │ └── requirements.txt # 后端服务的Python依赖
├── tools/ ├── tools/
@@ -27,8 +26,7 @@
│ ├── knowledge_base/ # 【处理后】存放build_knowledge_base.py生成的.ndjson文件 │ ├── knowledge_base/ # 【处理后】存放build_knowledge_base.py生成的.ndjson文件
│ ├── vector_store/ # 【数据库】存放最终的ChromaDB向量数据库 │ ├── vector_store/ # 【数据库】存放最终的ChromaDB向量数据库
│ ├── build_knowledge_base.py # 【步骤1】用于将原始数据转换为自然语言知识 │ ├── build_knowledge_base.py # 【步骤1】用于将原始数据转换为自然语言知识
── ingest.py # 【步骤2】用于将自然语言知识摄入向量数据库 ── ingest.py # 【步骤2】用于将自然语言知识摄入向量数据库
│ └── test_llama_server.py # 直接调用本地8081端口llama-server支持 --system / --system-file
├── / # ROS2接口定义 (保持不变) ├── / # ROS2接口定义 (保持不变)
└── docs/ └── docs/
@@ -63,6 +61,18 @@
```bash ```bash
./llama-server -m ~/models/gguf/Qwen/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf --port 8081 --gpu-layers 36 --host 0.0.0.0 -c 8192 ./llama-server -m ~/models/gguf/Qwen/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf --port 8081 --gpu-layers 36 --host 0.0.0.0 -c 8192
``` ```
至此llama.cpp推理框架就完成了无需进一步即可启动后端
如果使用vllm后端则执行以下命令
```bash
vllm serve Qwen3-4B-AWQ --host=0.0.0.0 --port=8081 --dtype=auto --max-num-seqs=1 --max-model-len=16384 --served-model-name "qwen3-4b-awq" --trust-remote-code --gpu-memory-utilization=0.75 --uvicorn-log-level=debug
```
由于调用vllm时在发送HTTP请求时需要指定模型名称所以在启动后端服务前需要添加环境变量执行以下命令
```bash
export CLASSIFIER_MODEL="qwen3-4b-awq"
export SIMPLE_MODEL="qwen3-4b-awq"
export COMPLEX_MODEL="qwen3-4b-awq"
```
2. **Embedding模型部署** 2. **Embedding模型部署**
@@ -97,10 +107,6 @@
通用API Key`OPENAI_API_KEY` 通用API Key`OPENAI_API_KEY`
推理链捕获相关:
- `ENABLE_REASONING_CAPTURE`:是否允许模型返回含有 <think> 的原文以便捕获推理链;默认 true。
- `REASONING_PREVIEW_LINES`:在后端日志中打印推理链预览的行数;默认 20。
示例: 示例:
```bash ```bash
export CLASSIFIER_MODEL="qwen2.5-1.8b-instruct" export CLASSIFIER_MODEL="qwen2.5-1.8b-instruct"
@@ -110,10 +116,6 @@ export CLASSIFIER_BASE_URL="http://$ORIN_IP:8081/v1"
export SIMPLE_BASE_URL="http://$ORIN_IP:8081/v1" export SIMPLE_BASE_URL="http://$ORIN_IP:8081/v1"
export COMPLEX_BASE_URL="http://$ORIN_IP:8081/v1" export COMPLEX_BASE_URL="http://$ORIN_IP:8081/v1"
export OPENAI_API_KEY="sk-no-key-required" export OPENAI_API_KEY="sk-no-key-required"
# 推理链捕获(可选)
export ENABLE_REASONING_CAPTURE=true # 默认已为true如需关闭设置为 false
export REASONING_PREVIEW_LINES=30 # 调整日志预览行数
``` ```
### 测试简单模式 ### 测试简单模式
@@ -127,22 +129,6 @@ python test_api.py
示例输入:“简单模式,起飞” 或 “起飞到10米”。返回结果为简单JSON无 `root`):包含 `mode`、`action`、`plan_id`、`visualization_url`。 示例输入:“简单模式,起飞” 或 “起飞到10米”。返回结果为简单JSON无 `root`):包含 `mode`、`action`、`plan_id`、`visualization_url`。
### 直接调用 llama-server绕过后端
当仅需测试本地 8081 端口的推理服务OpenAI 兼容接口)时,可使用内置脚本:
```bash
python tools/test_llama_server.py \
--system-file backend_service/src/prompts/system_prompt.txt \
--user "起飞到10米然后降落" \
--base-url "http://127.0.0.1:8081/v1" \
--verbose
```
说明:
- 支持 `--system` 或 `--system-file` 自定义提示词文件;`--system-file` 优先。
- 默认解析 OpenAI 风格返回,若包含 `<think>` 推理内容会显示在输出中(具体取决于模型和服务配置)。
--- ---
## 工作流程 ## 工作流程
@@ -228,96 +214,14 @@ python ingest.py
完成前两个阶段后,即可启动并测试后端服务。 完成前两个阶段后,即可启动并测试后端服务。
#### 1. 启动所有服务(推荐方式:一键启动脚本) #### 1. 启动后端服务
我们提供了一个一键启动脚本 `start_all.sh`,可以自动启动所有必需的服务: 启动服务的关键在于**按顺序激活环境**先激活ROS 2工作空间再激活Conda环境。
```bash ```bash
# 1. 切换到项目根目录 # 1. 切换到项目根目录
cd /path/to/your/drone cd /path/to/your/drone
# 2. 使用一键启动脚本(推荐)
./start_all.sh start
# 或者直接运行start是默认命令
./start_all.sh
```
**脚本功能:**
- 自动启动推理模型服务llama-server端口8081
- 自动启动Embedding模型服务llama-server端口8090
- 自动启动FastAPI后端服务端口8000
- 自动检查端口占用、模型文件、环境配置等
- 自动等待服务就绪
- 统一管理日志文件(保存在 `logs/` 目录)
**环境变量配置(可选):**
在运行脚本前,可以通过环境变量自定义配置:
```bash
# 设置llama-server路径如果不在默认位置
export LLAMA_SERVER_DIR="/path/to/llama.cpp/build/bin"
# 设置模型路径(如果不在默认位置)
export INFERENCE_MODEL="~/models/gguf/Qwen/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf"
export EMBEDDING_MODEL="~/models/gguf/Qwen/Qwen3-embedding-4B/Qwen3-Embedding-4B-Q4_K_M.gguf"
# 设置Conda环境名称如果使用不同的环境名
export CONDA_ENV="backend"
# 然后运行脚本
./start_all.sh
```
**脚本命令:**
```bash
./start_all.sh start # 启动所有服务(默认)
./start_all.sh stop # 停止所有服务
./start_all.sh restart # 重启所有服务
./start_all.sh status # 查看服务状态
```
**日志查看:**
所有服务的日志都保存在 `logs/` 目录下:
```bash
# 查看所有日志
tail -f logs/*.log
# 查看特定服务日志
tail -f logs/inference_model.log # 推理模型
tail -f logs/embedding_model.log # Embedding模型
tail -f logs/fastapi.log # FastAPI服务
```
#### 2. 手动启动服务(备选方式)
如果您需要手动控制每个服务的启动,可以按照以下步骤操作:
**启动推理模型服务:**
```bash
cd /llama.cpp/build/bin
./llama-server -m ~/models/gguf/Qwen/Qwen3-8B-GGUF/Qwen3-8B-Q4_K_M.gguf --port 8081 --gpu-layers 36 --host 0.0.0.0 -c 8192
```
**启动Embedding模型服务**
在另一个终端中:
```bash
cd /llama.cpp/build/bin
./llama-server -m ~/models/gguf/Qwen/Qwen3-embedding-4B/Qwen3-Embedding-4B-Q4_K_M.gguf --gpu-layers 36 --port 8090 --embeddings --pooling last --host 0.0.0.0
```
**启动FastAPI后端服务**
在第三个终端中:
```bash
# 1. 切换到项目根目录
cd /path/to/your/drone
# 2. 激活ROS 2编译环境 # 2. 激活ROS 2编译环境
# 作用:将我们编译好的`drone_interfaces`包的路径告知系统否则Python会报`ModuleNotFoundError`。 # 作用:将我们编译好的`drone_interfaces`包的路径告知系统否则Python会报`ModuleNotFoundError`。
# 注意:此命令必须在每次打开新终端时执行一次。 # 注意:此命令必须在每次打开新终端时执行一次。
@@ -328,9 +232,9 @@ conda activate backend
# 4. 启动FastAPI服务 # 4. 启动FastAPI服务
cd backend_service/ cd backend_service/
# 如果使用vllm后端此时还应当指定使用的模型名称
uvicorn src.main:app --host 0.0.0.0 --port 8000 uvicorn src.main:app --host 0.0.0.0 --port 8000
``` ```
当您看到日志中出现 `Uvicorn running on http://0.0.0.0:8000` 时,表示服务已成功启动。 当您看到日志中出现 `Uvicorn running on http://0.0.0.0:8000` 时,表示服务已成功启动。
#### 2. 运行API接口测试 #### 2. 运行API接口测试

View File

@@ -1,43 +0,0 @@
好的我现在需要处理用户的任务指令生成一个符合要求的行为树JSON。首先我得仔细阅读用户的指令和参考知识确保理解所有要求。
用户的目标是搜索并锁定危险性最高的气球(红色>蓝色>绿色然后跟踪30秒后进行打击。参考知识中提到了三个地点但用户可能希望搜索的区域是这些地点附近或者需要根据这些坐标来规划路径。
首先,我需要确定无人机的起降点。参考知识中的地点坐标可能作为搜索区域的中心。比如,用户提到的“学生宿舍”坐标是(5,3,2)但可能需要选择一个合适的中心点进行搜索。不过用户没有明确指定搜索区域可能需要使用search_pattern来覆盖这些区域或者直接在某个中心点周围搜索。
接下来,任务流程应该是:起飞→飞往搜索区域→搜索目标→检测到目标后跟踪→打击。同时必须包含安全监控。
根据用户提供的参考知识,可能需要将搜索区域设置为某个中心点。比如,用户提到的“跷跷板”在(x:15, y:-8.5, z:1.2)但z坐标需要调整到至少1米这里已经是1.2,没问题。或者可能选择其他地点作为搜索中心。但用户没有明确说明,可能需要假设搜索区域是这些地点附近,或者使用一个综合的中心点。
不过用户可能希望无人机先飞往某个特定的搜索区。比如参考知识中的“学生宿舍”可能是一个可能的区域但需要确认。或者用户可能希望无人机在某个中心点周围进行搜索。例如使用search_pattern的中心点可能选在某个已知地点比如“跷跷板”附近或者综合多个点。
但用户没有明确指定搜索区域所以可能需要使用search_pattern的中心点为某个已知地点比如“跷跷板”的坐标或者选择一个合理的中心点。例如假设搜索区域是“跷跷板”所在的位置那么中心坐标为(15, -8.5, 1.2)。或者可能需要将搜索区域设置为多个地点的组合,但用户没有说明,所以可能需要选择一个中心点。
接下来考虑使用search_pattern来搜索因为目标位置未知。参数中需要指定pattern_type比如spiral或grid。假设选择spiral模式覆盖更大的区域。中心点可能选在某个已知地点比如“跷跷板”的坐标或者综合多个点。但用户没有明确所以可能需要选择一个合理的中心点比如“跷跷板”的坐标。
然后检测到目标后需要跟踪30秒再打击。所以流程是起飞→飞往搜索区→搜索→检测→跟踪→打击→降落。
安全监控必须包含在Parallel节点中监控电池和GPS并在紧急情况下返航。
现在,构建行为树的结构:
根节点是Parallel包含主任务和安全监控。主任务是Sequence包含起飞、飞往搜索区、搜索、检测、跟踪、打击、降落。安全监控是Selector包含电池和GPS条件以及紧急处理Sequence。
在搜索部分使用search_pattern参数包括pattern_type为spiral中心点选在某个已知地点比如“跷跷板”的坐标(15, -8.5, 1.2)半径可能设为50米覆盖较大区域。目标类别是balloon描述为“红色气球危险性高于蓝色气球高于绿色气球”但参数中description需要描述目标属性比如“红>蓝>绿”。
检测到目标后使用track_object参数target_class为balloondescription为“红>蓝>绿”track_time为30秒。然后strike_target最后评估战损。
需要确保所有参数符合约束比如z坐标在1-5000米之间半径在5-1000米之间速度等参数在合理范围。
现在将各个步骤的参数填入JSON中。例如起飞到2米飞往搜索区的中心点可能选在“跷跷板”的坐标(15, -8.5, 1.2)但z需要调整到至少1米这里已经是1.2。所以fly_to_waypoint的参数x=15y=-8.5z=1.2接受半径2米。
搜索使用search_patternpattern_type为spiral中心点为(15, -8.5, 1.2)半径设为50米覆盖区域。目标类别是balloondescription为“红>蓝>绿”。
检测到目标后使用track_object参数target_class为balloondescription为“红>蓝>绿”track_time为30秒min_confidence设为0.7safe_distance设为15米。
然后strike_target参数target_class为balloondescription为“红>蓝>绿”count为1。
最后,降落。
安全监控部分电池阈值设为0.35GPS的min_satellites设为8紧急处理Sequence包括emergency_return和land。
现在将所有步骤的参数填入JSON中确保符合所有规则。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 224 KiB

View File

@@ -15,8 +15,8 @@ chromadb>=0.4.0
# Visualization # Visualization
graphviz>=0.20.0 graphviz>=0.20.0
# ROS 2 Python Client - 已注释项目已与ROS2解耦 # ROS 2 Python Client
# rclpy>=0.0.1 rclpy>=0.0.1
# Document Processing # Document Processing
unstructured[all]>=0.11.0 unstructured[all]>=0.11.0
@@ -30,10 +30,10 @@ rich>=13.7.0
# Type Hints Support # Type Hints Support
typing-extensions>=4.8.0 typing-extensions>=4.8.0
# ROS 2 Build Dependencies - 已注释项目已与ROS2解耦 # ROS 2 Build Dependencies
# empy==3.3.4 empy==3.3.4
# catkin-pkg>=0.4.0 catkin-pkg>=0.4.0
# lark>=1.1.0 lark>=1.1.0
# colcon-common-extensions>=0.3.0 colcon-common-extensions>=0.3.0
# vcstool>=0.2.0 vcstool>=0.2.0
# rosdep>=0.22.0 rosdep>=0.22.0

View File

@@ -3,13 +3,13 @@ import os
from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
import logging import logging
# import threading # ROS2相关已注释 import threading
# import rclpy # ROS2相关已注释 import rclpy
from .models import GeneratePlanRequest, ExecuteMissionRequest from .models import GeneratePlanRequest, ExecuteMissionRequest
from .websocket_manager import websocket_manager from .websocket_manager import websocket_manager
from .py_tree_generator import py_tree_generator from .py_tree_generator import py_tree_generator
# from .ros2_client import MissionActionClient # ROS2相关已注释 from .ros2_client import MissionActionClient
# --- Application Setup --- # --- Application Setup ---
app = FastAPI( app = FastAPI(
@@ -23,15 +23,14 @@ static_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'gene
app.mount("/static", StaticFiles(directory=static_dir), name="static") app.mount("/static", StaticFiles(directory=static_dir), name="static")
# --- ROS2 Node and Client Initialization --- # --- ROS2 Node and Client Initialization ---
# ROS2相关代码已注释项目已与ROS2解耦 rclpy.init()
# rclpy.init() ros2_client = MissionActionClient()
# ros2_client = MissionActionClient()
# def run_ros2_node(): def run_ros2_node():
# """Spins the ROS2 node in a dedicated thread.""" """Spins the ROS2 node in a dedicated thread."""
# logging.info("Starting to spin ROS2 node...") logging.info("Starting to spin ROS2 node...")
# rclpy.spin(ros2_client) rclpy.spin(ros2_client)
# logging.info("ROS2 node has stopped spinning.") logging.info("ROS2 node has stopped spinning.")
# --- API Endpoints --- # --- API Endpoints ---
@@ -50,12 +49,9 @@ async def generate_plan_endpoint(request: GeneratePlanRequest):
async def execute_mission_endpoint(request: ExecuteMissionRequest): async def execute_mission_endpoint(request: ExecuteMissionRequest):
""" """
Receives a `py_tree.json` and sends it to the drone for execution. Receives a `py_tree.json` and sends it to the drone for execution.
ROS2相关功能已注释项目已与ROS2解耦。
""" """
# ROS2相关代码已注释 ros2_client.send_goal(request.py_tree)
# ros2_client.send_goal(request.py_tree) return {"status": "execution_started"}
logging.warning("execute_mission endpoint called but ROS2 is disabled. Mission execution is not available.")
return {"status": "execution_disabled", "message": "ROS2 integration is disabled. Mission execution is not available."}
@app.websocket("/ws/status") @app.websocket("/ws/status")
async def websocket_endpoint(websocket: WebSocket): async def websocket_endpoint(websocket: WebSocket):
@@ -77,23 +73,21 @@ async def websocket_endpoint(websocket: WebSocket):
async def startup_event(): async def startup_event():
""" """
On startup, get the current asyncio event loop and pass it to the websocket manager. On startup, get the current asyncio event loop and pass it to the websocket manager.
ROS2相关功能已注释项目已与ROS2解耦。 Also, start the ROS2 node in a background thread.
""" """
# Configure WebSocket Manager # Configure WebSocket Manager
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
websocket_manager.set_loop(loop) websocket_manager.set_loop(loop)
logging.info("WebSocket event loop configured.") logging.info("WebSocket event loop configured.")
# ROS2相关代码已注释
# Start ROS2 node in a background thread # Start ROS2 node in a background thread
# ros2_thread = threading.Thread(target=run_ros2_node, daemon=True) ros2_thread = threading.Thread(target=run_ros2_node, daemon=True)
# ros2_thread.start() ros2_thread.start()
# logging.info("ROS2 node thread started.") logging.info("ROS2 node thread started.")
@app.on_event("shutdown") @app.on_event("shutdown")
async def shutdown_event(): async def shutdown_event():
logging.info("Backend service shutting down.") logging.info("Backend service shutting down.")
# ROS2相关代码已注释 ros2_client.destroy_node()
# ros2_client.destroy_node() rclpy.shutdown()
# rclpy.shutdown() logging.info("ROS2 node shut down successfully.")
# logging.info("ROS2 node shut down successfully.")

View File

@@ -1,23 +1,26 @@
任务根据用户任意任务指令生成结构化可执行的无人机行为树PytreeJSON。**仅输出单一JSON对象无任何自然语言、注释或额外内容**。 任务根据用户任意任务指令生成结构化可执行的无人机行为树PytreeJSON。**仅输出单一JSON对象无任何自然语言、注释或额外内容**需严格适配后端节点解析与Schema验证逻辑
## 一、核心节点定义(格式不可修改,确保后端解析)
#### 1. 可用节点定义 (必须遵守) ## 一、核心规则:确保后端能解析允许的节点(必严格遵守
你必须严格从以下JSON定义的列表中选择节点构建行为树不允许使用未定义节点 后端会从提示词中解析允许的节点列表,以下节点定义部分**格式不可修改**,否则会导致解析失败(进而触发节点非法错误)。
#### 2. 可用节点定义 (必须遵守)
你必须严格从以下JSON定义的列表中选择节点来构建行为树。不允许使用任何未定义的节点如"lock_target"等)。
```json ```json
{ {
"actions": [ "actions": [
{"name":"takeoff","params":{"altitude":"float[1,100]默认2"}}, {"name":"takeoff","params":{"altitude":"float, 范围[1,100]默认2"}},
{"name":"land","params":{"mode":"'current'/'home'"}}, {"name":"land","params":{"mode":"string, 'current'/'home'"}},
{"name":"fly_to_waypoint","params":{"x":"±10000","y":"±10000","z":"[1,5000]","acceptance_radius":"默认2.0"}}, {"name":"fly_to_waypoint","params":{"x":"±10000","y":"±10000","z":"[1,5000]","acceptance_radius":"默认2.0"}},
{"name":"move_direction","params":{"direction":"north/south/east/west/forward/backward/left/right","distance":"[1,10000],缺省持续移动"}}, {"name":"move_direction","params":{"direction":"north/south/east/west/forward/backward/left/right","distance":"[1,10000],缺省持续移动"}},
{"name":"orbit_around_point","params":{"center_x":"±10000","center_y":"±10000","center_z":"[1,5000]","radius":"[5,1000]","laps":"[1,20]","clockwise":"默认true","speed_mps":"[0.5,15]","gimbal_lock":"默认true"}}, {"name":"orbit_around_point","params":{"center_x":"±10000","center_y":"±10000","center_z":"[1,5000]","radius":"[5,1000]","laps":"[1,20]","clockwise":"默认true","speed_mps":"[0.5,15]","gimbal_lock":"默认true"}},
{"name":"orbit_around_target","params":{"target_class":"见object_detect列表","description":"可选,目标属性","radius":"[5,1000]","laps":"[1,20]","clockwise":"默认true","speed_mps":"[0.5,15]","gimbal_lock":"默认true"}}, {"name":"orbit_around_target","params":{"target_class":"见object_detect列表","description":"可选","radius":"[5,1000]","laps":"[1,20]","clockwise":"默认true","speed_mps":"[0.5,15]","gimbal_lock":"默认true"}},
{"name":"loiter","params":{"duration":"[1,600]秒/until_condition:可选"}}, {"name":"loiter","params":{"duration":"[1,600]秒/until_condition:可选"}},
{"name":"object_detect","params":{"target_class":"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush","description":"可选,","count":"默认1"}}, {"name":"object_detect","params":{"target_class":"person,bicycle,car,motorcycle,airplane,bus,train,truck,boat,traffic_light,fire_hydrant,stop_sign,parking_meter,bench,bird,cat,dog,horse,sheep,cow,elephant,bear,zebra,giraffe,backpack,umbrella,handbag,tie,suitcase,frisbee,skis,snowboard,sports_ball,kite,baseball_bat,baseball_glove,skateboard,surfboard,tennis_racket,bottle,wine_glass,cup,fork,knife,spoon,bowl,banana,apple,sandwich,orange,broccoli,carrot,hot_dog,pizza,donut,cake,chair,couch,potted_plant,bed,dining_table,toilet,tv,laptop,mouse,remote,keyboard,cell_phone,microwave,oven,toaster,sink,refrigerator,book,clock,vase,scissors,teddy_bear,hair_drier,toothbrush","description":"可选,目标属性(如'穿黑色衣服'","count":"默认1"}},
{"name":"strike_target","params":{"target_class":"同object_detect","description":"可选,目标属性","count":"默认1"}}, {"name":"strike_target","params":{"target_class":"同object_detect","description":"可选,目标属性","count":"默认1"}},
{"name":"battle_damage_assessment","params":{"target_class":"同object_detect","assessment_time":"[5,60]默认15"}}, {"name":"battle_damage_assessment","params":{"target_class":"同object_detect","assessment_time":"[5,60]默认15"}},
{"name":"search_pattern","params":{"pattern_type":"spiral/grid","center_x":"±10000","center_y":"±10000","center_z":"[1,5000]","radius":"[5,1000]","target_class":"同object_detect","description":"可选,目标属性","count":"默认1"}}, {"name":"search_pattern","params":{"pattern_type":"spiral/grid","center_x":"±10000","center_y":"±10000","center_z":"[1,5000]","radius":"[5,1000]","target_class":"同object_detect","description":"可选","count":"默认1"}},
{"name":"track_object","params":{"target_class":"同object_detect","description":"可选,目标属性","track_time":"[1,600]秒(必传,不可用'duration'","min_confidence":"[0.5,1.0]默认0.7","safe_distance":"[2,50]默认10"}}, {"name":"track_object","params":{"target_class":"同object_detect","description":"可选","track_time":"[1,600]秒(必传,不可用'duration'","min_confidence":"[0.5,1.0]默认0.7","safe_distance":"[2,50]默认10"}},
{"name":"deliver_payload","params":{"payload_type":"string","release_altitude":"[2,100]默认5"}}, {"name":"deliver_payload","params":{"payload_type":"string","release_altitude":"[2,100]默认5"}},
{"name":"preflight_checks","params":{"check_level":"basic/comprehensive"}}, {"name":"preflight_checks","params":{"check_level":"basic/comprehensive"}},
{"name":"emergency_return","params":{"reason":"string"}} {"name":"emergency_return","params":{"reason":"string"}}
@@ -25,31 +28,33 @@
"conditions": [ "conditions": [
{"name":"battery_above","params":{"threshold":"[0.0,1.0],必传"}}, {"name":"battery_above","params":{"threshold":"[0.0,1.0],必传"}},
{"name":"at_waypoint","params":{"x":"±10000","y":"±10000","z":"[1,5000]","tolerance":"默认3.0"}}, {"name":"at_waypoint","params":{"x":"±10000","y":"±10000","z":"[1,5000]","tolerance":"默认3.0"}},
{"name":"object_detected","params":{"target_class":"同object_detect必传","description":"可选,目标属性","count":"默认1"}}, {"name":"object_detected","params":{"target_class":"同object_detect必传","description":"可选","count":"默认1"}},
{"name":"target_destroyed","params":{"target_class":"同object_detect","description":"可选,目标属性","confidence":"[0.5,1.0]默认0.8"}}, {"name":"target_destroyed","params":{"target_class":"同object_detect","description":"可选","confidence":"[0.5,1.0]默认0.8"}},
{"name":"time_elapsed","params":{"duration":"[1,2700]秒"}}, {"name":"time_elapsed","params":{"duration":"[1,2700]秒"}},
{"name":"gps_status","params":{"min_satellites":"int[6,15]必传如8"}} {"name":"gps_status","params":{"min_satellites":"int, 范围[6,15]必传如8"}}
], ],
"control_flow": [ "control_flow": [
{"name":"Sequence","params":{},"children":"子节点数组(按序执行,全成功则成功)"}, {"name":"Sequence","params":{},"children":"子节点数组(按序执行,全成功则成功)"},
{"name":"Selector","params":{"memory":"默认true"},"children":"子节点数组(执行到成功为止)"}, {"name":"Selector","params":{"memory":"默认true"},"children":"子节点数组(执行到成功为止)"},
{"name":"Parallel","params":{"policy":"all_success"},"children":"子节点数组(同时执行,严禁用'one_success'"} {"name":"Parallel","params":{"policy":"all_success/one_success"},"children":"子节点数组(同时执行)"}
] ]
} }
``` ```
## 二、节点必填字段后端Schema强制要求缺一验证失败 ## 二、节点必填字段后端Schema强制要求缺一验证失败
每个节点必须包含以下字段,字段名/类型不可自定义: 每个节点必须包含以下字段,字段名不可自定义:
1. **`type`** 1. **`type`**节点类型(严格匹配)
- 动作节点`"action"`,条件节点→`"condition"`,控制流节点→`"Sequence"`/`"Selector"`/`"Parallel"`(与`name`字段值完全一致); - 动作节点`"action"`
2. **`name`**必须是上述JSON中`actions`/`conditions`/`control_flow`下的`name`值如“gps_status”不可错写为“gps_check” - 条件节点:`"condition"`
3. **`params`**:严格匹配上述节点的`params`定义无自定义参数如优先级排序不可加“priority”字段仅用`description` - 控制流节点:`"Sequence"`/`"Selector"`/`"Parallel"`(与`name`字段值完全一致)
4. **`children`**:仅控制流节点必含(子节点数组),动作/条件节点无此字段。 2. **`name`**节点名称必须是上述JSON中`actions`/`conditions`/`control_flow`下的`name`值,如"gps_status"而非其他)
3. **`params`**参数对象严格匹配上述JSON中对应节点的`params`定义,不可加自定义参数,如`object_detected`不可加"color",需用"description"
4. **`children`**:子节点数组(仅控制流节点必含,动作/条件节点无此字段)
## 三、行为树固定结构(通用不变,确保安全验证) ## 三、根节点与安全监控固定结构(后端安全验证必含
根节点必须是`Parallel``children`含`MainTask`Sequence和`SafetyMonitor`Selector结构不随任务类型(含优先级排序)修改: 根节点必须是`Parallel``children`含`MainTask`Sequence和`SafetyMonitor`Selector结构不修改:
```json ```json
{ {
"root": { "root": {
@@ -62,14 +67,15 @@
"name": "MainTask", "name": "MainTask",
"params": {}, "params": {},
"children": [ "children": [
// 通用主任务步骤(含优先级排序任务示例,需按用户指令替换): // 主任务步骤按用户指令分解如preflight_checks→takeoff→fly_to_waypoint→...→land
// 示例步骤(需替换为用户任务):
{"type":"action","name":"preflight_checks","params":{"check_level":"comprehensive"}}, {"type":"action","name":"preflight_checks","params":{"check_level":"comprehensive"}},
{"type":"action","name":"takeoff","params":{"altitude":10.0}}, {"type":"action","name":"takeoff","params":{"altitude":2.0}},
{"type":"action","name":"fly_to_waypoint","params":{"x":200.0,"y":150.0,"z":10.0}}, // 搜索区坐标(用户未给时填合理值) {"type":"action","name":"fly_to_waypoint","params":{"x":100.0,"y":80.0,"z":10.0}},
{"type":"action","name":"search_pattern","params":{"pattern_type":"grid","center_x":200.0,"center_y":150.0,"center_z":10.0,"radius":50.0,"target_class":"balloon","description":"红色"}}, {"type":"action","name":"object_detect","params":{"target_class":"person","description":"穿黑色衣服"}},
{"type":"condition","name":"object_detected","params":{"target_class":"balloon","description":"红色"}}, // 确认高优先级目标 {"type":"condition","name":"object_detected","params":{"target_class":"person","description":"穿黑色衣服"}},
{"type":"action","name":"track_object","params":{"target_class":"balloon","description":"红色","track_time":30.0}}, {"type":"action","name":"track_object","params":{"target_class":"person","description":"穿黑色衣服","track_time":30.0}},
{"type":"action","name":"strike_target","params":{"target_class":"balloon","description":"红色"}}, {"type":"action","name":"strike_target","params":{"target_class":"person","description":"穿黑色衣服"}},
{"type":"action","name":"land","params":{"mode":"home"}} {"type":"action","name":"land","params":{"mode":"home"}}
] ]
}, },
@@ -78,6 +84,7 @@
"name": "SafetyMonitor", "name": "SafetyMonitor",
"params": {"memory": true}, "params": {"memory": true},
"children": [ "children": [
// 必含电池监控battery_above、GPS监控gps_status、紧急处理EmergencyHandler
{"type":"condition","name":"battery_above","params":{"threshold":0.3}}, {"type":"condition","name":"battery_above","params":{"threshold":0.3}},
{"type":"condition","name":"gps_status","params":{"min_satellites":8}}, {"type":"condition","name":"gps_status","params":{"min_satellites":8}},
{ {
@@ -97,21 +104,15 @@
``` ```
## 四、优先级排序任务通用示例 ## 四、高频错误规避(后端验证常失败点)
当用户指令中明确提出有多个待考察且具有优先级关系的物体时,节点描述须为优先级关系。比如当指令为已知有三个气球,危险级关系为红色气球大于蓝色气球大于绿色气球,要求优先跟踪最危险的气球时,节点的描述参考下表情形。 1. **禁止自定义节点**:如"lock_target"是未定义节点,必须删除,用"object_detect"+"object_detected"替代锁定逻辑。
| 用户指令场景 | `target_class` | `description` | 核心节点示例search_pattern | 2. **参数名严格匹配**
|-----------------------------|-----------------|-------------------------|------------------------------------------------------------------------------------------------| - `track_object`用`track_time`(不可用`duration`
| 红气球>蓝气球>绿气球 | `balloon` | `(红>蓝>绿)` | `{"type":"action","name":"search_pattern","params":{"pattern_type":"grid","center_x":200,"center_y":150,"center_z":10,"radius":50,"target_class":"balloon","description":"(红>蓝>绿)"}}` | - `object_detected`描述目标属性用`description`(不可用`color`/`target`等);
| 军用卡车>民用卡车>面包车 | `truck` | `(军用卡车>民用卡车>面包车)` | `{"type":"action","name":"object_detect","params":{"target_class":"truck","description":"(军用卡车>民用卡车>面包车)"}}` | - `gps_status`必传`min_satellites`范围6-15如8
3. **条件节点`object_detected`必含`target_class`**值必须是上述JSON中`object_detect`的`target_class`列表中的值(如"person")。
4. **控制流节点`name`与`type`一致**:如`type:"Sequence"`则`name:"Sequence"`,不可自定义`name`。
## 五、高频错误规避(确保验证通过) ## 五、输出要求
1. 优先级排序不可修改`target_class`:如“民用卡车、面包车与军用卡车中,军用卡车优先”,`target_class`仍为`truck`,仅用`description`填排序规则; 仅输出1个严格符合上述所有规则的JSON对象**确保后端能解析到所有节点尤其是conditions中的gps_status且无任何冗余内容**。
2. 在没有明确指出物体之间的优先级关系情况下,`description`字段只描述物体属性本身,严禁与用户指令中不存在的物体进行排序;
3. `track_object`必传`track_time`:不可用`duration`替代如跟踪30秒填`"track_time":30.0`
4. `gps_status`的`min_satellites`必须在6-15之间如8不可缺省
5. 无自定义节点:“锁定高优先级目标”需通过`object_detect`+`object_detected`实现不可用“lock_high_risk_target”。
## 六、输出要求
仅输出1个严格符合上述所有规则的JSON对象**确保1. 优先级排序逻辑正确填入`description`2. `target_class`匹配预定义列表3. 行为树结构不变4. 后端解析与Schema验证无错误**,无任何冗余内容。

View File

@@ -201,7 +201,7 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
"sandwich", "orange", "broccoli", "carrot", "hot_dog", "pizza", "donut", "cake", "chair", "sandwich", "orange", "broccoli", "carrot", "hot_dog", "pizza", "donut", "cake", "chair",
"couch", "potted_plant", "bed", "dining_table", "toilet", "tv", "laptop", "mouse", "remote", "couch", "potted_plant", "bed", "dining_table", "toilet", "tv", "laptop", "mouse", "remote",
"keyboard", "cell_phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "keyboard", "cell_phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book",
"clock", "vase", "scissors", "teddy_bear", "hair_drier", "toothbrush","balloon" "clock", "vase", "scissors", "teddy_bear", "hair_drier", "toothbrush"
] ]
# 递归节点定义 # 递归节点定义
@@ -337,28 +337,35 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
def _generate_simple_mode_schema(allowed_actions: set) -> dict: def _generate_simple_mode_schema(allowed_actions: set) -> dict:
""" """
生成简单模式JSON Schema{"mode":"simple","action":{...}} 生成简单模式JSON Schema{"root":{"type":"action","name":"<action_name>","params":{...}}}
仅校验动作名称在允许集合内,以及基本结构完整性;参数按对象形状放宽,由上游提示词与运行时再约束。 仅校验动作名称在允许集合内,以及基本结构完整性;参数按对象形状放宽,由上游提示词与运行时再约束。
""" """
# 使用复杂模式Schema中的node定义但限制root节点必须是action类型
node_definition = {
"type": "object",
"properties": {
"type": {"type": "string", "const": "action"},
"name": {"type": "string", "enum": sorted(list(allowed_actions))},
"params": {"type": "object"}
},
"required": ["type", "name"],
"additionalProperties": False
}
schema = { schema = {
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"title": "SimpleMode", "title": "SimpleMode",
"definitions": {
"node": node_definition
},
"type": "object", "type": "object",
"properties": { "properties": {
"mode": {"type": "string", "const": "simple"}, "root": { "$ref": "#/definitions/node" }
"action": {
"type": "object",
"properties": {
"name": {"type": "string", "enum": sorted(list(allowed_actions))},
"params": {"type": "object"}
},
"required": ["name"],
"additionalProperties": True
}
}, },
"required": ["mode", "action"], "required": ["root"],
"additionalProperties": False "additionalProperties": False
} }
return schema return schema
def _validate_pytree_with_schema(pytree_instance: dict, schema: dict) -> bool: def _validate_pytree_with_schema(pytree_instance: dict, schema: dict) -> bool:
@@ -548,16 +555,6 @@ class PyTreeGenerator:
# Updated output directory for visualizations # Updated output directory for visualizations
self.vis_dir = os.path.abspath(os.path.join(self.base_dir, '..', 'generated_visualizations')) self.vis_dir = os.path.abspath(os.path.join(self.base_dir, '..', 'generated_visualizations'))
os.makedirs(self.vis_dir, exist_ok=True) os.makedirs(self.vis_dir, exist_ok=True)
# Reasoning content output directory (Markdown files)
self.reasoning_dir = os.path.abspath(os.path.join(self.base_dir, '..', 'generated_reasoning_content'))
os.makedirs(self.reasoning_dir, exist_ok=True)
# 控制是否允许模型返回含 <think> 的原文不强制JSON以便提取推理链
self.enable_reasoning_capture = os.getenv("ENABLE_REASONING_CAPTURE", "true").lower() in ("1", "true", "yes")
# 终端预览的最大行数
try:
self.reasoning_preview_lines = int(os.getenv("REASONING_PREVIEW_LINES", "20"))
except Exception:
self.reasoning_preview_lines = 20
# 加载提示词:复杂模式复用现有 system_prompt.txt简单模式与分类器独立提示词 # 加载提示词:复杂模式复用现有 system_prompt.txt简单模式与分类器独立提示词
self.complex_prompt = self._load_prompt("system_prompt.txt") self.complex_prompt = self._load_prompt("system_prompt.txt")
self.simple_prompt = self._load_prompt("simple_mode_prompt.txt") self.simple_prompt = self._load_prompt("simple_mode_prompt.txt")
@@ -574,10 +571,6 @@ class PyTreeGenerator:
self.simple_base_url = os.getenv("SIMPLE_BASE_URL", f"http://{self.orin_ip}:8081/v1") self.simple_base_url = os.getenv("SIMPLE_BASE_URL", f"http://{self.orin_ip}:8081/v1")
self.complex_base_url = os.getenv("COMPLEX_BASE_URL", f"http://{self.orin_ip}:8081/v1") self.complex_base_url = os.getenv("COMPLEX_BASE_URL", f"http://{self.orin_ip}:8081/v1")
self.api_key = os.getenv("OPENAI_API_KEY", "sk-no-key-required") self.api_key = os.getenv("OPENAI_API_KEY", "sk-no-key-required")
# 直接在代码中指定最大输出token数不通过环境变量
self.classifier_max_tokens = 512
self.simple_max_tokens = 8192
self.complex_max_tokens = 8192
# 为不同用途分别创建客户端 # 为不同用途分别创建客户端
self.classifier_client = openai.OpenAI(api_key=self.api_key, base_url=self.classifier_base_url) self.classifier_client = openai.OpenAI(api_key=self.api_key, base_url=self.classifier_base_url)
@@ -619,8 +612,6 @@ class PyTreeGenerator:
return None return None
context_str = "\n\n".join(retrieved_docs) context_str = "\n\n".join(retrieved_docs)
logging.info("--- 成功检索到上下文信息 ---") logging.info("--- 成功检索到上下文信息 ---")
# 打印检索到的上下文内容
logging.info(f"📚 检索到的上下文内容:\n{context_str}")
return context_str return context_str
except Exception as e: except Exception as e:
logging.error(f"从向量数据库检索时发生错误: {e}") logging.error(f"从向量数据库检索时发生错误: {e}")
@@ -642,11 +633,7 @@ class PyTreeGenerator:
{"role": "user", "content": user_prompt} {"role": "user", "content": user_prompt}
], ],
temperature=0.0, temperature=0.0,
response_format={"type": "json_object"}, # 强制JSON输出禁用思考功能 response_format={"type": "json_object"}
max_tokens=self.classifier_max_tokens,
# 禁用 Qwen3 模型的思考功能(通过 extra_body 传递)
# 注意:如果 API 服务器不支持此参数,会忽略
extra_body={"chat_template_kwargs": {"enable_thinking": False}}
) )
class_str = classifier_resp.choices[0].message.content class_str = classifier_resp.choices[0].message.content
class_obj = json.loads(class_str) class_obj = json.loads(class_str)
@@ -675,102 +662,27 @@ class PyTreeGenerator:
final_user_prompt += augmentation final_user_prompt += augmentation
else: else:
logging.warning("未检索到上下文或检索失败,将使用原始用户提示词。") logging.warning("未检索到上下文或检索失败,将使用原始用户提示词。")
# 构建完整的 final_prompt准确反映实际发送给大模型的内容结构
# 注意RAG检索结果被添加到 user prompt 中,而不是 system prompt
# System Prompt: use_prompt不包含RAG结果
# User Prompt: final_user_prompt包含原始user_prompt + RAG检索结果
final_prompt = f"=== System Prompt ===\n{use_prompt}\n\n=== User Prompt ===\n{final_user_prompt}"
for attempt in range(3): for attempt in range(3):
logging.info(f"--- 第 {attempt + 1}/3 次尝试生成Pytree ---") logging.info(f"--- 第 {attempt + 1}/3 次尝试生成Pytree ---")
try: try:
# 简单/复杂分流到不同模型与提示词 # 简单/复杂分流到不同模型与提示词
client = self.simple_llm_client if mode == "simple" else self.complex_llm_client client = self.simple_llm_client if mode == "simple" else self.complex_llm_client
model_name = self.simple_model if mode == "simple" else self.complex_model model_name = self.simple_model if mode == "simple" else self.complex_model
# 始终强制JSON响应并禁用思考功能 response = client.chat.completions.create(
response_kwargs = { model=model_name,
"model": model_name, messages=[
"messages": [
{"role": "system", "content": use_prompt}, {"role": "system", "content": use_prompt},
{"role": "user", "content": final_user_prompt} {"role": "user", "content": final_user_prompt}
], ],
"temperature": 0.1 if mode == "complex" else 0.0, temperature=0.1 if mode == "complex" else 0.0,
"response_format": {"type": "json_object"}, # 始终强制JSON输出禁用思考功能 response_format={"type": "json_object"}
# 禁用 Qwen3 模型的思考功能(通过 extra_body 传递) )
# 注意:如果 API 服务器不支持此参数,会忽略 pytree_str = response.choices[0].message.content
"extra_body": {"chat_template_kwargs": {"enable_thinking": False}}
}
# 基于模式设定最大输出token数直接在代码中配置
response_kwargs["max_tokens"] = self.simple_max_tokens if mode == "simple" else self.complex_max_tokens
response = client.chat.completions.create(**response_kwargs)
# 兼容可能存在的 reasoning_content 字段
try:
msg = response.choices[0].message
msg_content = getattr(msg, "content", None)
msg_reasoning = getattr(msg, "reasoning_content", None)
except Exception:
msg = response.choices[0]["message"] if isinstance(response.choices[0], dict) else None
msg_content = (msg or {}).get("content") if isinstance(msg, dict) else None
msg_reasoning = (msg or {}).get("reasoning_content") if isinstance(msg, dict) else None
combined_text = ""
if isinstance(msg_reasoning, str) and msg_reasoning.strip():
# 将 reasoning_content 包装为 <think>,便于统一解析
combined_text += f"<think>\n{msg_reasoning}\n</think>\n"
if isinstance(msg_content, str) and msg_content.strip():
combined_text += msg_content
pytree_str = combined_text if combined_text else (msg_content or "")
raw_full_text_for_logging = pytree_str # 保存完整原文(含 <think>)以便失败时完整打印
# 提取 <think> 推理链内容(若存在)
reasoning_text = None
try:
think_match = re.search(r"<think>([\s\S]*?)</think>", pytree_str)
if think_match:
reasoning_text = think_match.group(1).strip()
# 去除推理文本后再尝试解析JSON
pytree_str = re.sub(r"<think>[\s\S]*?</think>", "", pytree_str).strip()
except Exception:
reasoning_text = None
# 单独捕获JSON解析错误并打印原始响应 # 单独捕获JSON解析错误并打印原始响应
try: try:
pytree_dict = json.loads(pytree_str) pytree_dict = json.loads(pytree_str)
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
logging.error(f"❌ JSON解析失败{attempt + 1}/3 次)。\n—— 完整原始文本(含<think>) ——\n{raw_full_text_for_logging}") logging.error(f"❌ JSON解析失败{attempt + 1}/3 次)。原始响应如下:\n{pytree_str}")
# 尝试打印响应对象的完整结构
try:
raw_response_dump = None
if hasattr(response, 'model_dump_json'):
raw_response_dump = response.model_dump_json(indent=2, exclude_none=False)
elif hasattr(response, 'dict'):
raw_response_dump = json.dumps(response.dict(), ensure_ascii=False, indent=2, default=str)
else:
# 兜底尝试将choices与关键字段展开
safe_obj = {
"id": getattr(response, 'id', None),
"model": getattr(response, 'model', None),
"object": getattr(response, 'object', None),
"usage": getattr(response, 'usage', None),
"choices": [
{
"index": getattr(c, 'index', None),
"finish_reason": getattr(c, 'finish_reason', None),
"message": {
"role": getattr(getattr(c, 'message', None), 'role', None),
"content": getattr(getattr(c, 'message', None), 'content', None),
"reasoning_content": getattr(getattr(c, 'message', None), 'reasoning_content', None)
} if getattr(c, 'message', None) is not None else None
}
for c in getattr(response, 'choices', [])
] if hasattr(response, 'choices') else None
}
raw_response_dump = json.dumps(safe_obj, ensure_ascii=False, indent=2, default=str)
logging.error(f"—— 完整响应对象 ——\n{raw_response_dump}")
except Exception as dump_e:
try:
logging.error(f"响应对象转储失败repr如下\n{repr(response)}")
except Exception:
pass
continue continue
# 简单/复杂分别验证与返回 # 简单/复杂分别验证与返回
@@ -784,40 +696,14 @@ class PyTreeGenerator:
# 附加元信息并生成简单可视化(单动作) # 附加元信息并生成简单可视化(单动作)
plan_id = str(uuid.uuid4()) plan_id = str(uuid.uuid4())
pytree_dict['plan_id'] = plan_id pytree_dict['plan_id'] = plan_id
# 简单模式可视化:构造一个简化节点 # 简单模式可视化:直接使用root节点
try: try:
vis_filename = "py_tree.png" vis_filename = "py_tree.png"
vis_path = os.path.join(self.vis_dir, vis_filename) vis_path = os.path.join(self.vis_dir, vis_filename)
simple_node = { _visualize_pytree(pytree_dict['root'], os.path.splitext(vis_path)[0])
"type": "action",
"name": pytree_dict.get('action', {}).get('name', 'action'),
"params": pytree_dict.get('action', {}).get('params', {})
}
_visualize_pytree(simple_node, os.path.splitext(vis_path)[0])
pytree_dict['visualization_url'] = f"/static/{vis_filename}" pytree_dict['visualization_url'] = f"/static/{vis_filename}"
except Exception as e: except Exception as e:
logging.warning(f"简单模式可视化失败: {e}") logging.warning(f"简单模式可视化失败: {e}")
# 保存推理链(若有)
try:
if reasoning_text:
reasoning_path = os.path.join(self.reasoning_dir, "reasoning_content.md")
with open(reasoning_path, 'w', encoding='utf-8') as rf:
rf.write(reasoning_text)
logging.info(f"📝 推理链已保存: {reasoning_path}")
# 终端预览最多N行
try:
lines = reasoning_text.splitlines()
preview = "\n".join(lines[: self.reasoning_preview_lines])
logging.info("🧠 推理链预览(前%d行)\n%s", self.reasoning_preview_lines, preview)
except Exception:
pass
else:
logging.info("未在模型输出中发现 <think> 推理链片段。若需捕获,请设置 ENABLE_REASONING_CAPTURE=true 以放宽JSON强制格式。")
except Exception as e:
logging.warning(f"保存推理链Markdown失败: {e}")
# 添加 final_prompt 到返回结果
pytree_dict['final_prompt'] = final_prompt
return pytree_dict return pytree_dict
# 复杂模式回退:若模型误返回简单结构,则自动包装为含安全监控的行为树 # 复杂模式回退:若模型误返回简单结构,则自动包装为含安全监控的行为树
@@ -870,27 +756,6 @@ class PyTreeGenerator:
vis_path = os.path.join(self.vis_dir, vis_filename) vis_path = os.path.join(self.vis_dir, vis_filename)
_visualize_pytree(pytree_dict['root'], os.path.splitext(vis_path)[0]) _visualize_pytree(pytree_dict['root'], os.path.splitext(vis_path)[0])
pytree_dict['visualization_url'] = f"/static/{vis_filename}" pytree_dict['visualization_url'] = f"/static/{vis_filename}"
# 保存推理链(若有)
try:
if reasoning_text:
reasoning_path = os.path.join(self.reasoning_dir, "reasoning_content.md")
with open(reasoning_path, 'w', encoding='utf-8') as rf:
rf.write(reasoning_text)
logging.info(f"📝 推理链已保存: {reasoning_path}")
# 终端预览最多N行
try:
lines = reasoning_text.splitlines()
preview = "\n".join(lines[: self.reasoning_preview_lines])
logging.info("🧠 推理链预览(前%d行)\n%s", self.reasoning_preview_lines, preview)
except Exception:
pass
else:
logging.info("未在模型输出中发现 <think> 推理链片段。若需捕获,请设置 ENABLE_REASONING_CAPTURE=true 以放宽JSON强制格式。")
except Exception as e:
logging.warning(f"保存推理链Markdown失败: {e}")
# 添加 final_prompt 到返回结果
pytree_dict['final_prompt'] = final_prompt
return pytree_dict return pytree_dict
else: else:
# 打印未通过验证的Pytree以便排查 # 打印未通过验证的Pytree以便排查

View File

@@ -0,0 +1,67 @@
import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
import json
from typing import Dict, Any
import logging
from drone_interfaces.action import ExecuteMission
from .websocket_manager import websocket_manager
class MissionActionClient(Node):
"""
Interfaces with the drone's `ExecuteMission` ROS2 Action Server.
"""
def __init__(self):
super().__init__('mission_action_client')
self._action_client = ActionClient(self, ExecuteMission, 'execute_mission')
self.get_logger().info("MissionActionClient initialized.")
def send_goal(self, py_tree: Dict[str, Any]):
"""
Sends the mission (py_tree) to the action server.
"""
if not self._action_client.server_is_ready():
self.get_logger().error("Action server not available, goal not sent.")
# Optionally, you could broadcast a status update to the frontend here
return
self.get_logger().info("Received request to send goal to drone.")
goal_msg = ExecuteMission.Goal()
goal_msg.py_tree_json = json.dumps(py_tree)
self.get_logger().info(f"Sending goal to action server...")
send_goal_future = self._action_client.send_goal_async(
goal_msg,
feedback_callback=self.feedback_callback
)
send_goal_future.add_done_callback(self.goal_response_callback)
def goal_response_callback(self, future):
goal_handle = future.result()
if not goal_handle.accepted:
self.get_logger().info('Goal rejected :(')
return
self.get_logger().info('Goal accepted :)')
self._get_result_future = goal_handle.get_result_async()
self._get_result_future.add_done_callback(self.get_result_callback)
def get_result_callback(self, future):
result = future.result().result
self.get_logger().info(f'Result: {{success: {result.success}, message: {result.message}}}')
# Optionally, you can broadcast the final result via WebSocket here
def feedback_callback(self, feedback_msg):
"""
This callback is triggered by the action server.
It forwards the status to the QGC plugin via the WebSocket manager in a thread-safe manner.
"""
feedback = feedback_msg.feedback
feedback_payload = json.dumps({"node_id": feedback.node_id, "status": feedback.status})
self.get_logger().info(f"Received feedback: {feedback_payload}")
websocket_manager.broadcast(feedback_payload)
# Note: The rclpy.init() and spinning of the node will be handled in main.py

View File

@@ -22,8 +22,7 @@ class ConnectionManager:
def broadcast(self, message: str): def broadcast(self, message: str):
""" """
Thread-safely broadcasts a message to all active WebSocket connections. Thread-safely broadcasts a message to all active WebSocket connections.
This method is designed to be called from a different thread. This method is designed to be called from a different thread (e.g., a ROS2 callback).
(Note: ROS2 callback support has been removed as the project is decoupled from ROS2)
""" """
if not self.loop: if not self.loop:
logging.error("Event loop not set in ConnectionManager. Cannot broadcast.") logging.error("Event loop not set in ConnectionManager. Cannot broadcast.")

View File

@@ -1,406 +0,0 @@
#!/bin/bash
# ==============================================================================
# 无人机自然语言控制项目 - 一键启动脚本
# ==============================================================================
# 功能启动所有必需的服务llama-server推理模型、embedding模型、FastAPI后端
# 用法:./start_all.sh [选项]
# ==============================================================================
set -e # 遇到错误立即退出
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 默认配置(可通过环境变量覆盖)
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LLAMA_SERVER_DIR="${LLAMA_SERVER_DIR:-~/llama.cpp/build/bin}"
INFERENCE_MODEL="${INFERENCE_MODEL:-~/models/gguf/Qwen/Qwen3-4B/Qwen3-4B-Q5_K_M.gguf}"
EMBEDDING_MODEL="${EMBEDDING_MODEL:-~/models/gguf/Qwen/Qwen3-Embedding-4B/Qwen3-Embedding-4B-Q4_K_M.gguf}"
VENV_PATH="${VENV_PATH:-${PROJECT_ROOT}/backend_service/venv}"
LOG_DIR="${PROJECT_ROOT}/logs"
PID_FILE="${LOG_DIR}/services.pid"
# 端口配置
INFERENCE_PORT=8081
EMBEDDING_PORT=8090
API_PORT=8000
# 创建日志目录
mkdir -p "${LOG_DIR}"
# ==============================================================================
# 辅助函数
# ==============================================================================
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查命令是否存在
check_command() {
if ! command -v "$1" &> /dev/null; then
print_error "$1 命令未找到,请先安装"
return 1
fi
return 0
}
# 检查端口是否被占用
check_port() {
local port=$1
if lsof -Pi :${port} -sTCP:LISTEN -t >/dev/null 2>&1 ; then
return 0 # 端口被占用
else
return 1 # 端口空闲
fi
}
# 等待服务就绪
wait_for_service() {
local url=$1
local service_name=$2
local max_attempts=30
local attempt=0
print_info "等待 ${service_name} 启动..."
while [ $attempt -lt $max_attempts ]; do
if curl -s "${url}" > /dev/null 2>&1; then
print_success "${service_name} 已就绪"
return 0
fi
attempt=$((attempt + 1))
sleep 1
done
print_error "${service_name} 启动超时"
return 1
}
# 停止所有服务
stop_services() {
print_info "正在停止所有服务..."
if [ -f "${PID_FILE}" ]; then
while read pid; do
if ps -p $pid > /dev/null 2>&1; then
print_info "停止进程 PID: $pid"
kill $pid 2>/dev/null || true
fi
done < "${PID_FILE}"
rm -f "${PID_FILE}"
fi
# 尝试通过端口停止服务
for port in ${INFERENCE_PORT} ${EMBEDDING_PORT} ${API_PORT}; do
if check_port ${port}; then
local pid=$(lsof -ti:${port})
if [ ! -z "$pid" ]; then
print_info "停止占用端口 ${port} 的进程 (PID: $pid)"
kill $pid 2>/dev/null || true
fi
fi
done
print_success "所有服务已停止"
}
# 清理函数(脚本退出时调用)
cleanup() {
if [ "$?" -ne 0 ]; then
print_error "启动过程中发生错误,正在清理..."
fi
# 注意:这里不自动停止服务,让用户手动控制
}
trap cleanup EXIT
# ==============================================================================
# 主函数
# ==============================================================================
start_services() {
print_info "=========================================="
print_info " 无人机自然语言控制项目 - 服务启动"
print_info "=========================================="
echo ""
# 检查必要的命令
print_info "检查必要的命令..."
check_command "python3" || exit 1
check_command "curl" || exit 1
check_command "lsof" || print_warning "lsof 未安装,将无法检查端口占用"
echo ""
# 检查端口占用
print_info "检查端口占用..."
if check_port ${INFERENCE_PORT}; then
print_warning "端口 ${INFERENCE_PORT} 已被占用,推理模型可能已在运行"
fi
if check_port ${EMBEDDING_PORT}; then
print_warning "端口 ${EMBEDDING_PORT} 已被占用Embedding模型可能已在运行"
fi
if check_port ${API_PORT}; then
print_error "端口 ${API_PORT} 已被占用,请先停止占用该端口的服务"
exit 1
fi
echo ""
# 检查llama-server展开路径中的 ~
local llama_server_dir_expanded=$(eval echo "${LLAMA_SERVER_DIR}")
local llama_server="${llama_server_dir_expanded}/llama-server"
if [ ! -f "${llama_server}" ]; then
print_error "llama-server 未找到: ${llama_server}"
print_info "请设置 LLAMA_SERVER_DIR 环境变量指向正确的路径"
print_info "当前路径: ${LLAMA_SERVER_DIR}"
print_info "展开后路径: ${llama_server_dir_expanded}"
exit 1
fi
print_success "找到 llama-server: ${llama_server}"
echo ""
# 检查模型文件
local inference_model_expanded=$(eval echo "${INFERENCE_MODEL}")
local embedding_model_expanded=$(eval echo "${EMBEDDING_MODEL}")
if [ ! -f "${inference_model_expanded}" ]; then
print_error "推理模型文件未找到: ${inference_model_expanded}"
print_info "请设置 INFERENCE_MODEL 环境变量指向正确的模型路径"
exit 1
fi
print_success "找到推理模型: ${inference_model_expanded}"
if [ ! -f "${embedding_model_expanded}" ]; then
print_error "Embedding模型文件未找到: ${embedding_model_expanded}"
print_info "请设置 EMBEDDING_MODEL 环境变量指向正确的模型路径"
exit 1
fi
print_success "找到Embedding模型: ${embedding_model_expanded}"
echo ""
# 检查ROS2环境
local ros2_setup="${PROJECT_ROOT}/install/setup.bash"
if [ ! -f "${ros2_setup}" ]; then
print_warning "ROS2 setup文件未找到: ${ros2_setup}"
print_warning "如果项目已与ROS2解耦可以忽略此警告"
else
print_success "找到ROS2 setup文件: ${ros2_setup}"
fi
echo ""
# 检查venv虚拟环境
local venv_path_expanded=$(eval echo "${VENV_PATH}")
print_info "检查venv虚拟环境: ${venv_path_expanded}"
if [ ! -d "${venv_path_expanded}" ]; then
print_error "venv虚拟环境目录不存在: ${venv_path_expanded}"
print_info "请先创建venv环境: python3 -m venv ${venv_path_expanded}"
print_info "然后安装依赖: ${venv_path_expanded}/bin/pip install -r backend_service/requirements.txt"
exit 1
fi
if [ ! -f "${venv_path_expanded}/bin/activate" ]; then
print_error "venv激活脚本不存在: ${venv_path_expanded}/bin/activate"
print_error "这看起来不是一个有效的venv环境"
exit 1
fi
print_success "venv虚拟环境存在: ${venv_path_expanded}"
echo ""
# 初始化PID文件
> "${PID_FILE}"
# ==========================================================================
# 启动推理模型服务
# ==========================================================================
print_info "启动推理模型服务 (端口 ${INFERENCE_PORT})..."
cd "${llama_server_dir_expanded}"
nohup ./llama-server \
-m "${inference_model_expanded}" \
--port ${INFERENCE_PORT} \
--gpu-layers 36 \
--host 0.0.0.0 \
-c 8192 \
> "${LOG_DIR}/inference_model.log" 2>&1 &
local inference_pid=$!
echo $inference_pid >> "${PID_FILE}"
print_success "推理模型服务已启动 (PID: $inference_pid)"
print_info "日志文件: ${LOG_DIR}/inference_model.log"
echo ""
# ==========================================================================
# 启动Embedding模型服务
# ==========================================================================
print_info "启动Embedding模型服务 (端口 ${EMBEDDING_PORT})..."
nohup ./llama-server \
-m "${embedding_model_expanded}" \
--gpu-layers 36 \
--port ${EMBEDDING_PORT} \
--embeddings \
--pooling last \
--host 0.0.0.0 \
> "${LOG_DIR}/embedding_model.log" 2>&1 &
local embedding_pid=$!
echo $embedding_pid >> "${PID_FILE}"
print_success "Embedding模型服务已启动 (PID: $embedding_pid)"
print_info "日志文件: ${LOG_DIR}/embedding_model.log"
echo ""
# ==========================================================================
# 等待模型服务就绪
# ==========================================================================
print_info "等待模型服务就绪..."
sleep 3 # 给服务一些启动时间
# 等待推理模型服务
if ! wait_for_service "http://localhost:${INFERENCE_PORT}/health" "推理模型服务"; then
# 如果health端点不存在尝试检查根路径
if ! wait_for_service "http://localhost:${INFERENCE_PORT}/v1/models" "推理模型服务"; then
print_warning "推理模型服务可能未完全就绪,但将继续启动"
fi
fi
# 等待Embedding模型服务
if ! wait_for_service "http://localhost:${EMBEDDING_PORT}/health" "Embedding模型服务"; then
if ! wait_for_service "http://localhost:${EMBEDDING_PORT}/v1/models" "Embedding模型服务"; then
print_warning "Embedding模型服务可能未完全就绪但将继续启动"
fi
fi
echo ""
# ==========================================================================
# 启动FastAPI后端服务
# ==========================================================================
print_info "启动FastAPI后端服务 (端口 ${API_PORT})..."
cd "${PROJECT_ROOT}"
# 激活venv虚拟环境并启动FastAPI服务
# 使用bash -c来在新的shell中激活venv环境
bash -c "
# 激活ROS2环境如果存在
if [ -f '${ros2_setup}' ]; then
source '${ros2_setup}'
fi
# 激活venv虚拟环境
source '${venv_path_expanded}/bin/activate' && \
cd '${PROJECT_ROOT}/backend_service' && \
uvicorn src.main:app --host 0.0.0.0 --port ${API_PORT}
" > "${LOG_DIR}/fastapi.log" 2>&1 &
local api_pid=$!
echo $api_pid >> "${PID_FILE}"
print_success "FastAPI服务已启动 (PID: $api_pid)"
print_info "日志文件: ${LOG_DIR}/fastapi.log"
echo ""
# 等待FastAPI服务就绪
sleep 3
if wait_for_service "http://localhost:${API_PORT}/docs" "FastAPI服务"; then
print_success "所有服务已成功启动!"
else
print_warning "FastAPI服务可能未完全就绪请检查日志: ${LOG_DIR}/fastapi.log"
fi
echo ""
# 显示服务访问信息
print_info "=========================================="
print_info " 服务启动完成!"
print_info "=========================================="
print_info "推理模型API: http://localhost:${INFERENCE_PORT}/v1"
print_info "Embedding模型API: http://localhost:${EMBEDDING_PORT}/v1"
print_info "FastAPI后端: http://localhost:${API_PORT}"
print_info "API文档: http://localhost:${API_PORT}/docs"
print_info ""
print_info "日志文件位置:"
print_info " - 推理模型: ${LOG_DIR}/inference_model.log"
print_info " - Embedding模型: ${LOG_DIR}/embedding_model.log"
print_info " - FastAPI服务: ${LOG_DIR}/fastapi.log"
print_info ""
print_info "按 Ctrl+C 停止所有服务"
print_info "=========================================="
echo ""
# 设置信号处理确保Ctrl+C时能清理
trap 'print_info "\n正在停止服务..."; stop_services; exit 0' INT TERM
# 等待所有后台进程(保持脚本运行)
print_info "所有服务正在运行中,查看日志请使用:"
print_info " tail -f ${LOG_DIR}/*.log"
echo ""
# 等待所有后台进程
wait
}
# ==============================================================================
# 脚本入口
# ==============================================================================
case "${1:-start}" in
start)
start_services
;;
stop)
stop_services
;;
restart)
stop_services
sleep 2
start_services
;;
status)
print_info "检查服务状态..."
if [ -f "${PID_FILE}" ]; then
print_info "已记录的服务进程:"
while read pid; do
if ps -p $pid > /dev/null 2>&1; then
print_success "PID $pid: 运行中"
else
print_warning "PID $pid: 已停止"
fi
done < "${PID_FILE}"
else
print_info "未找到PID文件服务可能未启动"
fi
echo ""
print_info "端口占用情况:"
for port in ${INFERENCE_PORT} ${EMBEDDING_PORT} ${API_PORT}; do
if check_port ${port}; then
local pid=$(lsof -ti:${port})
print_success "端口 ${port}: 被占用 (PID: $pid)"
else
print_warning "端口 ${port}: 空闲"
fi
done
;;
*)
echo "用法: $0 {start|stop|restart|status}"
echo ""
echo "命令说明:"
echo " start - 启动所有服务(默认)"
echo " stop - 停止所有服务"
echo " restart - 重启所有服务"
echo " status - 查看服务状态"
echo ""
echo "环境变量配置:"
echo " LLAMA_SERVER_DIR - llama-server所在目录 (默认: ~/llama.cpp/build/bin)"
echo " INFERENCE_MODEL - 推理模型路径 (默认: ~/models/gguf/Qwen/Qwen3-4B/Qwen3-4B-Q5_K_M.gguf)"
echo " EMBEDDING_MODEL - Embedding模型路径 (默认: ~/models/gguf/Qwen/Qwen3-Embedding-4B/Qwen3-Embedding-4B-Q4_K_M.gguf)"
echo " VENV_PATH - venv虚拟环境路径 (默认: \${PROJECT_ROOT}/backend_service/venv)"
exit 1
;;
esac

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,5 @@
{"text": "在地图上有一个名为 '跷跷板' 的地点或区域它的leisure是'playground',其中心位置坐标大约在 (x:15, y:-8.5, z:1.2)。"} {"text": "在地图上有一个名为 '跷跷板' 的地点或区域它的leisure是'playground',其中心位置坐标大约在 (x:15, y:-8.5, z:1.2)。"}
{"text": "在地图上有一个名为 'A地' 的地点或区域它的building是'commercial',其中心位置坐标大约在 (x:10, y:-10, z:2)。"} {"text": "在地图上有一个名为 'A地' 的地点或区域它的building是'commercial',其中心位置坐标大约在 (x:10, y:-10, z:2)。"}
{"text": "在地图上有一个名为 '学生宿舍' 的地点或区域它的building是'dormitory',其中心位置坐标大约在 (x:5, y:3, z:2)。"} {"text": "在地图上有一个名为 '学生宿舍' 的地点或区域它的building是'dormitory',其中心位置坐标大约在 (x:5, y:3, z:2)。"}
{"text": "在地图上有一个名为 '作业区域' 的地点或区域它的building是'commercial',其中心位置坐标大约在 (x:13.0, y:0.0, z:1.5)。"}
{"text": "在地图上有一个名为 '搜索区' 的地点或区域它的building是'restaurant',其中心位置坐标大约在 (x:8.0, y:0.0, z:1.5)。"}

149
tools/response.json Normal file
View File

@@ -0,0 +1,149 @@
{
"plan_id": "9f743b03-8ba7-4a06-9260-337463887fc2",
"root": {
"children": [
{
"children": [
{
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
},
"type": "action"
},
{
"name": "takeoff",
"params": {
"altitude": 2
},
"type": "action"
},
{
"name": "fly_to_waypoint",
"params": {
"acceptance_radius": 2,
"x": 5,
"y": 3,
"z": 2
},
"type": "action"
},
{
"children": [
{
"children": [
{
"name": "loiter",
"params": {
"duration": 10
},
"type": "action"
},
{
"name": "object_detect",
"params": {
"count": 1,
"description": "学生",
"target_class": "person"
},
"type": "action"
}
],
"name": "DirectDetectionSequence",
"type": "Sequence"
},
{
"name": "search_pattern",
"params": {
"center_x": 5,
"center_y": 3,
"center_z": 2,
"count": 1,
"description": "学生",
"pattern_type": "spiral",
"radius": 50,
"target_class": "person"
},
"type": "action"
}
],
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"type": "Selector"
},
{
"name": "track_object",
"params": {
"description": "学生",
"min_confidence": 0.7,
"safe_distance": 10,
"target_class": "person",
"track_time": 20
},
"type": "action"
},
{
"name": "land",
"params": {
"mode": "home"
},
"type": "action"
}
],
"name": "MainTrackingTask",
"type": "Sequence"
},
{
"children": [
{
"name": "battery_above",
"params": {
"threshold": 0.35
},
"type": "condition"
},
{
"name": "gps_status",
"params": {
"min_satellites": 8
},
"type": "condition"
},
{
"children": [
{
"name": "emergency_return",
"params": {
"reason": "safety_breach"
},
"type": "action"
},
{
"name": "land",
"params": {
"mode": "home"
},
"type": "action"
}
],
"name": "EmergencyHandler",
"type": "Sequence"
}
],
"name": "SafetyMonitor",
"params": {
"memory": true
},
"type": "Selector"
}
],
"name": "TrackingMission",
"params": {
"policy": "all_success"
},
"type": "Parallel"
},
"visualization_url": "/static/py_tree.png"
}

View File

@@ -3,8 +3,6 @@
import requests import requests
import json import json
import os
from datetime import datetime
# --- Configuration --- # --- Configuration ---
# The base URL of your running FastAPI service # The base URL of your running FastAPI service
@@ -14,51 +12,19 @@ BASE_URL = "http://127.0.0.1:8000"
ENDPOINT = "/generate_plan" ENDPOINT = "/generate_plan"
# The user prompt we will send for the test # The user prompt we will send for the test
TEST_PROMPT = "已知目标检测红色气球危险性高于蓝色气球高于绿色气球飞往搜索区搜索并锁定危险性最高的气球对其跟踪30秒后进行打击操作" TEST_PROMPT = "无人机起飞后移动到学生宿舍投放救援物资"
# Log file path (will be created in the same directory as this script)
LOG_FILE = os.path.join(os.path.dirname(__file__), "api_test.log")
def write_log(message, print_to_console=True):
"""
Write a message to the log file in append mode.
Supports multi-line messages - only the first line gets timestamp.
Args:
message: The message to write (can be multi-line)
print_to_console: Whether to also print to console (default: True)
"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Split message into lines and add timestamp to first line only
lines = message.split('\n')
log_entries = [f"[{timestamp}] {lines[0]}\n"]
for line in lines[1:]:
log_entries.append(f"{' ' * (len(timestamp) + 3)}{line}\n") # Indent continuation lines
try:
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.writelines(log_entries)
except Exception as e:
print(f"⚠️ Warning: Failed to write to log file: {e}")
if print_to_console:
print(message)
def test_generate_plan(): def test_generate_plan():
""" """
Sends a request to the /generate_plan endpoint and validates the response. Sends a request to the /generate_plan endpoint and validates the response.
All results are logged to the log file for continuous tracking.
""" """
url = BASE_URL + ENDPOINT url = BASE_URL + ENDPOINT
payload = {"user_prompt": TEST_PROMPT} payload = {"user_prompt": TEST_PROMPT}
headers = {"Content-Type": "application/json"} headers = {"Content-Type": "application/json"}
# Write separator and test start info to log print("--- API Test: Generate Plan ---")
write_log("=" * 80, print_to_console=False) print(f"✅ URL: {url}")
write_log("--- API Test: Generate Plan ---") print(f"✅ Sending Prompt: \"{TEST_PROMPT}\"")
write_log(f"URL: {url}")
write_log(f"Sending Prompt: \"{TEST_PROMPT}\"")
try: try:
# Send the POST request # Send the POST request
@@ -70,85 +36,40 @@ def test_generate_plan():
# Parse the JSON response # Parse the JSON response
data = response.json() data = response.json()
# Extract and log organized prompt if available in response print("✅ Received Response:")
organized_prompt = None print(json.dumps(data, indent=2, ensure_ascii=False))
if isinstance(data, dict):
# Check for various possible field names for organized prompt
organized_prompt = data.get("organized_prompt") or \
data.get("processed_prompt") or \
data.get("final_prompt") or \
data.get("enhanced_prompt") or \
data.get("user_prompt_enhanced")
write_log("✅ Received Response:")
# Log organized prompt if found
if organized_prompt:
write_log("\n📝 组织后的Prompt:")
write_log(organized_prompt)
else:
# If not in response, log the original prompt for reference
write_log("\n📝 原始Prompt:")
write_log(f" {TEST_PROMPT}")
write_log(" (注: 组织后的prompt未在API响应中返回如需查看请检查后端日志)")
response_json = json.dumps(data, indent=2, ensure_ascii=False)
write_log("\n完整响应内容:")
write_log(response_json)
# --- Validation --- # --- Validation ---
write_log("\n--- Validation Checks ---") print("\n--- Validation Checks ---")
validation_results = []
# 1. Check if the response is a dictionary # 1. Check if the response is a dictionary
if isinstance(data, dict): if isinstance(data, dict):
validation_results.append("PASS: Response is a valid JSON object.") print("PASS: Response is a valid JSON object.")
else: else:
validation_results.append("FAIL: Response is not a valid JSON object.") print("FAIL: Response is not a valid JSON object.")
# Write all validation results to log before returning
for result in validation_results:
write_log(result)
write_log("=" * 80, print_to_console=False)
write_log("", print_to_console=False) # Empty line for readability
return return
# 2. Check for the existence of the 'root' key # 2. Check for the existence of the 'root' key
if "root" in data and isinstance(data['root'], dict): if "root" in data and isinstance(data['root'], dict):
validation_results.append("PASS: Response contains a valid 'root' key.") print("PASS: Response contains a valid 'root' key.")
else: else:
validation_results.append("FAIL: Response does not contain a valid 'root' key.") print("FAIL: Response does not contain a valid 'root' key.")
# 3. Check for the existence and format of the 'visualization_url' key # 3. Check for the existence and format of the 'visualization_url' key
if "visualization_url" in data and data["visualization_url"].endswith(".png"): if "visualization_url" in data and data["visualization_url"].endswith(".png"):
validation_results.append(f"PASS: Response contains a valid 'visualization_url': {data['visualization_url']}") print(f"PASS: Response contains a valid 'visualization_url': {data['visualization_url']}")
else: else:
validation_results.append("FAIL: Response does not contain a valid 'visualization_url'.") print("FAIL: Response does not contain a valid 'visualization_url'.")
# Write all validation results to log
for result in validation_results:
write_log(result)
# Write test completion marker
write_log("✅ Test completed successfully")
write_log("=" * 80, print_to_console=False)
write_log("", print_to_console=False) # Empty line for readability
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
error_msg = f"❌ TEST FAILED: Could not connect to the server.\n Please make sure the backend service is running.\n Error details: {e}" print(f"\n❌ TEST FAILED: Could not connect to the server.")
write_log(error_msg) print(" Please make sure the backend service is running.")
write_log("=" * 80, print_to_console=False) print(f" Error details: {e}")
write_log("", print_to_console=False) # Empty line for readability
except json.JSONDecodeError: except json.JSONDecodeError:
error_msg = f"❌ TEST FAILED: The server response was not valid JSON.\n Response text: {response.text}" print(f"\n❌ TEST FAILED: The server response was not valid JSON.")
write_log(error_msg) print(f" Response text: {response.text}")
write_log("=" * 80, print_to_console=False)
write_log("", print_to_console=False) # Empty line for readability
except Exception as e: except Exception as e:
error_msg = f"❌ TEST FAILED: An unexpected error occurred: {e}" print(f"\n❌ TEST FAILED: An unexpected error occurred: {e}")
write_log(error_msg)
write_log("=" * 80, print_to_console=False)
write_log("", print_to_console=False) # Empty line for readability
if __name__ == "__main__": if __name__ == "__main__":
test_generate_plan() test_generate_plan()

View File

@@ -1,174 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import json
import argparse
from typing import Any, Dict
import requests
def build_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="调用本地 llama-server (OpenAI兼容) 进行推理,支持自定义系统/用户提示词"
)
parser.add_argument(
"--base-url",
default=os.getenv("SIMPLE_BASE_URL", "http://127.0.0.1:8081/v1"),
help="llama-server 的基础URL默认: http://127.0.0.1:8081/v1或环境变量 SIMPLE_BASE_URL",
)
parser.add_argument(
"--model",
default=os.getenv("SIMPLE_MODEL", "local-model"),
help="模型名称(默认: local-model或环境变量 SIMPLE_MODEL",
)
parser.add_argument(
"--system",
default="You are a helpful assistant.",
help="系统提示词system role",
)
parser.add_argument(
"--system-file",
default=None,
help="系统提示词文件路径txt若提供则覆盖 --system 的字符串",
)
parser.add_argument(
"--user",
default=None,
help="用户提示词user role若不传则从交互式输入读取",
)
parser.add_argument(
"--temperature",
type=float,
default=0.2,
help="采样温度(默认: 0.2",
)
parser.add_argument(
"--max-tokens",
type=int,
default=4096,
help="最大生成Token数默认: 4096",
)
parser.add_argument(
"--timeout",
type=float,
default=120.0,
help="HTTP超时时间秒默认: 120",
)
parser.add_argument(
"--verbose",
action="store_true",
help="打印完整返回JSON",
)
return parser.parse_args()
def call_llama_server(
base_url: str,
model: str,
system_prompt: str,
user_prompt: str,
temperature: float,
max_tokens: int,
timeout: float,
) -> Dict[str, Any]:
endpoint = base_url.rstrip("/") + "/chat/completions"
headers: Dict[str, str] = {"Content-Type": "application/json"}
# 兼容需要API Key的代理/服务llama-server通常不强制
api_key = os.getenv("OPENAI_API_KEY")
if api_key:
headers["Authorization"] = f"Bearer {api_key}"
payload: Dict[str, Any] = {
"model": model,
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
"temperature": temperature,
"max_tokens": max_tokens,
}
resp = requests.post(endpoint, headers=headers, data=json.dumps(payload), timeout=timeout)
resp.raise_for_status()
return resp.json()
def main() -> None:
args = build_args()
user_prompt = args.user
if not user_prompt:
try:
user_prompt = input("请输入用户提示词: ")
except KeyboardInterrupt:
print("\n已取消。")
sys.exit(1)
# 解析系统提示词:优先使用 --system-file
system_prompt = args.system
if args.system_file:
try:
with open(args.system_file, "r", encoding="utf-8") as f:
system_prompt = f.read()
except Exception as e:
print("\n❌ 读取系统提示词文件失败:")
print(str(e))
sys.exit(1)
try:
print("--- llama-server 推理 ---")
print(f"Base URL: {args.base_url}")
print(f"Model: {args.model}")
if args.system_file:
print(f"System(from file): {args.system_file}")
else:
print(f"System: {system_prompt}")
print(f"User: {user_prompt}")
data = call_llama_server(
base_url=args.base_url,
model=args.model,
system_prompt=system_prompt,
user_prompt=user_prompt,
temperature=args.temperature,
max_tokens=args.max_tokens,
timeout=args.timeout,
)
if args.verbose:
print("\n完整返回JSON:")
print(json.dumps(data, ensure_ascii=False, indent=2))
# 尝试按OpenAI兼容格式提取assistant内容
content = None
try:
content = data["choices"][0]["message"]["content"]
except Exception:
pass
if content is not None:
print("\n模型输出:")
print(content)
else:
# 兜底打印
print("\n无法按OpenAI兼容字段解析内容原始返回如下")
print(json.dumps(data, ensure_ascii=False))
except requests.exceptions.RequestException as e:
print("\n❌ 请求失败:请确认 llama-server 已在 8081 端口启动并可访问。")
print(f"详情: {e}")
sys.exit(2)
except Exception as e:
print("\n❌ 发生未预期的错误:")
print(str(e))
sys.exit(3)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1 @@
instruction_index,instruction,run_number,success,attempts,response_time,plan_id,error,timestamp instruction_index,instruction,run_number,success,attempts,response_time,plan_id,error,timestamp
1,起飞后移动到学生宿舍上方降落,1,False,1,2.048215866088867,,,2025-12-02 20:44:56
2,起飞后移动到学生宿舍上方查找蓝色的车,1,True,1,14.806509971618652,8a6f282e-c306-4249-962c-d47d48c31bad,,2025-12-02 20:45:12
3,起飞后移动到学生宿舍上方寻找蓝色的车,1,True,1,15.240672826766968,f298e2f4-9295-4ffd-8fff-0d0eb9a0ee6c,,2025-12-02 20:45:28
4,起飞后移动到学生宿舍上方检测蓝色的车,1,True,1,13.8105788230896,31733491-2030-43b1-a5e4-eb1300b8d23f,,2025-12-02 20:45:43
5,飞到学生宿舍上方查找蓝色的车,1,True,1,12.74257755279541,4c855ef4-c251-48cd-b464-4816bc62fbb5,,2025-12-02 20:45:57
6,飞到学生宿舍上方查找蓝色车辆并进行打击,1,True,1,16.117226600646973,63d0e7c3-dcbb-40f0-b76b-6f0191c6512f,,2025-12-02 20:46:14
7,起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击,1,True,1,16.25989079475403,1b4a537e-c1be-4abf-897e-c21b677b83b7,,2025-12-02 20:46:31
8,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,True,1,16.014280796051025,f88ea46f-5e0b-48fb-b1da-326d287af3d6,,2025-12-02 20:46:48
9,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,True,1,15.530286073684692,f56c811a-8304-4c68-8260-01643928bf3e,,2025-12-02 20:47:05
10,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,True,1,16.660754919052124,07a13346-3026-4dce-a976-4e0faa132248,,2025-12-02 20:47:23
11,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,True,1,14.128317832946777,16426d41-4f02-4e27-a05e-f4eb84d6c935,,2025-12-02 20:47:38
1 instruction_index instruction run_number success attempts response_time plan_id error timestamp
1 起飞后移动到学生宿舍上方降落 1 False 1 2.048215866088867 2025-12-02 20:44:56
2 起飞后移动到学生宿舍上方查找蓝色的车 1 True 1 14.806509971618652 8a6f282e-c306-4249-962c-d47d48c31bad 2025-12-02 20:45:12
3 起飞后移动到学生宿舍上方寻找蓝色的车 1 True 1 15.240672826766968 f298e2f4-9295-4ffd-8fff-0d0eb9a0ee6c 2025-12-02 20:45:28
4 起飞后移动到学生宿舍上方检测蓝色的车 1 True 1 13.8105788230896 31733491-2030-43b1-a5e4-eb1300b8d23f 2025-12-02 20:45:43
5 飞到学生宿舍上方查找蓝色的车 1 True 1 12.74257755279541 4c855ef4-c251-48cd-b464-4816bc62fbb5 2025-12-02 20:45:57
6 飞到学生宿舍上方查找蓝色车辆并进行打击 1 True 1 16.117226600646973 63d0e7c3-dcbb-40f0-b76b-6f0191c6512f 2025-12-02 20:46:14
7 起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击 1 True 1 16.25989079475403 1b4a537e-c1be-4abf-897e-c21b677b83b7 2025-12-02 20:46:31
8 起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资 1 True 1 16.014280796051025 f88ea46f-5e0b-48fb-b1da-326d287af3d6 2025-12-02 20:46:48
9 飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆 1 True 1 15.530286073684692 f56c811a-8304-4c68-8260-01643928bf3e 2025-12-02 20:47:05
10 飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆 1 True 1 16.660754919052124 07a13346-3026-4dce-a976-4e0faa132248 2025-12-02 20:47:23
11 起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资 1 True 1 14.128317832946777 16426d41-4f02-4e27-a05e-f4eb84d6c935 2025-12-02 20:47:38

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "b99d8d9a-84e6-474c-a512-61f8e74945e8",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "c74dd92d-450c-4a95-80eb-84441812b7e5",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "c9a68f7d-e8c0-4446-8fcf-e5a9325827b6",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "9e34b939-8410-4aec-a9bb-2261e6a21c48",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "09c44e51-9323-4072-9cb4-61c623d49f76",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "5110f6fe-778d-4191-b321-f1a8c6de9877",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "51bb856d-4804-48fc-9a72-564c4c2f13ba",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "61fe6be0-5252-45f1-9b89-bf23387a9ada",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "2fdeb41f-99da-4055-adab-ea795def40d6",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,93 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "current"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.3
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "6259d34d-4ac3-4a45-a683-e36cd219fe8e",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "96546010-2887-463b-96aa-e9a4237944f2",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "92d92c59-b3cd-47d0-9371-967d6086dc11",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "a2f5a53d-c90d-4cd8-9a28-22399aab3b05",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "12f71128-f676-443f-89bc-8f0b5e16e9cd",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "4c0c5cb7-5438-444f-9278-741fd65d370a",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "65d91ac8-2526-4447-b5f6-113c8033f956",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "46a40452-9535-49aa-8eb9-e8ef77cfb0a1",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "aa95931b-6e05-4cd9-aadc-33405bef45a9",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "2bd7d8df-bfcd-487b-a313-645373b450d5",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "9eeccc4a-ab3b-469f-8aa5-ce9c5c921190",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "3b541f31-120d-4283-86c1-6a98cd6bf4a6",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "5b81b00f-fd8d-4e7b-97e5-5ad5f25b8199",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "26cdb6ce-bb70-4a58-92c6-19470551a931",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "6703241e-5367-42e9-bbcf-8518f7a7982f",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "71c89dc5-5e3b-46d5-9c0b-59535d5c12b2",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "1142491e-1a37-4a09-a64d-ed5773cea09e",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "35ff42a3-2871-4b6e-820d-69a2b05411f6",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "a836fb2c-74b1-4451-94a7-83ea9dc04fc5",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "d716a58c-8cb1-4792-98a1-c2a44d86ba72",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "cbb57237-e84d-4de8-bba1-a1f7a7dd8538",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "619957a5-92b3-4f1f-b556-7d744aee247f",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "7d1394a0-595f-4745-8c05-7c27bbe6a893",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "172d07ff-4746-48e0-a47c-ce721dbfd9da",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "15364c4e-badb-4cf0-ad55-9507b3f42ca6",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "ba86bac9-b1c9-4ea8-a255-f0589b776622",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "3518e34d-d5ab-4750-98e3-4aa5272b4617",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "410d15c8-a536-4ecc-a0e1-e0f8b0299285",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "c3f8c7f7-85d7-4be3-8c41-10731cae7d35",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "c4c5e35b-f1d1-4b0a-8b3a-c664322a6ffc",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "a486685e-679c-4a63-8582-192ea188e03a",
"visualization_url": "/static/py_tree.png"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,138 @@
{
"root": {
"type": "Parallel",
"name": "MissionWithSafety",
"params": {
"policy": "all_success"
},
"children": [
{
"type": "Sequence",
"name": "MainTask",
"children": [
{
"type": "action",
"name": "preflight_checks",
"params": {
"check_level": "comprehensive"
}
},
{
"type": "action",
"name": "takeoff",
"params": {
"altitude": 2.0
}
},
{
"type": "action",
"name": "fly_to_waypoint",
"params": {
"x": 5.0,
"y": 3.0,
"z": 2.0,
"acceptance_radius": 2.0
}
},
{
"type": "Selector",
"name": "TargetAcquisitionSelector",
"params": {
"memory": true
},
"children": [
{
"type": "Sequence",
"name": "DirectDetectionSequence",
"children": [
{
"type": "action",
"name": "loiter",
"params": {
"duration": 10.0
}
},
{
"type": "action",
"name": "object_detect",
"params": {
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "search_pattern",
"params": {
"pattern_type": "grid",
"center_x": 5.0,
"center_y": 3.0,
"center_z": 2.0,
"radius": 80.0,
"target_class": "car",
"description": "蓝色的车",
"count": 1
}
}
]
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
},
{
"type": "Selector",
"name": "SafetyMonitor",
"params": {
"memory": true
},
"children": [
{
"type": "condition",
"name": "battery_above",
"params": {
"threshold": 0.35
}
},
{
"type": "condition",
"name": "gps_status",
"params": {
"min_satellites": 8
}
},
{
"type": "Sequence",
"name": "EmergencyHandler",
"children": [
{
"type": "action",
"name": "emergency_return",
"params": {
"reason": "safety_breach"
}
},
{
"type": "action",
"name": "land",
"params": {
"mode": "home"
}
}
]
}
]
}
]
},
"plan_id": "776b10d3-2c2f-45d5-89df-8984ee0d4f1c",
"visualization_url": "/static/py_tree.png"
}

Some files were not shown because too many files have changed in this diff Show More