Merge pull request '1' (#7) from yjh_branch into main
@ -0,0 +1,32 @@
|
|||||||
|
# 应用环境
|
||||||
|
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
|
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 200 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 66 KiB |
@ -0,0 +1,110 @@
|
|||||||
|
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()
|
@ -0,0 +1,29 @@
|
|||||||
|
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()
|
@ -0,0 +1,14 @@
|
|||||||
|
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文件")
|
@ -0,0 +1,168 @@
|
|||||||
|
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/")
|
@ -0,0 +1,89 @@
|
|||||||
|
#!/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"
|
@ -0,0 +1,9 @@
|
|||||||
|
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
|
@ -0,0 +1,194 @@
|
|||||||
|
#!/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)
|
@ -0,0 +1,140 @@
|
|||||||
|
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("通信服务器已关闭")
|
@ -0,0 +1,19 @@
|
|||||||
|
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
|
@ -0,0 +1,271 @@
|
|||||||
|
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
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 192.75340195819638,
|
||||||
|
"y": 269.1060189546518,
|
||||||
|
"width": 442.41011984021304,
|
||||||
|
"height": 100.79002079002078,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 11.985121427837171,
|
||||||
|
"y": 117.62776025236593,
|
||||||
|
"width": 335.2926315789474,
|
||||||
|
"height": 184.41640378548897,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 12.780651033233484,
|
||||||
|
"y": 53.81395348837209,
|
||||||
|
"width": 707.7720207253885,
|
||||||
|
"height": 412.9186046511628,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 112.26251631820757,
|
||||||
|
"y": 376.3773436462995,
|
||||||
|
"width": 446.6321243523316,
|
||||||
|
"height": 147.99805825242714,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 677.3609536917098,
|
||||||
|
"y": 894.9805757837389,
|
||||||
|
"width": 1138.0725388601036,
|
||||||
|
"height": 442.63106796116494,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 194.732217611838,
|
||||||
|
"y": 293.69761911478724,
|
||||||
|
"width": 268.61626248216834,
|
||||||
|
"height": 167.63714902807772,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 142.80639735506196,
|
||||||
|
"y": 558.0339801654405,
|
||||||
|
"width": 488.30242510699003,
|
||||||
|
"height": 295.6647791619479,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 436.9429980658497,
|
||||||
|
"y": 254.91261424833132,
|
||||||
|
"width": 492.4352331606218,
|
||||||
|
"height": 341.12621359223294,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 225.6994747497875,
|
||||||
|
"y": 360.23300615329185,
|
||||||
|
"width": 537.2020725388602,
|
||||||
|
"height": 142.60194174757282,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,9 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"x": 16.974595112047698,
|
||||||
|
"y": 179.43037974683543,
|
||||||
|
"width": 453.0442105263158,
|
||||||
|
"height": 135.56962025316457,
|
||||||
|
"class": "casualty"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,342 @@
|
|||||||
|
/* 全局样式 */
|
||||||
|
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;
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
This is a placeholder for a real YOLO model file
|
@ -0,0 +1,9 @@
|
|||||||
|
# YOLOv5 数据集配置
|
||||||
|
path: src/ui/static/models\dataset
|
||||||
|
train: images/train
|
||||||
|
val: images/val
|
||||||
|
test: # 暂无测试集
|
||||||
|
|
||||||
|
# 类别
|
||||||
|
nc: 1 # 类别数量
|
||||||
|
names: ['casualty'] # 类别名称
|
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 200 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 32 KiB |
@ -0,0 +1 @@
|
|||||||
|
0 0.5519446158377372 0.6656271444784629 0.5898801597869507 0.20997920997920996
|
@ -0,0 +1 @@
|
|||||||
|
0 0.3789692768297698 0.6640378548895899 0.7073684210526316 0.583596214511041
|
@ -0,0 +1 @@
|
|||||||
|
0 0.4583333267449097 0.4874031007751938 0.8847150259067357 0.7732558139534884
|
@ -0,0 +1 @@
|
|||||||
|
0 0.4194732231179667 0.844983813832107 0.5582901554404145 0.2776699029126213
|
@ -0,0 +1 @@
|
|||||||
|
0 0.6085923941024227 0.8177993478126897 0.555699481865285 0.3242718446601941
|
@ -0,0 +1 @@
|
|||||||
|
0 0.4700576412184603 0.8171346182442123 0.38373751783166904 0.36285097192224613
|
@ -0,0 +1 @@
|
|||||||
|
0 0.5527965855836527 0.8003020065152091 0.6975748930099858 0.33522083805209507
|
@ -0,0 +1 @@
|
|||||||
|
0 0.632556124672371 0.590938501450622 0.455958549222798 0.4737864077669902
|
@ -0,0 +1 @@
|
|||||||
|
0 0.4576856583511274 0.599352745870942 0.49740932642487057 0.19805825242718447
|
@ -0,0 +1 @@
|
|||||||
|
0 0.5137061189350329 0.7848101265822786 0.9557894736842105 0.4303797468354431
|
@ -0,0 +1,170 @@
|
|||||||
|
{
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 244 KiB |
After Width: | Height: | Size: 482 KiB |
After Width: | Height: | Size: 483 KiB |
After Width: | Height: | Size: 486 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 200 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 461 KiB |