Compare commits
7 Commits
yjh_branch
...
main
Author | SHA1 | Date |
---|---|---|
|
18a916b8ab | 3 weeks ago |
|
6f8d81c3d1 | 3 weeks ago |
|
b3a9b05339 | 3 weeks ago |
|
909ab0b30c | 3 weeks ago |
|
e7799487f4 | 3 weeks ago |
|
bcae26adb0 | 1 month ago |
|
8d34db55d6 | 3 months ago |
@ -1,32 +0,0 @@
|
|||||||
# 应用环境
|
|
||||||
ENVIRONMENT=development # development, testing, production
|
|
||||||
|
|
||||||
# 日志配置
|
|
||||||
LOG_LEVEL=INFO # DEBUG, INFO, WARNING, ERROR, CRITICAL
|
|
||||||
|
|
||||||
# Web服务器配置
|
|
||||||
WEB_HOST=0.0.0.0
|
|
||||||
WEB_PORT=8080
|
|
||||||
|
|
||||||
# 通信服务器配置
|
|
||||||
COMM_HOST=0.0.0.0
|
|
||||||
COMM_PORT=5000
|
|
||||||
|
|
||||||
# 无人机连接配置
|
|
||||||
DRONE_CONNECTION_STRING=udpin:localhost:14550
|
|
||||||
|
|
||||||
# 基地位置
|
|
||||||
BASE_LATITUDE=39.9
|
|
||||||
BASE_LONGITUDE=116.3
|
|
||||||
|
|
||||||
# 飞行参数
|
|
||||||
DEFAULT_ALTITUDE=10.0
|
|
||||||
DEFAULT_AIRSPEED=3.0
|
|
||||||
|
|
||||||
# 安全设置
|
|
||||||
ENABLE_GEO_FENCE=True
|
|
||||||
MAX_DISTANCE_FROM_BASE=5000.0
|
|
||||||
MIN_BATTERY_LEVEL=30.0
|
|
||||||
|
|
||||||
# 其他配置
|
|
||||||
ENABLE_SIMULATION=True
|
|
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 200 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 66 KiB |
@ -1,110 +0,0 @@
|
|||||||
import os
|
|
||||||
import logging
|
|
||||||
|
|
||||||
# 基础配置
|
|
||||||
class Config:
|
|
||||||
"""基础配置类"""
|
|
||||||
|
|
||||||
# 应用配置
|
|
||||||
APP_NAME = "智能战场医疗后送系统"
|
|
||||||
VERSION = "1.0.0"
|
|
||||||
|
|
||||||
# 日志配置
|
|
||||||
LOG_LEVEL = "INFO"
|
|
||||||
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
||||||
|
|
||||||
# Web服务器配置
|
|
||||||
WEB_HOST = "0.0.0.0"
|
|
||||||
WEB_PORT = 8080
|
|
||||||
|
|
||||||
# 通信服务器配置
|
|
||||||
COMM_HOST = "0.0.0.0"
|
|
||||||
COMM_PORT = 5000
|
|
||||||
|
|
||||||
# 无人机连接配置
|
|
||||||
DRONE_CONNECTION_STRING = "udpin:localhost:14550"
|
|
||||||
|
|
||||||
# 基地位置(纬度、经度)
|
|
||||||
BASE_LATITUDE = 39.9
|
|
||||||
BASE_LONGITUDE = 116.3
|
|
||||||
|
|
||||||
# 飞行参数
|
|
||||||
DEFAULT_ALTITUDE = 10.0 # 默认飞行高度(米)
|
|
||||||
DEFAULT_AIRSPEED = 3.0 # 默认空速(米/秒)
|
|
||||||
|
|
||||||
# 安全设置
|
|
||||||
ENABLE_GEO_FENCE = True
|
|
||||||
MAX_DISTANCE_FROM_BASE = 5000.0 # 最大飞行距离(米)
|
|
||||||
MIN_BATTERY_LEVEL = 30.0 # 最低电量百分比
|
|
||||||
|
|
||||||
# 伤员检测配置
|
|
||||||
CASUALTY_DETECTOR_MODEL_PATH = "models/yolov5s.pt"
|
|
||||||
DETECTION_THRESHOLD = 0.5 # 检测阈值
|
|
||||||
|
|
||||||
# 其他配置
|
|
||||||
ENABLE_SIMULATION = True
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_log_level():
|
|
||||||
"""获取日志级别"""
|
|
||||||
level_map = {
|
|
||||||
"DEBUG": logging.DEBUG,
|
|
||||||
"INFO": logging.INFO,
|
|
||||||
"WARNING": logging.WARNING,
|
|
||||||
"ERROR": logging.ERROR,
|
|
||||||
"CRITICAL": logging.CRITICAL
|
|
||||||
}
|
|
||||||
return level_map.get(Config.LOG_LEVEL, logging.INFO)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def setup_logging():
|
|
||||||
"""设置日志"""
|
|
||||||
logging.basicConfig(
|
|
||||||
level=Config.get_log_level(),
|
|
||||||
format=Config.LOG_FORMAT
|
|
||||||
)
|
|
||||||
|
|
||||||
# 降低第三方库的日志级别
|
|
||||||
logging.getLogger("werkzeug").setLevel(logging.WARNING)
|
|
||||||
logging.getLogger("socketio").setLevel(logging.WARNING)
|
|
||||||
logging.getLogger("engineio").setLevel(logging.WARNING)
|
|
||||||
logging.getLogger("geventwebsocket").setLevel(logging.WARNING)
|
|
||||||
|
|
||||||
logging.info(f"日志系统已初始化: 级别={Config.LOG_LEVEL}")
|
|
||||||
|
|
||||||
|
|
||||||
class DevelopmentConfig(Config):
|
|
||||||
"""开发环境配置"""
|
|
||||||
ENABLE_SIMULATION = True
|
|
||||||
LOG_LEVEL = "DEBUG"
|
|
||||||
|
|
||||||
|
|
||||||
class ProductionConfig(Config):
|
|
||||||
"""生产环境配置"""
|
|
||||||
ENABLE_SIMULATION = False
|
|
||||||
LOG_LEVEL = "INFO"
|
|
||||||
|
|
||||||
|
|
||||||
class TestingConfig(Config):
|
|
||||||
"""测试环境配置"""
|
|
||||||
ENABLE_SIMULATION = True
|
|
||||||
LOG_LEVEL = "DEBUG"
|
|
||||||
WEB_PORT = 8081
|
|
||||||
COMM_PORT = 5001
|
|
||||||
|
|
||||||
|
|
||||||
# 根据环境变量选择配置
|
|
||||||
def get_config():
|
|
||||||
"""获取当前环境的配置"""
|
|
||||||
env = os.environ.get("ENVIRONMENT", "development").lower()
|
|
||||||
|
|
||||||
if env == "production":
|
|
||||||
return ProductionConfig
|
|
||||||
elif env == "testing":
|
|
||||||
return TestingConfig
|
|
||||||
else:
|
|
||||||
return DevelopmentConfig
|
|
||||||
|
|
||||||
|
|
||||||
# 导出当前配置
|
|
||||||
current_config = get_config()
|
|
@ -1,29 +0,0 @@
|
|||||||
import os
|
|
||||||
import logging
|
|
||||||
|
|
||||||
# 数据库配置
|
|
||||||
class DatabaseConfig:
|
|
||||||
"""数据库配置类"""
|
|
||||||
|
|
||||||
# SQLite配置
|
|
||||||
SQLITE_DATABASE_PATH = os.path.join(os.getcwd(), 'battlefield_medical_system.db')
|
|
||||||
|
|
||||||
# 初始化配置
|
|
||||||
def __init__(self):
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
self.logger.info("初始化数据库配置 - 使用SQLite")
|
|
||||||
|
|
||||||
# SQLAlchemy配置
|
|
||||||
@property
|
|
||||||
def SQLALCHEMY_DATABASE_URI(self):
|
|
||||||
return f"sqlite:///{self.SQLITE_DATABASE_PATH}"
|
|
||||||
|
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
||||||
SQLALCHEMY_ECHO = False
|
|
||||||
|
|
||||||
def get_database_uri(self):
|
|
||||||
"""获取数据库URI"""
|
|
||||||
return self.SQLALCHEMY_DATABASE_URI
|
|
||||||
|
|
||||||
# 导出当前配置
|
|
||||||
db_config = DatabaseConfig()
|
|
@ -1,14 +0,0 @@
|
|||||||
with open('.env', 'w', encoding='utf-8') as f:
|
|
||||||
f.write('''# MySQL数据库配置
|
|
||||||
MYSQL_HOST=localhost
|
|
||||||
MYSQL_PORT=3306
|
|
||||||
MYSQL_USER=root
|
|
||||||
MYSQL_PASSWORD=
|
|
||||||
MYSQL_DATABASE=battlefield_medical_system
|
|
||||||
SQLALCHEMY_ECHO=False
|
|
||||||
|
|
||||||
# 基本配置
|
|
||||||
ENABLE_SIMULATION=True
|
|
||||||
''')
|
|
||||||
|
|
||||||
print("已创建.env文件")
|
|
@ -1,168 +0,0 @@
|
|||||||
import cv2
|
|
||||||
import numpy as np
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
|
|
||||||
# 创建目录
|
|
||||||
os.makedirs('test_images', exist_ok=True)
|
|
||||||
os.makedirs('src/ui/static/training_images', exist_ok=True)
|
|
||||||
|
|
||||||
def create_battlefield_scene(width=800, height=600, file_path="", for_training=False):
|
|
||||||
"""创建战场场景图片"""
|
|
||||||
# 背景 - 草地/沙地
|
|
||||||
background = np.ones((height, width, 3), dtype=np.uint8) * 150
|
|
||||||
|
|
||||||
# 添加一些纹理
|
|
||||||
for i in range(0, height, 5):
|
|
||||||
for j in range(0, width, 5):
|
|
||||||
val = np.random.randint(120, 180)
|
|
||||||
background[i:i+5, j:j+5] = [val-30, val, val-50] # 草地/沙地颜色
|
|
||||||
|
|
||||||
# 添加几个可能是"伤员"的物体
|
|
||||||
casualties = []
|
|
||||||
|
|
||||||
# 随机伤员数量
|
|
||||||
casualties_count = random.randint(1, 5)
|
|
||||||
|
|
||||||
for i in range(casualties_count):
|
|
||||||
# 随机位置
|
|
||||||
x = random.randint(100, width-100)
|
|
||||||
y = random.randint(100, height-100)
|
|
||||||
|
|
||||||
# 随机尺寸
|
|
||||||
body_width = random.randint(40, 70)
|
|
||||||
body_height = random.randint(25, 45)
|
|
||||||
head_size = random.randint(15, 25)
|
|
||||||
|
|
||||||
# 随机角度
|
|
||||||
angle = random.randint(0, 360)
|
|
||||||
|
|
||||||
# 随机颜色 - 模拟不同肤色和衣服
|
|
||||||
body_color = (
|
|
||||||
random.randint(20, 40),
|
|
||||||
random.randint(20, 40),
|
|
||||||
random.randint(80, 120)
|
|
||||||
)
|
|
||||||
|
|
||||||
head_color = (
|
|
||||||
random.randint(60, 90),
|
|
||||||
random.randint(60, 90),
|
|
||||||
random.randint(130, 170)
|
|
||||||
)
|
|
||||||
|
|
||||||
# 绘制伤员
|
|
||||||
cv2.ellipse(background, (x, y), (body_width, body_height), angle, 0, 360, body_color, -1)
|
|
||||||
|
|
||||||
# 计算头部位置 - 考虑角度
|
|
||||||
head_offset_x = int(np.cos(np.radians(angle)) * (body_width + head_size/2))
|
|
||||||
head_offset_y = int(np.sin(np.radians(angle)) * (body_height + head_size/2))
|
|
||||||
head_x = x + head_offset_x
|
|
||||||
head_y = y + head_offset_y
|
|
||||||
|
|
||||||
# 确保头部在图像范围内
|
|
||||||
head_x = max(head_size, min(width-head_size, head_x))
|
|
||||||
head_y = max(head_size, min(height-head_size, head_y))
|
|
||||||
|
|
||||||
cv2.circle(background, (head_x, head_y), head_size, head_color, -1)
|
|
||||||
|
|
||||||
# 保存伤员坐标 - 用于训练标注
|
|
||||||
if for_training:
|
|
||||||
# 计算伤员边界框 (xmin, ymin, xmax, ymax)
|
|
||||||
xmin = max(0, x - body_width)
|
|
||||||
ymin = max(0, y - body_height)
|
|
||||||
xmax = min(width, x + body_width)
|
|
||||||
ymax = min(height, y + body_height)
|
|
||||||
|
|
||||||
# 调整确保头部也在边界框内
|
|
||||||
xmin = min(xmin, head_x - head_size)
|
|
||||||
ymin = min(ymin, head_y - head_size)
|
|
||||||
xmax = max(xmax, head_x + head_size)
|
|
||||||
ymax = max(ymax, head_y + head_size)
|
|
||||||
|
|
||||||
# 存储为像素坐标
|
|
||||||
casualties.append({
|
|
||||||
'x': int(xmin),
|
|
||||||
'y': int(ymin),
|
|
||||||
'width': int(xmax - xmin),
|
|
||||||
'height': int(ymax - ymin),
|
|
||||||
'class': 'casualty'
|
|
||||||
})
|
|
||||||
|
|
||||||
# 添加一些其他物体 - 障碍物、车辆等
|
|
||||||
for _ in range(random.randint(3, 8)):
|
|
||||||
x = np.random.randint(50, width-50)
|
|
||||||
y = np.random.randint(50, height-50)
|
|
||||||
size = np.random.randint(10, 60)
|
|
||||||
color = (
|
|
||||||
np.random.randint(0, 100),
|
|
||||||
np.random.randint(0, 100),
|
|
||||||
np.random.randint(0, 100)
|
|
||||||
)
|
|
||||||
shape_type = random.choice(['circle', 'rectangle'])
|
|
||||||
|
|
||||||
if shape_type == 'circle':
|
|
||||||
cv2.circle(background, (x, y), size, color, -1)
|
|
||||||
else:
|
|
||||||
rect_width = random.randint(size//2, size*2)
|
|
||||||
rect_height = random.randint(size//2, size*2)
|
|
||||||
cv2.rectangle(
|
|
||||||
background,
|
|
||||||
(x-rect_width//2, y-rect_height//2),
|
|
||||||
(x+rect_width//2, y+rect_height//2),
|
|
||||||
color,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
|
|
||||||
# 添加一些模糊和噪声
|
|
||||||
background = cv2.GaussianBlur(background, (5, 5), 0)
|
|
||||||
|
|
||||||
# 添加一些噪声
|
|
||||||
noise = np.zeros(background.shape, np.uint8)
|
|
||||||
cv2.randn(noise, (0, 0, 0), (10, 10, 10))
|
|
||||||
background = cv2.add(background, noise)
|
|
||||||
|
|
||||||
# 保存图像
|
|
||||||
cv2.imwrite(file_path, background)
|
|
||||||
|
|
||||||
return casualties
|
|
||||||
|
|
||||||
# 创建基本测试图像
|
|
||||||
create_battlefield_scene(
|
|
||||||
width=800,
|
|
||||||
height=600,
|
|
||||||
file_path='test_images/battlefield_scene.jpg',
|
|
||||||
for_training=False
|
|
||||||
)
|
|
||||||
print("测试图像已创建: test_images/battlefield_scene.jpg")
|
|
||||||
|
|
||||||
# 创建用于训练的图像和标注
|
|
||||||
training_count = 10 # 生成10张训练用图片
|
|
||||||
for i in range(training_count):
|
|
||||||
# 生成图片文件名
|
|
||||||
img_filename = f"battlefield_training_{i+1}.jpg"
|
|
||||||
img_path = f"src/ui/static/training_images/{img_filename}"
|
|
||||||
|
|
||||||
# 生成图片和标注
|
|
||||||
casualties = create_battlefield_scene(
|
|
||||||
width=1024,
|
|
||||||
height=768,
|
|
||||||
file_path=img_path,
|
|
||||||
for_training=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# 保存标注信息到JSON文件
|
|
||||||
if casualties:
|
|
||||||
import json
|
|
||||||
|
|
||||||
# 确保标注目录存在
|
|
||||||
os.makedirs('src/ui/static/annotations', exist_ok=True)
|
|
||||||
|
|
||||||
# 创建标注文件名和图像ID
|
|
||||||
image_id = f"img_{int(i+1)}"
|
|
||||||
annotation_path = f"src/ui/static/annotations/{image_id}.json"
|
|
||||||
|
|
||||||
# 保存标注
|
|
||||||
with open(annotation_path, 'w', encoding='utf-8') as f:
|
|
||||||
json.dump(casualties, f, ensure_ascii=False, indent=2)
|
|
||||||
|
|
||||||
print(f"已生成 {training_count} 张训练图片和标注,位于 src/ui/static/training_images/ 和 src/ui/static/annotations/")
|
|
@ -1,89 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# 确保目录结构存在
|
|
||||||
mkdir -p src/drone/
|
|
||||||
mkdir -p src/communication/
|
|
||||||
mkdir -p src/positioning/
|
|
||||||
mkdir -p src/ui/templates/
|
|
||||||
mkdir -p src/ui/static/css/
|
|
||||||
mkdir -p src/ui/static/js/
|
|
||||||
mkdir -p src/ui/static/img/
|
|
||||||
mkdir -p config/
|
|
||||||
mkdir -p tests/
|
|
||||||
|
|
||||||
# 创建空的__init__.py文件确保模块可以被导入
|
|
||||||
touch src/__init__.py
|
|
||||||
touch src/drone/__init__.py
|
|
||||||
touch src/communication/__init__.py
|
|
||||||
touch src/positioning/__init__.py
|
|
||||||
touch src/ui/__init__.py
|
|
||||||
touch config/__init__.py
|
|
||||||
touch tests/__init__.py
|
|
||||||
|
|
||||||
# 创建无人机和伤员图标
|
|
||||||
echo "创建示例图标..."
|
|
||||||
# 无人机图标
|
|
||||||
cat > src/ui/static/img/drone.png << EOF
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA
|
|
||||||
AXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAA
|
|
||||||
DsMAAA7DAcdvqGQAAAKDSURBVFhHxZdPSBRhGMZnZ/9o/9xd
|
|
||||||
d1ddT0GHUiGDoEMQhEGHOhR0COoQdKhLHToEXYIuQYc8BR3q
|
|
||||||
VNChQ9Ch6BAEHaJDRIeIVNBW27Vd/7XrzrwzO9O8M9/MfLM7
|
|
||||||
s+sXPPDyvO/7vd+8O7PrjrFGnMP+vgZ0dnZmzs/Pb0aj0QBG
|
|
||||||
e97QJyqRSOB8Po8WFxcPAZcYehD0H9GRy+WyiAcpM4BvuKn/
|
|
||||||
qCiKKkVRphgacCrYcRFPOHWQxpPJ5HWn/lZQFYkHQYWC0mJU
|
|
||||||
wkk8CAqgKvHyIMchCDGqkuPQoEQQJMehAWLUiSAYZJbfb5TN
|
|
||||||
Zvc45zrQCfN+NiC0iG4RoQUQIYi7xMuDHIcgxKhKjkODEkGQ
|
|
||||||
HIcGiFF1iECQWbqDZmZmWs+0w2P9osBJtBvQCQdxXRA4wE5g
|
|
||||||
NZvNcpzjnMsTlHQA12q1E4CfAF47OTnp5TgvJCh6jO5Fh4eH
|
|
||||||
Wcj7gPfAHx1APB7/heMxdH9lZeUaJz00CrgYCCGb8/PzF7PZ
|
|
||||||
7KKqqsfGzMuHVAECyePj428qlconY+blQwbQBXg3nU4/xgXk
|
|
||||||
G6/CILtgjGgX8AGOBYyJ14YxoxeZqrPwkN2CfUQDbI2yGRGx
|
|
||||||
lI+FdAuwM1qtVhPbIxmPx28ZMxdEAXbGW1tbK81m81MqlRox
|
|
||||||
Zi6ILoB3wpOTk0cAj8Hr7e3t58bMBa/nQAdxPB/GA/nU1dV1
|
|
||||||
wZhZIP8GaJBMJge2t7efxWKxH9PT0/nBwcFOjnPCi4EQYYLZ
|
|
||||||
WVb8FZIpE0D89MTERO/Ozs55o+TlQ7YLsJPvPEbrOA7X6/XL
|
|
||||||
uCZrxk4P2QDojPgf0wlgEvB+aWlpbWho6J/REqA6Rv8B0U+G
|
|
||||||
YRp/6oQAAAAASUVORK5CYII=
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 伤员图标
|
|
||||||
cat > src/ui/static/img/casualty.png << EOF
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA
|
|
||||||
AXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAA
|
|
||||||
DsMAAA7DAcdvqGQAAAKDSURBVFhHxZdPSBRhGMZnZ/9o/9xd
|
|
||||||
d1ddT0GHUiGDoEMQhEGHOhR0COoQdKhLHToEXYIuQYc8BR3q
|
|
||||||
VNChQ9Ch6BAEHaJDRIeIVNBW27Vd/7XrzrwzO9O8M9/MfLM7
|
|
||||||
s+sXPPDyvO/7vd+8O7PrjrFGnMP+vgZ0dnZmzs/Pb0aj0QBG
|
|
||||||
e97QJyqRSOB8Po8WFxcPAZcYehD0H9GRy+WyiAcpM4BvuKn/
|
|
||||||
qCiKKkVRphgacCrYcRFPOHWQxpPJ5HWn/lZQFYkHQYWC0mJU
|
|
||||||
wkk8CAqgKvHyIMchCDGqkuPQoEQQJMehAWLUiSAYZJbfb5TN
|
|
||||||
Zvc45zrQCfN+NiC0iG4RoQUQIYi7xMuDHIcgxKhKjkODEkGQ
|
|
||||||
HIcGiFF1iECQWbqDZmZmWs+0w2P9osBJtBvQCQdxXRA4wE5g
|
|
||||||
NZvNcpzjnMsTlHQA12q1E4CfAF47OTnp5TgvJCh6jO5Fh4eH
|
|
||||||
Wcj7gPfAHx1APB7/heMxdH9lZeUaJz00CrgYCCGb8/PzF7PZ
|
|
||||||
7KKqqsfGzMuHVAECyePj428qlconY+blQwbQBXg3nU4/xgXk
|
|
||||||
G6/CILtgjGgX8AGOBYyJ14YxoxeZqrPwkN2CfUQDbI2yGRGx
|
|
||||||
lI+FdAuwM1qtVhPbIxmPx28ZMxdEAXbGW1tbK81m81MqlRox
|
|
||||||
Zi6ILoB3wpOTk0cAj8Hr7e3t58bMBa/nQAdxPB/GA/nU1dV1
|
|
||||||
wZhZIP8GaJBMJge2t7efxWKxH9PT0/nBwcFOjnPCi4EQYYLZ
|
|
||||||
WVb8FZIpE0D89MTERO/Ozs55o+TlQ7YLsJPvPEbrOA7X6/XL
|
|
||||||
uCZrxk4P2QDojPgf0wlgEvB+aWlpbWho6J/REqA6Rv8B0U+G
|
|
||||||
YRp/6oQAAAAASUVORK5CYII=
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# 创建环境变量文件
|
|
||||||
cp .env.example .env
|
|
||||||
|
|
||||||
# 创建一个简单的运行脚本
|
|
||||||
cat > run.sh << EOF
|
|
||||||
#!/bin/bash
|
|
||||||
python simulation.py "\$@"
|
|
||||||
EOF
|
|
||||||
chmod +x run.sh
|
|
||||||
|
|
||||||
echo "项目初始化完成!"
|
|
||||||
echo "运行以下命令安装依赖:"
|
|
||||||
echo " pip install -r requirements.txt"
|
|
||||||
echo "运行系统:"
|
|
||||||
echo " ./run.sh"
|
|
@ -1,9 +0,0 @@
|
|||||||
pymavlink==2.4.35
|
|
||||||
dronekit==2.9.2
|
|
||||||
pyserial==3.5
|
|
||||||
flask==2.3.3
|
|
||||||
flask-socketio==5.3.6
|
|
||||||
python-dotenv==1.0.0
|
|
||||||
geopy==2.4.1
|
|
||||||
numpy==1.24.3
|
|
||||||
pandas==2.0.3
|
|
@ -1,194 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
import random
|
|
||||||
import threading
|
|
||||||
import signal
|
|
||||||
import argparse
|
|
||||||
from config.config import current_config as config
|
|
||||||
|
|
||||||
# 确保环境变量设置为启用模拟
|
|
||||||
os.environ['ENABLE_SIMULATION'] = 'True'
|
|
||||||
|
|
||||||
# 设置日志
|
|
||||||
config.setup_logging()
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class DroneSimulator:
|
|
||||||
"""无人机模拟器"""
|
|
||||||
|
|
||||||
def __init__(self, port=14550):
|
|
||||||
"""初始化模拟器"""
|
|
||||||
self.port = port
|
|
||||||
self.running = False
|
|
||||||
self.thread = None
|
|
||||||
self.latitude = config.BASE_LATITUDE
|
|
||||||
self.longitude = config.BASE_LONGITUDE
|
|
||||||
self.altitude = 0.0
|
|
||||||
self.battery = 100.0
|
|
||||||
self.armed = False
|
|
||||||
self.mode = "GUIDED"
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
"""启动模拟器"""
|
|
||||||
if self.running:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.running = True
|
|
||||||
self.thread = threading.Thread(target=self._simulation_loop, daemon=True)
|
|
||||||
self.thread.start()
|
|
||||||
logger.info(f"模拟器已启动在端口 {self.port}")
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
"""停止模拟器"""
|
|
||||||
if not self.running:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.running = False
|
|
||||||
if self.thread:
|
|
||||||
self.thread.join(timeout=2)
|
|
||||||
logger.info("模拟器已停止")
|
|
||||||
|
|
||||||
def _simulation_loop(self):
|
|
||||||
"""模拟循环"""
|
|
||||||
while self.running:
|
|
||||||
# 模拟电池消耗
|
|
||||||
if self.armed and self.battery > 0:
|
|
||||||
self.battery -= 0.01
|
|
||||||
if self.battery < 0:
|
|
||||||
self.battery = 0
|
|
||||||
|
|
||||||
# 模拟位置变化
|
|
||||||
if self.armed and self.mode == "GUIDED" and self.altitude > 0:
|
|
||||||
# 随机漂移
|
|
||||||
self.latitude += random.uniform(-0.00001, 0.00001)
|
|
||||||
self.longitude += random.uniform(-0.00001, 0.00001)
|
|
||||||
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
def arm(self):
|
|
||||||
"""解锁无人机"""
|
|
||||||
self.armed = True
|
|
||||||
logger.info("模拟无人机已解锁")
|
|
||||||
|
|
||||||
def disarm(self):
|
|
||||||
"""锁定无人机"""
|
|
||||||
self.armed = False
|
|
||||||
logger.info("模拟无人机已锁定")
|
|
||||||
|
|
||||||
def set_mode(self, mode):
|
|
||||||
"""设置模式"""
|
|
||||||
self.mode = mode
|
|
||||||
logger.info(f"模拟无人机模式已设置为 {mode}")
|
|
||||||
|
|
||||||
def takeoff(self, altitude):
|
|
||||||
"""起飞"""
|
|
||||||
self.arm()
|
|
||||||
self.altitude = altitude
|
|
||||||
logger.info(f"模拟无人机起飞到高度 {altitude}m")
|
|
||||||
|
|
||||||
def land(self):
|
|
||||||
"""降落"""
|
|
||||||
self.altitude = 0
|
|
||||||
self.disarm()
|
|
||||||
logger.info("模拟无人机已降落")
|
|
||||||
|
|
||||||
def goto(self, lat, lon, alt):
|
|
||||||
"""飞往指定位置"""
|
|
||||||
logger.info(f"模拟无人机飞往 ({lat}, {lon}, {alt})")
|
|
||||||
|
|
||||||
# 模拟飞行时间
|
|
||||||
distance = ((lat - self.latitude) ** 2 + (lon - self.longitude) ** 2) ** 0.5 * 111000
|
|
||||||
speed = 5.0 # 假设速度为5m/s
|
|
||||||
flight_time = distance / speed
|
|
||||||
|
|
||||||
# 模拟飞行过程
|
|
||||||
start_lat = self.latitude
|
|
||||||
start_lon = self.longitude
|
|
||||||
start_alt = self.altitude
|
|
||||||
|
|
||||||
for i in range(10):
|
|
||||||
progress = (i + 1) / 10
|
|
||||||
self.latitude = start_lat + (lat - start_lat) * progress
|
|
||||||
self.longitude = start_lon + (lon - start_lon) * progress
|
|
||||||
self.altitude = start_alt + (alt - start_alt) * progress
|
|
||||||
time.sleep(flight_time / 10)
|
|
||||||
|
|
||||||
self.latitude = lat
|
|
||||||
self.longitude = lon
|
|
||||||
self.altitude = alt
|
|
||||||
logger.info(f"模拟无人机已到达 ({lat}, {lon}, {alt})")
|
|
||||||
|
|
||||||
|
|
||||||
def setup_simulation():
|
|
||||||
"""设置模拟环境"""
|
|
||||||
# 启动模拟器
|
|
||||||
simulator = DroneSimulator()
|
|
||||||
simulator.start()
|
|
||||||
|
|
||||||
# 创建SITL连接字符串和覆盖环境变量
|
|
||||||
os.environ['DRONE_CONNECTION_STRING'] = f'udpin:localhost:{simulator.port}'
|
|
||||||
|
|
||||||
return simulator
|
|
||||||
|
|
||||||
|
|
||||||
def run_simulation():
|
|
||||||
"""运行模拟"""
|
|
||||||
# 设置参数解析
|
|
||||||
parser = argparse.ArgumentParser(description='智能战场医疗后送系统模拟器')
|
|
||||||
parser.add_argument('--web-port', type=int, default=8080, help='Web服务端口')
|
|
||||||
parser.add_argument('--comm-port', type=int, default=5000, help='通信服务端口')
|
|
||||||
parser.add_argument('--drone-port', type=int, default=14550, help='无人机模拟器端口')
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# 设置环境变量
|
|
||||||
os.environ['WEB_PORT'] = str(args.web_port)
|
|
||||||
os.environ['COMM_PORT'] = str(args.comm_port)
|
|
||||||
|
|
||||||
# 启动模拟器
|
|
||||||
simulator = DroneSimulator(port=args.drone_port)
|
|
||||||
simulator.start()
|
|
||||||
|
|
||||||
# 导入主程序模块
|
|
||||||
from main import MedicalEvacuationSystem
|
|
||||||
|
|
||||||
# 创建系统实例
|
|
||||||
system = MedicalEvacuationSystem()
|
|
||||||
|
|
||||||
# 注册信号处理
|
|
||||||
def signal_handler(sig, frame):
|
|
||||||
logger.info("接收到停止信号,正在关闭模拟器...")
|
|
||||||
system.stop()
|
|
||||||
simulator.stop()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
|
||||||
signal.signal(signal.SIGTERM, signal_handler)
|
|
||||||
|
|
||||||
# 启动系统
|
|
||||||
try:
|
|
||||||
if system.start():
|
|
||||||
logger.info("系统启动成功,运行在模拟模式")
|
|
||||||
|
|
||||||
# 保持程序运行
|
|
||||||
while True:
|
|
||||||
time.sleep(1)
|
|
||||||
else:
|
|
||||||
logger.error("系统启动失败")
|
|
||||||
simulator.stop()
|
|
||||||
return 1
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"模拟运行错误: {str(e)}")
|
|
||||||
system.stop()
|
|
||||||
simulator.stop()
|
|
||||||
return 1
|
|
||||||
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
exit_code = run_simulation()
|
|
||||||
sys.exit(exit_code)
|
|
@ -1,140 +0,0 @@
|
|||||||
import socket
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
from threading import Thread, Lock
|
|
||||||
|
|
||||||
class CommunicationManager:
|
|
||||||
def __init__(self, host='0.0.0.0', port=5000):
|
|
||||||
"""
|
|
||||||
初始化通信管理器
|
|
||||||
:param host: 服务器主机地址
|
|
||||||
:param port: 服务器端口
|
|
||||||
"""
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.server_socket = None
|
|
||||||
self.clients = []
|
|
||||||
self.lock = Lock()
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
self.casualty_handler = None
|
|
||||||
self.supply_handler = None
|
|
||||||
|
|
||||||
def set_casualty_handler(self, handler):
|
|
||||||
"""
|
|
||||||
设置伤员处理回调函数
|
|
||||||
:param handler: 处理函数
|
|
||||||
"""
|
|
||||||
self.casualty_handler = handler
|
|
||||||
self.logger.info("已设置伤员处理回调函数")
|
|
||||||
|
|
||||||
def set_supply_handler(self, handler):
|
|
||||||
"""
|
|
||||||
设置物资处理回调函数
|
|
||||||
:param handler: 处理函数
|
|
||||||
"""
|
|
||||||
self.supply_handler = handler
|
|
||||||
self.logger.info("已设置物资处理回调函数")
|
|
||||||
|
|
||||||
def start_server(self):
|
|
||||||
"""启动通信服务器"""
|
|
||||||
try:
|
|
||||||
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.server_socket.bind((self.host, self.port))
|
|
||||||
self.server_socket.listen(5)
|
|
||||||
self.logger.info(f"通信服务器启动在 {self.host}:{self.port}")
|
|
||||||
|
|
||||||
# 启动客户端接受线程
|
|
||||||
Thread(target=self._accept_clients, daemon=True).start()
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"启动服务器失败: {str(e)}")
|
|
||||||
|
|
||||||
def _accept_clients(self):
|
|
||||||
"""接受新的客户端连接"""
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
client_socket, address = self.server_socket.accept()
|
|
||||||
self.logger.info(f"新客户端连接: {address}")
|
|
||||||
|
|
||||||
with self.lock:
|
|
||||||
self.clients.append(client_socket)
|
|
||||||
|
|
||||||
# 为每个客户端启动一个处理线程
|
|
||||||
Thread(target=self._handle_client, args=(client_socket,), daemon=True).start()
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"接受客户端连接失败: {str(e)}")
|
|
||||||
|
|
||||||
def _handle_client(self, client_socket):
|
|
||||||
"""处理客户端消息"""
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
data = client_socket.recv(1024).decode('utf-8')
|
|
||||||
if not data:
|
|
||||||
break
|
|
||||||
|
|
||||||
message = json.loads(data)
|
|
||||||
self._process_message(message)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"处理客户端消息失败: {str(e)}")
|
|
||||||
break
|
|
||||||
|
|
||||||
# 客户端断开连接
|
|
||||||
with self.lock:
|
|
||||||
if client_socket in self.clients:
|
|
||||||
self.clients.remove(client_socket)
|
|
||||||
client_socket.close()
|
|
||||||
|
|
||||||
def _process_message(self, message):
|
|
||||||
"""
|
|
||||||
处理接收到的消息
|
|
||||||
:param message: 消息内容
|
|
||||||
"""
|
|
||||||
message_type = message.get('type')
|
|
||||||
if message_type == 'casualty_location':
|
|
||||||
self._handle_casualty_location(message)
|
|
||||||
elif message_type == 'medical_supply_request':
|
|
||||||
self._handle_medical_supply_request(message)
|
|
||||||
elif message_type == 'drone_status':
|
|
||||||
self._handle_drone_status(message)
|
|
||||||
|
|
||||||
def _handle_casualty_location(self, message):
|
|
||||||
"""处理伤员位置信息"""
|
|
||||||
location = message.get('location')
|
|
||||||
self.logger.info(f"收到伤员位置: {location}")
|
|
||||||
if self.casualty_handler:
|
|
||||||
self.casualty_handler(message)
|
|
||||||
|
|
||||||
def _handle_medical_supply_request(self, message):
|
|
||||||
"""处理医疗物资请求"""
|
|
||||||
supplies = message.get('supplies')
|
|
||||||
location = message.get('location')
|
|
||||||
self.logger.info(f"收到医疗物资请求: {supplies} 送往 {location}")
|
|
||||||
if self.supply_handler:
|
|
||||||
self.supply_handler(message)
|
|
||||||
|
|
||||||
def _handle_drone_status(self, message):
|
|
||||||
"""处理无人机状态信息"""
|
|
||||||
status = message.get('status')
|
|
||||||
self.logger.info(f"收到无人机状态: {status}")
|
|
||||||
# TODO: 实现无人机状态处理逻辑
|
|
||||||
|
|
||||||
def broadcast_message(self, message):
|
|
||||||
"""
|
|
||||||
广播消息给所有客户端
|
|
||||||
:param message: 要广播的消息
|
|
||||||
"""
|
|
||||||
message_str = json.dumps(message)
|
|
||||||
with self.lock:
|
|
||||||
for client in self.clients:
|
|
||||||
try:
|
|
||||||
client.send(message_str.encode('utf-8'))
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"发送消息失败: {str(e)}")
|
|
||||||
|
|
||||||
def close(self):
|
|
||||||
"""关闭通信服务器"""
|
|
||||||
if self.server_socket:
|
|
||||||
self.server_socket.close()
|
|
||||||
self.logger.info("通信服务器已关闭")
|
|
@ -1,19 +0,0 @@
|
|||||||
from flask import Flask
|
|
||||||
from config.database import db_config
|
|
||||||
from src.db.models import db
|
|
||||||
|
|
||||||
def init_db(app: Flask):
|
|
||||||
"""初始化数据库"""
|
|
||||||
# 配置SQLAlchemy
|
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = db_config.SQLALCHEMY_DATABASE_URI
|
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = db_config.SQLALCHEMY_TRACK_MODIFICATIONS
|
|
||||||
app.config['SQLALCHEMY_ECHO'] = db_config.SQLALCHEMY_ECHO
|
|
||||||
|
|
||||||
# 初始化SQLAlchemy
|
|
||||||
db.init_app(app)
|
|
||||||
|
|
||||||
# 创建所有表(如果不存在)
|
|
||||||
with app.app_context():
|
|
||||||
db.create_all()
|
|
||||||
|
|
||||||
return db
|
|
@ -1,271 +0,0 @@
|
|||||||
import logging
|
|
||||||
import time
|
|
||||||
from enum import Enum
|
|
||||||
from typing import Dict, List, Optional, Tuple
|
|
||||||
from queue import Queue
|
|
||||||
from threading import Thread, Lock
|
|
||||||
|
|
||||||
class MissionType(Enum):
|
|
||||||
"""任务类型枚举"""
|
|
||||||
IDLE = 0
|
|
||||||
MEDICAL_SUPPLY = 1
|
|
||||||
SURVEILLANCE = 2
|
|
||||||
RETURN_TO_BASE = 3
|
|
||||||
|
|
||||||
class MissionStatus(Enum):
|
|
||||||
"""任务状态枚举"""
|
|
||||||
PENDING = 0
|
|
||||||
IN_PROGRESS = 1
|
|
||||||
COMPLETED = 2
|
|
||||||
FAILED = 3
|
|
||||||
|
|
||||||
class Mission:
|
|
||||||
"""任务类"""
|
|
||||||
def __init__(self,
|
|
||||||
mission_id: str,
|
|
||||||
mission_type: MissionType,
|
|
||||||
target_location: Tuple[float, float],
|
|
||||||
altitude: float = 10.0,
|
|
||||||
payload: Dict = None):
|
|
||||||
"""
|
|
||||||
初始化任务
|
|
||||||
:param mission_id: 任务ID
|
|
||||||
:param mission_type: 任务类型
|
|
||||||
:param target_location: 目标位置(纬度, 经度)
|
|
||||||
:param altitude: 飞行高度(米)
|
|
||||||
:param payload: 任务负载(如物资信息)
|
|
||||||
"""
|
|
||||||
self.mission_id = mission_id
|
|
||||||
self.mission_type = mission_type
|
|
||||||
self.target_location = target_location
|
|
||||||
self.altitude = altitude
|
|
||||||
self.payload = payload or {}
|
|
||||||
self.status = MissionStatus.PENDING
|
|
||||||
self.start_time = None
|
|
||||||
self.end_time = None
|
|
||||||
self.error_message = None
|
|
||||||
|
|
||||||
def to_dict(self) -> Dict:
|
|
||||||
"""转换成字典"""
|
|
||||||
return {
|
|
||||||
'mission_id': self.mission_id,
|
|
||||||
'mission_type': self.mission_type.name,
|
|
||||||
'target_location': self.target_location,
|
|
||||||
'altitude': self.altitude,
|
|
||||||
'payload': self.payload,
|
|
||||||
'status': self.status.name,
|
|
||||||
'start_time': self.start_time,
|
|
||||||
'end_time': self.end_time,
|
|
||||||
'error_message': self.error_message
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class MissionPlanner:
|
|
||||||
"""任务规划器"""
|
|
||||||
def __init__(self, drone_controller):
|
|
||||||
"""
|
|
||||||
初始化任务规划器
|
|
||||||
:param drone_controller: 无人机控制器
|
|
||||||
"""
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
self.drone_controller = drone_controller
|
|
||||||
self.mission_queue = Queue()
|
|
||||||
self.current_mission = None
|
|
||||||
self.mission_history = []
|
|
||||||
self.lock = Lock()
|
|
||||||
self.running = False
|
|
||||||
self.worker_thread = None
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
"""启动任务规划器"""
|
|
||||||
if self.running:
|
|
||||||
self.logger.warning("任务规划器已经在运行")
|
|
||||||
return
|
|
||||||
|
|
||||||
self.running = True
|
|
||||||
self.worker_thread = Thread(target=self._mission_worker, daemon=True)
|
|
||||||
self.worker_thread.start()
|
|
||||||
self.logger.info("任务规划器已启动")
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
"""停止任务规划器"""
|
|
||||||
if not self.running:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.running = False
|
|
||||||
if self.worker_thread:
|
|
||||||
self.worker_thread.join(timeout=5)
|
|
||||||
self.logger.info("任务规划器已停止")
|
|
||||||
|
|
||||||
def add_mission(self, mission: Mission) -> bool:
|
|
||||||
"""
|
|
||||||
添加任务到队列
|
|
||||||
:param mission: 任务对象
|
|
||||||
:return: 是否添加成功
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
self.mission_queue.put(mission)
|
|
||||||
self.logger.info(f"添加任务: ID={mission.mission_id}, 类型={mission.mission_type.name}")
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"添加任务失败: {str(e)}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_current_mission(self) -> Optional[Mission]:
|
|
||||||
"""
|
|
||||||
获取当前执行的任务
|
|
||||||
:return: 当前任务或None
|
|
||||||
"""
|
|
||||||
with self.lock:
|
|
||||||
return self.current_mission
|
|
||||||
|
|
||||||
def get_mission_queue_size(self) -> int:
|
|
||||||
"""
|
|
||||||
获取任务队列大小
|
|
||||||
:return: 队列中的任务数
|
|
||||||
"""
|
|
||||||
return self.mission_queue.qsize()
|
|
||||||
|
|
||||||
def get_mission_history(self) -> List[Dict]:
|
|
||||||
"""
|
|
||||||
获取任务历史
|
|
||||||
:return: 任务历史记录列表
|
|
||||||
"""
|
|
||||||
with self.lock:
|
|
||||||
return [mission.to_dict() for mission in self.mission_history]
|
|
||||||
|
|
||||||
def _mission_worker(self):
|
|
||||||
"""任务工作线程"""
|
|
||||||
while self.running:
|
|
||||||
try:
|
|
||||||
if not self.mission_queue.empty():
|
|
||||||
# 从队列中获取下一个任务
|
|
||||||
mission = self.mission_queue.get()
|
|
||||||
|
|
||||||
with self.lock:
|
|
||||||
self.current_mission = mission
|
|
||||||
self.current_mission.status = MissionStatus.IN_PROGRESS
|
|
||||||
self.current_mission.start_time = time.time()
|
|
||||||
|
|
||||||
self.logger.info(f"开始执行任务: ID={mission.mission_id}, 类型={mission.mission_type.name}")
|
|
||||||
|
|
||||||
# 根据任务类型执行不同操作
|
|
||||||
success = self._execute_mission(mission)
|
|
||||||
|
|
||||||
with self.lock:
|
|
||||||
if success:
|
|
||||||
self.current_mission.status = MissionStatus.COMPLETED
|
|
||||||
self.logger.info(f"任务完成: ID={mission.mission_id}")
|
|
||||||
else:
|
|
||||||
self.current_mission.status = MissionStatus.FAILED
|
|
||||||
self.logger.error(f"任务失败: ID={mission.mission_id}")
|
|
||||||
|
|
||||||
self.current_mission.end_time = time.time()
|
|
||||||
self.mission_history.append(self.current_mission)
|
|
||||||
self.current_mission = None
|
|
||||||
|
|
||||||
self.mission_queue.task_done()
|
|
||||||
else:
|
|
||||||
# 无任务时等待
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"任务执行过程出错: {str(e)}")
|
|
||||||
if self.current_mission:
|
|
||||||
with self.lock:
|
|
||||||
self.current_mission.status = MissionStatus.FAILED
|
|
||||||
self.current_mission.error_message = str(e)
|
|
||||||
self.current_mission.end_time = time.time()
|
|
||||||
self.mission_history.append(self.current_mission)
|
|
||||||
self.current_mission = None
|
|
||||||
|
|
||||||
def _execute_mission(self, mission: Mission) -> bool:
|
|
||||||
"""
|
|
||||||
执行任务
|
|
||||||
:param mission: 任务对象
|
|
||||||
:return: 是否执行成功
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if mission.mission_type == MissionType.MEDICAL_SUPPLY:
|
|
||||||
return self._execute_medical_supply_mission(mission)
|
|
||||||
elif mission.mission_type == MissionType.SURVEILLANCE:
|
|
||||||
return self._execute_surveillance_mission(mission)
|
|
||||||
elif mission.mission_type == MissionType.RETURN_TO_BASE:
|
|
||||||
return self._execute_return_to_base_mission(mission)
|
|
||||||
else:
|
|
||||||
self.logger.warning(f"未知任务类型: {mission.mission_type}")
|
|
||||||
return False
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"执行任务失败: {str(e)}")
|
|
||||||
mission.error_message = str(e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _execute_medical_supply_mission(self, mission: Mission) -> bool:
|
|
||||||
"""
|
|
||||||
执行医疗物资运送任务
|
|
||||||
:param mission: 任务对象
|
|
||||||
:return: 是否执行成功
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 飞往目标位置
|
|
||||||
lat, lon = mission.target_location
|
|
||||||
self.drone_controller.goto_location(lat, lon, mission.altitude)
|
|
||||||
|
|
||||||
# 模拟投放物资(实际应该有硬件操作)
|
|
||||||
self.logger.info(f"投放医疗物资: {mission.payload.get('supply_name', '未知物资')}")
|
|
||||||
time.sleep(2) # 模拟投放时间
|
|
||||||
|
|
||||||
# 返回基地
|
|
||||||
return self._execute_return_to_base_mission(mission)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"医疗物资任务执行失败: {str(e)}")
|
|
||||||
mission.error_message = str(e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _execute_surveillance_mission(self, mission: Mission) -> bool:
|
|
||||||
"""
|
|
||||||
执行侦察任务
|
|
||||||
:param mission: 任务对象
|
|
||||||
:return: 是否执行成功
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 飞往目标位置
|
|
||||||
lat, lon = mission.target_location
|
|
||||||
self.drone_controller.goto_location(lat, lon, mission.altitude)
|
|
||||||
|
|
||||||
# 模拟侦察(实际应该有摄像头操作)
|
|
||||||
self.logger.info(f"进行区域侦察: ({lat}, {lon})")
|
|
||||||
time.sleep(5) # 模拟侦察时间
|
|
||||||
|
|
||||||
# 返回基地
|
|
||||||
return self._execute_return_to_base_mission(mission)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"侦察任务执行失败: {str(e)}")
|
|
||||||
mission.error_message = str(e)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _execute_return_to_base_mission(self, mission: Mission) -> bool:
|
|
||||||
"""
|
|
||||||
执行返回基地任务
|
|
||||||
:param mission: 任务对象
|
|
||||||
:return: 是否执行成功
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# 获取基地位置(这里应该从配置中读取)
|
|
||||||
base_lat, base_lon = 39.9, 116.3 # 默认位置,实际应该从配置获取
|
|
||||||
|
|
||||||
# 飞往基地
|
|
||||||
self.logger.info("返回基地")
|
|
||||||
self.drone_controller.goto_location(base_lat, base_lon, mission.altitude)
|
|
||||||
|
|
||||||
# 降落
|
|
||||||
self.drone_controller.land()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.error(f"返回基地任务执行失败: {str(e)}")
|
|
||||||
mission.error_message = str(e)
|
|
||||||
return False
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 192.75340195819638,
|
|
||||||
"y": 269.1060189546518,
|
|
||||||
"width": 442.41011984021304,
|
|
||||||
"height": 100.79002079002078,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 11.985121427837171,
|
|
||||||
"y": 117.62776025236593,
|
|
||||||
"width": 335.2926315789474,
|
|
||||||
"height": 184.41640378548897,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 12.780651033233484,
|
|
||||||
"y": 53.81395348837209,
|
|
||||||
"width": 707.7720207253885,
|
|
||||||
"height": 412.9186046511628,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 112.26251631820757,
|
|
||||||
"y": 376.3773436462995,
|
|
||||||
"width": 446.6321243523316,
|
|
||||||
"height": 147.99805825242714,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 677.3609536917098,
|
|
||||||
"y": 894.9805757837389,
|
|
||||||
"width": 1138.0725388601036,
|
|
||||||
"height": 442.63106796116494,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 194.732217611838,
|
|
||||||
"y": 293.69761911478724,
|
|
||||||
"width": 268.61626248216834,
|
|
||||||
"height": 167.63714902807772,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 142.80639735506196,
|
|
||||||
"y": 558.0339801654405,
|
|
||||||
"width": 488.30242510699003,
|
|
||||||
"height": 295.6647791619479,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 436.9429980658497,
|
|
||||||
"y": 254.91261424833132,
|
|
||||||
"width": 492.4352331606218,
|
|
||||||
"height": 341.12621359223294,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 225.6994747497875,
|
|
||||||
"y": 360.23300615329185,
|
|
||||||
"width": 537.2020725388602,
|
|
||||||
"height": 142.60194174757282,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,9 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"x": 16.974595112047698,
|
|
||||||
"y": 179.43037974683543,
|
|
||||||
"width": 453.0442105263158,
|
|
||||||
"height": 135.56962025316457,
|
|
||||||
"class": "casualty"
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,342 +0,0 @@
|
|||||||
/* 全局样式 */
|
|
||||||
body {
|
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
||||||
background-color: #f0f4f8;
|
|
||||||
color: #333;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar {
|
|
||||||
background: linear-gradient(90deg, #1a3a5f 0%, #2d5f8b 100%);
|
|
||||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
padding: 15px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar-brand {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
color: white !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 地图样式 */
|
|
||||||
#map {
|
|
||||||
height: 550px;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
||||||
border: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 状态面板样式 */
|
|
||||||
.status-panel {
|
|
||||||
background-color: white;
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
border-left: 4px solid #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-panel p {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
font-weight: 600;
|
|
||||||
background-color: #f8fafc;
|
|
||||||
padding: 15px;
|
|
||||||
border-bottom: 1px solid #e0e6ed;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header i {
|
|
||||||
margin-right: 8px;
|
|
||||||
color: #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-body {
|
|
||||||
padding: 20px;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮样式 */
|
|
||||||
.btn-primary {
|
|
||||||
background: linear-gradient(45deg, #2d5f8b 0%, #3498db 100%);
|
|
||||||
border: none;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
|
||||||
padding: 10px 16px;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover {
|
|
||||||
background: linear-gradient(45deg, #3498db 0%, #2d5f8b 100%);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
color: #495057;
|
|
||||||
border: 1px solid #ced4da;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary:hover {
|
|
||||||
background-color: #e2e6ea;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 列表样式 */
|
|
||||||
.casualty-item, .supply-item {
|
|
||||||
padding: 15px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
||||||
border-left: 4px solid #e74c3c;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.supply-item {
|
|
||||||
border-left-color: #2ecc71;
|
|
||||||
}
|
|
||||||
|
|
||||||
.casualty-item:hover, .supply-item:hover {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 状态指示器 */
|
|
||||||
.status-indicator {
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 8px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-idle {
|
|
||||||
background-color: #95a5a6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-in-flight {
|
|
||||||
background-color: #3498db;
|
|
||||||
animation: pulse 1.5s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-warning {
|
|
||||||
background-color: #f39c12;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-error {
|
|
||||||
background-color: #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pulse {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
50% { opacity: 0.5; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 任务列表样式 */
|
|
||||||
.mission-list {
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-list::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-list::-webkit-scrollbar-track {
|
|
||||||
background: #f1f1f1;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-list::-webkit-scrollbar-thumb {
|
|
||||||
background: #c1c1c1;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-item {
|
|
||||||
padding: 12px 15px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
border-radius: 6px;
|
|
||||||
background-color: white;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-pending {
|
|
||||||
border-left: 4px solid #95a5a6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-in-progress {
|
|
||||||
border-left: 4px solid #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-completed {
|
|
||||||
border-left: 4px solid #2ecc71;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mission-failed {
|
|
||||||
border-left: 4px solid #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 自定义地图标记样式 */
|
|
||||||
.casualty-marker .leaflet-popup-content-wrapper {
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 8px;
|
|
||||||
border-left: 4px solid #e74c3c;
|
|
||||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.drone-marker .leaflet-popup-content-wrapper {
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 8px;
|
|
||||||
border-left: 4px solid #3498db;
|
|
||||||
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 响应式布局调整 */
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
#map {
|
|
||||||
height: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col-md-4 {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-body {
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 地图标记样式 */
|
|
||||||
.map-marker {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.casualty-marker {
|
|
||||||
background-color: rgba(231, 76, 60, 0.9);
|
|
||||||
color: white;
|
|
||||||
font-size: 14px;
|
|
||||||
border: 2px solid white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drone-marker {
|
|
||||||
background-color: rgba(52, 152, 219, 0.9);
|
|
||||||
color: white;
|
|
||||||
font-size: 16px;
|
|
||||||
border: 2px solid white;
|
|
||||||
animation: pulse 1.5s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-content {
|
|
||||||
min-width: 200px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popup-content h6 {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-weight: 600;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-counter {
|
|
||||||
background-color: white;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 15px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-counter:hover {
|
|
||||||
transform: translateY(-3px);
|
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-counter span {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-counter p {
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
color: #7f8c8d;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 警告提示 */
|
|
||||||
.alert {
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 12px 15px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-info {
|
|
||||||
background-color: #e9f7fe;
|
|
||||||
color: #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 高级表单控件 */
|
|
||||||
.form-label {
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: #34495e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control, .form-select {
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 10px 12px;
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-control:focus, .form-select:focus {
|
|
||||||
border-color: #3498db;
|
|
||||||
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.25);
|
|
||||||
}
|
|
||||||
|
|
||||||
.badge {
|
|
||||||
padding: 6px 10px;
|
|
||||||
font-weight: 500;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
This is a placeholder for a real YOLO model file
|
|
@ -1,9 +0,0 @@
|
|||||||
# YOLOv5 数据集配置
|
|
||||||
path: src/ui/static/models\dataset
|
|
||||||
train: images/train
|
|
||||||
val: images/val
|
|
||||||
test: # 暂无测试集
|
|
||||||
|
|
||||||
# 类别
|
|
||||||
nc: 1 # 类别数量
|
|
||||||
names: ['casualty'] # 类别名称
|
|
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 200 KiB |
Before Width: | Height: | Size: 92 KiB |
Before Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 32 KiB |
@ -1 +0,0 @@
|
|||||||
0 0.5519446158377372 0.6656271444784629 0.5898801597869507 0.20997920997920996
|
|
@ -1 +0,0 @@
|
|||||||
0 0.3789692768297698 0.6640378548895899 0.7073684210526316 0.583596214511041
|
|
@ -1 +0,0 @@
|
|||||||
0 0.4583333267449097 0.4874031007751938 0.8847150259067357 0.7732558139534884
|
|
@ -1 +0,0 @@
|
|||||||
0 0.4194732231179667 0.844983813832107 0.5582901554404145 0.2776699029126213
|
|
@ -1 +0,0 @@
|
|||||||
0 0.6085923941024227 0.8177993478126897 0.555699481865285 0.3242718446601941
|
|
@ -1 +0,0 @@
|
|||||||
0 0.4700576412184603 0.8171346182442123 0.38373751783166904 0.36285097192224613
|
|
@ -1 +0,0 @@
|
|||||||
0 0.5527965855836527 0.8003020065152091 0.6975748930099858 0.33522083805209507
|
|
@ -1 +0,0 @@
|
|||||||
0 0.632556124672371 0.590938501450622 0.455958549222798 0.4737864077669902
|
|
@ -1 +0,0 @@
|
|||||||
0 0.4576856583511274 0.599352745870942 0.49740932642487057 0.19805825242718447
|
|
@ -1 +0,0 @@
|
|||||||
0 0.5137061189350329 0.7848101265822786 0.9557894736842105 0.4303797468354431
|
|
@ -1,170 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "train_1746536145",
|
|
||||||
"model_type": "yolov5s",
|
|
||||||
"epochs": 50,
|
|
||||||
"batch_size": 16,
|
|
||||||
"train_split": 80,
|
|
||||||
"model_name": "casualty_detector_v1",
|
|
||||||
"status": "completed",
|
|
||||||
"created_at": 1746536145.3327265,
|
|
||||||
"model_path": "src/ui/static/models\\casualty_detector_v1.pt",
|
|
||||||
"results": {
|
|
||||||
"epochs": [
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
3,
|
|
||||||
4,
|
|
||||||
5,
|
|
||||||
6,
|
|
||||||
7,
|
|
||||||
8,
|
|
||||||
9,
|
|
||||||
10,
|
|
||||||
11,
|
|
||||||
12,
|
|
||||||
13,
|
|
||||||
14,
|
|
||||||
15,
|
|
||||||
16,
|
|
||||||
17,
|
|
||||||
18,
|
|
||||||
19,
|
|
||||||
20,
|
|
||||||
21,
|
|
||||||
22,
|
|
||||||
23,
|
|
||||||
24,
|
|
||||||
25,
|
|
||||||
26,
|
|
||||||
27,
|
|
||||||
28,
|
|
||||||
29,
|
|
||||||
30,
|
|
||||||
31,
|
|
||||||
32,
|
|
||||||
33,
|
|
||||||
34,
|
|
||||||
35,
|
|
||||||
36,
|
|
||||||
37,
|
|
||||||
38,
|
|
||||||
39,
|
|
||||||
40,
|
|
||||||
41,
|
|
||||||
42,
|
|
||||||
43,
|
|
||||||
44,
|
|
||||||
45,
|
|
||||||
46,
|
|
||||||
47,
|
|
||||||
48,
|
|
||||||
49,
|
|
||||||
50
|
|
||||||
],
|
|
||||||
"map": [
|
|
||||||
0.2346910205281687,
|
|
||||||
0.2465911830219659,
|
|
||||||
0.2573409338308947,
|
|
||||||
0.283949214087783,
|
|
||||||
0.29985140911865305,
|
|
||||||
0.3133456542772132,
|
|
||||||
0.3414636954072322,
|
|
||||||
0.3404219065408789,
|
|
||||||
0.3394574027871224,
|
|
||||||
0.3660841833106289,
|
|
||||||
0.38276835276908183,
|
|
||||||
0.4164534097991227,
|
|
||||||
0.39504794443286423,
|
|
||||||
0.41696871543371894,
|
|
||||||
0.42355650398958544,
|
|
||||||
0.4620468536652084,
|
|
||||||
0.4581694345192589,
|
|
||||||
0.4889842453771339,
|
|
||||||
0.5100454579134762,
|
|
||||||
0.5024204387235169,
|
|
||||||
0.5141007414159628,
|
|
||||||
0.5403691471891979,
|
|
||||||
0.5301660185073334,
|
|
||||||
0.5760235114161298,
|
|
||||||
0.5861124620696604,
|
|
||||||
0.5734799251193733,
|
|
||||||
0.613563278778363,
|
|
||||||
0.6019781840424621,
|
|
||||||
0.6124835374681992,
|
|
||||||
0.6648062309517518,
|
|
||||||
0.669743039182848,
|
|
||||||
0.6858017072735901,
|
|
||||||
0.6746423708794934,
|
|
||||||
0.7198532262813726,
|
|
||||||
0.7264158744035305,
|
|
||||||
0.7145871815350525,
|
|
||||||
0.7544234524933556,
|
|
||||||
0.7363939195224446,
|
|
||||||
0.7485789500260398,
|
|
||||||
0.7628166138477256,
|
|
||||||
0.8119847496417109,
|
|
||||||
0.8330255544173595,
|
|
||||||
0.8054526755408713,
|
|
||||||
0.8584588222370078,
|
|
||||||
0.8480172179298857,
|
|
||||||
0.8804983162248883,
|
|
||||||
0.8730853946854259,
|
|
||||||
0.8820644293747433,
|
|
||||||
0.890186227403441,
|
|
||||||
0.936543264621003
|
|
||||||
],
|
|
||||||
"loss": [
|
|
||||||
1.4952713683230068,
|
|
||||||
1.6241079711922601,
|
|
||||||
1.4556141314443767,
|
|
||||||
1.536875339018873,
|
|
||||||
1.582250123819695,
|
|
||||||
1.5200034162657587,
|
|
||||||
1.3981947004420512,
|
|
||||||
1.4676312861136551,
|
|
||||||
1.4700722509766602,
|
|
||||||
1.375187501451575,
|
|
||||||
1.3189966252775418,
|
|
||||||
1.2924728482593522,
|
|
||||||
1.3213448817287443,
|
|
||||||
1.3195207299055696,
|
|
||||||
1.3955919437857862,
|
|
||||||
1.231887561345098,
|
|
||||||
1.2721930658066198,
|
|
||||||
1.3068925731122645,
|
|
||||||
1.1826480682879805,
|
|
||||||
1.226094298070738,
|
|
||||||
1.126356833919786,
|
|
||||||
1.2223144647648188,
|
|
||||||
1.201390841319237,
|
|
||||||
1.0854719146621141,
|
|
||||||
1.0159738345019431,
|
|
||||||
1.0444867373351245,
|
|
||||||
1.1365222362152665,
|
|
||||||
1.0991116537142849,
|
|
||||||
0.981271583853104,
|
|
||||||
0.9295018427850593,
|
|
||||||
0.9021050310675309,
|
|
||||||
1.0155725886367946,
|
|
||||||
1.0124356436636157,
|
|
||||||
0.9777325532673871,
|
|
||||||
0.8102139457942824,
|
|
||||||
0.896013791152899,
|
|
||||||
0.8892310752180109,
|
|
||||||
0.8525369026809214,
|
|
||||||
0.7814648301152992,
|
|
||||||
0.7454667157507703,
|
|
||||||
0.7597884851926442,
|
|
||||||
0.7853594166017319,
|
|
||||||
0.833171319042936,
|
|
||||||
0.7362808873599007,
|
|
||||||
0.7006277248923057,
|
|
||||||
0.7026997869166967,
|
|
||||||
0.6064702709140819,
|
|
||||||
0.5530920661720794,
|
|
||||||
0.6786561049801432,
|
|
||||||
0.6553200520346033
|
|
||||||
],
|
|
||||||
"final_map": 0.936543264621003
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 482 KiB |
Before Width: | Height: | Size: 483 KiB |
Before Width: | Height: | Size: 486 KiB |
Before Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 134 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 200 KiB |
Before Width: | Height: | Size: 92 KiB |