diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..065a8c0a --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# ============ 日志 ============ +logs/ + +# ============ 向量库(RAG 检索用) ============ +**/vector_store/ +vector_store/ + +# ============ 测试脚本的测试结果 ============ +tools/test_validate/validation/ + +# ============ 生成的图片 ============ +backend_service/generated_visualizations/ +tools/test_validate/validation/**/*.png +tools/test_validate/validation/**/*.jpg + +# ============ Python ============ +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +venv/ +.venv/ +env/ +.env/ + +# ============ 其他常见忽略 ============ +*.log +.DS_Store +.idea/ +.vscode/ +*.swp +*.swo +*~ diff --git a/backend_service/generated_visualizations/py_tree.png b/backend_service/generated_visualizations/py_tree.png deleted file mode 100644 index dcfa34eb..00000000 Binary files a/backend_service/generated_visualizations/py_tree.png and /dev/null differ diff --git a/logs/embedding_model.log b/logs/embedding_model.log deleted file mode 100644 index 4112bd84..00000000 --- a/logs/embedding_model.log +++ /dev/null @@ -1,256 +0,0 @@ -ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no -ggml_cuda_init: GGML_CUDA_FORCE_CUBLAS: no -ggml_cuda_init: found 1 CUDA devices: - Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9, VMM: yes -build: 6097 (9515c613) with cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 for x86_64-linux-gnu -system info: n_threads = 8, n_threads_batch = 8, total_threads = 16 - -system_info: n_threads = 8 (n_threads_batch = 8) / 16 | CUDA : ARCHS = 500,610,700,750,800,860,890 | USE_GRAPHS = 1 | PEER_MAX_BATCH_SIZE = 128 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX_VNNI = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 | - -main: binding port with default address family -main: HTTP server is listening, hostname: 0.0.0.0, port: 8090, http threads: 15 -main: loading model -srv load_model: loading model '/home/huangfukk/models/gguf/Qwen3/Qwen3-Embedding-4B/Qwen3-Embedding-4B-Q5_K_M.gguf' -llama_model_load_from_file_impl: using device CUDA0 (NVIDIA GeForce RTX 4060 Ti) - 15225 MiB free -llama_model_loader: loaded meta data with 36 key-value pairs and 398 tensors from /home/huangfukk/models/gguf/Qwen3/Qwen3-Embedding-4B/Qwen3-Embedding-4B-Q5_K_M.gguf (version GGUF V3 (latest)) -llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output. -llama_model_loader: - kv 0: general.architecture str = qwen3 -llama_model_loader: - kv 1: general.type str = model -llama_model_loader: - kv 2: general.name str = Qwen3 Embedding 4B -llama_model_loader: - kv 3: general.basename str = Qwen3-Embedding -llama_model_loader: - kv 4: general.size_label str = 4B -llama_model_loader: - kv 5: general.license str = apache-2.0 -llama_model_loader: - kv 6: general.base_model.count u32 = 1 -llama_model_loader: - kv 7: general.base_model.0.name str = Qwen3 4B Base -llama_model_loader: - kv 8: general.base_model.0.organization str = Qwen -llama_model_loader: - kv 9: general.base_model.0.repo_url str = https://huggingface.co/Qwen/Qwen3-4B-... -llama_model_loader: - kv 10: general.tags arr[str,5] = ["transformers", "sentence-transforme... -llama_model_loader: - kv 11: qwen3.block_count u32 = 36 -llama_model_loader: - kv 12: qwen3.context_length u32 = 40960 -llama_model_loader: - kv 13: qwen3.embedding_length u32 = 2560 -llama_model_loader: - kv 14: qwen3.feed_forward_length u32 = 9728 -llama_model_loader: - kv 15: qwen3.attention.head_count u32 = 32 -llama_model_loader: - kv 16: qwen3.attention.head_count_kv u32 = 8 -llama_model_loader: - kv 17: qwen3.rope.freq_base f32 = 1000000.000000 -llama_model_loader: - kv 18: qwen3.attention.layer_norm_rms_epsilon f32 = 0.000001 -llama_model_loader: - kv 19: qwen3.attention.key_length u32 = 128 -llama_model_loader: - kv 20: qwen3.attention.value_length u32 = 128 -llama_model_loader: - kv 21: qwen3.pooling_type u32 = 3 -llama_model_loader: - kv 22: tokenizer.ggml.model str = gpt2 -llama_model_loader: - kv 23: tokenizer.ggml.pre str = qwen2 -llama_model_loader: - kv 24: tokenizer.ggml.tokens arr[str,151665] = ["!", "\"", "#", "$", "%", "&", "'", ... -llama_model_loader: - kv 25: tokenizer.ggml.token_type arr[i32,151665] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... -llama_model_loader: - kv 26: tokenizer.ggml.merges arr[str,151387] = ["Ġ Ġ", "ĠĠ ĠĠ", "i n", "Ġ t",... -llama_model_loader: - kv 27: tokenizer.ggml.eos_token_id u32 = 151643 -llama_model_loader: - kv 28: tokenizer.ggml.padding_token_id u32 = 151643 -llama_model_loader: - kv 29: tokenizer.ggml.eot_token_id u32 = 151645 -llama_model_loader: - kv 30: tokenizer.ggml.bos_token_id u32 = 151643 -llama_model_loader: - kv 31: tokenizer.ggml.add_eos_token bool = true -llama_model_loader: - kv 32: tokenizer.ggml.add_bos_token bool = false -llama_model_loader: - kv 33: tokenizer.chat_template str = {%- if tools %}\n {{- '<|im_start|>... -llama_model_loader: - kv 34: general.quantization_version u32 = 2 -llama_model_loader: - kv 35: general.file_type u32 = 17 -llama_model_loader: - type f32: 145 tensors -llama_model_loader: - type q5_K: 216 tensors -llama_model_loader: - type q6_K: 37 tensors -print_info: file format = GGUF V3 (latest) -print_info: file type = Q5_K - Medium -print_info: file size = 2.68 GiB (5.73 BPW) -load: printing all EOG tokens: -load: - 151643 ('<|endoftext|>') -load: - 151645 ('<|im_end|>') -load: - 151662 ('<|fim_pad|>') -load: - 151663 ('<|repo_name|>') -load: - 151664 ('<|file_sep|>') -load: special tokens cache size = 22 -load: token to piece cache size = 0.9310 MB -print_info: arch = qwen3 -print_info: vocab_only = 0 -print_info: n_ctx_train = 40960 -print_info: n_embd = 2560 -print_info: n_layer = 36 -print_info: n_head = 32 -print_info: n_head_kv = 8 -print_info: n_rot = 128 -print_info: n_swa = 0 -print_info: is_swa_any = 0 -print_info: n_embd_head_k = 128 -print_info: n_embd_head_v = 128 -print_info: n_gqa = 4 -print_info: n_embd_k_gqa = 1024 -print_info: n_embd_v_gqa = 1024 -print_info: f_norm_eps = 0.0e+00 -print_info: f_norm_rms_eps = 1.0e-06 -print_info: f_clamp_kqv = 0.0e+00 -print_info: f_max_alibi_bias = 0.0e+00 -print_info: f_logit_scale = 0.0e+00 -print_info: f_attn_scale = 0.0e+00 -print_info: n_ff = 9728 -print_info: n_expert = 0 -print_info: n_expert_used = 0 -print_info: causal attn = 1 -print_info: pooling type = 3 -print_info: rope type = 2 -print_info: rope scaling = linear -print_info: freq_base_train = 1000000.0 -print_info: freq_scale_train = 1 -print_info: n_ctx_orig_yarn = 40960 -print_info: rope_finetuned = unknown -print_info: model type = 4B -print_info: model params = 4.02 B -print_info: general.name = Qwen3 Embedding 4B -print_info: vocab type = BPE -print_info: n_vocab = 151665 -print_info: n_merges = 151387 -print_info: BOS token = 151643 '<|endoftext|>' -print_info: EOS token = 151643 '<|endoftext|>' -print_info: EOT token = 151645 '<|im_end|>' -print_info: PAD token = 151643 '<|endoftext|>' -print_info: LF token = 198 'Ċ' -print_info: FIM PRE token = 151659 '<|fim_prefix|>' -print_info: FIM SUF token = 151661 '<|fim_suffix|>' -print_info: FIM MID token = 151660 '<|fim_middle|>' -print_info: FIM PAD token = 151662 '<|fim_pad|>' -print_info: FIM REP token = 151663 '<|repo_name|>' -print_info: FIM SEP token = 151664 '<|file_sep|>' -print_info: EOG token = 151643 '<|endoftext|>' -print_info: EOG token = 151645 '<|im_end|>' -print_info: EOG token = 151662 '<|fim_pad|>' -print_info: EOG token = 151663 '<|repo_name|>' -print_info: EOG token = 151664 '<|file_sep|>' -print_info: max token length = 256 -load_tensors: loading model tensors, this can take a while... (mmap = true) -load_tensors: offloading 36 repeating layers to GPU -load_tensors: offloaded 36/37 layers to GPU -load_tensors: CUDA0 model buffer size = 2445.68 MiB -load_tensors: CPU_Mapped model buffer size = 303.75 MiB -.......................................................................................... -llama_context: constructing llama_context -llama_context: n_seq_max = 1 -llama_context: n_ctx = 4096 -llama_context: n_ctx_per_seq = 4096 -llama_context: n_batch = 2048 -llama_context: n_ubatch = 512 -llama_context: causal_attn = 1 -llama_context: flash_attn = 0 -llama_context: kv_unified = false -llama_context: freq_base = 1000000.0 -llama_context: freq_scale = 1 -llama_context: n_ctx_per_seq (4096) < n_ctx_train (40960) -- the full capacity of the model will not be utilized -llama_context: CPU output buffer size = 0.59 MiB -llama_kv_cache_unified: CUDA0 KV buffer size = 576.00 MiB -llama_kv_cache_unified: size = 576.00 MiB ( 4096 cells, 36 layers, 1/1 seqs), K (f16): 288.00 MiB, V (f16): 288.00 MiB -llama_context: CUDA0 compute buffer size = 604.96 MiB -llama_context: CUDA_Host compute buffer size = 17.01 MiB -llama_context: graph nodes = 1411 -llama_context: graph splits = 4 (with bs=512), 3 (with bs=1) -common_init_from_params: added <|endoftext|> logit bias = -inf -common_init_from_params: added <|im_end|> logit bias = -inf -common_init_from_params: added <|fim_pad|> logit bias = -inf -common_init_from_params: added <|repo_name|> logit bias = -inf -common_init_from_params: added <|file_sep|> logit bias = -inf -common_init_from_params: setting dry_penalty_last_n to ctx_size = 4096 -common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable) -srv init: initializing slots, n_slots = 1 -slot init: id 0 | task -1 | new slot n_ctx_slot = 4096 -main: model loaded -main: chat template, chat_template: {%- if tools %} - {{- '<|im_start|>system\n' }} - {%- if messages[0]['role'] == 'system' %} - {{- messages[0]['content'] }} - {%- else %} - {{- 'You are a helpful assistant.' }} - {%- endif %} - {{- "\n\n# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }} - {%- for tool in tools %} - {{- "\n" }} - {{- tool | tojson }} - {%- endfor %} - {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }} -{%- else %} - {%- if messages[0]['role'] == 'system' %} - {{- '<|im_start|>system\n' + messages[0]['content'] + '<|im_end|>\n' }} - {%- else %} - {{- '<|im_start|>system\nYou are a helpful assistant.<|im_end|>\n' }} - {%- endif %} -{%- endif %} -{%- for message in messages %} - {%- if (message.role == "user") or (message.role == "system" and not loop.first) or (message.role == "assistant" and not message.tool_calls) %} - {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }} - {%- elif message.role == "assistant" %} - {{- '<|im_start|>' + message.role }} - {%- if message.content %} - {{- '\n' + message.content }} - {%- endif %} - {%- for tool_call in message.tool_calls %} - {%- if tool_call.function is defined %} - {%- set tool_call = tool_call.function %} - {%- endif %} - {{- '\n\n{"name": "' }} - {{- tool_call.name }} - {{- '", "arguments": ' }} - {{- tool_call.arguments | tojson }} - {{- '}\n' }} - {%- endfor %} - {{- '<|im_end|>\n' }} - {%- elif message.role == "tool" %} - {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != "tool") %} - {{- '<|im_start|>user' }} - {%- endif %} - {{- '\n\n' }} - {{- message.content }} - {{- '\n' }} - {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} - {{- '<|im_end|>\n' }} - {%- endif %} - {%- endif %} -{%- endfor %} -{%- if add_generation_prompt %} - {{- '<|im_start|>assistant\n' }} -{%- endif %} -, example_format: '<|im_start|>system -You are a helpful assistant<|im_end|> -<|im_start|>user -Hello<|im_end|> -<|im_start|>assistant -Hi there<|im_end|> -<|im_start|>user -How are you?<|im_end|> -<|im_start|>assistant -' -main: server is listening on http://0.0.0.0:8090 - starting the main loop -srv update_slots: all slots are idle -srv log_server_r: request: GET /health 127.0.0.1 200 -slot launch_slot_: id 0 | task 1 | processing task -slot update_slots: id 0 | task 1 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9 -slot update_slots: id 0 | task 1 | kv cache rm [0, end) -slot update_slots: id 0 | task 1 | prompt processing progress, n_past = 9, n_tokens = 9, progress = 1.000000 -slot update_slots: id 0 | task 1 | prompt done, n_past = 9, n_tokens = 9 -slot release: id 0 | task 1 | stop processing: n_past = 9, truncated = 0 -slot launch_slot_: id 0 | task 0 | processing task -slot update_slots: id 0 | task 0 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9 -slot update_slots: id 0 | task 0 | need to evaluate at least 1 token for each active slot, n_past = 9, n_prompt_tokens = 9 -slot update_slots: id 0 | task 0 | kv cache rm [8, end) -slot update_slots: id 0 | task 0 | prompt processing progress, n_past = 9, n_tokens = 1, progress = 0.111111 -slot update_slots: id 0 | task 0 | prompt done, n_past = 9, n_tokens = 1 -srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200 -slot release: id 0 | task 0 | stop processing: n_past = 9, truncated = 0 -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200 -slot launch_slot_: id 0 | task 4 | processing task -slot update_slots: id 0 | task 4 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9 -slot update_slots: id 0 | task 4 | need to evaluate at least 1 token for each active slot, n_past = 9, n_prompt_tokens = 9 -slot update_slots: id 0 | task 4 | kv cache rm [8, end) -slot update_slots: id 0 | task 4 | prompt processing progress, n_past = 9, n_tokens = 1, progress = 0.111111 -slot update_slots: id 0 | task 4 | prompt done, n_past = 9, n_tokens = 1 -slot release: id 0 | task 4 | stop processing: n_past = 9, truncated = 0 -slot launch_slot_: id 0 | task 6 | processing task -slot update_slots: id 0 | task 6 | new prompt, n_ctx_slot = 4096, n_keep = 0, n_prompt_tokens = 9 -slot update_slots: id 0 | task 6 | need to evaluate at least 1 token for each active slot, n_past = 9, n_prompt_tokens = 9 -slot update_slots: id 0 | task 6 | kv cache rm [8, end) -slot update_slots: id 0 | task 6 | prompt processing progress, n_past = 9, n_tokens = 1, progress = 0.111111 -slot update_slots: id 0 | task 6 | prompt done, n_past = 9, n_tokens = 1 -srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200 -slot release: id 0 | task 6 | stop processing: n_past = 9, truncated = 0 -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/embeddings 127.0.0.1 200 diff --git a/logs/fastapi.log b/logs/fastapi.log deleted file mode 100644 index 51f081a3..00000000 --- a/logs/fastapi.log +++ /dev/null @@ -1,107 +0,0 @@ -2026-02-26 19:00:57,073 - INFO - Anonymized telemetry enabled. See https://docs.trychroma.com/telemetry for more information. -2026-02-26 19:00:57,211 - INFO - 成功找到节点定义JSON代码块 -2026-02-26 19:00:57,211 - INFO - 成功解析出动作节点: ['approach_target', 'deliver_payload', 'fly_sequence', 'fly_to_waypoint', 'land', 'loiter', 'manual_confirmation', 'move_direction', 'object_detect', 'return_emergency', 'rotate', 'rotate_search', 'search_pattern', 'system_checks', 'take_photos', 'takeoff', 'track_object'] -2026-02-26 19:00:57,211 - INFO - 成功解析出条件节点: ['at_waypoint', 'object_detected'] -INFO: Started server process [26111] -INFO: Waiting for application startup. -2026-02-26 19:00:57,217 - INFO - WebSocket event loop configured. -INFO: Application startup complete. -INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: 127.0.0.1:46065 - "GET /docs HTTP/1.1" 200 OK -2026-02-26 19:01:05,074 - INFO - ========== [Stage 1] Task Understanding ========== -2026-02-26 19:01:05,881 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK" -2026-02-26 19:01:05,886 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[] -INFO: 127.0.0.1:46071 - "POST /debug_stage HTTP/1.1" 200 OK -2026-02-26 19:01:23,412 - INFO - ========== [Stage 1] Task Understanding ========== -2026-02-26 19:01:23,780 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK" -2026-02-26 19:01:23,780 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[] -INFO: 127.0.0.1:44329 - "POST /debug_stage HTTP/1.1" 200 OK -2026-02-26 19:01:36,748 - INFO - ========== [Stage 1] Task Understanding ========== -2026-02-26 19:01:37,168 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK" -2026-02-26 19:01:37,169 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[] -INFO: 127.0.0.1:44483 - "POST /debug_stage HTTP/1.1" 200 OK -2026-02-26 19:15:34,050 - INFO - ========== [Stage 1] Task Understanding ========== -2026-02-26 19:15:34,569 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK" -2026-02-26 19:15:34,570 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[] -2026-02-26 19:15:34,570 - INFO - ========== [Stage 2] Context Binding ========== -2026-02-26 19:15:34,799 - INFO - Context Binding Results: Required Actions=['Selector', 'Sequence', 'fly_to_waypoint', 'land', 'move_direction', 'object_detect', 'object_detected', 'rotate_search', 'take_photos', 'takeoff'], RAG Scopes=['location', 'pattern'] -INFO: 127.0.0.1:47143 - "POST /debug_stage HTTP/1.1" 200 OK -2026-02-26 19:18:26,812 - INFO - ========== [Stage 1] Task Understanding ========== -2026-02-26 19:18:27,220 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK" -2026-02-26 19:18:27,220 - INFO - Task Understanding Results: mode=scene1, state=in_air, intent=generic_mission, risks=[] -2026-02-26 19:18:27,220 - INFO - ========== [Stage 2] Context Binding ========== -2026-02-26 19:18:27,276 - INFO - Context Binding Results: Required Actions=['Selector', 'Sequence', 'fly_to_waypoint', 'land', 'move_direction', 'object_detect', 'object_detected', 'rotate_search', 'take_photos', 'takeoff'], RAG Scopes=['location', 'pattern'] -2026-02-26 19:18:27,276 - INFO - ========== [Stage 3] Macro Planning (Round 1) ========== -2026-02-26 19:18:27,278 - INFO - [Round 1] System Prompt Preview (first 500 chars): -任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。 - -你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事: -1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。 -2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。 - -**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。 - -输出格式约定: -```json -{ - "macro_tree": { ... 纯结构树 ... }, - "parameter_requests": [ - { - "node": "节点名称", - "intent": "对该节点意图的简短描述", - "extracted_entities": { - "实体key": "实体value" - } - } - ] -} -``` - -## 一、核心节点定义(裁剪后) -#### 1. 可用节点定义 (必须遵守... -2026-02-26 19:18:27,278 - INFO - [Round 1] User Prompt: -飞到广场东边50米 - ---- -参考知识: -【地点知识】 -{"property": "location", "information": {"name": "广场", "coordinates": {"x": 100, "y": 260, "z": 0}}} - -{"property": "location", "information": {"name": "飞行场地", "coordinates": {"x": 0, "y": 0, "z": 0}}} - -{"property": "location", "information": {"name": "大楼外围四个点东南天坐标系坐标", "coordinates": {"A": {"x": -24.0, "y": 241.8, "z": 0}, "B": {"x": -108.5, "y": 241.8, "z": 0}, "C": {"x": -108.5, "y": 289.8, "z": 0}, "D": {"x": -24.0, "y": 292.8, "z": 0}}}} - -【任务模式】 -无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。 - -无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。 - -地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。 ---- -2026-02-26 19:18:36,039 - INFO - HTTP Request: POST http://localhost:8081/v1/chat/completions "HTTP/1.1 200 OK" -2026-02-26 19:18:36,039 - INFO - [Round 1] Output Macro Tree: -{ - "root": { - "type": "Sequence", - "name": "FlyToSquareEast50", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint" - } - ] - } -} -2026-02-26 19:18:36,039 - INFO - [Round 1] Output Parameter Requests: -[ - { - "node": "fly_to_waypoint", - "intent": "前往广场东边50米", - "extracted_entities": { - "landmark": "广场", - "direction": "东", - "distance": 50.0 - } - } -] -INFO: 127.0.0.1:46185 - "POST /debug_stage HTTP/1.1" 200 OK diff --git a/logs/inference_model.log b/logs/inference_model.log deleted file mode 100644 index d58187c8..00000000 --- a/logs/inference_model.log +++ /dev/null @@ -1,480 +0,0 @@ -ggml_cuda_init: GGML_CUDA_FORCE_MMQ: no -ggml_cuda_init: GGML_CUDA_FORCE_CUBLAS: no -ggml_cuda_init: found 1 CUDA devices: - Device 0: NVIDIA GeForce RTX 4060 Ti, compute capability 8.9, VMM: yes -build: 6097 (9515c613) with cc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 for x86_64-linux-gnu -system info: n_threads = 8, n_threads_batch = 8, total_threads = 16 - -system_info: n_threads = 8 (n_threads_batch = 8) / 16 | CUDA : ARCHS = 500,610,700,750,800,860,890 | USE_GRAPHS = 1 | PEER_MAX_BATCH_SIZE = 128 | CPU : SSE3 = 1 | SSSE3 = 1 | AVX = 1 | AVX_VNNI = 1 | AVX2 = 1 | F16C = 1 | FMA = 1 | BMI2 = 1 | LLAMAFILE = 1 | OPENMP = 1 | REPACK = 1 | - -main: binding port with default address family -main: HTTP server is listening, hostname: 0.0.0.0, port: 8081, http threads: 15 -main: loading model -srv load_model: loading model '/home/huangfukk/models/gguf/Qwen3/Qwen3-4B/Qwen3-4B-Q5_K_M.gguf' -llama_model_load_from_file_impl: using device CUDA0 (NVIDIA GeForce RTX 4060 Ti) - 15225 MiB free -llama_model_loader: loaded meta data with 28 key-value pairs and 398 tensors from /home/huangfukk/models/gguf/Qwen3/Qwen3-4B/Qwen3-4B-Q5_K_M.gguf (version GGUF V3 (latest)) -llama_model_loader: Dumping metadata keys/values. Note: KV overrides do not apply in this output. -llama_model_loader: - kv 0: general.architecture str = qwen3 -llama_model_loader: - kv 1: general.type str = model -llama_model_loader: - kv 2: general.name str = Qwen3 4B Instruct -llama_model_loader: - kv 3: general.finetune str = Instruct -llama_model_loader: - kv 4: general.basename str = Qwen3 -llama_model_loader: - kv 5: general.size_label str = 4B -llama_model_loader: - kv 6: qwen3.block_count u32 = 36 -llama_model_loader: - kv 7: qwen3.context_length u32 = 40960 -llama_model_loader: - kv 8: qwen3.embedding_length u32 = 2560 -llama_model_loader: - kv 9: qwen3.feed_forward_length u32 = 9728 -llama_model_loader: - kv 10: qwen3.attention.head_count u32 = 32 -llama_model_loader: - kv 11: qwen3.attention.head_count_kv u32 = 8 -llama_model_loader: - kv 12: qwen3.rope.freq_base f32 = 1000000.000000 -llama_model_loader: - kv 13: qwen3.attention.layer_norm_rms_epsilon f32 = 0.000001 -llama_model_loader: - kv 14: qwen3.attention.key_length u32 = 128 -llama_model_loader: - kv 15: qwen3.attention.value_length u32 = 128 -llama_model_loader: - kv 16: tokenizer.ggml.model str = gpt2 -llama_model_loader: - kv 17: tokenizer.ggml.pre str = qwen2 -llama_model_loader: - kv 18: tokenizer.ggml.tokens arr[str,151936] = ["!", "\"", "#", "$", "%", "&", "'", ... -llama_model_loader: - kv 19: tokenizer.ggml.token_type arr[i32,151936] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... -llama_model_loader: - kv 20: tokenizer.ggml.merges arr[str,151387] = ["Ġ Ġ", "ĠĠ ĠĠ", "i n", "Ġ t",... -llama_model_loader: - kv 21: tokenizer.ggml.eos_token_id u32 = 151645 -llama_model_loader: - kv 22: tokenizer.ggml.padding_token_id u32 = 151643 -llama_model_loader: - kv 23: tokenizer.ggml.bos_token_id u32 = 151643 -llama_model_loader: - kv 24: tokenizer.ggml.add_bos_token bool = false -llama_model_loader: - kv 25: tokenizer.chat_template str = {%- if tools %}\n {{- '<|im_start|>... -llama_model_loader: - kv 26: general.quantization_version u32 = 2 -llama_model_loader: - kv 27: general.file_type u32 = 17 -llama_model_loader: - type f32: 145 tensors -llama_model_loader: - type q5_K: 216 tensors -llama_model_loader: - type q6_K: 37 tensors -print_info: file format = GGUF V3 (latest) -print_info: file type = Q5_K - Medium -print_info: file size = 2.69 GiB (5.73 BPW) -load: printing all EOG tokens: -load: - 151643 ('<|endoftext|>') -load: - 151645 ('<|im_end|>') -load: - 151662 ('<|fim_pad|>') -load: - 151663 ('<|repo_name|>') -load: - 151664 ('<|file_sep|>') -load: special tokens cache size = 26 -load: token to piece cache size = 0.9311 MB -print_info: arch = qwen3 -print_info: vocab_only = 0 -print_info: n_ctx_train = 40960 -print_info: n_embd = 2560 -print_info: n_layer = 36 -print_info: n_head = 32 -print_info: n_head_kv = 8 -print_info: n_rot = 128 -print_info: n_swa = 0 -print_info: is_swa_any = 0 -print_info: n_embd_head_k = 128 -print_info: n_embd_head_v = 128 -print_info: n_gqa = 4 -print_info: n_embd_k_gqa = 1024 -print_info: n_embd_v_gqa = 1024 -print_info: f_norm_eps = 0.0e+00 -print_info: f_norm_rms_eps = 1.0e-06 -print_info: f_clamp_kqv = 0.0e+00 -print_info: f_max_alibi_bias = 0.0e+00 -print_info: f_logit_scale = 0.0e+00 -print_info: f_attn_scale = 0.0e+00 -print_info: n_ff = 9728 -print_info: n_expert = 0 -print_info: n_expert_used = 0 -print_info: causal attn = 1 -print_info: pooling type = -1 -print_info: rope type = 2 -print_info: rope scaling = linear -print_info: freq_base_train = 1000000.0 -print_info: freq_scale_train = 1 -print_info: n_ctx_orig_yarn = 40960 -print_info: rope_finetuned = unknown -print_info: model type = 4B -print_info: model params = 4.02 B -print_info: general.name = Qwen3 4B Instruct -print_info: vocab type = BPE -print_info: n_vocab = 151936 -print_info: n_merges = 151387 -print_info: BOS token = 151643 '<|endoftext|>' -print_info: EOS token = 151645 '<|im_end|>' -print_info: EOT token = 151645 '<|im_end|>' -print_info: PAD token = 151643 '<|endoftext|>' -print_info: LF token = 198 'Ċ' -print_info: FIM PRE token = 151659 '<|fim_prefix|>' -print_info: FIM SUF token = 151661 '<|fim_suffix|>' -print_info: FIM MID token = 151660 '<|fim_middle|>' -print_info: FIM PAD token = 151662 '<|fim_pad|>' -print_info: FIM REP token = 151663 '<|repo_name|>' -print_info: FIM SEP token = 151664 '<|file_sep|>' -print_info: EOG token = 151643 '<|endoftext|>' -print_info: EOG token = 151645 '<|im_end|>' -print_info: EOG token = 151662 '<|fim_pad|>' -print_info: EOG token = 151663 '<|repo_name|>' -print_info: EOG token = 151664 '<|file_sep|>' -print_info: max token length = 256 -load_tensors: loading model tensors, this can take a while... (mmap = true) -load_tensors: offloading 36 repeating layers to GPU -load_tensors: offloaded 36/37 layers to GPU -load_tensors: CUDA0 model buffer size = 2445.68 MiB -load_tensors: CPU_Mapped model buffer size = 304.29 MiB -.......................................................................................... -llama_context: constructing llama_context -llama_context: n_seq_max = 1 -llama_context: n_ctx = 16384 -llama_context: n_ctx_per_seq = 16384 -llama_context: n_batch = 2048 -llama_context: n_ubatch = 512 -llama_context: causal_attn = 1 -llama_context: flash_attn = 0 -llama_context: kv_unified = false -llama_context: freq_base = 1000000.0 -llama_context: freq_scale = 1 -llama_context: n_ctx_per_seq (16384) < n_ctx_train (40960) -- the full capacity of the model will not be utilized -llama_context: CPU output buffer size = 0.58 MiB -llama_kv_cache_unified: CUDA0 KV buffer size = 2304.00 MiB -llama_kv_cache_unified: size = 2304.00 MiB ( 16384 cells, 36 layers, 1/1 seqs), K (f16): 1152.00 MiB, V (f16): 1152.00 MiB -llama_context: CUDA0 compute buffer size = 1086.01 MiB -llama_context: CUDA_Host compute buffer size = 41.01 MiB -llama_context: graph nodes = 1410 -llama_context: graph splits = 4 (with bs=512), 3 (with bs=1) -common_init_from_params: added <|endoftext|> logit bias = -inf -common_init_from_params: added <|im_end|> logit bias = -inf -common_init_from_params: added <|fim_pad|> logit bias = -inf -common_init_from_params: added <|repo_name|> logit bias = -inf -common_init_from_params: added <|file_sep|> logit bias = -inf -common_init_from_params: setting dry_penalty_last_n to ctx_size = 16384 -common_init_from_params: warming up the model with an empty run - please wait ... (--no-warmup to disable) -srv init: initializing slots, n_slots = 1 -slot init: id 0 | task -1 | new slot n_ctx_slot = 16384 -main: model loaded -main: chat template, chat_template: {%- if tools %} - {{- '<|im_start|>system\n' }} - {%- if messages[0].role == 'system' %} - {{- messages[0].content + '\n\n' }} - {%- endif %} - {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within XML tags:\n" }} - {%- for tool in tools %} - {{- "\n" }} - {{- tool | tojson }} - {%- endfor %} - {{- "\n\n\nFor each function call, return a json object with function name and arguments within XML tags:\n\n{\"name\": , \"arguments\": }\n<|im_end|>\n" }} -{%- else %} - {%- if messages[0].role == 'system' %} - {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }} - {%- endif %} -{%- endif %} -{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %} -{%- for index in range(ns.last_query_index, -1, -1) %} - {%- set message = messages[index] %} - {%- if ns.multi_step_tool and message.role == "user" and not('' in message.content and '' in message.content) %} - {%- set ns.multi_step_tool = false %} - {%- set ns.last_query_index = index %} - {%- endif %} -{%- endfor %} -{%- for message in messages %} - {%- if (message.role == "user") or (message.role == "system" and not loop.first) %} - {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }} - {%- elif message.role == "assistant" %} - {%- set content = message.content %} - {%- set reasoning_content = '' %} - {%- if message.reasoning_content is defined and message.reasoning_content is not none %} - {%- set reasoning_content = message.reasoning_content %} - {%- else %} - {%- if '' in message.content %} - {%- set content = message.content.split('')[-1].lstrip('\n') %} - {%- set reasoning_content = message.content.split('')[0].rstrip('\n').split('')[-1].lstrip('\n') %} - {%- endif %} - {%- endif %} - {%- if loop.index0 > ns.last_query_index %} - {%- if loop.last or (not loop.last and reasoning_content) %} - {{- '<|im_start|>' + message.role + '\n\n' + reasoning_content.strip('\n') + '\n\n\n' + content.lstrip('\n') }} - {%- else %} - {{- '<|im_start|>' + message.role + '\n' + content }} - {%- endif %} - {%- else %} - {{- '<|im_start|>' + message.role + '\n' + content }} - {%- endif %} - {%- if message.tool_calls %} - {%- for tool_call in message.tool_calls %} - {%- if (loop.first and content) or (not loop.first) %} - {{- '\n' }} - {%- endif %} - {%- if tool_call.function %} - {%- set tool_call = tool_call.function %} - {%- endif %} - {{- '\n{"name": "' }} - {{- tool_call.name }} - {{- '", "arguments": ' }} - {%- if tool_call.arguments is string %} - {{- tool_call.arguments }} - {%- else %} - {{- tool_call.arguments | tojson }} - {%- endif %} - {{- '}\n' }} - {%- endfor %} - {%- endif %} - {{- '<|im_end|>\n' }} - {%- elif message.role == "tool" %} - {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %} - {{- '<|im_start|>user' }} - {%- endif %} - {{- '\n\n' }} - {{- message.content }} - {{- '\n' }} - {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %} - {{- '<|im_end|>\n' }} - {%- endif %} - {%- endif %} -{%- endfor %} -{%- if add_generation_prompt %} - {{- '<|im_start|>assistant\n' }} - {%- if enable_thinking is defined and enable_thinking is false %} - {{- '\n\n\n\n' }} - {%- endif %} -{%- endif %}, example_format: '<|im_start|>system -You are a helpful assistant<|im_end|> -<|im_start|>user -Hello<|im_end|> -<|im_start|>assistant -Hi there<|im_end|> -<|im_start|>user -How are you?<|im_end|> -<|im_start|>assistant -' -main: server is listening on http://0.0.0.0:8081 - starting the main loop -srv update_slots: all slots are idle -srv log_server_r: request: GET /health 127.0.0.1 200 -srv params_from_: Chat format: Content-only -slot launch_slot_: id 0 | task 0 | processing task -slot update_slots: id 0 | task 0 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423 -slot update_slots: id 0 | task 0 | kv cache rm [0, end) -slot update_slots: id 0 | task 0 | prompt processing progress, n_past = 423, n_tokens = 423, progress = 1.000000 -slot update_slots: id 0 | task 0 | prompt done, n_past = 423, n_tokens = 423 -slot release: id 0 | task 0 | stop processing: n_past = 429, truncated = 0 -slot print_timing: id 0 | task 0 | -prompt eval time = 534.22 ms / 423 tokens ( 1.26 ms per token, 791.81 tokens per second) - eval time = 155.33 ms / 7 tokens ( 22.19 ms per token, 45.07 tokens per second) - total time = 689.55 ms / 430 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Content-only -slot launch_slot_: id 0 | task 8 | processing task -slot update_slots: id 0 | task 8 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423 -slot update_slots: id 0 | task 8 | kv cache rm [409, end) -slot update_slots: id 0 | task 8 | prompt processing progress, n_past = 423, n_tokens = 14, progress = 0.033097 -slot update_slots: id 0 | task 8 | prompt done, n_past = 423, n_tokens = 14 -slot release: id 0 | task 8 | stop processing: n_past = 429, truncated = 0 -slot print_timing: id 0 | task 8 | -prompt eval time = 214.36 ms / 14 tokens ( 15.31 ms per token, 65.31 tokens per second) - eval time = 146.82 ms / 7 tokens ( 20.97 ms per token, 47.68 tokens per second) - total time = 361.19 ms / 21 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Content-only -slot launch_slot_: id 0 | task 16 | processing task -slot update_slots: id 0 | task 16 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423 -slot update_slots: id 0 | task 16 | kv cache rm [408, end) -slot update_slots: id 0 | task 16 | prompt processing progress, n_past = 423, n_tokens = 15, progress = 0.035461 -slot update_slots: id 0 | task 16 | prompt done, n_past = 423, n_tokens = 15 -slot release: id 0 | task 16 | stop processing: n_past = 429, truncated = 0 -slot print_timing: id 0 | task 16 | -prompt eval time = 270.02 ms / 15 tokens ( 18.00 ms per token, 55.55 tokens per second) - eval time = 144.12 ms / 7 tokens ( 20.59 ms per token, 48.57 tokens per second) - total time = 414.14 ms / 22 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 24 | processing task -slot update_slots: id 0 | task 24 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 422 -slot update_slots: id 0 | task 24 | kv cache rm [400, end) -slot update_slots: id 0 | task 24 | prompt processing progress, n_past = 422, n_tokens = 22, progress = 0.052133 -slot update_slots: id 0 | task 24 | prompt done, n_past = 422, n_tokens = 22 -slot release: id 0 | task 24 | stop processing: n_past = 596, truncated = 0 -slot print_timing: id 0 | task 24 | -prompt eval time = 399.30 ms / 22 tokens ( 18.15 ms per token, 55.10 tokens per second) - eval time = 3861.49 ms / 175 tokens ( 22.07 ms per token, 45.32 tokens per second) - total time = 4260.79 ms / 197 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 200 | processing task -slot update_slots: id 0 | task 200 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426 -slot update_slots: id 0 | task 200 | kv cache rm [417, end) -slot update_slots: id 0 | task 200 | prompt processing progress, n_past = 426, n_tokens = 9, progress = 0.021127 -slot update_slots: id 0 | task 200 | prompt done, n_past = 426, n_tokens = 9 -slot release: id 0 | task 200 | stop processing: n_past = 436, truncated = 0 -slot print_timing: id 0 | task 200 | -prompt eval time = 253.59 ms / 9 tokens ( 28.18 ms per token, 35.49 tokens per second) - eval time = 234.29 ms / 11 tokens ( 21.30 ms per token, 46.95 tokens per second) - total time = 487.87 ms / 20 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 212 | processing task -slot update_slots: id 0 | task 212 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426 -slot update_slots: id 0 | task 212 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426 -slot update_slots: id 0 | task 212 | kv cache rm [425, end) -slot update_slots: id 0 | task 212 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347 -slot update_slots: id 0 | task 212 | prompt done, n_past = 426, n_tokens = 1 -slot release: id 0 | task 212 | stop processing: n_past = 436, truncated = 0 -slot print_timing: id 0 | task 212 | -prompt eval time = 24.00 ms / 1 tokens ( 24.00 ms per token, 41.67 tokens per second) - eval time = 234.10 ms / 11 tokens ( 21.28 ms per token, 46.99 tokens per second) - total time = 258.10 ms / 12 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 224 | processing task -slot update_slots: id 0 | task 224 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426 -slot update_slots: id 0 | task 224 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426 -slot update_slots: id 0 | task 224 | kv cache rm [425, end) -slot update_slots: id 0 | task 224 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347 -slot update_slots: id 0 | task 224 | prompt done, n_past = 426, n_tokens = 1 -slot release: id 0 | task 224 | stop processing: n_past = 436, truncated = 0 -slot print_timing: id 0 | task 224 | -prompt eval time = 42.68 ms / 1 tokens ( 42.68 ms per token, 23.43 tokens per second) - eval time = 369.06 ms / 11 tokens ( 33.55 ms per token, 29.81 tokens per second) - total time = 411.74 ms / 12 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 236 | processing task -slot update_slots: id 0 | task 236 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426 -slot update_slots: id 0 | task 236 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426 -slot update_slots: id 0 | task 236 | kv cache rm [425, end) -slot update_slots: id 0 | task 236 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347 -slot update_slots: id 0 | task 236 | prompt done, n_past = 426, n_tokens = 1 -slot release: id 0 | task 236 | stop processing: n_past = 436, truncated = 0 -slot print_timing: id 0 | task 236 | -prompt eval time = 35.69 ms / 1 tokens ( 35.69 ms per token, 28.02 tokens per second) - eval time = 272.33 ms / 11 tokens ( 24.76 ms per token, 40.39 tokens per second) - total time = 308.02 ms / 12 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 248 | processing task -slot update_slots: id 0 | task 248 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426 -slot update_slots: id 0 | task 248 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426 -slot update_slots: id 0 | task 248 | kv cache rm [425, end) -slot update_slots: id 0 | task 248 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347 -slot update_slots: id 0 | task 248 | prompt done, n_past = 426, n_tokens = 1 -slot release: id 0 | task 248 | stop processing: n_past = 436, truncated = 0 -slot print_timing: id 0 | task 248 | -prompt eval time = 333.94 ms / 1 tokens ( 333.94 ms per token, 2.99 tokens per second) - eval time = 222.91 ms / 11 tokens ( 20.26 ms per token, 49.35 tokens per second) - total time = 556.85 ms / 12 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 260 | processing task -slot update_slots: id 0 | task 260 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426 -slot update_slots: id 0 | task 260 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426 -slot update_slots: id 0 | task 260 | kv cache rm [425, end) -slot update_slots: id 0 | task 260 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347 -slot update_slots: id 0 | task 260 | prompt done, n_past = 426, n_tokens = 1 -slot release: id 0 | task 260 | stop processing: n_past = 436, truncated = 0 -slot print_timing: id 0 | task 260 | -prompt eval time = 24.23 ms / 1 tokens ( 24.23 ms per token, 41.27 tokens per second) - eval time = 232.33 ms / 11 tokens ( 21.12 ms per token, 47.35 tokens per second) - total time = 256.56 ms / 12 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 272 | processing task -slot update_slots: id 0 | task 272 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 426 -slot update_slots: id 0 | task 272 | need to evaluate at least 1 token for each active slot, n_past = 426, n_prompt_tokens = 426 -slot update_slots: id 0 | task 272 | kv cache rm [425, end) -slot update_slots: id 0 | task 272 | prompt processing progress, n_past = 426, n_tokens = 1, progress = 0.002347 -slot update_slots: id 0 | task 272 | prompt done, n_past = 426, n_tokens = 1 -slot release: id 0 | task 272 | stop processing: n_past = 436, truncated = 0 -slot print_timing: id 0 | task 272 | -prompt eval time = 32.14 ms / 1 tokens ( 32.14 ms per token, 31.11 tokens per second) - eval time = 225.34 ms / 11 tokens ( 20.49 ms per token, 48.82 tokens per second) - total time = 257.48 ms / 12 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 284 | processing task -slot update_slots: id 0 | task 284 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 180 -slot update_slots: id 0 | task 284 | kv cache rm [4, end) -slot update_slots: id 0 | task 284 | prompt processing progress, n_past = 180, n_tokens = 176, progress = 0.977778 -slot update_slots: id 0 | task 284 | prompt done, n_past = 180, n_tokens = 176 -slot release: id 0 | task 284 | stop processing: n_past = 189, truncated = 0 -slot print_timing: id 0 | task 284 | -prompt eval time = 62.74 ms / 176 tokens ( 0.36 ms per token, 2805.14 tokens per second) - eval time = 217.64 ms / 10 tokens ( 21.76 ms per token, 45.95 tokens per second) - total time = 280.39 ms / 186 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 295 | processing task -slot update_slots: id 0 | task 295 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 180 -slot update_slots: id 0 | task 295 | need to evaluate at least 1 token for each active slot, n_past = 180, n_prompt_tokens = 180 -slot update_slots: id 0 | task 295 | kv cache rm [179, end) -slot update_slots: id 0 | task 295 | prompt processing progress, n_past = 180, n_tokens = 1, progress = 0.005556 -slot update_slots: id 0 | task 295 | prompt done, n_past = 180, n_tokens = 1 -slot release: id 0 | task 295 | stop processing: n_past = 189, truncated = 0 -slot print_timing: id 0 | task 295 | -prompt eval time = 24.62 ms / 1 tokens ( 24.62 ms per token, 40.62 tokens per second) - eval time = 215.17 ms / 10 tokens ( 21.52 ms per token, 46.47 tokens per second) - total time = 239.79 ms / 11 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Hermes 2 Pro -slot launch_slot_: id 0 | task 306 | processing task -slot update_slots: id 0 | task 306 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 180 -slot update_slots: id 0 | task 306 | kv cache rm [164, end) -slot update_slots: id 0 | task 306 | prompt processing progress, n_past = 180, n_tokens = 16, progress = 0.088889 -slot update_slots: id 0 | task 306 | prompt done, n_past = 180, n_tokens = 16 -slot release: id 0 | task 306 | stop processing: n_past = 189, truncated = 0 -slot print_timing: id 0 | task 306 | -prompt eval time = 44.44 ms / 16 tokens ( 2.78 ms per token, 360.08 tokens per second) - eval time = 210.16 ms / 10 tokens ( 21.02 ms per token, 47.58 tokens per second) - total time = 254.60 ms / 26 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Content-only -slot launch_slot_: id 0 | task 317 | processing task -slot update_slots: id 0 | task 317 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423 -slot update_slots: id 0 | task 317 | kv cache rm [4, end) -slot update_slots: id 0 | task 317 | prompt processing progress, n_past = 423, n_tokens = 419, progress = 0.990544 -slot update_slots: id 0 | task 317 | prompt done, n_past = 423, n_tokens = 419 -slot release: id 0 | task 317 | stop processing: n_past = 429, truncated = 0 -slot print_timing: id 0 | task 317 | -prompt eval time = 316.01 ms / 419 tokens ( 0.75 ms per token, 1325.92 tokens per second) - eval time = 141.87 ms / 7 tokens ( 20.27 ms per token, 49.34 tokens per second) - total time = 457.88 ms / 426 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Content-only -slot launch_slot_: id 0 | task 325 | processing task -slot update_slots: id 0 | task 325 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 423 -slot update_slots: id 0 | task 325 | need to evaluate at least 1 token for each active slot, n_past = 423, n_prompt_tokens = 423 -slot update_slots: id 0 | task 325 | kv cache rm [422, end) -slot update_slots: id 0 | task 325 | prompt processing progress, n_past = 423, n_tokens = 1, progress = 0.002364 -slot update_slots: id 0 | task 325 | prompt done, n_past = 423, n_tokens = 1 -slot release: id 0 | task 325 | stop processing: n_past = 429, truncated = 0 -slot print_timing: id 0 | task 325 | -prompt eval time = 256.66 ms / 1 tokens ( 256.66 ms per token, 3.90 tokens per second) - eval time = 143.27 ms / 7 tokens ( 20.47 ms per token, 48.86 tokens per second) - total time = 399.92 ms / 8 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 -srv params_from_: Chat format: Content-only -slot launch_slot_: id 0 | task 333 | processing task -slot update_slots: id 0 | task 333 | new prompt, n_ctx_slot = 16384, n_keep = 0, n_prompt_tokens = 7547 -slot update_slots: id 0 | task 333 | kv cache rm [3, end) -slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 2051, n_tokens = 2048, progress = 0.271366 -slot update_slots: id 0 | task 333 | kv cache rm [2051, end) -slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 4099, n_tokens = 2048, progress = 0.542732 -slot update_slots: id 0 | task 333 | kv cache rm [4099, end) -slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 6147, n_tokens = 2048, progress = 0.814098 -slot update_slots: id 0 | task 333 | kv cache rm [6147, end) -slot update_slots: id 0 | task 333 | prompt processing progress, n_past = 7547, n_tokens = 1400, progress = 0.999602 -slot update_slots: id 0 | task 333 | prompt done, n_past = 7547, n_tokens = 1400 -slot release: id 0 | task 333 | stop processing: n_past = 7680, truncated = 0 -slot print_timing: id 0 | task 333 | -prompt eval time = 4829.54 ms / 7544 tokens ( 0.64 ms per token, 1562.05 tokens per second) - eval time = 3913.28 ms / 134 tokens ( 29.20 ms per token, 34.24 tokens per second) - total time = 8742.83 ms / 7678 tokens -srv update_slots: all slots are idle -srv log_server_r: request: POST /v1/chat/completions 127.0.0.1 200 diff --git a/logs/services.pid b/logs/services.pid deleted file mode 100644 index 278f77c7..00000000 --- a/logs/services.pid +++ /dev/null @@ -1,3 +0,0 @@ -26023 -26024 -26109 diff --git a/logs/services_vllm.pid b/logs/services_vllm.pid deleted file mode 100644 index 0a3fd610..00000000 --- a/logs/services_vllm.pid +++ /dev/null @@ -1,2 +0,0 @@ -43538 -43539 diff --git a/logs/vllm_inference_model.log b/logs/vllm_inference_model.log deleted file mode 100644 index fe3a57c3..00000000 --- a/logs/vllm_inference_model.log +++ /dev/null @@ -1,150 +0,0 @@ -[DEBUG] conda_env=VLLM -[DEBUG] CONDA_PREFIX=/home/huangfukk/miniconda3/envs/VLLM -[DEBUG] which python: /home/huangfukk/miniconda3/envs/VLLM/bin/python -[DEBUG] which vllm: /home/huangfukk/miniconda3/envs/VLLM/bin/vllm -0.13.0 -[DEBUG] python: 3.12.12 | packaged by Anaconda, Inc. | (main, Oct 21 2025, 20:16:04) [GCC 11.2.0] -[DEBUG] torch: 2.9.0+cu128 cuda: 12.8 available: True -(APIServer pid=43538) INFO 01-20 16:25:05 [api_server.py:1351] vLLM API server version 0.13.0 -(APIServer pid=43538) INFO 01-20 16:25:05 [utils.py:253] non-default args: {'model_tag': '/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', 'host': '0.0.0.0', 'port': 8081, 'uvicorn_log_level': 'debug', 'chat_template': '/home/huangfukk/DronePlanning/tools/vllm_templates/qwen3_xml_tool.jinja', 'chat_template_content_format': 'string', 'enable_auto_tool_choice': True, 'tool_call_parser': 'qwen3_xml', 'model': '/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', 'trust_remote_code': True, 'max_model_len': 16384, 'served_model_name': ['local-model'], 'max_parallel_loading_workers': 4, 'gpu_memory_utilization': 0.5, 'max_num_seqs': 1} -(APIServer pid=43538) The argument `trust_remote_code` is to be used with Auto classes. It has no effect here and is ignored. -(APIServer pid=43538) INFO 01-20 16:25:05 [model.py:514] Resolved architecture: Qwen3ForCausalLM -(APIServer pid=43538) INFO 01-20 16:25:05 [model.py:1661] Using max model len 16384 -(APIServer pid=43538) INFO 01-20 16:25:05 [awq_marlin.py:162] The model is convertible to awq_marlin during runtime. Using awq_marlin kernel. -(APIServer pid=43538) WARNING 01-20 16:25:05 [parallel.py:595] max_parallel_loading_workers is currently not supported and will be ignored. -(APIServer pid=43538) INFO 01-20 16:25:05 [scheduler.py:230] Chunked prefill is enabled with max_num_batched_tokens=2048. -(APIServer pid=43538) WARNING 01-20 16:25:06 [interface.py:465] Using 'pin_memory=False' as WSL is detected. This may slow down the performance. -(EngineCore_DP0 pid=43785) INFO 01-20 16:25:10 [core.py:93] Initializing a V1 LLM engine (v0.13.0) with config: model='/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', speculative_config=None, tokenizer='/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507', skip_tokenizer_init=False, tokenizer_mode=auto, revision=None, tokenizer_revision=None, trust_remote_code=True, dtype=torch.bfloat16, max_seq_len=16384, download_dir=None, load_format=auto, tensor_parallel_size=1, pipeline_parallel_size=1, data_parallel_size=1, disable_custom_all_reduce=False, quantization=awq_marlin, enforce_eager=False, kv_cache_dtype=auto, device_config=cuda, structured_outputs_config=StructuredOutputsConfig(backend='auto', disable_fallback=False, disable_any_whitespace=False, disable_additional_properties=False, reasoning_parser='', reasoning_parser_plugin='', enable_in_reasoning=False), observability_config=ObservabilityConfig(show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None, kv_cache_metrics=False, kv_cache_metrics_sample=0.01, cudagraph_metrics=False, enable_layerwise_nvtx_tracing=False), seed=0, served_model_name=local-model, enable_prefix_caching=True, enable_chunked_prefill=True, pooler_config=None, compilation_config={'level': None, 'mode': , 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['none'], 'splitting_ops': ['vllm::unified_attention', 'vllm::unified_attention_with_output', 'vllm::unified_mla_attention', 'vllm::unified_mla_attention_with_output', 'vllm::mamba_mixer2', 'vllm::mamba_mixer', 'vllm::short_conv', 'vllm::linear_attention', 'vllm::plamo2_mamba_mixer', 'vllm::gdn_attention_core', 'vllm::kda_attention', 'vllm::sparse_attn_indexer'], 'compile_mm_encoder': False, 'compile_sizes': [], 'compile_ranges_split_points': [2048], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': , 'cudagraph_num_of_warmups': 1, 'cudagraph_capture_sizes': [1, 2], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': False, 'fuse_act_quant': False, 'fuse_attn_quant': False, 'eliminate_noops': True, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False}, 'max_cudagraph_capture_size': 2, 'dynamic_shapes_config': {'type': , 'evaluate_guards': False}, 'local_cache_dir': None} -(EngineCore_DP0 pid=43785) INFO 01-20 16:25:11 [parallel_state.py:1203] world_size=1 rank=0 local_rank=0 distributed_init_method=tcp://192.168.31.62:43504 backend=nccl -[W120 16:25:21.543804205 socket.cpp:209] [c10d] The hostname of the client socket cannot be retrieved. err=-3 -(EngineCore_DP0 pid=43785) INFO 01-20 16:25:21 [parallel_state.py:1411] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank 0 -(EngineCore_DP0 pid=43785) WARNING 01-20 16:25:21 [interface.py:465] Using 'pin_memory=False' as WSL is detected. This may slow down the performance. -(EngineCore_DP0 pid=43785) INFO 01-20 16:25:22 [gpu_model_runner.py:3562] Starting to load model /home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507... -(EngineCore_DP0 pid=43785) INFO 01-20 16:25:22 [cuda.py:351] Using FLASH_ATTN attention backend out of potential backends: ('FLASH_ATTN', 'FLASHINFER', 'TRITON_ATTN', 'FLEX_ATTENTION') -(EngineCore_DP0 pid=43785) Loading safetensors checkpoint shards: 0% Completed | 0/1 [00:00system -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- if messages[0].role == 'system' -%} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {{ messages[0].content }} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- else -%} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] You are a helpful assistant. -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endif -%} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] # Tools -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] You may call one or more functions to assist with the user query. -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] The function signatures are provided below: -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- for tool in tools %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {{ tool | tojson }} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endfor %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] When you need to call a tool, respond with XML tags in this exact format: -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] value1 -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] value2 -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_end|> -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- else %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- if messages[0].role == 'system' -%} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>system -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {{ messages[0].content }}<|im_end|> -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endif -%} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endif %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- for message in messages %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- if (message.role == "user") or (message.role == "system" and not loop.first) %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>{{ message.role }} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {{ message.content }}<|im_end|> -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- elif message.role == "assistant" %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>assistant -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- if message.content %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {{ message.content }} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endif %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_end|> -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- elif message.role == "tool" %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>user -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {{ message.content }} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_end|> -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endif %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endfor %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- if add_generation_prompt %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] <|im_start|>assistant -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] {%- endif %} -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] -(APIServer pid=43538) WARNING 01-20 16:25:42 [utils.py:312] It is different from official chat template '/home/huangfukk/models/AWQ/Qwen3-4B-Instruct-2507'. This discrepancy may lead to performance degradation. -(APIServer pid=43538) WARNING 01-20 16:25:42 [model.py:1487] Default sampling parameters have been overridden by the model's Hugging Face generation config recommended from the model creator. If this is not intended, please relaunch vLLM instance with `--generation-config vllm`. -(APIServer pid=43538) INFO 01-20 16:25:42 [serving_responses.py:201] Using default chat sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8} -(APIServer pid=43538) INFO 01-20 16:25:42 [serving_engine.py:270] "auto" tool choice has been enabled. -(APIServer pid=43538) INFO 01-20 16:25:42 [serving_engine.py:270] "auto" tool choice has been enabled. -(APIServer pid=43538) INFO 01-20 16:25:42 [serving_chat.py:137] Using default chat sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8} -(APIServer pid=43538) INFO 01-20 16:25:42 [serving_completion.py:77] Using default completion sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8} -(APIServer pid=43538) INFO 01-20 16:25:42 [serving_engine.py:270] "auto" tool choice has been enabled. -(APIServer pid=43538) INFO 01-20 16:25:42 [serving_chat.py:137] Using default chat sampling params from model: {'temperature': 0.7, 'top_k': 20, 'top_p': 0.8} -(APIServer pid=43538) INFO 01-20 16:25:42 [api_server.py:1425] Starting vLLM API server 0 on http://0.0.0.0:8081 -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:38] Available routes are: -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /openapi.json, Methods: GET, HEAD -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /docs, Methods: GET, HEAD -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /docs/oauth2-redirect, Methods: GET, HEAD -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /redoc, Methods: GET, HEAD -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /scale_elastic_ep, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /is_scaling_elastic_ep, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /tokenize, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /detokenize, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /inference/v1/generate, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /pause, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /resume, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /is_paused, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /metrics, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /health, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /load, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/models, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /version, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/responses, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/responses/{response_id}, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/responses/{response_id}/cancel, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/messages, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/chat/completions, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/completions, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/audio/transcriptions, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/audio/translations, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /ping, Methods: GET -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /ping, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /invocations, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /classify, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/embeddings, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /score, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/score, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /rerank, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v1/rerank, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /v2/rerank, Methods: POST -(APIServer pid=43538) INFO 01-20 16:25:42 [launcher.py:46] Route: /pooling, Methods: POST -(APIServer pid=43538) INFO: Started server process [43538] -(APIServer pid=43538) INFO: Waiting for application startup. -(APIServer pid=43538) INFO: Application startup complete. -(APIServer pid=43538) INFO: 127.0.0.1:46791 - "GET /health HTTP/1.1" 200 OK -(APIServer pid=43538) INFO: 127.0.0.1:43619 - "POST /v1/chat/completions HTTP/1.1" 200 OK -(APIServer pid=43538) INFO 01-21 20:22:50 [loggers.py:248] Engine 000: Avg prompt throughput: 168.4 tokens/s, Avg generation throughput: 0.6 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0% -(APIServer pid=43538) INFO 01-21 20:23:00 [loggers.py:248] Engine 000: Avg prompt throughput: 0.0 tokens/s, Avg generation throughput: 0.0 tokens/s, Running: 0 reqs, Waiting: 0 reqs, GPU KV cache usage: 0.0%, Prefix cache hit rate: 0.0% diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/data_level0.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/data_level0.bin deleted file mode 100644 index c656b189..00000000 Binary files a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/data_level0.bin and /dev/null differ diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/header.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/header.bin deleted file mode 100644 index e89c5c59..00000000 Binary files a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/header.bin and /dev/null differ diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/length.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/length.bin deleted file mode 100644 index 4fd4818c..00000000 Binary files a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/length.bin and /dev/null differ diff --git a/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/link_lists.bin b/tools/rag/vector_store/432998d6-0171-48e2-b1dd-888168f2549f/link_lists.bin deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/data_level0.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/data_level0.bin deleted file mode 100644 index c656b189..00000000 Binary files a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/data_level0.bin and /dev/null differ diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/header.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/header.bin deleted file mode 100644 index e89c5c59..00000000 Binary files a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/header.bin and /dev/null differ diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/length.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/length.bin deleted file mode 100644 index 502d41c5..00000000 Binary files a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/length.bin and /dev/null differ diff --git a/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/link_lists.bin b/tools/rag/vector_store/93a1b605-dd3b-4cf6-b2f6-60c3e3cca5cb/link_lists.bin deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/data_level0.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/data_level0.bin deleted file mode 100644 index 86568df2..00000000 Binary files a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/data_level0.bin and /dev/null differ diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/header.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/header.bin deleted file mode 100644 index b6867c78..00000000 Binary files a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/header.bin and /dev/null differ diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/length.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/length.bin deleted file mode 100644 index ba4322f2..00000000 Binary files a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/length.bin and /dev/null differ diff --git a/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/link_lists.bin b/tools/rag/vector_store/cb34653b-ced6-4028-80bd-cb20ec5d8251/link_lists.bin deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/data_level0.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/data_level0.bin deleted file mode 100644 index c656b189..00000000 Binary files a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/data_level0.bin and /dev/null differ diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/header.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/header.bin deleted file mode 100644 index e89c5c59..00000000 Binary files a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/header.bin and /dev/null differ diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/length.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/length.bin deleted file mode 100644 index d832af0a..00000000 Binary files a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/length.bin and /dev/null differ diff --git a/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/link_lists.bin b/tools/rag/vector_store/ce707eb5-3cab-4107-9c61-f56f4c6f6efb/link_lists.bin deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/rag/vector_store/chroma.sqlite3 b/tools/rag/vector_store/chroma.sqlite3 deleted file mode 100644 index 74687312..00000000 Binary files a/tools/rag/vector_store/chroma.sqlite3 and /dev/null differ diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/data_level0.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/data_level0.bin deleted file mode 100644 index c656b189..00000000 Binary files a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/data_level0.bin and /dev/null differ diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/header.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/header.bin deleted file mode 100644 index e89c5c59..00000000 Binary files a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/header.bin and /dev/null differ diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/length.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/length.bin deleted file mode 100644 index cb3e1628..00000000 Binary files a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/length.bin and /dev/null differ diff --git a/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/link_lists.bin b/tools/rag/vector_store/eb012611-c2fa-46d6-9b5a-234ffcd5a720/link_lists.bin deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/test_validate/validation/20260203224629/instructions_backup.txt b/tools/test_validate/validation/20260203224629/instructions_backup.txt deleted file mode 100644 index ec249598..00000000 --- a/tools/test_validate/validation/20260203224629/instructions_backup.txt +++ /dev/null @@ -1,10 +0,0 @@ -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。 -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。 -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。 -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。 -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。 -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。 -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。 -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。 -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。 -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。 \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/test_details.csv b/tools/test_validate/validation/20260203224629/test_details.csv deleted file mode 100644 index 06477161..00000000 --- a/tools/test_validate/validation/20260203224629/test_details.csv +++ /dev/null @@ -1,11 +0,0 @@ -instruction,run_id,success,latency,error -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,True,13.293935775756836, -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,True,10.266583442687988, -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,True,11.274949550628662, -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,True,1.6364917755126953, -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,True,10.27147102355957, -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,True,13.89813232421875, -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,True,3.24064302444458, -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,True,19.873026847839355, -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,True,13.099174499511719, -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,True,8.792617082595825, diff --git a/tools/test_validate/validation/20260203224629/test_summary.csv b/tools/test_validate/validation/20260203224629/test_summary.csv deleted file mode 100644 index 5c49f92e..00000000 --- a/tools/test_validate/validation/20260203224629/test_summary.csv +++ /dev/null @@ -1,11 +0,0 @@ -Instruction,Total Runs,Success Runs,Success Rate,Avg Latency -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,1,100.0%,13.29s -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,1,100.0%,10.27s -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,1,100.0%,11.27s -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,1,100.0%,1.64s -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,1,100.0%,10.27s -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,1,100.0%,13.90s -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,1,100.0%,3.24s -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,1,100.0%,19.87s -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,1,100.0%,13.10s -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,1,100.0%,8.79s diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json deleted file mode 100644 index db79db6d..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "comprehensive" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 10.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 10.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子" - } - }, - { - "type": "action", - "name": "approach_target", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子", - "stop_distance": 5.0 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子", - "track_time": 10.0 - } - } - ] - }, - "plan_id": "ec05c1a4-720d-4cde-9590-a66f81a72561", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png deleted file mode 100644 index 9db598be..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json deleted file mode 100644 index 4f94b740..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "root": { - "type": "action", - "name": "object_detect", - "params": { - "target_class": "person", - "description": "长头发", - "count": 1 - } - }, - "plan_id": "70eb9449-6857-4a27-a99c-7c6708d12db1", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n你是一个无人机简单指令执行规划器。你的任务:当用户给出“简单指令”(单一原子动作即可完成)时,输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root节点必须是action类型节点,不能是控制流节点。\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “移动到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n- “飞机自检” → {\"root\":{\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}}}\n\n—— 可用节点定义——\n```json\n{\n \"actions\": [\n {\"name\":\"takeoff\",\"params\":{\"altitude\":\"float[1,100],默认2\"}},\n {\"name\":\"land\",\"params\":{\"mode\":\"'current'/'home'\"}},\n {\"name\":\"fly_to_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"acceptance_radius\":\"默认2.0\"}},\n {\"name\":\"fly_sequence\",\"params\":{\"waypoints\":\"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\"coordinate_frame\":\"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\"speed\":\"float,可选\"}},\n {\"name\":\"move_direction\",\"params\":{\"direction\":\"north/south/east/west/forward/backward/left/right/up/down\",\"distance\":\"[1,10000],缺省持续移动\",\"speed\":\"float,可选\"}},\n {\"name\":\"approach_target\",\"params\":{\"target_class\":\"string,要趋近的目标类别\",\"description\":\"string,可选,目标属性描述\",\"stop_distance\":\"float,期望的最终停止距离\",\"speed\":\"float,可选,期望的逼近速度\"}},\n {\"name\":\"rotate\",\"params\":{\"angle\":\"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\"angular_velocity\":\"rad/s,旋转角速度\"}},\n {\"name\":\"rotate_search\",\"params\":{\"target_class\":\"string,要搜寻的目标类别\",\"description\":\"string,可选,目标属性描述\",\"step_angle\":\"float,可选,每一步旋转的角度\",\"total_rotation\":\"float,可选,总共旋转搜索的角度\"}},\n {\"name\":\"manual_confirmation\",\"params\":{}},\n {\"name\":\"loiter\",\"params\":{\"duration\":\"[1,600]秒/until_condition:可选\"}},\n {\"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,garbage\",\"description\":\"可选,\",\"count\":\"默认1\"}},\n {\"name\":\"strike_target\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"battle_damage_assessment\",\"params\":{\"target_class\":\"同object_detect\",\"assessment_time\":\"[5,60],默认15\"}},\n {\"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\"}},\n {\"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\"}},\n {\"name\":\"deliver_payload\",\"params\":{\"payload_type\":\"string\",\"release_altitude\":\"[2,100]默认5\"}},\n {\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic/comprehensive\"}},\n {\"name\":\"return_emergency\",\"params\":{\"reason\":\"string,此节点仅用于【无明确目的地】的立即返航。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"}},\n {\"name\":\"take_photos\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"track_time\":\"[1,600]秒(必传,不可用'duration')\",\"min_confidence\":\"[0.5,1.0]默认0.7\",\"safe_distance\":\"[2,50]默认10\"}}\n ],\n \"conditions\": [\n {\"name\":\"at_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"tolerance\":\"默认3.0\"}},\n {\"name\":\"object_detected\",\"params\":{\"target_class\":\"同object_detect(必传)\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"target_destroyed\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"confidence\":\"[0.5,1.0]默认0.8\"}},\n {\"name\":\"time_elapsed\",\"params\":{\"duration\":\"[1,2700]秒\"}},\n {\"name\":\"gps_status\",\"params\":{\"min_satellites\":\"int[6,15],必传(如8)\"}}\n ]\n}\n```\n\n—— 参数约束——\n- takeoff.altitude: [1, 100]\n- fly_to_waypoint.z: [1, 5000]\n- fly_to_waypoint.x,y: [-10000, 10000]\n- search_pattern.radius: [5, 1000]\n- move_direction.distance: [1, 10000]\n- 若参考知识提供坐标,必须使用并裁剪到约束范围内\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png deleted file mode 100644 index 584d9f92..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json deleted file mode 100644 index 4606716c..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "root": { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 0.0, - "acceptance_radius": 2.0 - } - }, - "plan_id": "ee762817-34de-406a-a216-f0ec3e0edb6e", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n你是一个无人机简单指令执行规划器。你的任务:当用户给出“简单指令”(单一原子动作即可完成)时,输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root节点必须是action类型节点,不能是控制流节点。\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “移动到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n- “飞机自检” → {\"root\":{\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}}}\n\n—— 可用节点定义——\n```json\n{\n \"actions\": [\n {\"name\":\"takeoff\",\"params\":{\"altitude\":\"float[1,100],默认2\"}},\n {\"name\":\"land\",\"params\":{\"mode\":\"'current'/'home'\"}},\n {\"name\":\"fly_to_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"acceptance_radius\":\"默认2.0\"}},\n {\"name\":\"fly_sequence\",\"params\":{\"waypoints\":\"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\"coordinate_frame\":\"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\"speed\":\"float,可选\"}},\n {\"name\":\"move_direction\",\"params\":{\"direction\":\"north/south/east/west/forward/backward/left/right/up/down\",\"distance\":\"[1,10000],缺省持续移动\",\"speed\":\"float,可选\"}},\n {\"name\":\"approach_target\",\"params\":{\"target_class\":\"string,要趋近的目标类别\",\"description\":\"string,可选,目标属性描述\",\"stop_distance\":\"float,期望的最终停止距离\",\"speed\":\"float,可选,期望的逼近速度\"}},\n {\"name\":\"rotate\",\"params\":{\"angle\":\"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\"angular_velocity\":\"rad/s,旋转角速度\"}},\n {\"name\":\"rotate_search\",\"params\":{\"target_class\":\"string,要搜寻的目标类别\",\"description\":\"string,可选,目标属性描述\",\"step_angle\":\"float,可选,每一步旋转的角度\",\"total_rotation\":\"float,可选,总共旋转搜索的角度\"}},\n {\"name\":\"manual_confirmation\",\"params\":{}},\n {\"name\":\"loiter\",\"params\":{\"duration\":\"[1,600]秒/until_condition:可选\"}},\n {\"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,garbage\",\"description\":\"可选,\",\"count\":\"默认1\"}},\n {\"name\":\"strike_target\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"battle_damage_assessment\",\"params\":{\"target_class\":\"同object_detect\",\"assessment_time\":\"[5,60],默认15\"}},\n {\"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\"}},\n {\"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\"}},\n {\"name\":\"deliver_payload\",\"params\":{\"payload_type\":\"string\",\"release_altitude\":\"[2,100]默认5\"}},\n {\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic/comprehensive\"}},\n {\"name\":\"return_emergency\",\"params\":{\"reason\":\"string,此节点仅用于【无明确目的地】的立即返航。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"}},\n {\"name\":\"take_photos\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"track_time\":\"[1,600]秒(必传,不可用'duration')\",\"min_confidence\":\"[0.5,1.0]默认0.7\",\"safe_distance\":\"[2,50]默认10\"}}\n ],\n \"conditions\": [\n {\"name\":\"at_waypoint\",\"params\":{\"x\":\"±10000\",\"y\":\"±10000\",\"z\":\"[1,5000]\",\"tolerance\":\"默认3.0\"}},\n {\"name\":\"object_detected\",\"params\":{\"target_class\":\"同object_detect(必传)\",\"description\":\"可选,目标属性\",\"count\":\"默认1\"}},\n {\"name\":\"target_destroyed\",\"params\":{\"target_class\":\"同object_detect\",\"description\":\"可选,目标属性\",\"confidence\":\"[0.5,1.0]默认0.8\"}},\n {\"name\":\"time_elapsed\",\"params\":{\"duration\":\"[1,2700]秒\"}},\n {\"name\":\"gps_status\",\"params\":{\"min_satellites\":\"int[6,15],必传(如8)\"}}\n ]\n}\n```\n\n—— 参数约束——\n- takeoff.altitude: [1, 100]\n- fly_to_waypoint.z: [1, 5000]\n- fly_to_waypoint.x,y: [-10000, 10000]\n- search_pattern.radius: [5, 1000]\n- move_direction.distance: [1, 10000]\n- 若参考知识提供坐标,必须使用并裁剪到约束范围内\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png deleted file mode 100644 index 44349152..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json deleted file mode 100644 index b71864ef..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "comprehensive" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 10.0 - } - }, - { - "type": "action", - "name": "move_direction", - "params": { - "direction": "east", - "distance": 30.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "身穿白色衣服,头戴帽子的男子" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "身穿白色衣服,头戴帽子的男子" - } - }, - { - "type": "action", - "name": "manual_confirmation", - "params": {} - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "身穿白色衣服,头戴帽子的男子", - "track_time": 10.0 - } - } - ] - }, - "plan_id": "24122475-d286-4034-b9a5-e7e37aff8564", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png deleted file mode 100644 index 866e0c54..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json deleted file mode 100644 index 03f0280a..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": -50.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "穿红色衣服的人", - "track_time": 5.0 - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "任务完成" - } - } - ] - }, - "plan_id": "3f212bfa-0915-4bc4-a9b1-59266248c05c", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png deleted file mode 100644 index a811ad7f..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json deleted file mode 100644 index 8db81934..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "戴帽子的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "戴帽子的人" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "戴帽子的人", - "track_time": 10.0 - } - } - ] - }, - "plan_id": "ad362dde-0c33-435b-9870-9d29beee9278", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png deleted file mode 100644 index 4a654bdd..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json deleted file mode 100644 index 4267f08b..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": -50.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "Parallel", - "name": "MonitorAndPhoto", - "params": { - "policy": "success_on_one" - }, - "children": [ - { - "type": "action", - "name": "loiter", - "params": { - "duration": 300 - } - }, - { - "type": "decorator", - "name": "SuccessIsFailure", - "child": { - "type": "Sequence", - "name": "CheckAndPhoto", - "children": [ - { - "type": "action", - "name": "object_detect", - "params": { - "target_class": "person" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person" - } - } - ] - } - } - ] - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "任务完成" - } - } - ] - }, - "plan_id": "c7382dba-30c3-48b9-b175-ec42cb7f90d8", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png deleted file mode 100644 index 4737b375..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json deleted file mode 100644 index 9563cfc0..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "SearchPhotoConfirmReturn", - "children": [ - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "action", - "name": "manual_confirmation", - "params": {} - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "确认后返航" - } - } - ] - }, - "plan_id": "00394bf3-1df8-49aa-917a-4d81acb535ec", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png deleted file mode 100644 index d72aa331..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json deleted file mode 100644 index e01e69cd..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "approach_target", - "params": { - "target_class": "person", - "description": "白色衣服戴帽子的男子", - "stop_distance": 3.0 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "白色衣服戴帽子的男子", - "track_time": 5.0 - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "任务完成" - } - } - ] - }, - "plan_id": "f31e2045-5987-4aab-8543-31d15fa17704", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png b/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png deleted file mode 100644 index 35ebf526..00000000 Binary files a/tools/test_validate/validation/20260203224629/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203224629/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json b/tools/test_validate/validation/20260203224629/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json deleted file mode 100644 index fe891f8b..00000000 --- a/tools/test_validate/validation/20260203224629/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "error": "在3次尝试后,仍未能生成一个有效的Pytree。" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/instructions_backup.txt b/tools/test_validate/validation/20260203225625/instructions_backup.txt deleted file mode 100644 index ec249598..00000000 --- a/tools/test_validate/validation/20260203225625/instructions_backup.txt +++ /dev/null @@ -1,10 +0,0 @@ -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。 -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。 -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。 -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。 -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。 -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。 -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。 -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。 -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。 -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。 \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/test_details.csv b/tools/test_validate/validation/20260203225625/test_details.csv deleted file mode 100644 index 4d9169ae..00000000 --- a/tools/test_validate/validation/20260203225625/test_details.csv +++ /dev/null @@ -1,11 +0,0 @@ -instruction,run_id,success,latency,error -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,True,14.206302165985107, -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,True,9.870139360427856, -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,True,11.775025844573975, -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,True,10.768753051757812, -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,True,10.050657749176025, -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,True,13.982521057128906, -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,True,12.104306697845459, -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,True,21.10497808456421, -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,True,11.49827790260315, -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,True,9.288247346878052, diff --git a/tools/test_validate/validation/20260203225625/test_summary.csv b/tools/test_validate/validation/20260203225625/test_summary.csv deleted file mode 100644 index 52f86c8e..00000000 --- a/tools/test_validate/validation/20260203225625/test_summary.csv +++ /dev/null @@ -1,11 +0,0 @@ -Instruction,Total Runs,Success Runs,Success Rate,Avg Latency -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。,1,1,100.0%,14.21s -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。,1,1,100.0%,9.87s -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。,1,1,100.0%,11.78s -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。,1,1,100.0%,10.77s -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。,1,1,100.0%,10.05s -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。,1,1,100.0%,13.98s -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。,1,1,100.0%,12.10s -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。,1,1,100.0%,21.10s -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。,1,1,100.0%,11.50s -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。,1,1,100.0%,9.29s diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json deleted file mode 100644 index e23f0722..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "comprehensive" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 10.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 10.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子" - } - }, - { - "type": "action", - "name": "approach_target", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子", - "stop_distance": 5.0 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "穿红色衣服的男子", - "track_time": 10.0 - } - } - ] - }, - "plan_id": "e6dd50ed-5ce0-4032-91fa-bb7b9e28233c", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png deleted file mode 100644 index 9db598be..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json deleted file mode 100644 index d95911b0..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "comprehensive" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 10.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "长头发的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "长头发的人" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "长头发的人", - "track_time": 5.0 - } - } - ] - }, - "plan_id": "02ac6a8d-630b-43d7-8374-679cc07f37ed", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png deleted file mode 100644 index e959795b..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json deleted file mode 100644 index d8e83caf..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "comprehensive" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 10.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "未带帽子" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "未带帽子" - } - }, - { - "type": "action", - "name": "approach_target", - "params": { - "target_class": "person", - "description": "未带帽子", - "stop_distance": 5.0 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "未带帽子", - "track_time": 10.0 - } - } - ] - }, - "plan_id": "dca5568f-e062-4d82-b8db-61ef2bed669a", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png deleted file mode 100644 index 172bbd21..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json deleted file mode 100644 index beb858e7..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "comprehensive" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 10.0 - } - }, - { - "type": "action", - "name": "move_direction", - "params": { - "direction": "east", - "distance": 30.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "身穿白色衣服,头戴帽子的男子" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "身穿白色衣服,头戴帽子的男子" - } - }, - { - "type": "action", - "name": "manual_confirmation", - "params": {} - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "身穿白色衣服,头戴帽子的男子", - "track_time": 10.0 - } - } - ] - }, - "plan_id": "046d1b14-1c37-4143-98c5-5a80a61213a1", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png deleted file mode 100644 index 866e0c54..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json deleted file mode 100644 index 850874f3..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": -50.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "穿红色衣服的人", - "track_time": 5.0 - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "任务完成" - } - } - ] - }, - "plan_id": "ded7065b-453b-4b55-8737-1e00388f6a06", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png deleted file mode 100644 index a811ad7f..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json deleted file mode 100644 index e7df2f0a..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "戴帽子的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "戴帽子的人" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "戴帽子的人", - "track_time": 10.0 - } - } - ] - }, - "plan_id": "35f56771-b284-4d58-b738-e404f5aa29a1", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png deleted file mode 100644 index 4a654bdd..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json deleted file mode 100644 index 5fe0d871..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": -50.0, - "y": 0.0, - "z": 0.0 - } - }, - { - "type": "Parallel", - "name": "MonitorAndPhoto", - "params": { - "policy": "success_on_one" - }, - "children": [ - { - "type": "action", - "name": "loiter", - "params": { - "duration": 300 - } - }, - { - "type": "decorator", - "name": "SuccessIsFailure", - "child": { - "type": "Sequence", - "name": "CheckAndPhoto", - "children": [ - { - "type": "action", - "name": "object_detect", - "params": { - "target_class": "person" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person" - } - } - ] - } - } - ] - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "任务完成" - } - } - ] - }, - "plan_id": "f54dd51c-b9f5-4a9a-802f-941bba44ca12", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png deleted file mode 100644 index 4737b375..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json deleted file mode 100644 index 7a38b417..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "SearchPhotoConfirmReturn", - "children": [ - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "action", - "name": "manual_confirmation", - "params": {} - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "穿红色衣服的人" - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "确认后返航" - } - } - ] - }, - "plan_id": "642ee3ce-45a3-4c7b-b1a4-b323cc0dbf6b", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png deleted file mode 100644 index d72aa331..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json deleted file mode 100644 index 879be75b..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "approach_target", - "params": { - "target_class": "person", - "description": "白色衣服戴帽子的男子", - "stop_distance": 3.0 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "person", - "description": "白色衣服戴帽子的男子", - "track_time": 5.0 - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "任务完成" - } - } - ] - }, - "plan_id": "7e65d4ad-dd23-49ac-80d9-70b648c17cd4", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png b/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png deleted file mode 100644 index 35ebf526..00000000 Binary files a/tools/test_validate/validation/20260203225625/无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260203225625/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json b/tools/test_validate/validation/20260203225625/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json deleted file mode 100644 index fe891f8b..00000000 --- a/tools/test_validate/validation/20260203225625/无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。/1.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "error": "在3次尝试后,仍未能生成一个有效的Pytree。" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260221090219/instructions_backup.txt b/tools/test_validate/validation/20260221090219/instructions_backup.txt deleted file mode 100644 index ec249598..00000000 --- a/tools/test_validate/validation/20260221090219/instructions_backup.txt +++ /dev/null @@ -1,10 +0,0 @@ -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。 -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。 -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。 -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。 -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。 -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。 -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。 -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。 -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。 -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。 \ No newline at end of file diff --git a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json deleted file mode 100644 index b9216d96..00000000 --- a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0, - "y": 0, - "z": 0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "穿红色衣服的男子", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "穿红色衣服的男子", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "穿红色衣服的男子", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "plan_id": "71b277b7-08d2-482f-bbb7-141c667b2c7d", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png deleted file mode 100644 index 9c453124..00000000 Binary files a/tools/test_validate/validation/20260221090219/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224120937/instructions_backup.txt b/tools/test_validate/validation/20260224120937/instructions_backup.txt deleted file mode 100644 index ec249598..00000000 --- a/tools/test_validate/validation/20260224120937/instructions_backup.txt +++ /dev/null @@ -1,10 +0,0 @@ -无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。 -无人机当前在空中,回到飞行场地,对戴帽子的人进行拍照。 -无人机当前在空中,去飞行场地西边50米,对过往穿红色衣服的人拍张照,然后返航。 -无人机当前在地面,到飞行场地查找长头发的人,看见了拍个照片。 -无人机当前在空中,搜索穿红色衣服的人,搜索到了拍张照,我确认后再决定要不要返航。 -无人机当前在空中,往飞行场地西边飞50米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。 -无人机当前在地面,到飞行场地,发现未带帽子的飞近后拍照。 -无人机当前在空中,紧急回到飞行场地,看见了树之后直接降落。 -无人机当前在地面,快速去往东边30米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。 -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。 \ No newline at end of file diff --git a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json deleted file mode 100644 index ce3614b2..00000000 --- a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 100.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "穿红色衣服的男子", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "穿红色衣服的男子", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "穿红色衣服的男子", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "plan_id": "c936a4fc-09d3-4ab4-aae3-34b4e228a798", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png deleted file mode 100644 index c137bec6..00000000 Binary files a/tools/test_validate/validation/20260224120937/无人机当前在地面,到飞行场地查找穿红色衣服的男子,找到后近距离拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224121211/instructions_backup.txt b/tools/test_validate/validation/20260224121211/instructions_backup.txt deleted file mode 100644 index 5b6dc3d2..00000000 --- a/tools/test_validate/validation/20260224121211/instructions_backup.txt +++ /dev/null @@ -1,9 +0,0 @@ -无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。 -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。 -无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。 -无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。 -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。 -无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。 -无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。 -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。 -无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。 \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/test_details.csv b/tools/test_validate/validation/20260224121211/test_details.csv deleted file mode 100644 index 8a88d711..00000000 --- a/tools/test_validate/validation/20260224121211/test_details.csv +++ /dev/null @@ -1,10 +0,0 @@ -instruction,run_id,success,latency,error -无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。,1,True,16.063878774642944, -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。,1,False,16.235912084579468,500 Server Error: Internal Server Error for url: http://127.0.0.1:8000/generate_plan -无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。,1,True,11.32945990562439, -无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。,1,False,18.68914246559143,500 Server Error: Internal Server Error for url: http://127.0.0.1:8000/generate_plan -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。,1,True,14.857678651809692, -无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。,1,True,11.974151134490967, -无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。,1,True,15.218279838562012, -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。,1,True,15.252280473709106, -无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。,1,True,12.335286378860474, diff --git a/tools/test_validate/validation/20260224121211/test_summary.csv b/tools/test_validate/validation/20260224121211/test_summary.csv deleted file mode 100644 index a98d404c..00000000 --- a/tools/test_validate/validation/20260224121211/test_summary.csv +++ /dev/null @@ -1,10 +0,0 @@ -Instruction,Total Runs,Success Runs,Success Rate,Avg Latency -无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。,1,1,100.0%,16.06s -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。,1,0,0.0%,0.00s -无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。,1,1,100.0%,11.33s -无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。,1,0,0.0%,0.00s -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。,1,1,100.0%,14.86s -无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。,1,1,100.0%,11.97s -无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。,1,1,100.0%,15.22s -无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。,1,1,100.0%,15.25s -无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。,1,1,100.0%,12.34s diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.json deleted file mode 100644 index 05a3594c..00000000 --- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 100.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "人", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "人", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "人", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "context": { - "relative_refs": [ - { - "anchor": "front_building", - "relation": "front", - "distance_m": 12.0 - } - ] - }, - "plan_id": "36c0375e-4033-4016-9b0d-a79c5d5ccb35", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.png deleted file mode 100644 index 461968e0..00000000 Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的人并拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.json deleted file mode 100644 index 323fef11..00000000 --- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 100.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "杂物堆积", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "杂物堆积", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "杂物堆积", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "context": { - "relative_refs": [ - { - "anchor": "front_building", - "relation": "front", - "distance_m": 12.0 - } - ] - }, - "plan_id": "cfac2789-64b3-4669-a2e1-8f497ab86330", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.png deleted file mode 100644 index 91feffad..00000000 Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.json deleted file mode 100644 index 95d995d6..00000000 --- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 100.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "人", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "人", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "人", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "context": { - "relative_refs": [ - { - "anchor": "front_building", - "relation": "front", - "distance_m": 12.0 - } - ] - }, - "plan_id": "20182393-9686-4473-825f-c4b0a0ee3aab", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.png deleted file mode 100644 index 461968e0..00000000 Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.json deleted file mode 100644 index a15efff1..00000000 --- a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 100.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "打开的窗户", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "打开的窗户", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "打开的窗户", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "context": { - "relative_refs": [ - { - "anchor": "front_building", - "relation": "front", - "distance_m": 12.0 - } - ] - }, - "plan_id": "b98bf664-f8f6-4330-b22b-179424a135c1", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.png deleted file mode 100644 index da88f4cd..00000000 Binary files a/tools/test_validate/validation/20260224121211/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.json deleted file mode 100644 index df017b11..00000000 --- a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0, - "y": 0, - "z": 1000, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "大楼外围" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "目标类别", - "description": "", - "count": 1 - }, - "children": [ - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "目标类别", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - } - ] - }, - "plan_id": "d3dd62cb-0ae2-4103-9678-4a057dc93f40", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.png deleted file mode 100644 index eba34872..00000000 Binary files a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.json deleted file mode 100644 index 6635e057..00000000 --- a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "move_direction", - "params": { - "distance": "3米" - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "大楼外围" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "目标类别", - "count": 1 - }, - "children": [ - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "目标类别", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - } - ] - }, - "plan_id": "8fb53945-4c01-460e-9219-deb9d21cbe56", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.png deleted file mode 100644 index 5e97be50..00000000 Binary files a/tools/test_validate/validation/20260224121211/无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.json b/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.json deleted file mode 100644 index 4a3dee2a..00000000 --- a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "move_direction", - "params": { - "direction": "下", - "distance": "3米" - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "大楼外围" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "目标类别", - "count": 1 - }, - "children": [ - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "目标类别", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - } - ] - }, - "plan_id": "3e1c7b7c-8af1-450a-9981-be2bbb736b13", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.png b/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.png deleted file mode 100644 index 38d2839f..00000000 Binary files a/tools/test_validate/validation/20260224121211/无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224125506/instructions_backup.txt b/tools/test_validate/validation/20260224125506/instructions_backup.txt deleted file mode 100644 index cf77a61d..00000000 --- a/tools/test_validate/validation/20260224125506/instructions_backup.txt +++ /dev/null @@ -1,11 +0,0 @@ -无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。 -无人机当前在空中,回到广场,对戴帽子的人进行拍照。 -无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。 -无人机当前在地面,到广场查找绿色公交车,看见了拍个照片。 -无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。 -无人机当前在空中,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航。 -无人机当前在空中,往广场南边飞40米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。 -无人机当前在地面,到广场边上的施工区域内,发现有没带安全帽的飞近后拍照。 -无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。 -无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。 -无人机当前在空中,离白色衣服戴帽子的人太远了照片看不清,贴近到3米距离拍,拍完可以直接返航。 \ No newline at end of file diff --git a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.json b/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.json deleted file mode 100644 index f20fc89a..00000000 --- a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 0.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "穿红色衣服的人", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "穿红色衣服的人", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "穿红色衣服的人", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "plan_id": "1c13a764-87bb-426e-a8ec-79739a8e2c1d", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.png b/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.png deleted file mode 100644 index dcfa34eb..00000000 Binary files a/tools/test_validate/validation/20260224125506/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.json b/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.json deleted file mode 100644 index e2ac0b8f..00000000 --- a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0, - "y": 0, - "z": 100, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "object_detect", - "params": { - "target_class": "公交车", - "description": "", - "count": 1 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "公交车", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "公交车", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "未检测到目标" - } - } - ] - }, - "plan_id": "cf3f649f-03e2-4fe3-9d42-75290e00c09d", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.png b/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.png deleted file mode 100644 index 746e5fe1..00000000 Binary files a/tools/test_validate/validation/20260224125506/无人机当前在空中,去广场南边40米,对过往的公交车拍张照,然后返航。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.json b/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.json deleted file mode 100644 index 9d947429..00000000 --- a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0, - "y": 0, - "z": 1000, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "戴帽子的人", - "description": "", - "step_angle": 30.0, - "total_rotation": 180.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "戴帽子的人", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "戴帽子的人", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "plan_id": "fefcc502-0416-4b7d-979d-973aa5f9173f", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在空中,回到广场,对戴帽子的人进行拍照。" -} \ No newline at end of file diff --git a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.png b/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.png deleted file mode 100644 index 83ef278d..00000000 Binary files a/tools/test_validate/validation/20260224125506/无人机当前在空中,回到广场,对戴帽子的人进行拍照。/1.png and /dev/null differ diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在地面,起飞/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在地面,起飞/response.json deleted file mode 100644 index b287d3b3..00000000 --- a/tools/test_validate/validation/temporary/stage1_无人机当前在地面,起飞/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "on_ground", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "无人机当前在地面,起飞" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场/response.json deleted file mode 100644 index 6343aa0e..00000000 --- a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "无人机当前在空中,飞到广场" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场北边50米/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场北边50米/response.json deleted file mode 100644 index 0f7d49d6..00000000 --- a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到广场北边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "无人机当前在空中,飞到广场北边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到面前的大楼/response.json b/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到面前的大楼/response.json deleted file mode 100644 index 67d038a6..00000000 --- a/tools/test_validate/validation/temporary/stage1_无人机当前在空中,飞到面前的大楼/response.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": true, - "entities": { - "raw_prompt": "无人机当前在空中,飞到面前的大楼" - }, - "risk_flags": [ - "relative_reference_detected" - ], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_无空中,飞到广场/response.json b/tools/test_validate/validation/temporary/stage1_无空中,飞到广场/response.json deleted file mode 100644 index ab61cf65..00000000 --- a/tools/test_validate/validation/temporary/stage1_无空中,飞到广场/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene4", - "drone_state": "on_ground", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "无空中,飞到广场" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_起飞/response.json b/tools/test_validate/validation/temporary/stage1_起飞/response.json deleted file mode 100644 index 19c32ac5..00000000 --- a/tools/test_validate/validation/temporary/stage1_起飞/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "on_ground", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "起飞" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到南广场/response.json b/tools/test_validate/validation/temporary/stage1_飞到南广场/response.json deleted file mode 100644 index e35b15f3..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到南广场/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "in_air", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到南广场" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到大楼/response.json b/tools/test_validate/validation/temporary/stage1_飞到大楼/response.json deleted file mode 100644 index 4977c55e..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到大楼/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到大楼" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到学校/response.json b/tools/test_validate/validation/temporary/stage1_飞到学校/response.json deleted file mode 100644 index a3a37645..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到学校/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "in_air", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到学校" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到学校北边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到学校北边50米/response.json deleted file mode 100644 index 57dc9d43..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到学校北边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到学校北边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍/response.json deleted file mode 100644 index 50b0123d..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到宿舍/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "in_air", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到宿舍" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍北边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍北边50米/response.json deleted file mode 100644 index 1294ba3f..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到宿舍北边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到宿舍北边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍南边50米/response.json deleted file mode 100644 index 9e09d9c9..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到宿舍南边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边60米/response.json b/tools/test_validate/validation/temporary/stage1_飞到宿舍南边60米/response.json deleted file mode 100644 index 421d47f4..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到宿舍南边60米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到宿舍南边60米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场/response.json deleted file mode 100644 index c931498b..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到广场/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "in_air", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到广场" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场北边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场北边50米/response.json deleted file mode 100644 index 7aceb36b..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到广场北边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到广场北边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场南边/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场南边/response.json deleted file mode 100644 index 43f8ad2c..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到广场南边/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到广场南边" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场南边40米/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场南边40米/response.json deleted file mode 100644 index 13db964d..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到广场南边40米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到广场南边40米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场南边50米/response.json deleted file mode 100644 index 2fff8e82..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到广场南边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到广场南边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到广场西边/response.json b/tools/test_validate/validation/temporary/stage1_飞到广场西边/response.json deleted file mode 100644 index 82d4582f..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到广场西边/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到广场西边" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到建筑物A/response.json b/tools/test_validate/validation/temporary/stage1_飞到建筑物A/response.json deleted file mode 100644 index e524f45d..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到建筑物A/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "in_air", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到建筑物A" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到建筑物A南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到建筑物A南边50米/response.json deleted file mode 100644 index e1f750ae..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到建筑物A南边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到建筑物A南边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东侧30米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东侧30米/response.json deleted file mode 100644 index de812b36..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到研究所东侧30米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "in_air", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到研究所东侧30米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东边50米/response.json deleted file mode 100644 index a0352261..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到研究所东边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到研究所东边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米/response.json deleted file mode 100644 index 4217ceba..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到研究所东边60米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米的施工场所/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米的施工场所/response.json deleted file mode 100644 index 0d4caaa6..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到研究所东边60米的施工场所/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到研究所东边60米的施工场所" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究所南边50米/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究所南边50米/response.json deleted file mode 100644 index 89f2f424..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到研究所南边50米/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "scene1", - "drone_state": "in_air", - "intent_type": "generic_mission", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到研究所南边50米" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage1_飞到研究院/response.json b/tools/test_validate/validation/temporary/stage1_飞到研究院/response.json deleted file mode 100644 index 5c880900..00000000 --- a/tools/test_validate/validation/temporary/stage1_飞到研究院/response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "target_stage": 1, - "stage_name": "TaskUnderstanding", - "output": { - "scene_mode": "simple", - "drone_state": "in_air", - "intent_type": "single_action", - "requires_relative_target": false, - "entities": { - "raw_prompt": "飞到研究院" - }, - "risk_flags": [], - "constraints": {} - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage2_飞到广场东边50米/response.json b/tools/test_validate/validation/temporary/stage2_飞到广场东边50米/response.json deleted file mode 100644 index 01db533a..00000000 --- a/tools/test_validate/validation/temporary/stage2_飞到广场东边50米/response.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "target_stage": 2, - "stage_name": "ContextBinding", - "output": { - "location_context": "{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}", - "pattern_context": "无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。", - "rules_context": "", - "citations": { - "location": [ - "{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}", - "{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}", - "{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}" - ], - "pattern": [ - "无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。", - "无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。", - "地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。" - ], - "rules": [] - }, - "resolved_refs": {}, - "precomputed_waypoints": [ - { - "x": 150.0, - "y": 260.0, - "z": 0.0 - } - ], - "relative_refs": [], - "required_actions": [ - "Selector", - "Sequence", - "fly_to_waypoint", - "land", - "move_direction", - "object_detect", - "object_detected", - "rotate_search", - "take_photos", - "takeoff" - ] - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/stage3_飞到广场东边50米/response.json b/tools/test_validate/validation/temporary/stage3_飞到广场东边50米/response.json deleted file mode 100644 index cce7602b..00000000 --- a/tools/test_validate/validation/temporary/stage3_飞到广场东边50米/response.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "target_stage": 3, - "stage_name": "BTDraft", - "output": { - "system_prompt": "任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`", - "user_prompt": "飞到广场东边50米\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n---", - "allowed_nodes": { - "actions": [ - "Selector", - "Sequence", - "fly_to_waypoint", - "land", - "move_direction", - "object_detect", - "object_detected", - "rotate_search", - "take_photos", - "takeoff" - ], - "conditions": [ - "object_detected" - ] - }, - "llm_raw_json": { - "macro_tree": { - "root": { - "type": "Sequence", - "name": "FlyToSquareEast50", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint" - } - ] - } - }, - "parameter_requests": [ - { - "node": "fly_to_waypoint", - "intent": "前往广场东边50米", - "extracted_entities": { - "landmark": "广场", - "direction": "东", - "distance": 50.0 - } - } - ] - }, - "macro_tree": { - "root": { - "type": "Sequence", - "name": "FlyToSquareEast50", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint" - } - ] - } - }, - "parameter_requests": [ - { - "node": "fly_to_waypoint", - "intent": "前往广场东边50米", - "extracted_entities": { - "landmark": "广场", - "direction": "东", - "distance": 50.0 - } - } - ], - "reasoning_text": null, - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **in_air(空中)** 时,通常的流程包含:方向移动或直接飞行至目标点 -> (执行任务)。**严禁**使用 `system_checks` 与 `takeoff`。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"},\n {\"type\": \"action\", \"name\": \"rotate_search\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"前往广场中心\",\n \"extracted_entities\": {\n \"landmark\": \"广场中心\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`\n\n=== User Prompt ===\n飞到广场东边50米\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n---" - } -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/plan.png b/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/plan.png deleted file mode 100644 index dcfa34eb..00000000 Binary files a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/plan.png and /dev/null differ diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/process.log b/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/process.log deleted file mode 100644 index 5e86d323..00000000 --- a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/process.log +++ /dev/null @@ -1,4 +0,0 @@ -Prompt: 无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。 -Status: 200 -Latency: 15.905311346054077 -Response: {"root": {"type": "Sequence", "name": "MainTask", "children": [{"type": "action", "name": "system_checks", "params": {"check_level": "basic"}}, {"type": "action", "name": "takeoff", "params": {"altitude": 2.0}}, {"type": "action", "name": "fly_to_waypoint", "params": {"x": 0.0, "y": 0.0, "z": 0.0, "acceptance_radius": 2.0}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "穿红色衣服的人", "description": "", "step_angle": 10.0, "total_rotation": 360.0}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "穿红色衣服的人", "description": "", "count": 1}}, {"type": "action", "name": "take_photos", "params": {"target_class": "穿红色衣服的人", "description": "", "track_time": 10, "min_confidence": 0.7, "safe_distance": 10}}]}, "plan_id": "4dd158c1-c01d-4ea4-a8a9-ea7759af4185", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n---"} diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/response.json b/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/response.json deleted file mode 100644 index 58f6b74d..00000000 --- a/tools/test_validate/validation/temporary/无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。/response.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 0.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "穿红色衣服的人", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "穿红色衣服的人", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "穿红色衣服的人", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "plan_id": "4dd158c1-c01d-4ea4-a8a9-ea7759af4185", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,到广场查找穿红色衣服的人,找到后近距离拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。\n\n无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/plan.png b/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/plan.png deleted file mode 100644 index da88f4cd..00000000 Binary files a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/plan.png and /dev/null differ diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/process.log b/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/process.log deleted file mode 100644 index dbc36b36..00000000 --- a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/process.log +++ /dev/null @@ -1,4 +0,0 @@ -Prompt: 无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。 -Status: 200 -Latency: 16.045084238052368 -Response: {"root": {"type": "Sequence", "name": "MainTask", "children": [{"type": "action", "name": "system_checks", "params": {"check_level": "basic"}}, {"type": "action", "name": "takeoff", "params": {"altitude": 2.0}}, {"type": "action", "name": "fly_to_waypoint", "params": {"x": 0.0, "y": 0.0, "z": 100.0, "acceptance_radius": 2.0}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "打开的窗户", "description": "", "step_angle": 10.0, "total_rotation": 360.0}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "打开的窗户", "description": "", "count": 1}}, {"type": "action", "name": "take_photos", "params": {"target_class": "打开的窗户", "description": "", "track_time": 10, "min_confidence": 0.7, "safe_distance": 10}}]}, "context": {"relative_refs": [{"anchor": "front_building", "relation": "front", "distance_m": 12.0}]}, "plan_id": "55402b5a-07e5-41bc-ac73-48e959a512de", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---"} diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/response.json b/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/response.json deleted file mode 100644 index b22795c1..00000000 --- a/tools/test_validate/validation/temporary/无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。/response.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": 0.0, - "y": 0.0, - "z": 100.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "打开的窗户", - "description": "", - "step_angle": 10.0, - "total_rotation": 360.0 - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "打开的窗户", - "description": "", - "count": 1 - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "打开的窗户", - "description": "", - "track_time": 10, - "min_confidence": 0.7, - "safe_distance": 10 - } - } - ] - }, - "context": { - "relative_refs": [ - { - "anchor": "front_building", - "relation": "front", - "distance_m": 12.0 - } - ] - }, - "plan_id": "55402b5a-07e5-41bc-ac73-48e959a512de", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n## 任务意图标签\n- intent_type: `search_and_photo`\n\n=== User Prompt ===\n无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"广场\", \"coordinates\": {\"x\": 100, \"y\": 260, \"z\": 0}}}\n\n【任务模式】\n无人机已在空中,先往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n\n【规则知识】\n有明确目的地时使用 fly_to_waypoint;无明确目的地的立即返航才使用 return_emergency。\n\n当只有方向+距离且无具体地点名词时,优先使用 move_direction;不要生成 fly_to_waypoint。\n\n仅当用户明确要求人工确认时才注入 manual_confirmation 节点;否则禁止主动添加。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/plan.png b/tools/test_validate/validation/temporary/无人机当前在地面,起飞/plan.png deleted file mode 100644 index f043935c..00000000 Binary files a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/plan.png and /dev/null differ diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/process.log b/tools/test_validate/validation/temporary/无人机当前在地面,起飞/process.log deleted file mode 100644 index 1ee097c1..00000000 --- a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/process.log +++ /dev/null @@ -1,4 +0,0 @@ -Prompt: 无人机当前在地面,起飞 -Status: 200 -Latency: 1.738889217376709 -Response: {"root": {"type": "action", "name": "takeoff", "params": {"altitude": 10.0}}, "plan_id": "aad1912a-c27d-4abd-bf62-3179fd61d6aa", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n你是一个无人机简单指令执行规划器。\n假设输入一定是“单一原子动作即可完成”的简单指令。你的任务是输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构固定为:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root 节点必须是 action,禁止输出 Sequence/Selector/Parallel 等控制流节点。\n- params 只能包含该动作定义内的字段,禁止自定义字段。\n- 数值请使用数字类型(例如 10.0)。\n\n可用动作(simple 模式只允许从下列动作中选择其一):\n1) takeoff: {\"altitude\": float[1,100]}(仅当地面起飞)\n2) land: {\"mode\": \"current\"|\"home\"}\n3) fly_to_waypoint: {\"x\": number, \"y\": number, \"z\": number, \"acceptance_radius\": number(可选)}\n4) move_direction: {\"direction\": \"north\"|\"south\"|\"east\"|\"west\"|\"forward\"|\"backward\"|\"left\"|\"right\"|\"up\"|\"down\", \"distance\": number}\n5) rotate: {\"angle\": number, \"angular_velocity\": number(可选)}\n6) loiter: {\"duration\": number}\n7) system_checks: {\"check_level\":\"basic\"|\"comprehensive\"}(仅当指令明确在地面且用户要求自检)\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “往北飞50米” → {\"root\":{\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"north\",\"distance\":50.0}}}\n- “飞到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n\n\n=== User Prompt ===\n无人机当前在地面,起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"} diff --git a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/response.json b/tools/test_validate/validation/temporary/无人机当前在地面,起飞/response.json deleted file mode 100644 index 02395b01..00000000 --- a/tools/test_validate/validation/temporary/无人机当前在地面,起飞/response.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "root": { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 10.0 - } - }, - "plan_id": "aad1912a-c27d-4abd-bf62-3179fd61d6aa", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n你是一个无人机简单指令执行规划器。\n假设输入一定是“单一原子动作即可完成”的简单指令。你的任务是输出一个严格的JSON对象。\n\n输出要求(必须遵守):\n- 只输出一个JSON对象,不要任何解释或多余文本。\n- JSON结构固定为:\n{\"root\":{\"type\":\"action\",\"name\":\"\",\"params\":{...}}}\n- root 节点必须是 action,禁止输出 Sequence/Selector/Parallel 等控制流节点。\n- params 只能包含该动作定义内的字段,禁止自定义字段。\n- 数值请使用数字类型(例如 10.0)。\n\n可用动作(simple 模式只允许从下列动作中选择其一):\n1) takeoff: {\"altitude\": float[1,100]}(仅当地面起飞)\n2) land: {\"mode\": \"current\"|\"home\"}\n3) fly_to_waypoint: {\"x\": number, \"y\": number, \"z\": number, \"acceptance_radius\": number(可选)}\n4) move_direction: {\"direction\": \"north\"|\"south\"|\"east\"|\"west\"|\"forward\"|\"backward\"|\"left\"|\"right\"|\"up\"|\"down\", \"distance\": number}\n5) rotate: {\"angle\": number, \"angular_velocity\": number(可选)}\n6) loiter: {\"duration\": number}\n7) system_checks: {\"check_level\":\"basic\"|\"comprehensive\"}(仅当指令明确在地面且用户要求自检)\n\n示例:\n- “起飞到10米” → {\"root\":{\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}}}\n- “往北飞50米” → {\"root\":{\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"north\",\"distance\":50.0}}}\n- “飞到(120,80,20)” → {\"root\":{\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":120.0,\"y\":80.0,\"z\":20.0,\"acceptance_radius\":2.0}}}\n\n\n=== User Prompt ===\n无人机当前在地面,起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/起飞/plan.png b/tools/test_validate/validation/temporary/起飞/plan.png deleted file mode 100644 index 0da2b820..00000000 Binary files a/tools/test_validate/validation/temporary/起飞/plan.png and /dev/null differ diff --git a/tools/test_validate/validation/temporary/起飞/process.log b/tools/test_validate/validation/temporary/起飞/process.log deleted file mode 100644 index c3ec7a15..00000000 --- a/tools/test_validate/validation/temporary/起飞/process.log +++ /dev/null @@ -1,4 +0,0 @@ -Prompt: 起飞 -Status: 200 -Latency: 38.906864643096924 -Response: {"root": {"type": "Sequence", "name": "TakeoffAndPatrolBuilding", "children": [{"type": "action", "name": "system_checks", "params": {"check_level": "basic"}}, {"type": "action", "name": "takeoff", "params": {"altitude": 2.0}}, {"type": "Sequence", "name": "FlyAndDetectWindows", "children": [{"type": "action", "name": "fly_to_waypoint", "params": {"x": -24.0, "y": 241.8, "z": 12.0, "acceptance_radius": 2.0}}, {"type": "Parallel", "name": "PatrolAndDetectWindows", "params": {"policy": "success_on_one"}, "children": [{"type": "action", "name": "fly_sequence", "params": {"waypoints": [{"x": -24.0, "y": 241.8, "z": 12.0}, {"x": -108.5, "y": 241.8, "z": 12.0}, {"x": -108.5, "y": 289.8, "z": 12.0}, {"x": -24.0, "y": 292.8, "z": 12.0}, {"x": -24.0, "y": 241.8, "z": 12.0}], "coordinate_frame": "local_enu"}}, {"type": "decorator", "name": "SuccessIsFailure", "child": {"type": "Sequence", "name": "DetectOpenWindowsWhileFlying", "children": [{"type": "action", "name": "object_detect", "params": {"target_class": "window", "description": "打开的窗户"}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "window", "description": "打开的窗户"}}, {"type": "action", "name": "take_photos", "params": {"target_class": "window", "description": "打开的窗户", "track_time": 10.0}}]}}]}]}]}, "plan_id": "e1864626-d71c-49d6-9bc6-fb3d2181dd73", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`\n\n=== User Prompt ===\n起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---"} diff --git a/tools/test_validate/validation/temporary/起飞/response.json b/tools/test_validate/validation/temporary/起飞/response.json deleted file mode 100644 index a7cabfe5..00000000 --- a/tools/test_validate/validation/temporary/起飞/response.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "TakeoffAndPatrolBuilding", - "children": [ - { - "type": "action", - "name": "system_checks", - "params": { - "check_level": "basic" - } - }, - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 2.0 - } - }, - { - "type": "Sequence", - "name": "FlyAndDetectWindows", - "children": [ - { - "type": "action", - "name": "fly_to_waypoint", - "params": { - "x": -24.0, - "y": 241.8, - "z": 12.0, - "acceptance_radius": 2.0 - } - }, - { - "type": "Parallel", - "name": "PatrolAndDetectWindows", - "params": { - "policy": "success_on_one" - }, - "children": [ - { - "type": "action", - "name": "fly_sequence", - "params": { - "waypoints": [ - { - "x": -24.0, - "y": 241.8, - "z": 12.0 - }, - { - "x": -108.5, - "y": 241.8, - "z": 12.0 - }, - { - "x": -108.5, - "y": 289.8, - "z": 12.0 - }, - { - "x": -24.0, - "y": 292.8, - "z": 12.0 - }, - { - "x": -24.0, - "y": 241.8, - "z": 12.0 - } - ], - "coordinate_frame": "local_enu" - } - }, - { - "type": "decorator", - "name": "SuccessIsFailure", - "child": { - "type": "Sequence", - "name": "DetectOpenWindowsWhileFlying", - "children": [ - { - "type": "action", - "name": "object_detect", - "params": { - "target_class": "window", - "description": "打开的窗户" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "window", - "description": "打开的窗户" - } - }, - { - "type": "action", - "name": "take_photos", - "params": { - "target_class": "window", - "description": "打开的窗户", - "track_time": 10.0 - } - } - ] - } - } - ] - } - ] - } - ] - }, - "plan_id": "e1864626-d71c-49d6-9bc6-fb3d2181dd73", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt (Macro) ===\n任务:根据用户的自然语言指令,规划无人机的宏观执行流程结构,并提取执行该流程所需的外部参数。\n\n你现在是第一阶段“宏观规划与意图提取”AI。你只需要做两件事:\n1. 分析意图并排出正确的骨架树(不需要填充任何 parameters/params)。\n2. 从用户指令中提取出需要查询确切位置或目标属性的实体清单(如地标、方向、距离、识别目标)。\n\n**严格约束**:仅输出符合以下 JSON 格式的数据,**禁止**包含任何外部分析、Markdown 标记外的纯文本,或者多余的字段。\n\n输出格式约定:\n```json\n{\n \"macro_tree\": { ... 纯结构树 ... },\n \"parameter_requests\": [\n {\n \"node\": \"节点名称\",\n \"intent\": \"对该节点意图的简短描述\",\n \"extracted_entities\": {\n \"实体key\": \"实体value\"\n }\n }\n ]\n}\n```\n\n## 一、核心节点定义(裁剪后)\n#### 1. 可用节点定义 (必须遵守)\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"desc\": \"起飞并达到指定高度\"\n },\n {\n \"name\": \"land\",\n \"desc\": \"降落到地面\"\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"desc\": \"飞往指定坐标\"\n },\n {\n \"name\": \"move_direction\",\n \"desc\": \"向指定方向移动(东西南北等)\"\n },\n {\n \"name\": \"rotate_search\",\n \"desc\": \"原地旋转并搜索目标\"\n },\n {\n \"name\": \"object_detect\",\n \"desc\": \"检测视野内的目标\"\n },\n {\n \"name\": \"take_photos\",\n \"desc\": \"对目标进行拍照\"\n }\n ],\n \"conditions\": [\n {\n \"name\": \"object_detected\",\n \"desc\": \"判断视野中是否检测到目标\"\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"desc\": \"顺序执行子节点,全成功则成功\"\n },\n {\n \"name\": \"Selector\",\n \"desc\": \"执行子节点到第一个成功为止\"\n },\n {\n \"name\": \"Parallel\",\n \"desc\": \"同时执行子节点\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"desc\": \"将子节点的成功反转为失败\"\n }\n ]\n}\n```\n\n## 三、顶层 JSON 结构规范与模板\n\n当无人机状态为 **on_ground(地面)** 时,通常的流程包含:`system_checks` -> `takeoff` -> (飞行至目标点等后续动作)。\n如果指令要求“沿外围”,需使用 `fly_sequence`。\n\n你必须同时输出 `macro_tree`(必须剔除 params)和 `parameter_requests` 两个字段。\n结构范例(注意:此仅为结构展示,不代表真实逻辑):\n\n```json\n{\n \"macro_tree\": {\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\": \"action\", \"name\": \"system_checks\"},\n {\"type\": \"action\", \"name\": \"takeoff\"},\n {\"type\": \"action\", \"name\": \"fly_to_waypoint\"}\n ]\n }\n },\n \"parameter_requests\": [\n {\n \"node\": \"fly_to_waypoint\",\n \"intent\": \"飞行到目标点\",\n \"extracted_entities\": {\n \"landmark\": \"广场西边\"\n }\n }\n ]\n}\n```\n\n## 六、高频错误规避(硬规则,必须遵守)\n\n0. 严格 JSON 输出:\n- 只能输出一个 JSON 对象。\n- 禁止输出 Markdown、解释、注释、代码块标记。\n- 禁止在 JSON 中出现 // 或 /* */ 注释,禁止尾随逗号。\n\n1. 控制流节点的 type 只能是 \"Sequence\" / \"Selector\" / \"Parallel\"。\n\n2. 人工确认节点(manual_confirmation):\n- 必须添加:仅当指令明确包含“我确认 / 等待确认 / 经允许 / 我通过后 / 允许后”等人工介入关键词时,必须在相应动作前添加 manual_confirmation。\n- 严禁添加:指令未提及人工确认时,严禁主动添加 manual_confirmation。\n\n3. 搜索-条件-拍照链路:\n- 若出现 condition: object_detected,则在其前必须有搜索类 action(优先 rotate_search;仅当需大范围移动时用 search_pattern)。\n- 若使用 rotate_search 或 object_detect,则后续必须出现 object_detected(同 target_class)。\n\n4. 当前位置任务:\n- 指令明确“在当前位置 / 原地 / 不用过去 / 就在这”时,无需 fly_to_waypoint。\n\n5. 严格区分无人机状态:\n- 指令明确“当前在空中”:严禁使用 system_checks 与 takeoff。\n- 指令明确“当前在地面”:如需要飞行任务,优先 system_checks -> takeoff 再执行后续动作。\n\n6. fly_to_waypoint 与 return_emergency 辨析:\n- 若指令包含具体目的地(例如“回到广场 / 飞回大门 / 去机库”(即使包含“紧急”二字)),必须使用 fly_to_waypoint,绝对禁止使用 return_emergency。\n- return_emergency 仅用于“无明确目的地”的立即返航(默认回起飞点)。\n\n7. approach_target 使用:\n- 指令提及“靠近 / 飞近 / 贴近 / 距离XX米拍清楚”时,必须在 take_photos 之前使用 approach_target。\n- 未提及上述关键词时,严禁添加 approach_target。\n\n8. 方向移动优先:\n- 当指令仅为“方向 + 距离”且没有具体地点名词时(例如“往东 60 米”),必须使用 move_direction,严禁使用 fly_to_waypoint 或任何地点坐标。\n\n9. loiter 参数名:\n- loiter 的时间参数一律使用 params.duration(单位:秒),禁止使用 time。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n\n本系统统一使用东南天(ENU)坐标系:\n- X轴:正方向 东(East),负方向 西(West)\n- Y轴:正方向 南(South),负方向 北(North)\n- Z轴:正方向 上(Up),负方向 下(Down)\n\n仅当指令涉及“具体地点 + 方向 + 距离”的偏移位置时,才计算绝对坐标并使用 fly_to_waypoint:\n- 单一方向(东/西/南/北/上/下):必须先调用 calc_offset_enu,再使用 fly_to_waypoint。\n- 中文复合方位(东南/西北/南偏东10度 等):必须先调用 calc_offset_esu_direction_text,再使用 fly_to_waypoint。\n- 禁止将复合方位简化为单一方向。\n\n当指令只有“方向 + 距离”且没有具体地点名词时,禁止调用 calc_offset_enu,必须使用 move_direction。\n\n## 八、输出要求\n仅输出 1 个严格符合上述所有规则的 JSON 对象。\n\n#### 场景 7:空中上升后沿建筑外围侦察(Sequence + Selector)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有人,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,无需自检与起飞。先向上移动3米(仅方向+距离,使用`move_direction`)。随后“边飞边判断”:用`Parallel`并行执行`fly_sequence`与持续检测分支。检测分支使用`object_detect` + `object_detected` + `take_photos`,再用`SuccessIsFailure`保证不会提前结束并行;并行策略为`success_on_one`,当巡查飞行完成即结束任务。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndPatrolPerimeter\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"up\",\n \"distance\": 3.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetect\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAndPhotoWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"建筑外围人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 8:地面起飞到楼前12米高度并沿外围查找杂物(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有的杂物堆积并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,需自检后起飞。指令是到具体地点且明确高度,使用`fly_sequence`沿外围巡查,所有航点设置为12米高度(`depth`=12)。为满足“边飞边判断”,使用`Parallel`并行飞行与检测,检测分支持续执行`object_detect` + `object_detected` + `take_photos`,用`SuccessIsFailure`避免提前结束。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 9:地面到12米绕外围查看打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有打开的窗户,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,先自检起飞。随后使用`fly_sequence`沿外围绕飞,航点高度为12米(`depth`=12)。同时并行执行检测分支,发现打开窗户就拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 10:地面到12米沿外围查找打开的窗户(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围查找所有打开的窗户并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后使用`fly_sequence`沿外围巡查(`depth`=12),并行持续检测打开的窗户并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectAllOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 11:空中上升后绕外围侦察打开窗户(Sequence)\n**指令**:“无人机当前在空中,再往上飞3米,接着绕这栋楼外围侦察有没有打开的窗户,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先上升3米。随后并行执行绕飞巡查与检测,发现打开窗户立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"RiseAndDetectOpenWindows\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"up\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectOpenWindows\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectOpenWindowsWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"window\",\"description\":\"打开的窗户\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 12:地面到12米绕外围巡视杂物堆积(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围巡视杂物堆积现象,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测杂物堆积并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoGarbageObserve\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbageObserve\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 13:空中下降后绕外围侦察杂物堆积(Sequence)\n**指令**:“无人机当前在空中,往下飞3米,接着绕这栋楼外围侦察有没有杂物堆积,看到了就拍照传回来。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在空中,先下降3米。随后并行执行绕飞巡查与检测,发现杂物堆积立即拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"DescendAndDetectGarbage\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"move_direction\",\"params\":{\"direction\":\"down\",\"distance\":3.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectGarbage\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 241.8},\n {\"x\": -108.5, \"y\": 289.8},\n {\"x\": -24.0, \"y\": 292.8},\n {\"x\": -24.0, \"y\": 241.8}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectGarbageWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"garbage\",\"description\":\"杂物堆积\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 14:地面到12米绕外围查看是否有人(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,绕着外围看有没有人,发现则进行拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后沿外围绕飞(`depth`=12),并行检测人员并拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 15:地面到12米沿外围逆时针查找人员(Sequence)\n**指令**:“无人机当前在地面,去面前大楼的12米高处,沿着外围逆时针查找所有的人并拍照。”\n**参考信息**:面前的大楼外围四个点东南天坐标系坐标:A(-24.00, 241.80),B(-108.50, 241.80),C(-108.50, 289.80),D(-24.00, 292.80)。\n**思路**:无人机在地面,起飞后按逆时针顺序巡查外围(示例航点顺序:A→D→C→B→A),并行检测人员与拍照。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlyPerimeterCounterClockwiseAndPhotoPerson\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Parallel\",\n \"name\": \"PatrolCCWAndDetectPerson\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": [\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 292.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 289.8, \"depth\": 12.0},\n {\"x\": -108.5, \"y\": 241.8, \"depth\": 12.0},\n {\"x\": -24.0, \"y\": 241.8, \"depth\": 12.0}\n ],\n \"coordinate_frame\": \"local_enu\"\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"DetectPersonWhileFlying\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"人员\",\"track_time\":10.0}}\n ]\n }\n }\n ]\n }\n ]\n }\n}\n```\n\n## 任务意图标签\n- intent_type: `generic_mission`\n\n=== User Prompt ===\n起飞\n\n---\n参考知识:\n【地点知识】\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n\n【任务模式】\n无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。\n\n地面起飞后到面前大楼约12米高度,沿外围巡查打开窗户;如发现窗户则拍照回传。\n\n无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。\n---" -} \ No newline at end of file diff --git a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/plan.png b/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/plan.png deleted file mode 100644 index 639983a5..00000000 Binary files a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/plan.png and /dev/null differ diff --git a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/process.log b/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/process.log deleted file mode 100644 index a470a2da..00000000 --- a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/process.log +++ /dev/null @@ -1,4 +0,0 @@ -Prompt: 起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航 -Status: 200 -Latency: 12.107423305511475 -Response: {"root": {"type": "Sequence", "name": "MainTask", "children": [{"type": "action", "name": "takeoff", "params": {"altitude": 1.0}}, {"type": "action", "name": "move_direction", "params": {"direction": "forward", "distance": 1.0}}, {"type": "action", "name": "rotate_search", "params": {"target_class": "person", "description": "穿迷彩衣服的人"}}, {"type": "condition", "name": "object_detected", "params": {"target_class": "person", "description": "穿迷彩衣服的人"}}, {"type": "action", "name": "approach_target", "params": {"target_class": "person", "description": "穿迷彩衣服的人", "stop_distance": 5.0}}, {"type": "action", "name": "return_emergency", "params": {"reason": "任务完成"}}]}, "plan_id": "fd63525f-41b0-46e4-8405-09278be536ac", "visualization_url": "/static/py_tree.png", "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---"} diff --git a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/response.json b/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/response.json deleted file mode 100644 index 132f8050..00000000 --- a/tools/test_validate/validation/temporary/起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航/response.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "root": { - "type": "Sequence", - "name": "MainTask", - "children": [ - { - "type": "action", - "name": "takeoff", - "params": { - "altitude": 1.0 - } - }, - { - "type": "action", - "name": "move_direction", - "params": { - "direction": "forward", - "distance": 1.0 - } - }, - { - "type": "action", - "name": "rotate_search", - "params": { - "target_class": "person", - "description": "穿迷彩衣服的人" - } - }, - { - "type": "condition", - "name": "object_detected", - "params": { - "target_class": "person", - "description": "穿迷彩衣服的人" - } - }, - { - "type": "action", - "name": "approach_target", - "params": { - "target_class": "person", - "description": "穿迷彩衣服的人", - "stop_distance": 5.0 - } - }, - { - "type": "action", - "name": "return_emergency", - "params": { - "reason": "任务完成" - } - } - ] - }, - "plan_id": "fd63525f-41b0-46e4-8405-09278be536ac", - "visualization_url": "/static/py_tree.png", - "final_prompt": "=== System Prompt ===\n任务:根据用户任意任务指令,生成结构化可执行的无人机行为树(Pytree)JSON。**仅输出单一JSON对象,无任何自然语言、注释或额外内容**。\n\n## 一、核心节点定义(格式不可修改,确保后端解析)\n#### 1. 可用节点定义 (必须遵守)\n你必须严格从以下JSON定义的列表中选择节点构建行为树,不允许使用未定义节点:\n```json\n{\n \"actions\": [\n {\n \"name\": \"takeoff\",\n \"params\": {\n \"altitude\": \"float[1,100],默认2\"\n }\n },\n {\n \"name\": \"land\",\n \"params\": {\n \"mode\": \"'current'/'home'\"\n }\n },\n {\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"acceptance_radius\": \"默认2.0\",\n \"desc\": \"仅当指令提及具体地点(如'去广场'、'去大门')或需计算明确坐标时使用\"\n }\n },\n {\n \"name\": \"fly_sequence\",\n \"params\": {\n \"waypoints\": \"list[dict] (e.g. [{'x':10,'y':20,'depth':5}, ...];depth可选,不填则保持当前高度)\",\n \"coordinate_frame\": \"'global'/'local_enu'(global:经纬度, local_enu:以起飞点为原点的东南天坐标系)\",\n \"speed\": \"float,可选\"\n }\n },\n {\n \"name\": \"move_direction\",\n \"params\": {\n \"direction\": \"north/south/east/west/forward/backward/left/right\",\n \"distance\": \"[1,10000],缺省则持续移动\",\n \"speed\": \"float,可选\",\n \"desc\": \"当指令仅包含'往东/西...飞xx米'且无具体地点名词时,必须使用此节点\"\n }\n },\n {\n \"name\": \"approach_target\",\n \"params\": {\n \"target_class\": \"string,要趋近的目标类别\",\n \"description\": \"string,可选,目标属性描述\",\n \"stop_distance\": \"float,期望的最终停止距离\",\n \"speed\": \"float,可选,期望的逼近速度\"\n }\n },\n {\n \"name\": \"rotate\",\n \"params\": {\n \"angle\": \"float,无人机自身旋转角度(正数逆时针,负数顺时针)\",\n \"angular_velocity\": \"rad/s,旋转角速度\"\n }\n },\n {\n \"name\": \"rotate_search\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"string,可选,目标属性描述\",\n \"step_angle\": \"float,可选,每一步旋转的角度\",\n \"total_rotation\": \"float,可选,总共旋转搜索的角度\"\n }\n },\n {\n \"name\": \"manual_confirmation\",\n \"params\": {}\n },\n {\n \"name\": \"loiter\",\n \"params\": {\n \"duration\": \"[1,600]秒/until_condition:可选\"\n }\n },\n {\n \"name\": \"object_detect\",\n \"params\": {\n \"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,garbage\",\n \"description\": \"可选,\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"search_pattern\",\n \"params\": {\n \"pattern_type\": \"spiral/grid\",\n \"center_x\": \"±10000\",\n \"center_y\": \"±10000\",\n \"center_z\": \"[1,5000]\",\n \"radius\": \"[5,1000]\",\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n },\n {\n \"name\": \"track_object\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n },\n {\n \"name\": \"deliver_payload\",\n \"params\": {\n \"payload_type\": \"string\",\n \"release_altitude\": \"[2,100]默认5\"\n }\n },\n {\n \"name\": \"system_checks\",\n \"params\": {\n \"check_level\": \"basic/comprehensive,只能在起飞takeoff节点前使用,空中无需使用该节点\"\n }\n },\n {\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"string,此节点仅用于【无明确目的地】的立即返航(默认回起飞点)。若指令包含“回到xx地”、“去xx地”(即使包含“紧急”二字),**严禁**使用此节点,必须使用fly_to_waypoint\"\n }\n },\n {\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"同object_detect\",\n \"description\": \"可选,目标属性\",\n \"track_time\": \"[1,600]秒(必传,不可用'duration')\",\n \"min_confidence\": \"[0.5,1.0]默认0.7\",\n \"safe_distance\": \"[2,50]默认10\"\n }\n }\n ],\n \"conditions\": [\n {\n \"name\": \"at_waypoint\",\n \"params\": {\n \"x\": \"±10000\",\n \"y\": \"±10000\",\n \"z\": \"[1,5000]\",\n \"tolerance\": \"默认3.0\"\n }\n },\n {\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"同object_detect(必传)\",\n \"description\": \"可选,目标属性\",\n \"count\": \"默认1\"\n }\n }\n ],\n \"control_flow\": [\n {\n \"name\": \"Sequence\",\n \"params\": {},\n \"children\": \"子节点数组(按序执行,全成功则成功)\"\n },\n {\n \"name\": \"Selector\",\n \"params\": {\n \"memory\": \"默认true\"\n },\n \"children\": \"子节点数组(执行到成功为止)\"\n },\n {\n \"name\": \"Parallel\",\n \"params\": {\n \"policy\": \"all_success/success_on_one\"\n },\n \"children\": \"子节点数组(同时执行,默认all_success)\"\n }\n ],\n \"decorators\": [\n {\n \"name\": \"SuccessIsFailure\",\n \"params\": {},\n \"child\": \"单一子节点(将子节点的成功结果反转为失败)\"\n }\n ]\n}\n```\n\n## 二、节点必填字段(后端Schema强制要求,缺一验证失败)\n每个节点必须包含以下字段,字段名/类型不可自定义:\n1. **`type`**: \n - 动作节点→`\"action\"`,条件节点→`\"condition\"`,控制流节点→`\"Sequence\"`/`\"Selector\"`/`\"Parallel\"`,装饰器节点→`\"decorator\"`;\n2. **`name`**:必须是上述JSON中定义的`name`值;\n3. **`params`**:严格匹配上述节点的`params`定义,无自定义参数;\n4. **`children`**:仅控制流节点必含(子节点数组);\n5. **`child`**:仅装饰器节点必含(单一子节点对象,非数组)。\n\n## 三、标准任务结构模板(单次起降流程)\n当无人机在地面时,大多数任务应遵循“起飞 -> 移动 -> 条件判断 -> 执行 -> 返航/降落”的单次闭环流程,参考结构如下:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, // 接近目标区域\n // --- 核心任务区 (根据指令替换) ---\n // 默认不需要降落节点,除非用户明确要求\n ]\n }\n}\n```\n而当无人机在空中时,则无需system_checks与takeoff环节,直接执行用户任务即可\n\n## 四、场景示例(请灵活参考)\n\n#### 场景 1:线性搜索任务(Sequence + Selector)\n**指令**:“无人机当前在地面,去研究所正大门,搜索扎辫子女子,找到后拍照。”\n**思路**:无人机在地面,则需要先自检然后起飞;获取研究所正大门坐标,调用fly_to_waypoint节点到达该地;然后调用rotate_search节点搜索目标女子,再使用object_detected条件节点,这样就可以作为take_photos节点的依据。\n**结构**:Sequence (按顺序执行)\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainSearchTask\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}, \n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\n \"type\": \"Selector\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"Sequence\",\n \"name\": \"PhotoIfFound\",\n \"children\": [\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"person\",\"description\":\"扎辫子女子\",\"track_time\":10.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}} // 未发现时的备选动作\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 2:带中断逻辑的巡逻(Selector 示例)\n**指令**:“无人机当前在地面,飞往航点A。如果途中发现可疑人员,则悬停。”\n**参考知识**:航点A的坐标(x:100.0,y:50.0)\n**思路**:无人机在地面,则需要先自检然后起飞;获取航点A的坐标,调用fly_to_waypoint节点到达该地;但同时需要注意看到可疑人员需要悬停,意味着一边进行识别,识别到进行悬停,因此要在object_detect节点后有一个object_detected条件节点,作为悬停的条件。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"basic\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\n \"type\": \"Selector\",\n \"name\": \"FlyOrDetect\",\n \"children\": [\n {\n \"type\": \"Sequence\", \n \"name\": \"InterruptionLogic\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"object_detect\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"person\"}},\n {\"type\":\"action\",\"name\":\"loiter\",\"params\":{\"duration\":5.0}}\n ]\n },\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":100.0,\"y\":50.0,\"z\":10.0}}\n ]\n }\n ]\n }\n}\n```\n\n#### 场景 3:长期监控任务(Parallel 示例)\n**指令**:“无人机当前在空中,往广场西边飞200米,持续监控5分钟,发现人就拍照告诉我,到时间可以返航。”\n**参考知识**:广场西边200米的坐标(x:50.0,y:50.0,z:10.0)\n**思路**:无人机在空中,直接前往目标点;到达后需要并行执行两件事:1. 倒计时5分钟(主控时间);2. 持续检测人并拍照(从属任务)。\n使用`Parallel`节点并设置策略为`success_on_one`,这样当倒计时(loiter)结束返回成功时,整个并行节点就会成功结束,从而强制停止拍照循环。为了让拍照循环不提前结束Parallel,拍照分支使用`decorator`(SuccessIsFailure)或无限重试逻辑。\n**结构**:\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"MainTask\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"fly_to_waypoint\",\n \"params\": {\n \"x\": 50.0,\n \"y\": 50.0,\n \"z\": 10.0\n }\n },\n {\n \"type\": \"Parallel\",\n \"name\": \"MonitorAndPhoto\",\n \"params\": {\n \"policy\": \"success_on_one\"\n },\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"loiter\",\n \"params\": {\n \"time\": 300\n }\n },\n {\n \"type\": \"decorator\",\n \"name\": \"SuccessIsFailure\",\n \"child\": {\n \"type\": \"Sequence\",\n \"name\": \"CheckAndPhoto\",\n \"children\": [\n {\n \"type\": \"action\",\n \"name\": \"object_detect\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"condition\",\n \"name\": \"object_detected\",\n \"params\": {\n \"target_class\": \"person\"\n }\n },\n {\n \"type\": \"action\",\n \"name\": \"take_photos\",\n \"params\": {\n \"target_class\": \"person\"\n }\n }\n ]\n }\n }\n ]\n },\n {\n \"type\": \"action\",\n \"name\": \"return_emergency\",\n \"params\": {\n \"reason\": \"任务完成\"\n }\n }\n ]\n }\n}\n```\n\n#### 场景 4:交互式确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在空中,搜索小汽车,搜索到了我确认后再决定要不要拍照。”\n**思路**:无人机已在空中,无需起飞,直接进行搜索。首先使用`rotate_search`主动搜索目标,配合`object_detected`条件节点确认目标是否被检测到。检测到后,执行`manual_confirmation`节点等待用户确认。只有用户确认通过(返回Success),才会继续执行后续的`take_photos`动作。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchConfirmPhoto\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}}\n ]\n }\n}\n```\n\n#### 场景 5:后置确认任务(Sequence + Manual Confirmation)\n**指令**:“无人机当前在地面,搜索小汽车,搜索到了拍张照,我确认后再决定要不要返航”\n**思路**:无人机在地面,需起飞。搜索小汽车(`rotate_search` + `object_detected`)。搜索到后,先执行拍照(`take_photos`)。之后执行人工确认(`manual_confirmation`),确认通过后才执行返航(`return_emergency`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"SearchPhotoConfirmReturn\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"system_checks\",\"params\":{\"check_level\":\"comprehensive\"}},\n {\"type\":\"action\",\"name\":\"takeoff\",\"params\":{\"altitude\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"take_photos\",\"params\":{\"target_class\":\"car\",\"description\":\"小汽车\"}},\n {\"type\":\"action\",\"name\":\"manual_confirmation\",\"params\":{}},\n {\"type\":\"action\",\"name\":\"return_emergency\",\"params\":{\"reason\":\"确认后返航\"}}\n ]\n }\n}\n```\n\n#### 场景 6:移动后条件降落(Sequence)\n**指令**:“无人机当前在空中,紧急回到广场,看见了红绿灯之后直接降落。”\n**参考知识**:广场坐标(x:0.0, y:0.0, z:10.0)\n**思路**:无人机在空中,无需起飞。首先飞往广场(`fly_to_waypoint`),严禁使用`return_emergency`。到达后,为了满足“看见红绿灯”的条件,必须先执行主动搜索(`rotate_search`)。一旦检测到红绿灯(`object_detected`),即执行降落(`land`)。\n**结构**:Sequence\n```json\n{\n \"root\": {\n \"type\": \"Sequence\",\n \"name\": \"FlySearchLand\",\n \"children\": [\n {\"type\":\"action\",\"name\":\"fly_to_waypoint\",\"params\":{\"x\":0.0,\"y\":0.0,\"z\":10.0}},\n {\"type\":\"action\",\"name\":\"rotate_search\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"condition\",\"name\":\"object_detected\",\"params\":{\"target_class\":\"traffic_light\",\"description\":\"红绿灯\"}},\n {\"type\":\"action\",\"name\":\"land\",\"params\":{\"mode\":\"current\"}}\n ]\n }\n}\n```\n\n## 六、高频错误规避\n1. 控制流节点的 `type` 必须是 `\"Sequence\"`, `\"Selector\"` 或 `\"Parallel\"`\n2. **人工确认节点 (`manual_confirmation`) 使用原则**:\n - **必须添加**:仅当指令中明确包含“我确认”、“等待确认”、“经允许”、“我通过后”等人工介入关键词时,**必须**在相应动作前添加此节点。\n - **严禁添加**:若指令未提及上述关键词,**严禁**主动添加此节点(即使是拍照、返航或降落等动作,只要用户没说要确认,就直接执行)。\n3. 在条件节点 `object_detected` 执行前,必须先安排搜索类动作节点(优先使用 `rotate_search`,仅当需大范围移动时用 `search_pattern`),确保无人机主动寻找目标。\n4. 当使用rotate_search或者object_detect节点时,必须有object_detected节点\n5. 用户指令中要求在当前位置执行任务时,无需fly_to_waypoint节点\n6. **严格区分无人机状态**:当用户指令明确无人机在**空中**时,严禁使用system_checks与takeoff节点;仅当用户指令明确在**地面**时,才可使用这两个节点\n7. **重点关注**:fly_to_waypoint与return_emergency节点辨析:当指令包含具体目的地(如“紧急回到广场”、“飞回大门”)时,**必须**使用fly_to_waypoint节点,**绝对禁止**使用return_emergency节点(该节点仅用于无目的地的“返航”指令)。\n8. 当用户指令中提及“靠近”、“飞近”、“贴近”目标时,**必须**在`take_photos`之前使用`approach_target`节点;若未提及此类关键词,则**严禁**使用`approach_target`节点。\n9. **方向移动优先原则**:当指令为“快速去往东边100米”,直接使用 `move_direction` 节点+距离参数,严禁使用fly_to_waypoint\n10. **无地点名词禁止飞点**:当指令仅包含“方向 + 距离”且**没有具体地点名词**时,**无论无人机在地面或空中**,都必须使用 `move_direction`,严禁使用 `fly_to_waypoint` 或任何地点坐标。\n\n示例(必须遵守):\n- “无人机当前在地面,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n- “无人机当前在空中,快速去往东边60米,有身穿白色衣服,头戴帽子的男子在挟持他人,对其进行拍照。” → 同样必须使用 `move_direction`(east, 60),不得生成 `fly_to_waypoint` 或引用任何地点坐标。\n\n## 七、坐标计算规则(东南天坐标系 ENU)\n本系统统一使用东南天(ENU)坐标系:\n- **X轴**:正方向为**东** (East),负方向为**西** (West)\n- **Y轴**:正方向为**南** (South)向为**北** (North)\n- **Z轴**:正方向为**天** (Up),负方向为**地** (Down)\n\n**仅当指令涉及前往“具体地点”(如广场、大门)的偏移位置时,才需计算绝对坐标并使用`fly_to_waypoint`:**\n\n当指令包含“具体地点 + 方向 + 距离”的偏移时,按方向类型选择工具:\n- **单一方向**(东/西/南/北/上/下,如“广场西边200米”):**必须**先调用工具`calc_offset_enu`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction`: east/west/north/south/up/down\n - `distance`: 偏移距离(米)\n- **中文复合方位**(东南/西北/东北/西南/南偏东10度/北偏西15度等):**必须**先调用工具`calc_offset_esu_direction_text`计算绝对坐标,再使用`fly_to_waypoint`。工具参数:\n - `base`: 参考地点的ENU坐标(含x/y/z)\n - `direction_text`: 中文方位原文(如“东南”“南偏东10度”)\n - `distance`: 偏移距离(米)\n- **禁止简化**:当出现“东南/西北/东北/西南/南偏东/北偏西”等复合方位时,禁止将其简化为单一方向(如仅“东”或仅“南”)。\n\n示例(必须遵守):\n- “飞到广场东南方向100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"东南\"`,`distance` 为 `100`,再使用 `fly_to_waypoint`。\n- “飞到广场南偏东10度100米” → 必须调用 `calc_offset_esu_direction_text`,参数 `direction_text` 为 `\"南偏东10度\"`,`distance` 为 `100`。\n\n当指令只有“方向 + 距离”且**没有具体地点名词**时,**禁止**调用`calc_offset_enu`,必须使用`move_direction`。\n当指令描述“附近/边上/区域内”等模糊位置且**无方向+距离**时,视为到该地点本身,不做偏移计算。\n\n## 八、输出要求\n仅输出1个严格符合上述所有规则的JSON对象。\n\n【强制规则】仅生成包含root的复杂行为树JSON,不得输出简单模式(不得包含mode字段或仅有action节点)。\n\n=== User Prompt ===\n起飞到1米,向前飞1米,寻找穿迷彩衣服的人,找到后靠近,然后返航\n\n---\n参考知识:\n以下是从知识库中检索到的、与当前任务最相关的信息,请优先参考这些信息来生成结果:\n{\"property\": \"rules\", \"information\": {\"name\": \"紧急返航\", \"description\": \"当指令中要求紧急返航到某地时,必须使用fly_to_waypoint节点,严禁使用return_emergency节点。\"}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"飞行场地\", \"coordinates\": {\"x\": 0, \"y\": 0, \"z\": 0}}}\n\n{\"property\": \"location\", \"information\": {\"name\": \"大楼外围四个点东南天坐标系坐标\", \"coordinates\": {\"A\": {\"x\": -24.0, \"y\": 241.8, \"z\": 0}, \"B\": {\"x\": -108.5, \"y\": 241.8, \"z\": 0}, \"C\": {\"x\": -108.5, \"y\": 289.8, \"z\": 0}, \"D\": {\"x\": -24.0, \"y\": 292.8, \"z\": 0}}}}\n---" -} \ No newline at end of file diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/data_level0.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/data_level0.bin deleted file mode 100644 index c656b189..00000000 Binary files a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/data_level0.bin and /dev/null differ diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/header.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/header.bin deleted file mode 100644 index e89c5c59..00000000 Binary files a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/header.bin and /dev/null differ diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/length.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/length.bin deleted file mode 100644 index cb3e1628..00000000 Binary files a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/length.bin and /dev/null differ diff --git a/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/link_lists.bin b/tools/vector_store/2298535b-1808-4498-8a3a-59146f62ce97/link_lists.bin deleted file mode 100644 index e69de29b..00000000 diff --git a/tools/vector_store/chroma.sqlite3 b/tools/vector_store/chroma.sqlite3 deleted file mode 100644 index 8972f8b3..00000000 Binary files a/tools/vector_store/chroma.sqlite3 and /dev/null differ