1071 lines
25 KiB
Markdown
1071 lines
25 KiB
Markdown
# 机场碰撞预警系统设计文档
|
||
|
||
## 1. 系统概述
|
||
|
||
### 1.1 系统目标
|
||
|
||
实现机场内航空器与车辆的实时位置监控和碰撞预警。
|
||
|
||
### 1.2 主要功能
|
||
|
||
- 实时获取航空器位置数据
|
||
- 实时获取车辆位置数据
|
||
- 碰撞风险检测
|
||
- 预警信息输出
|
||
|
||
## 2. 系统架构
|
||
|
||
### 2.1 整体架构
|
||
|
||
- 数据采集层:负责从外部系统获取位置数据
|
||
- 数据处理层:进行坐标转换和数据规范化
|
||
- 碰撞检测层:执行碰撞风险分析
|
||
- 预警输出层:生成和发送预警信息
|
||
|
||
### 2.2 核心模块
|
||
|
||
1. System:系统总控模块
|
||
2. DataCollector:数据采集模块
|
||
3. CollisionDetector:碰撞检测模块
|
||
4. CoordinateConverter:坐标转换模块
|
||
|
||
## 3. 数据模型
|
||
|
||
### 3.1 基础数据类型
|
||
|
||
```cpp
|
||
// 移动物体类型
|
||
enum class MovingObjectType {
|
||
AIRCRAFT, // 航空器
|
||
SPECIAL, // 特勤车
|
||
UNMANNED // 无人车(可控车辆)
|
||
};
|
||
|
||
// 二维向量
|
||
struct Vector2D {
|
||
double x; // 东西方向(米)
|
||
double y; // 南北方向(米)
|
||
|
||
double magnitude() const; // 计算向量大小
|
||
double direction() const; // 计算向量方向
|
||
};
|
||
|
||
// 地理坐标
|
||
struct GeoPosition {
|
||
double latitude; // 纬度
|
||
double longitude; // 经度
|
||
};
|
||
|
||
// 位置记录
|
||
struct PositionRecord {
|
||
GeoPosition geo; // 地理位置
|
||
uint64_t timestamp; // 时间戳
|
||
};
|
||
|
||
// 移动物体基类
|
||
class MovingObject {
|
||
public:
|
||
std::string id; // 唯一标识
|
||
Vector2D position; // 平面坐标
|
||
GeoPosition geo; // 地理坐标
|
||
double heading; // 航向角
|
||
double speed; // 速度
|
||
int64_t timestamp; // 时间戳
|
||
MovingObjectType type; // 物体类型
|
||
std::deque<PositionRecord> positionHistory; // 位置历史记录
|
||
|
||
virtual bool isValidPosition(const GeoPosition& newPos) const = 0;
|
||
virtual bool isValidSpeed(double speed) const = 0;
|
||
void updateMotion(const GeoPosition& newPos, uint64_t newTime);
|
||
};
|
||
```
|
||
|
||
### 3.2 业务数据类型
|
||
|
||
```cpp
|
||
// 航空器
|
||
class Aircraft : public MovingObject {
|
||
public:
|
||
std::string flightNo; // 航班号
|
||
std::string trackNumber; // 航迹号
|
||
double altitude; // 高度(米)
|
||
|
||
static constexpr double MAX_SPEED = 100.0; // 最大速度(米/秒)
|
||
static constexpr double MAX_POSITION_JUMP = 50.0; // 最大位置跳变(米)
|
||
|
||
bool isValidPosition(const GeoPosition& newPos) const override;
|
||
bool isValidSpeed(double speed) const override;
|
||
};
|
||
|
||
// 车辆
|
||
class Vehicle : public MovingObject {
|
||
public:
|
||
std::string vehicleNo; // 车牌号
|
||
bool isControllable; // 是否可控
|
||
|
||
static constexpr double MAX_SPEED = 20.0; // 最大速度(米/秒)
|
||
static constexpr double MAX_POSITION_JUMP = 10.0; // 最大位置跳变(米)
|
||
|
||
bool isValidPosition(const GeoPosition& newPos) const override;
|
||
bool isValidSpeed(double speed) const override;
|
||
};
|
||
```
|
||
|
||
### 3.3 配置数据类型
|
||
|
||
```cpp
|
||
// 可控车辆配置
|
||
struct ControllableVehicleConfig {
|
||
std::string vehicleNo; // 车牌号
|
||
std::string ip; // 车辆IP地址
|
||
int port; // 车辆端口号
|
||
};
|
||
```
|
||
|
||
## 4. 接口设计
|
||
|
||
### 4.1 数据源接口
|
||
|
||
```cpp
|
||
class DataSource {
|
||
virtual std::vector<Aircraft> getAircraftData() = 0;
|
||
virtual std::vector<Vehicle> getVehicleData() = 0;
|
||
};
|
||
```
|
||
|
||
### 4.2 碰撞检测接口
|
||
|
||
```cpp
|
||
class CollisionDetector {
|
||
bool detectAircraft(const Aircraft& a1, const Aircraft& a2);
|
||
bool detectAircraftVehicle(const Aircraft& aircraft, const Vehicle& vehicle);
|
||
};
|
||
```
|
||
|
||
## 5. 碰撞检测算法
|
||
|
||
### 5.1 碰撞类型
|
||
|
||
系统支持以下碰撞类型:
|
||
|
||
1. HEAD_ON:相向碰撞(航向差大于 150 度)
|
||
2. CROSSING:交叉碰撞(航向差在 15-165 度之间)
|
||
3. PARALLEL:平行碰撞(航向差小于 30 度)
|
||
4. STATIC:静止碰撞(双方速度接近 0)
|
||
|
||
### 5.2 风险等级
|
||
|
||
```cpp
|
||
enum class RiskLevel {
|
||
NONE = 0, // 无风险
|
||
WARNING = 1, // 预警:进入预警区域
|
||
CRITICAL = 2 // 告警:进入危险区域
|
||
};
|
||
|
||
enum class WarningZoneType {
|
||
NONE = 0, // 无风险区域
|
||
WARNING = 1, // 预警区域
|
||
DANGER = 2 // 危险区域
|
||
};
|
||
```
|
||
|
||
### 5.3 碰撞检测流程
|
||
|
||
1. 距离检测:
|
||
|
||
```cpp
|
||
// 计算当前距离
|
||
double dx = obj2.position.x - obj1.position.x;
|
||
double dy = obj2.position.y - obj1.position.y;
|
||
double current_distance = std::sqrt(dx*dx + dy*dy);
|
||
|
||
// 如果当前距离大于警告区域,直接返回不会碰撞
|
||
if (current_distance > (warning_radius1 + warning_radius2)) {
|
||
return false;
|
||
}
|
||
```
|
||
|
||
2. 碰撞类型判断:
|
||
|
||
```cpp
|
||
double angle_diff = getAngleDifference(heading1, heading2);
|
||
if (angle_diff > 150.0) {
|
||
// 相向碰撞检测
|
||
type = CollisionType::HEAD_ON;
|
||
} else if (angle_diff > 15.0 && angle_diff < 165.0) {
|
||
// 交叉碰撞检测
|
||
type = CollisionType::CROSSING;
|
||
} else {
|
||
// 平行碰撞检测
|
||
type = CollisionType::PARALLEL;
|
||
}
|
||
```
|
||
|
||
3. 相对运动分析:
|
||
|
||
```cpp
|
||
// 计算速度分量
|
||
double vx1 = speed1 * std::cos((90.0 - heading1) * M_PI / 180.0);
|
||
double vy1 = speed1 * std::sin((90.0 - heading1) * M_PI / 180.0);
|
||
double vx2 = speed2 * std::cos((90.0 - heading2) * M_PI / 180.0);
|
||
double vy2 = speed2 * std::sin((90.0 - heading2) * M_PI / 180.0);
|
||
|
||
// 计算相对运动
|
||
double rel_vx = vx2 - vx1;
|
||
double rel_vy = vy2 - vy1;
|
||
double rel_speed = std::sqrt(rel_vx*rel_vx + rel_vy*rel_vy);
|
||
```
|
||
|
||
4. 碰撞预测:
|
||
|
||
```cpp
|
||
// 在时间窗口内采样检查
|
||
for (int i = 1; i <= STEPS; ++i) {
|
||
double t = i * dt;
|
||
|
||
// 计算t时刻的位置
|
||
Vector2D future1 = predictPosition(pos1, speed1, heading1, t);
|
||
Vector2D future2 = predictPosition(pos2, speed2, heading2, t);
|
||
|
||
// 计算t时刻的距离
|
||
double distance = calculateDistance(future1, future2);
|
||
|
||
// 检查是否会碰撞
|
||
if (distance <= safe_distance) {
|
||
return true;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.4 碰撞记录管理
|
||
|
||
```cpp
|
||
struct CollisionRecord {
|
||
Vector2D collisionPoint; // 冲突点位置
|
||
int64_t detectedTime; // 检测到冲突的时间
|
||
RiskLevel maxLevel; // 历史最高风险等级
|
||
bool resolved; // 是否已解除
|
||
};
|
||
```
|
||
|
||
碰撞解除条件:
|
||
|
||
1. 对于已通过交叉点的情况:
|
||
- 物体距离交叉点的距离大于安全距离
|
||
2. 对于未通过交叉点的情况:
|
||
- 两个物体都在安全距离之外
|
||
- 预测不会发生碰撞
|
||
|
||
### 5.5 区域特定阈值
|
||
|
||
不同区域采用不同的安全距离阈值:
|
||
|
||
| 区域 | 航空器地面阈值 | 车辆阈值 |
|
||
|----------|----------------|-----------|
|
||
| 跑道 | 100米 | 50米 |
|
||
| 滑行道 | 50米 | 30米 |
|
||
| 停机位 | 40米 | 20米 |
|
||
| 服务区 | 30米 | 15米 |
|
||
|
||
### 5.6 空间优化
|
||
|
||
使用四叉树进行空间索引,优化查询性能:
|
||
|
||
1.四叉树构建:
|
||
|
||
```cpp
|
||
QuadTree<Vehicle> vehicleTree_(bounds, 8); // 容量为8的四叉树
|
||
```
|
||
|
||
2.邻近查询:
|
||
|
||
```cpp
|
||
auto nearbyVehicles = vehicleTree_.queryNearby(
|
||
position, // 中心点
|
||
threshold // 查询半径
|
||
);
|
||
```
|
||
|
||
### 5.7 性能考虑
|
||
|
||
1. 空间复杂度:
|
||
- 四叉树:O(n),其中 n 为车辆数量
|
||
- 航空器列表:O(m),其中 m 为航空器数量
|
||
|
||
2. 时间复杂度:
|
||
- 四叉树查询:O(log n)
|
||
- 总体碰撞检测:O(m * log n)
|
||
|
||
### 5.8 安全保障
|
||
|
||
1. 距离冗余:
|
||
- 使用阈值的一半作为直接报警条件
|
||
- 为不同区域设置合适的安全距离
|
||
|
||
2. 运动预测:
|
||
- 考虑物体的相对运动
|
||
- 提前发现潜在碰撞风险
|
||
|
||
3. 降级处理:
|
||
- 当无法计算相对运动时,仅使用距离判断
|
||
- 保证基本的安全检测功能
|
||
|
||
### 5.9 碰撞检测主流程
|
||
|
||
```cpp
|
||
// 加载可控车辆配置
|
||
std::vector<ControllableVehicleConfig> controllableVehicles = loadControllableVehicleConfig();
|
||
|
||
for (const auto& aircraft : aircrafts) {
|
||
for (const auto& vehicle : vehicles) {
|
||
if (detectCollision(aircraft, vehicle)) {
|
||
// 检查是否为可控车辆
|
||
auto iter = std::find_if(controllableVehicles.begin(), controllableVehicles.end(),
|
||
[&](const ControllableVehicleConfig& config) {
|
||
return config.vehicleNo == vehicle.vehicleNo;
|
||
});
|
||
|
||
if (iter != controllableVehicles.end()) {
|
||
// 生成控制指令
|
||
auto command = generateCommand(aircraft, vehicle);
|
||
// 发送控制指令
|
||
sendCommand(command, iter->ip, iter->port);
|
||
} else {
|
||
// 发送普通预警
|
||
sendWarning(aircraft, vehicle);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.10 可控车辆配置加载
|
||
|
||
从配置文件加载可控车辆信息:
|
||
|
||
```cpp
|
||
std::vector<ControllableVehicleConfig> loadControllableVehicleConfig() {
|
||
std::vector<ControllableVehicleConfig> configs;
|
||
|
||
// 读取配置文件
|
||
std::ifstream file("controllable_vehicles.json");
|
||
nlohmann::json jsonConfig;
|
||
file >> jsonConfig;
|
||
|
||
// 解析配置项
|
||
for (const auto& item : jsonConfig["vehicles"]) {
|
||
ControllableVehicleConfig config;
|
||
config.vehicleNo = item["vehicleNo"].get<std::string>();
|
||
config.ip = item["ip"].get<std::string>();
|
||
config.port = item["port"].get<int>();
|
||
configs.push_back(config);
|
||
}
|
||
|
||
return configs;
|
||
}
|
||
```
|
||
|
||
配置文件 `controllable_vehicles.json` 的格式如下:
|
||
|
||
```json
|
||
{
|
||
"vehicles": [
|
||
{
|
||
"vehicleNo": "VEH001",
|
||
"ip": "192.168.1.101",
|
||
"port": 8080
|
||
},
|
||
{
|
||
"vehicleNo": "VEH002",
|
||
"ip": "192.168.1.102",
|
||
"port": 8080
|
||
},
|
||
{
|
||
"vehicleNo": "VEH003",
|
||
"ip": "192.168.1.103",
|
||
"port": 8080
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 6. 坐标转换
|
||
|
||
### 6.1 转换方法
|
||
|
||
- 使用等角投影方法
|
||
- 基于机场参考点(青岛胶东国际机场:北纬36°21'43.2",东经120°05'16.8")
|
||
- 考虑地球曲率影响
|
||
- WGS84椭球体参数
|
||
|
||
## 7. 数据更新策略
|
||
|
||
### 7.1 数据采集
|
||
|
||
- 定时轮询(默认1秒)
|
||
- 独立的数据采集线程
|
||
- 分别缓存航空器和车辆数据
|
||
|
||
### 7.2 碰撞检测
|
||
|
||
- 实时检测(默认100ms)
|
||
- 独立的检测线程
|
||
- 分类处理不同类型的碰撞风险
|
||
|
||
## 8. 开发规范
|
||
|
||
### 8.1 代码规范
|
||
|
||
- Google C++ Style
|
||
- 智能指针管理
|
||
- 异常安全
|
||
- RAII原则
|
||
|
||
### 8.2 性能规范
|
||
|
||
- 避免虚函数滥用
|
||
- 减少动态内存分配
|
||
- 合理使用模板
|
||
- 注意数据对齐
|
||
|
||
### 8.3 网络编程规范
|
||
|
||
#### 8.3.1 数据读取策略
|
||
|
||
- 使用分块读取代替一次性读取
|
||
- 合理设置分块大小(如1KB)
|
||
- 正确处理部分读取的情况
|
||
- 验证数据完整性
|
||
|
||
#### 8.3.2 错误处理
|
||
|
||
- 实现请求重试机制
|
||
- 设置合理的超时时间
|
||
- 正确处理连接断开
|
||
- 完善的错误日志记录
|
||
|
||
#### 8.3.3 连接管理
|
||
|
||
- 及时关闭无用连接
|
||
- 正确处理连接状态
|
||
- 实现连接池(如需要)
|
||
- 处理并发连接
|
||
|
||
#### 8.3.4 性能考虑
|
||
|
||
- 使用异步操作处理并发
|
||
- 实现数据缓存机制
|
||
- 免频繁建立连接
|
||
- 合理控制缓冲区大小
|
||
|
||
#### 8.3.5 最佳实践
|
||
|
||
```cpp
|
||
// 分块读取示例
|
||
const size_t chunk_size = 1024; // 1KB per chunk
|
||
while (total_read < content_length) {
|
||
size_t to_read = std::min(chunk_size, content_length - total_read);
|
||
// 读取数据块
|
||
// 处理错误
|
||
// 更新计数
|
||
}
|
||
|
||
// 重试机制示例
|
||
const int max_retries = 3;
|
||
for (int retry = 0; retry < max_retries; ++retry) {
|
||
try {
|
||
// 尝试操作
|
||
break; // 成功则退出
|
||
} catch (...) {
|
||
if (retry == max_retries - 1) throw; // 最后一次重试失败
|
||
// 等待后重试
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.4 HTTP 数据读取规范
|
||
|
||
#### 8.4.1 问题描述
|
||
|
||
在使用 Boost.Asio 读取 HTTP 响应时,可能会遇到 "End of file" 错误。这个错误通常发生在:
|
||
|
||
- 读取响应体时
|
||
- 服务器已关闭连接
|
||
- 数据未完全读取
|
||
|
||
#### 8.4.2 错误原因分析
|
||
|
||
1. HTTP 响应头读取时可能已包含部分响应体数据
|
||
2. 忽略缓冲区中的这部分数据会导致:
|
||
- 数据丢失
|
||
- 读取位置错误
|
||
- 连接提前关闭
|
||
|
||
#### 8.4.3 解决方案
|
||
|
||
1. 正确处理响应数据:
|
||
|
||
```cpp
|
||
// 1. 读取响应头
|
||
size_t header_length = asio::read_until(*socket_, response_buf, "\r\n\r\n");
|
||
|
||
// 2. 处理缓冲区中的响应体数据
|
||
size_t body_part = response_buf.size() - header_length;
|
||
if (body_part > 0) {
|
||
// 提取已缓冲的响应体数据
|
||
body.append(
|
||
asio::buffers_begin(response_buf.data()) + header_length,
|
||
asio::buffers_end(response_buf.data())
|
||
);
|
||
total_read += body_part;
|
||
}
|
||
|
||
// 3. 继续读取剩余数据
|
||
while (total_read < content_length) {
|
||
// 读取剩余的响应体
|
||
}
|
||
```
|
||
|
||
#### 8.4.4 最佳实践
|
||
|
||
1. 数据读取原则:
|
||
- 使用简单直接的读取逻辑
|
||
- 准确跟踪已读取的数据量
|
||
- 正确处理缓冲区中的所有数据
|
||
- 避免复杂的重试机制
|
||
|
||
2. 错误处理:
|
||
- 及时检查错误码
|
||
- 提供详细的错误日志
|
||
- 在错误发生时及时关闭连接
|
||
- 保持连接状态的一致性
|
||
|
||
3. 数据完整性:
|
||
- 验证 Content-Length
|
||
- 确保读取完整的响应体
|
||
- 避免数据丢失或重复
|
||
- 正确处理分块数据
|
||
|
||
4. 日志记录:
|
||
- 记录关键操作步骤
|
||
- 包含详细的错误信息
|
||
- 记录数据读取进度
|
||
- 便于问题诊断和调试
|
||
|
||
## 9. 测试策略
|
||
|
||
### 9.1 单元测试
|
||
|
||
- 模块功能测试
|
||
- 边界条件测试
|
||
- 异常处理测试
|
||
- 内存泄漏测试
|
||
- 坐标转换精度测试
|
||
|
||
### 9.2 性能测试
|
||
|
||
- 延迟测试
|
||
- 并发测试
|
||
- 压力测试
|
||
- 内存使用测试
|
||
- 坐标转换性能测试
|
||
|
||
## 9. 测试场景
|
||
|
||
### 9.1 碰撞风险场景模拟
|
||
|
||
#### 9.1.1 场景描述
|
||
|
||
模拟一个典型的地面碰撞风险场景:
|
||
|
||
- 航空器在跑道上滑行
|
||
- 地面车辆垂直接近跑道
|
||
- 两者轨迹存在交叉点
|
||
- 如不采取措施将发生碰撞
|
||
|
||
#### 9.1.2 场景参数
|
||
|
||
1. 航空器参数:
|
||
- 初始位置:跑道西端 (AIRPORT_LON - 0.002, AIRPORT_LAT)
|
||
- 运动方向:向东滑行
|
||
- 运动速度:0.0002经度/秒
|
||
- 高度:5米(地面滑行高度)
|
||
|
||
2. 车辆参数:
|
||
- 初始位置:跑道南侧 (AIRPORT_LON, AIRPORT_LAT - 0.002)
|
||
- 运动方向:向北行驶
|
||
- 运动速度:0.0002纬度/秒
|
||
- 与航空器轨迹垂直相交
|
||
|
||
3. 时间参数:
|
||
- 更新频率:每秒一次
|
||
- 场景周期:10秒
|
||
- 碰撞风险时间:约5秒(场景中点)
|
||
|
||
#### 9.1.3 数据特点
|
||
|
||
1. 位置数据:
|
||
- 只提供实时位置信息
|
||
- 不包含速度信息
|
||
- 不包含方向信息
|
||
- 位置精度:小数点后6位
|
||
|
||
2. 数据格式:
|
||
|
||
```json
|
||
// 航空器数据
|
||
{
|
||
"flightNo": "CES2501",
|
||
"longitude": 120.088003,
|
||
"latitude": 36.361999,
|
||
"time": 1700123456,
|
||
}
|
||
|
||
// 车辆数据
|
||
{
|
||
"vehicleNo": "VEH001",
|
||
"longitude": 120.088003,
|
||
"latitude": 36.361999,
|
||
"time": 1700123456
|
||
}
|
||
```
|
||
|
||
#### 9.1.4 预期结果
|
||
|
||
1. 碰撞检测:
|
||
- 在交叉点附近应触发预警
|
||
- 预警时间:碰撞前约5秒
|
||
- 持续时间:直到危险解除
|
||
|
||
2. 风险等级:
|
||
- 距离大于100米:低风险
|
||
- 距离50-100米:中等风险
|
||
- 距离小于50米:高风险
|
||
|
||
3. 系统响应:
|
||
- 实时计算相对距离
|
||
- 及时发出预警信息
|
||
- 记录完整的碰撞风险过程
|
||
|
||
## 10. 风险控制
|
||
|
||
### 10.1 技术风险
|
||
|
||
- 实时性保证
|
||
- 内存管理
|
||
- 多线程同步
|
||
- 系统稳定性
|
||
- 坐标转换精度
|
||
|
||
### 10.2 解决方案
|
||
|
||
- 性能优化
|
||
- 资源监控
|
||
- 故障恢复
|
||
- 降级处理
|
||
- 坐标转换验证
|
||
|
||
## 11. 后续优化
|
||
|
||
1. 引入GPU加速计算
|
||
2. 优化空间索引算法
|
||
3. 改进故障检测机制
|
||
4. 增加自适应负载均衡
|
||
5. 完善监控告警系统
|
||
6. 优化坐标转换算法
|
||
7. 支持多种投影方式
|
||
|
||
使用纯C++实现可以获得:
|
||
|
||
1. 最佳的实时性能
|
||
2. 直接的硬件控制
|
||
3. 精确的内存管理
|
||
4. 最小的系统开销
|
||
5. 可预测的行为表现
|
||
|
||
## 10. 单元测试
|
||
|
||
### 10.1 测试框架
|
||
|
||
- 使用 Google Test 框架
|
||
- 支持 EXPECT 和 ASSERT 断言
|
||
- 支持 Mock 对象
|
||
- 支持测试夹具(Test Fixtures)
|
||
|
||
### 10.2 测试用例组织
|
||
|
||
#### 10.2.1 基础类型测试 (BasicTypesTest)
|
||
|
||
1. Vector2D 测试
|
||
- 测试向量大小计算
|
||
- 测试方向角计算
|
||
|
||
2. MovingObject 测试
|
||
- 测试速度计算
|
||
- 测试航向角计算
|
||
- 验证位置历史记录
|
||
|
||
3. 数据有效性测试
|
||
- 测试航空器数据
|
||
- 测试车辆数据
|
||
- 验证速度和位置限制
|
||
|
||
#### 10.2.2 碰撞检测测试 (CollisionDetectorTest)
|
||
|
||
1. 安全距离测试
|
||
- 测试水平安全距离
|
||
- 测试垂直安全距离
|
||
|
||
2. 边界条件测试
|
||
- 测试临界距离
|
||
- 测试高度边界
|
||
|
||
3. 特殊情况测试
|
||
- 测试零距离情况
|
||
- 测试对角线距离
|
||
|
||
#### 10.2.3 数据采集测试 (DataCollectorTest)
|
||
|
||
1. 速度计算测试
|
||
|
||
```cpp
|
||
// 测试数据生成
|
||
double lon = 120.08 + (LON_CHANGE_PER_SEC * i); // 每秒经度变化
|
||
uint64_t timestamp = baseTime + (i * 1); // 每秒一个点
|
||
|
||
// 验证速度计算
|
||
EXPECT_NEAR(aircraft.speed, 55.0, 5.0); // 允许5m/s误差
|
||
```
|
||
|
||
2. Mock 数据源
|
||
|
||
```cpp
|
||
class MockDataSource : public DataSource {
|
||
MOCK_METHOD(bool, connect, (), (override));
|
||
MOCK_METHOD(bool, fetchAircraftData, (std::vector<Aircraft>&), (override));
|
||
MOCK_METHOD(bool, fetchVehicleData, (std::vector<Vehicle>&), (override));
|
||
};
|
||
```
|
||
|
||
### 10.3 测试数据生成
|
||
|
||
#### 10.3.1 位置数据
|
||
|
||
1. 航空器数据
|
||
- 基于青岛胶东机场坐标
|
||
- 模拟地面滑行场景
|
||
- 生成连续位置点
|
||
|
||
2. 车辆数据
|
||
- 模拟地面车辆运动
|
||
- 生成可能的碰撞场景
|
||
|
||
#### 10.3.2 时间序列
|
||
|
||
1. 时间戳生成
|
||
- 使用 Unix 时间戳
|
||
- 每秒更新一次
|
||
- 保证时间连性
|
||
|
||
2. 数据更新频率
|
||
- 模拟实际系统的更新频率
|
||
- 确保数据连续性
|
||
- 避免时间戳重复
|
||
|
||
### 10.4 测试覆盖率
|
||
|
||
1. 基础功能测试
|
||
- 坐标转换
|
||
- 速度计算
|
||
- 航向计算
|
||
|
||
2. 错误处理测试
|
||
- 无效数据处理
|
||
- 连接错误处理
|
||
- 数据解析错误
|
||
|
||
3. 边界条件测试
|
||
- 最大/最小速度
|
||
- 位置跳变限制
|
||
- 时间戳异常
|
||
|
||
### 10.5 测试最佳实践
|
||
|
||
1. 测试数据准备
|
||
- 使用实际的地理坐标
|
||
- 模拟真实的运动场景
|
||
- 考虑数据精度
|
||
|
||
2. Mock 对象使用
|
||
- 模拟外部依赖
|
||
- 控制测试环境
|
||
- 验证交互逻辑
|
||
|
||
3. 日志记录
|
||
- 记录测试过程
|
||
- 输出中间结果
|
||
- 便于问题诊断
|
||
|
||
## 11. 可控车辆通信
|
||
|
||
### 11.1 通信方式
|
||
|
||
使用 HTTP 协议与可控车辆通信:
|
||
|
||
- 碰撞检测系统作为 HTTP 客户端,向可控车辆发送 POST 请求
|
||
- 请求地址格式为: `http://<vehicle_ip>:<port>/command`
|
||
- 请求 Body 中包含控制指令的 JSON 表示
|
||
- 可控车辆作为 HTTP 服务器,接收并处理控制指令
|
||
|
||
### 11.2 指令格式
|
||
|
||
使用 JSON 格式表示控制指令:
|
||
|
||
```json
|
||
POST /command HTTP/1.1
|
||
Host: <vehicle_ip>:<port>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"command": "stop",
|
||
"timestamp": 1700123456
|
||
}
|
||
```
|
||
|
||
或者:
|
||
|
||
```json
|
||
POST /command HTTP/1.1
|
||
Host: <vehicle_ip>:<port>
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"command": "change_route",
|
||
"route": [
|
||
{"longitude": 120.08, "latitude": 36.36},
|
||
{"longitude": 120.09, "latitude": 36.37},
|
||
{"longitude": 120.10, "latitude": 36.38}
|
||
],
|
||
"timestamp": 1700123456
|
||
}
|
||
```
|
||
|
||
### 11.3 可控车辆响应
|
||
|
||
可控车辆收到指令后,需要及时响应:
|
||
|
||
1. 立即执行停车、减速等指令
|
||
2. 如果是改变路线,则规划新的路径并切换
|
||
3. 将执行结果以 JSON 格式返回:
|
||
|
||
```json
|
||
HTTP/1.1 200 OK
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"status": "ok",
|
||
"message": "Command executed successfully",
|
||
"timestamp": 1700123456
|
||
}
|
||
```
|
||
|
||
或者:
|
||
|
||
```json
|
||
HTTP/1.1 500 Internal Server Error
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"status": "error",
|
||
"message": "Failed to execute command",
|
||
"error": "No route found",
|
||
"timestamp": 1700123456
|
||
}
|
||
```
|
||
|
||
### 11.4 安全考虑
|
||
|
||
由于 HTTP 是明文传输协议,存在安全隐患。需要采取以下措施:
|
||
|
||
1. 使用 HTTPS 代替 HTTP,实现加密通信
|
||
2. 对可控车辆的访问进行身份验证,防止非法控制
|
||
3. 对控制指令进行数字签名,防止指令被篡改
|
||
4. 对敏感数据(如路径点坐标)进行加密,防止泄露
|
||
|
||
### 11.5 可用性考虑
|
||
|
||
为保证可控车辆的控制链路高可用,需要:
|
||
|
||
1. 监控可控车辆的 HTTP 服务可用性,发现异常及时告警
|
||
2. 对控制指令的发送进行重试和超时处理,避免单次请求失败导致控制中断
|
||
3. 考虑引入备用的控制方式(如 MQTT),作为 HTTP 不可用时的降级方案
|
||
|
||
### 11.6 指令发送
|
||
|
||
根据可控车辆的IP地址和端口号,发送控制指令:
|
||
|
||
```cpp
|
||
void sendCommand(const ControlCommand& command, const std::string& ip, int port) {
|
||
// 创建HTTP客户端
|
||
HttpClient client(ip, port);
|
||
|
||
// 构造请求
|
||
HttpRequest request;
|
||
request.setMethod(HttpRequest::POST);
|
||
request.setPath("/command");
|
||
request.setHeader("Content-Type", "application/json");
|
||
request.setBody(command.toJson());
|
||
|
||
// 发送请求
|
||
HttpResponse response = client.send(request);
|
||
|
||
// 处理响应
|
||
if (response.getStatus() == HttpResponse::OK) {
|
||
// 指令发送成功
|
||
logger.info("Command sent successfully");
|
||
} else {
|
||
// 指令发送失败
|
||
logger.error("Failed to send command, status code: {}", response.getStatus());
|
||
}
|
||
}
|
||
```
|
||
|
||
使用 HTTP 客户端库,向可控车辆发送 POST 请求。请求路径为 `/command`,请求体为控制指令的 JSON 表示。根据响应状态码判断指令是否发送成功。
|
||
|
||
## 遗留问题
|
||
|
||
### 1. Python 包依赖问题
|
||
|
||
- 当前部署脚本在 Python 3.6 环境下存在依赖问题
|
||
- 需要添加 importlib-metadata 和 zipp 包
|
||
- 需要调整包版本以兼容 Python 3.6
|
||
- 考虑使用系统自带的 Python 包替代 pip 安装
|
||
|
||
### 2. 部署脚本改进
|
||
|
||
- prepare_deploy.sh 中下载 Python 包时需要包含所有依赖
|
||
- deploy.sh 中需要按正确顺序安装 Python 包
|
||
- 考虑使用 requirements.txt 管理 Python 依赖
|
||
- 需要优化部署脚本的错误处理和日志输出
|
||
|
||
### 3. 生产环境适配
|
||
|
||
- 需要适配离线环境的部署需求
|
||
- 需要完善 SELinux 相关的配置
|
||
- 需要优化日志文件的管理
|
||
- 需要完善服务启动失败的故障排查机制
|
||
|
||
### 4. 后续优化建议
|
||
|
||
- 简化部署步骤,减少人工干预
|
||
- 添加部署回滚机制
|
||
- 添加部署验证步骤
|
||
- 完善部署文档
|
||
- 简化部署步骤,减少人工干预
|
||
- 添加部署回滚机制
|
||
- 添加部署验证步骤
|
||
- 完善部署文档
|
||
|
||
## 机场边界设计
|
||
|
||
### 问题描述
|
||
|
||
实际机场通常是倾斜的(如东南-西北走向),需要一个合适的方案来判断车辆和飞机是否在机场各个区域内。
|
||
|
||
### 设计方案
|
||
|
||
#### 坐标系统设计
|
||
|
||
1. 世界坐标系
|
||
- 使用标准的笛卡尔坐标系
|
||
- X 轴指向东,Y 轴指向北
|
||
|
||
2. 机场局部坐标系
|
||
- 原点:可配置的机场参考点
|
||
- 方向:通过旋转角度将世界坐标系对齐到机场主轴
|
||
- 旋转规则:
|
||
- 以正北方向为基准
|
||
- 正值表示逆时针旋转
|
||
- 负值表示顺时针旋转
|
||
- 例:东南-西北走向的机场(以青岛国际机场为例),从东南指向西北为 -21.47 度
|
||
|
||
#### 核心组件
|
||
|
||
1. `AirportBounds` 类
|
||
- 负责管理机场边界和区域定义
|
||
- 提供坐标转换功能
|
||
- 判断位置所属区域
|
||
|
||
2. 配置文件 (`airport_bounds.json`)
|
||
|
||
```json
|
||
{
|
||
"airport": {
|
||
"rotation_angle": -45.0, // 机场旋转角度(度)
|
||
"reference_point": { // 机场参考点
|
||
"x": 0.0,
|
||
"y": 0.0
|
||
},
|
||
"bounds": { // 机场总边界
|
||
"x": -2000,
|
||
"y": -1000,
|
||
"width": 4000,
|
||
"height": 2000
|
||
}
|
||
},
|
||
"areas": { // 各功能区定义
|
||
// ... 具体区域配置
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 坐标转换流程
|
||
|
||
1. 位置判断流程
|
||
- 接收世界坐标系中的点坐标
|
||
- 将点坐标转换到机场局部坐标系
|
||
- 在局部坐标系中进行边界检查
|
||
|
||
2. 坐标转换算法
|
||
|
||
```cpp
|
||
Vector2D toAirportCoordinate(const Vector2D& point) {
|
||
// 1. 平移到参考点为原点
|
||
double dx = point.x - referencePoint_.x;
|
||
double dy = point.y - referencePoint_.y;
|
||
|
||
// 2. 应用旋转变换
|
||
double cos_angle = std::cos(rotationAngle_);
|
||
double sin_angle = std::sin(rotationAngle_);
|
||
|
||
return Vector2D{
|
||
dx * cos_angle + dy * sin_angle,
|
||
-dx * sin_angle + dy * cos_angle
|
||
};
|
||
}
|
||
```
|
||
|
||
### 优势
|
||
|
||
1. 实现简单,易于理解和维护
|
||
2. 计算开销小
|
||
3. 不需要修改现有的碰撞检测逻辑
|
||
4. 可以方便地调整机场方向
|
||
5. 支持不同区域的差异化配置
|
||
|
||
### 使用说明
|
||
|
||
1. 确定机场实际旋转角度
|
||
2. 选择合适的参考点(通常是机场中心或跑道中心)
|
||
3. 在机场局部坐标系中定义各个区域的边界
|
||
4. 配置各区域的安全参数(如碰撞半径、警告区域等)
|
||
|
||
### 注意事项
|
||
|
||
1. 角度配置采用度数(而非弧度)
|
||
2. 顺时针旋转使用负角度
|
||
3. 确保参考点选择合理,便于区域划分
|
||
4. 区域边界在局部坐标系中定义
|
||
|
||
如果需要计算角度(比如判断车辆朝向),则使用向量点积方法
|