feat: 完善批量可视化测试验证逻辑(仅提交业务代码)

This commit is contained in:
lulijing
2025-12-09 13:20:39 +08:00
parent c08cdfb339
commit 60f156f5e6
129 changed files with 21380 additions and 1984 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -14,7 +14,8 @@ BASE_URL = "http://127.0.0.1:8000"
ENDPOINT = "/generate_plan"
# The user prompt we will send for the test
TEST_PROMPT = "起飞"
#TEST_PROMPT = "无人机起飞到一米高度后先移动至搜索区搜索并锁定任一穿黑色衣服的人在对其进行跟踪30秒后进行打击操作"
TEST_PROMPT = "已知目标检测红色气球危险性高于蓝色气球高于绿色气球飞往搜索区搜索并锁定危险性最高的气球对其跟踪30秒"
# Log file path (will be created in the same directory as this script)
LOG_FILE = os.path.join(os.path.dirname(__file__), "api_test.log")

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,269 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
从API测试日志中提取JSON响应并批量可视化
"""
import json
import os
import re
import logging
import platform
import random
import html
from typing import Dict, List, Tuple
from collections import defaultdict
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def sanitize_filename(text: str) -> str:
"""将文本转换为安全的文件名"""
# 移除或替换不安全的字符
text = re.sub(r'[<>:"/\\|?*]', '_', text)
# 限制长度
if len(text) > 100:
text = text[:100]
return text
def _pick_zh_font():
"""选择合适的中文字体"""
sys = platform.system()
if sys == "Windows":
return "Microsoft YaHei"
elif sys == "Darwin":
return "PingFang SC"
else:
return "Noto Sans CJK SC"
def _add_nodes_and_edges(node: dict, dot, parent_id: str | None = None) -> str:
"""递归辅助函数,用于添加节点和边。"""
try:
from graphviz import Digraph
except ImportError:
logging.critical("错误未安装graphviz库。请运行: pip install graphviz")
return ""
current_id = f"{id(node)}_{random.randint(1000, 9999)}"
# 准备节点标签HTML-like正确换行与转义
name = html.escape(str(node.get('name', '')))
ntype = html.escape(str(node.get('type', '')))
label_parts = [f"<B>{name}</B> <FONT POINT-SIZE='10'><I>({ntype})</I></FONT>"]
# 格式化参数显示
params = node.get('params') or {}
if params:
params_lines = []
for key, value in params.items():
k = html.escape(str(key))
if isinstance(value, float):
value_str = f"{value:.2f}".rstrip('0').rstrip('.')
else:
value_str = str(value)
v = html.escape(value_str)
params_lines.append(f"{k}: {v}")
params_text = "<BR ALIGN='LEFT'/>".join(params_lines)
label_parts.append(f"<FONT POINT-SIZE='9' COLOR='#555555'>{params_text}</FONT>")
node_label = f"<{'<BR/>'.join(label_parts)}>"
# 根据类型设置节点样式和颜色
node_type = (node.get('type') or '').lower()
shape = 'ellipse'
style = 'filled'
fillcolor = '#e6e6e6' # 默认灰色填充
border_color = '#666666' # 默认描边色
if node_type == 'action':
shape = 'box'
style = 'rounded,filled'
fillcolor = "#cde4ff" # 浅蓝
elif node_type == 'condition':
shape = 'diamond'
style = 'filled'
fillcolor = "#fff2cc" # 浅黄
elif node_type == 'sequence':
shape = 'ellipse'
style = 'filled'
fillcolor = '#d5e8d4' # 绿色
elif node_type == 'selector':
shape = 'ellipse'
style = 'filled'
fillcolor = '#ffe6cc' # 橙色
elif node_type == 'parallel':
shape = 'ellipse'
style = 'filled'
fillcolor = '#e1d5e7' # 紫色
# 特别标记安全相关节点
if node.get('name') in ['battery_above', 'gps_status', 'SafetyMonitor']:
border_color = '#ff0000' # 红色边框突出显示安全节点
style = 'filled,bold' # 加粗
dot.node(current_id, label=node_label, shape=shape, style=style, fillcolor=fillcolor, color=border_color)
# 连接父节点
if parent_id:
dot.edge(parent_id, current_id)
# 递归处理子节点
children = node.get("children", [])
if not children:
return current_id
# 记录所有子节点的ID
child_ids = []
# 正确的递归连接:每个子节点都连接到当前节点
for child in children:
child_id = _add_nodes_and_edges(child, dot, current_id)
child_ids.append(child_id)
# 子节点同级排列(横向排布,更直观地表现同层)
if len(child_ids) > 1:
with dot.subgraph(name=f"rank_{current_id}") as s:
s.attr(rank='same')
for cid in child_ids:
s.node(cid)
return current_id
def _visualize_pytree(node: Dict, file_path: str):
"""
使用Graphviz将Pytree字典可视化并保存到指定路径。
"""
try:
from graphviz import Digraph
except ImportError:
logging.critical("错误未安装graphviz库。请运行: pip install graphviz")
return
fontname = _pick_zh_font()
dot = Digraph('Pytree', comment='Drone Mission Plan')
dot.attr(rankdir='TB', label='Drone Mission Plan', fontsize='20', fontname=fontname)
dot.attr('node', shape='box', style='rounded,filled', fontname=fontname)
dot.attr('edge', fontname=fontname)
_add_nodes_and_edges(node, dot)
try:
# 确保输出目录存在,并避免生成 .png.png
base_path, ext = os.path.splitext(file_path)
render_path = base_path if ext.lower() == '.png' else file_path
out_dir = os.path.dirname(render_path)
if out_dir and not os.path.exists(out_dir):
os.makedirs(out_dir, exist_ok=True)
# 保存为 .png 文件,并自动删除源码 .gv 文件
output_path = dot.render(render_path, format='png', cleanup=True, view=False)
logging.info(f"✅ 可视化成功: {output_path}")
except Exception as e:
logging.error(f"❌ 生成可视化图形失败: {e}")
def parse_log_file(log_file_path: str) -> Dict[str, List[Dict]]:
"""
解析日志文件提取原始指令和完整API响应JSON
返回: {原始指令: [JSON响应列表]}
"""
with open(log_file_path, 'r', encoding='utf-8') as f:
content = f.read()
# 按分隔符分割条目
entries = re.split(r'={80,}', content)
results = defaultdict(list)
for entry in entries:
if not entry.strip():
continue
# 提取原始指令
instruction_match = re.search(r'原始指令:\s*(.+)', entry)
if not instruction_match:
continue
original_instruction = instruction_match.group(1).strip()
# 提取完整API响应JSON
json_match = re.search(r'完整API响应:\s*\n(\{.*\})', entry, re.DOTALL)
if not json_match:
logging.warning(f"未找到指令 '{original_instruction}' 的JSON响应")
continue
json_str = json_match.group(1).strip()
try:
json_obj = json.loads(json_str)
results[original_instruction].append(json_obj)
logging.info(f"成功提取指令 '{original_instruction}' 的JSON响应")
except json.JSONDecodeError as e:
logging.error(f"解析指令 '{original_instruction}' 的JSON失败: {e}")
continue
return results
def process_and_visualize(log_file_path: str, output_dir: str):
"""
处理日志文件并批量可视化
"""
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 解析日志文件
logging.info(f"开始解析日志文件: {log_file_path}")
instruction_responses = parse_log_file(log_file_path)
logging.info(f"共找到 {len(instruction_responses)} 个不同的原始指令")
# 处理每个指令的所有响应
for instruction, responses in instruction_responses.items():
logging.info(f"\n处理指令: {instruction} (共 {len(responses)} 个响应)")
# 创建指令目录(使用安全的文件名)
safe_instruction_name = sanitize_filename(instruction)
instruction_dir = os.path.join(output_dir, safe_instruction_name)
os.makedirs(instruction_dir, exist_ok=True)
# 处理每个响应
for idx, response in enumerate(responses, 1):
try:
# 提取root节点
root_node = response.get('root')
if not root_node:
logging.warning(f"响应 #{idx} 没有root节点跳过")
continue
# 生成文件名
json_filename = f"response_{idx}.json"
png_filename = f"response_{idx}.png"
json_path = os.path.join(instruction_dir, json_filename)
png_path = os.path.join(instruction_dir, png_filename)
# 保存JSON文件
with open(json_path, 'w', encoding='utf-8') as f:
json.dump(response, f, ensure_ascii=False, indent=2)
logging.info(f" 保存JSON: {json_filename}")
# 生成可视化
_visualize_pytree(root_node, png_path)
logging.info(f" 生成可视化: {png_filename}")
except Exception as e:
logging.error(f"处理响应 #{idx} 时出错: {e}")
continue
logging.info(f"\n✅ 所有处理完成!结果保存在: {output_dir}")
if __name__ == "__main__":
log_file = "/home/iscas/WorkSpace/code/DronePlanning/tools/test_validate/api_test_log.txt"
output_directory = "/home/iscas/WorkSpace/code/DronePlanning/tools/test_validate/validation"
process_and_visualize(log_file, output_directory)

View File

@@ -10,5 +10,6 @@
飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆
飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆
起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资
无人机起飞到一米高度后先移动至搜索区搜索并锁定任一穿黑色衣服的人在对其进行跟踪30秒后进行打击操作
已知目标检测红色气球危险性高于蓝色气球高于绿色气球飞往搜索区搜索并锁定危险性最高的气球对其跟踪30秒

View File

@@ -1,13 +1,15 @@
instruction_index,instruction,run_number,success,attempts,response_time,plan_id,error,timestamp
1,起飞,1,True,1,2.4630444049835205,42903026-b02b-4089-859d-aec5cfa2435e,,2025-12-03 17:09:32
2,起飞后移动到学生宿舍上方降落,1,True,1,10.017558574676514,86238ad2-e275-4d50-905c-175bd2f26fd0,,2025-12-03 17:09:43
3,起飞后移动到学生宿舍上方查找蓝色的车,1,True,1,12.420023202896118,d8345bc3-b70f-41d7-b9fc-3e4898d7409e,,2025-12-03 17:09:56
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,True,1,12.864884614944458,29b5ee20-c809-4511-af08-80a85240c729,,2025-12-03 17:10:10
5,起飞后移动到学生宿舍上方检测蓝色的车,1,True,1,10.438142538070679,5e7eb8c7-287a-469a-b6c0-a4102c1b0dac,,2025-12-03 17:10:21
6,飞到学生宿舍上方查找蓝色的车,1,True,1,11.751057386398315,ef3d1981-1d51-433d-b2f4-2e92838075fd,,2025-12-03 17:10:34
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,True,1,32.890604972839355,d8fc4658-08af-4910-89c4-b029c9a5daa0,,2025-12-03 17:11:08
8,起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击,1,False,1,33.2862343788147,,,2025-12-03 17:11:42
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,True,1,12.312166213989258,7fbf0091-f7d3-4c3a-a6b7-4c0bfd4df66e,,2025-12-03 17:11:56
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,True,1,12.204660892486572,3ae0b258-b7e4-460c-9cfe-4b224266edc4,,2025-12-03 17:12:09
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,True,1,12.808414936065674,2acb84cf-c89e-460d-a4d9-8d1edb4ee69a,,2025-12-03 17:12:23
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,True,1,11.071707487106323,c05d46c9-1b1b-4c8d-b64b-86b76d0c4099,,2025-12-03 17:12:35
1,起飞,1,True,1,0.3463160991668701,0ffa333d-574d-453d-99cd-f8852411b7be,,2025-12-08 16:08:41
2,起飞后移动到学生宿舍上方降落,1,True,1,0.1823880672454834,46c5741f-1e51-4cbe-bd5a-1e099d0d53f5,,2025-12-08 16:08:42
3,起飞后移动到学生宿舍上方查找蓝色的车,1,True,1,0.24654889106750488,636bfbb8-c3be-42b6-93cf-caf87ac6424c,,2025-12-08 16:08:43
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,True,1,0.23946380615234375,744d6e87-5067-4f91-9f73-7f65432e1b83,,2025-12-08 16:08:45
5,起飞后移动到学生宿舍上方检测蓝色的车,1,True,1,3.5440704822540283,1bf6820d-0c04-4961-b624-49e9d919ac56,,2025-12-08 16:08:49
6,飞到学生宿舍上方查找蓝色的车,1,False,1,3.451496124267578,,,2025-12-08 16:08:54
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,False,1,3.321821689605713,,,2025-12-08 16:08:58
8,起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击,1,False,1,18.552793502807617,,,2025-12-08 16:09:17
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,True,1,1.5930235385894775,1ae38dbd-4e25-4a51-ac4f-8ed851fe8b1f,,2025-12-08 16:09:20
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,False,1,17.402809381484985,,,2025-12-08 16:09:38
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,True,1,1.269315481185913,24b02e2d-291d-4213-9e0f-acdd1165a1f1,,2025-12-08 16:09:41
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,True,1,3.885636329650879,685b1d6d-8a82-463c-ab68-051348403c89,,2025-12-08 16:09:46
13,无人机起飞到一米高度后先移动至搜索区搜索并锁定任一穿黑色衣服的人在对其进行跟踪30秒后进行打击操作,1,False,1,16.88854742050171,,,2025-12-08 16:10:04
14,已知目标检测红色气球危险性高于蓝色气球高于绿色气球飞往搜索区搜索并锁定危险性最高的气球对其跟踪30秒,1,False,1,3.594463586807251,,,2025-12-08 16:10:08
1 instruction_index instruction run_number success attempts response_time plan_id error timestamp
2 1 起飞 1 True 1 2.4630444049835205 0.3463160991668701 42903026-b02b-4089-859d-aec5cfa2435e 0ffa333d-574d-453d-99cd-f8852411b7be 2025-12-03 17:09:32 2025-12-08 16:08:41
3 2 起飞后移动到学生宿舍上方降落 1 True 1 10.017558574676514 0.1823880672454834 86238ad2-e275-4d50-905c-175bd2f26fd0 46c5741f-1e51-4cbe-bd5a-1e099d0d53f5 2025-12-03 17:09:43 2025-12-08 16:08:42
4 3 起飞后移动到学生宿舍上方查找蓝色的车 1 True 1 12.420023202896118 0.24654889106750488 d8345bc3-b70f-41d7-b9fc-3e4898d7409e 636bfbb8-c3be-42b6-93cf-caf87ac6424c 2025-12-03 17:09:56 2025-12-08 16:08:43
5 4 起飞后移动到学生宿舍上方寻找蓝色的车 1 True 1 12.864884614944458 0.23946380615234375 29b5ee20-c809-4511-af08-80a85240c729 744d6e87-5067-4f91-9f73-7f65432e1b83 2025-12-03 17:10:10 2025-12-08 16:08:45
6 5 起飞后移动到学生宿舍上方检测蓝色的车 1 True 1 10.438142538070679 3.5440704822540283 5e7eb8c7-287a-469a-b6c0-a4102c1b0dac 1bf6820d-0c04-4961-b624-49e9d919ac56 2025-12-03 17:10:21 2025-12-08 16:08:49
7 6 飞到学生宿舍上方查找蓝色的车 1 True False 1 11.751057386398315 3.451496124267578 ef3d1981-1d51-433d-b2f4-2e92838075fd 2025-12-03 17:10:34 2025-12-08 16:08:54
8 7 飞到学生宿舍上方查找蓝色车辆并进行打击 1 True False 1 32.890604972839355 3.321821689605713 d8fc4658-08af-4910-89c4-b029c9a5daa0 2025-12-03 17:11:08 2025-12-08 16:08:58
9 8 起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击 1 False 1 33.2862343788147 18.552793502807617 2025-12-03 17:11:42 2025-12-08 16:09:17
10 9 起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资 1 True 1 12.312166213989258 1.5930235385894775 7fbf0091-f7d3-4c3a-a6b7-4c0bfd4df66e 1ae38dbd-4e25-4a51-ac4f-8ed851fe8b1f 2025-12-03 17:11:56 2025-12-08 16:09:20
11 10 飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆 1 True False 1 12.204660892486572 17.402809381484985 3ae0b258-b7e4-460c-9cfe-4b224266edc4 2025-12-03 17:12:09 2025-12-08 16:09:38
12 11 飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆 1 True 1 12.808414936065674 1.269315481185913 2acb84cf-c89e-460d-a4d9-8d1edb4ee69a 24b02e2d-291d-4213-9e0f-acdd1165a1f1 2025-12-03 17:12:23 2025-12-08 16:09:41
13 12 起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资 1 True 1 11.071707487106323 3.885636329650879 c05d46c9-1b1b-4c8d-b64b-86b76d0c4099 685b1d6d-8a82-463c-ab68-051348403c89 2025-12-03 17:12:35 2025-12-08 16:09:46
14 13 无人机起飞到一米高度后,先移动至搜索区,搜索并锁定任一穿黑色衣服的人,在对其进行跟踪30秒后进行打击操作 1 False 1 16.88854742050171 2025-12-08 16:10:04
15 14 已知目标检测红色气球危险性高于蓝色气球高于绿色气球,飞往搜索区搜索并锁定危险性最高的气球,对其跟踪30秒 1 False 1 3.594463586807251 2025-12-08 16:10:08

View File

@@ -1,13 +1,15 @@
instruction_index,instruction,total_runs,successful_runs,success_rate,avg_response_time,min_response_time,max_response_time,total_response_time
1,起飞,1,1,100.00%,2.46s,2.46s,2.46s,2.46s
2,起飞后移动到学生宿舍上方降落,1,1,100.00%,10.02s,10.02s,10.02s,10.02s
3,起飞后移动到学生宿舍上方查找蓝色的车,1,1,100.00%,12.42s,12.42s,12.42s,12.42s
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,1,100.00%,12.86s,12.86s,12.86s,12.86s
5,起飞后移动到学生宿舍上方检测蓝色的车,1,1,100.00%,10.44s,10.44s,10.44s,10.44s
6,飞到学生宿舍上方查找蓝色的车,1,1,100.00%,11.75s,11.75s,11.75s,11.75s
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,1,100.00%,32.89s,32.89s,32.89s,32.89s
1,起飞,1,1,100.00%,0.35s,0.35s,0.35s,0.35s
2,起飞后移动到学生宿舍上方降落,1,1,100.00%,0.18s,0.18s,0.18s,0.18s
3,起飞后移动到学生宿舍上方查找蓝色的车,1,1,100.00%,0.25s,0.25s,0.25s,0.25s
4,起飞后移动到学生宿舍上方寻找蓝色的车,1,1,100.00%,0.24s,0.24s,0.24s,0.24s
5,起飞后移动到学生宿舍上方检测蓝色的车,1,1,100.00%,3.54s,3.54s,3.54s,3.54s
6,飞到学生宿舍上方查找蓝色的车,1,0,0.00%,N/A,N/A,N/A,0.00s
7,飞到学生宿舍上方查找蓝色车辆并进行打击,1,0,0.00%,N/A,N/A,N/A,0.00s
8,起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击,1,0,0.00%,N/A,N/A,N/A,0.00s
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,1,100.00%,12.31s,12.31s,12.31s,12.31s
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,1,100.00%,12.20s,12.20s,12.20s,12.20s
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,1,100.00%,12.81s,12.81s,12.81s,12.81s
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,1,100.00%,11.07s,11.07s,11.07s,11.07s
9,起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资,1,1,100.00%,1.59s,1.59s,1.59s,1.59s
10,飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆,1,0,0.00%,N/A,N/A,N/A,0.00s
11,飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆,1,1,100.00%,1.27s,1.27s,1.27s,1.27s
12,起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资,1,1,100.00%,3.89s,3.89s,3.89s,3.89s
13,无人机起飞到一米高度后先移动至搜索区搜索并锁定任一穿黑色衣服的人在对其进行跟踪30秒后进行打击操作,1,0,0.00%,N/A,N/A,N/A,0.00s
14,已知目标检测红色气球危险性高于蓝色气球高于绿色气球飞往搜索区搜索并锁定危险性最高的气球对其跟踪30秒,1,0,0.00%,N/A,N/A,N/A,0.00s
1 instruction_index instruction total_runs successful_runs success_rate avg_response_time min_response_time max_response_time total_response_time
2 1 起飞 1 1 100.00% 2.46s 0.35s 2.46s 0.35s 2.46s 0.35s 2.46s 0.35s
3 2 起飞后移动到学生宿舍上方降落 1 1 100.00% 10.02s 0.18s 10.02s 0.18s 10.02s 0.18s 10.02s 0.18s
4 3 起飞后移动到学生宿舍上方查找蓝色的车 1 1 100.00% 12.42s 0.25s 12.42s 0.25s 12.42s 0.25s 12.42s 0.25s
5 4 起飞后移动到学生宿舍上方寻找蓝色的车 1 1 100.00% 12.86s 0.24s 12.86s 0.24s 12.86s 0.24s 12.86s 0.24s
6 5 起飞后移动到学生宿舍上方检测蓝色的车 1 1 100.00% 10.44s 3.54s 10.44s 3.54s 10.44s 3.54s 10.44s 3.54s
7 6 飞到学生宿舍上方查找蓝色的车 1 1 0 100.00% 0.00% 11.75s N/A 11.75s N/A 11.75s N/A 11.75s 0.00s
8 7 飞到学生宿舍上方查找蓝色车辆并进行打击 1 1 0 100.00% 0.00% 32.89s N/A 32.89s N/A 32.89s N/A 32.89s 0.00s
9 8 起飞后移动到学生宿舍上方搜索蓝色车辆,并进行打击 1 0 0.00% N/A N/A N/A 0.00s
10 9 起飞到学生宿舍上方搜索被困人员,并为被困人员投递救援物资 1 1 100.00% 12.31s 1.59s 12.31s 1.59s 12.31s 1.59s 12.31s 1.59s
11 10 飞到学生宿舍上方搜索方圆10米范围内的蓝色车辆 1 1 0 100.00% 0.00% 12.20s N/A 12.20s N/A 12.20s N/A 12.20s 0.00s
12 11 飞到学生宿舍上方搜索半径为10米区域范围内的蓝色车辆 1 1 100.00% 12.81s 1.27s 12.81s 1.27s 12.81s 1.27s 12.81s 1.27s
13 12 起飞到学生宿舍搜索有没有被困人员,然后抛洒救援物资 1 1 100.00% 11.07s 3.89s 11.07s 3.89s 11.07s 3.89s 11.07s 3.89s
14 13 无人机起飞到一米高度后,先移动至搜索区,搜索并锁定任一穿黑色衣服的人,在对其进行跟踪30秒后进行打击操作 1 0 0.00% N/A N/A N/A 0.00s
15 14 已知目标检测红色气球危险性高于蓝色气球高于绿色气球,飞往搜索区搜索并锁定危险性最高的气球,对其跟踪30秒 1 0 0.00% N/A N/A N/A 0.00s

View File

@@ -505,4 +505,4 @@ def main():
print(f"统计摘要: {SUMMARY_CSV}")
if __name__ == "__main__":
main()
main()

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

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