修改了碰撞检测逻辑。

This commit is contained in:
Tian jianyong 2024-12-11 16:58:36 +08:00
parent 49f40cc56e
commit 4954605295
36 changed files with 3388 additions and 476 deletions

View File

@ -43,4 +43,5 @@
- 先询问代码的用途
- 理解代码的功能和作用
- 确认是否可以修改或删除
- 如果不确定就直接问我
- 如果不确定就直接问我
- 不要随便修改原有代码中的中文注释

View File

@ -51,6 +51,7 @@ set(LIB_SOURCES
src/detector/CollisionDetector.cpp
src/network/HTTPDataSource.cpp
src/network/WebSocketServer.cpp
src/network/HTTPClient.cpp
src/spatial/AirportBounds.cpp
src/spatial/CoordinateConverter.cpp
src/types/BasicTypes.cpp
@ -124,14 +125,7 @@ message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
message(STATUS "CMAKE_EXE_LINKER_FLAGS: ${CMAKE_EXE_LINKER_FLAGS}")
#
configure_file(
${CMAKE_SOURCE_DIR}/config/airport_bounds.json
${CMAKE_BINARY_DIR}/bin/config/airport_bounds.json
COPYONLY
)
configure_file(
${CMAKE_SOURCE_DIR}/config/vehicle_speed_limits.json
${CMAKE_BINARY_DIR}/bin/config/vehicle_speed_limits.json
COPYONLY
)
configure_file(${CMAKE_SOURCE_DIR}/config/system_config.json ${CMAKE_BINARY_DIR}/config/system_config.json COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/config/intersections.json ${CMAKE_BINARY_DIR}/config/intersections.json COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/config/vehicle_control.json ${CMAKE_BINARY_DIR}/config/vehicle_control.json COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/config/airport_bounds.json ${CMAKE_BINARY_DIR}/config/airport_bounds.json COPYONLY)

View File

@ -10,54 +10,77 @@
"areas": {
"runway": {
"bounds": {
"x": 1000,
"y": 1500,
"width": 3000,
"height": 60
"x": 0,
"y": 0,
"width": 1,
"height": 1
},
"config": {
"vehicle_collision_radius": 50.0,
"aircraft_ground_radius": 100.0,
"height_threshold": 15.0
"height_threshold": 15.0,
"warning_zone_radius": 100.0,
"alert_zone_radius": 50.0
}
},
"taxiway": {
"bounds": {
"x": 500,
"y": 1000,
"width": 4000,
"height": 30
"x": 0,
"y": 0,
"width": 1,
"height": 1
},
"config": {
"vehicle_collision_radius": 30.0,
"aircraft_ground_radius": 50.0,
"height_threshold": 10.0
"height_threshold": 10.0,
"warning_zone_radius": 50.0,
"alert_zone_radius": 25.0
}
},
"gate": {
"bounds": {
"x": 100,
"y": 2000,
"width": 4800,
"height": 1000
"x": 0,
"y": 0,
"width": 1,
"height": 1
},
"config": {
"vehicle_collision_radius": 20.0,
"aircraft_ground_radius": 40.0,
"height_threshold": 5.0
"height_threshold": 5.0,
"warning_zone_radius": 40.0,
"alert_zone_radius": 20.0
}
},
"service": {
"bounds": {
"x": 0,
"y": 3000,
"width": 5000,
"height": 1000
"y": 0,
"width": 1,
"height": 1
},
"config": {
"vehicle_collision_radius": 15.0,
"aircraft_ground_radius": 30.0,
"height_threshold": 5.0
"height_threshold": 5.0,
"warning_zone_radius": 30.0,
"alert_zone_radius": 15.0
}
},
"test_zone": {
"bounds": {
"x": 0,
"y": 0,
"width": 5000,
"height": 4000
},
"config": {
"vehicle_collision_radius": 25.0,
"aircraft_ground_radius": 50.0,
"height_threshold": 10.0,
"warning_zone_radius": 100.0,
"alert_zone_radius": 50.0
}
}
}

View File

@ -1,11 +1,11 @@
{
"intersections": [
{
"id": "intersection_001",
"id": "西路口",
"name": "无人车与特勤车交叉路口",
"trafficLightId": "TL001",
"position": {
"longitude": 120.088003,
"longitude": 120.086003,
"latitude": 36.361999,
"altitude": 12.5
},
@ -13,11 +13,11 @@
"stopDistance": 50.0
},
{
"id": "intersection_002",
"id": "东路口",
"name": "无人车与飞机交叉路口",
"trafficLightId": "TL002",
"position": {
"longitude": 120.088303,
"longitude": 120.089003,
"latitude": 36.361999,
"altitude": 12.5
},

View File

@ -34,6 +34,11 @@
},
"collision_detection": {
"update_interval_ms": 200,
"prediction": {
"time_window": 30.0,
"vehicle_size": 10.0,
"aircraft_size": 50.0
},
"thresholds": {
"runway": {
"aircraft_ground": 100.0,

View File

@ -0,0 +1,14 @@
{
"vehicles": [
{
"vehicleNo": "QN001",
"ip": "localhost",
"port": 8081
},
{
"vehicleNo": "QN002",
"ip": "localhost",
"port": 8081
}
]
}

View File

@ -1,19 +0,0 @@
{
"vehicles": [
{
"vehicleNo": "QN001",
"ip": "192.168.1.101",
"port": 8080
},
{
"vehicleNo": "QN002",
"ip": "192.168.1.102",
"port": 8080
},
{
"vehicleNo": "TQ001",
"ip": "192.168.1.103",
"port": 8080
}
]
}

301
docs/mock_server.md Normal file
View File

@ -0,0 +1,301 @@
# Mock 服务设计与使用说明
## 1. 概述
Mock 服务用于模拟机场场面的移动物体(航空器和车辆),提供位置更新和响应控制指令的功能。服务包含两个主要部分:
- HTTP API 服务:提供位置查询和车辆控制接口
- 位置更新模拟:定期更新各个移动物体的位置
## 2. 移动物体配置
### 2.1 航空器配置
```python
{
"flightNo": "AC001", # 航班号
"latitude": 36.362647780875804, # 纬度
"longitude": 120.088303, # 经度
"direction": 1, # 1表示向北
"speed": 50.0 # 滑行速度 50km/h
}
```
### 2.2 车辆配置
```python
{
"vehicleNo": "QN001", # 无人车1西路口
"latitude": WEST_INTERSECTION["latitude"], # 纬度
"longitude": WEST_INTERSECTION["longitude"], # 经度
"direction": 1, # 1表示向东-1表示向西
"speed": 36.0 # 行驶速度 36km/h
}
```
## 3. 运动模式
### 3.1 航空器运动
- 沿跑道南北方向移动
- 到达边界时自动调头
- 保持恒定速度 50km/h
### 3.2 无人车运动
- QN001在西路口东西向往返范围 50 米
- QN002在东路口东西方向往返范围 100-150 米
- TQ001先东西移动到达指定位置后转向南北移动然后返回
## 4. HTTP API 接口
### 4.1 位置查询接口
```http
GET /api/position
```
返回所有移动物体的当前位置信息:
```json
{
"aircraft": [
{
"flightNo": "AC001",
"latitude": 36.362647780875804,
"longitude": 120.088303,
"heading": 0.0,
"speed": 13.89,
"timestamp": 1733741411167
}
],
"vehicles": [
{
"vehicleNo": "QN001",
"latitude": 36.362448155990975,
"longitude": 120.08844920958369,
"heading": 90.0,
"speed": 10.0,
"timestamp": 1733741411168
}
]
}
```
### 4.2 车辆控制接口
```http
POST /api/vehicle/command
Content-Type: application/json
```
请求格式:
```json
{
"vehicleId": "QN001",
"type": "SIGNAL", // SIGNAL, ALERT, WARNING, RESUME
"reason": "TRAFFIC_LIGHT", // TRAFFIC_LIGHT, AIRCRAFT_CROSSING, SPECIAL_VEHICLE, AIRCRAFT_PUSH, RESUME_TRAFFIC
"timestamp": 1733741411167,
"signalState": "RED", // 可选,仅当 type 为 SIGNAL 时需要
"targetPosition": { // 可选
"x": 100.0,
"y": 200.0
},
"speed": 0.0, // 可选
"distance": 0.0 // 可选
}
```
响应格式:
```json
{
"status": "ok", // ok 或 error
"message": "Command executed successfully"
}
```
## 5. 指令优先级
车辆控制指令按以下优先级处理:
1. ALERT (5):告警指令,最高优先级
- 用于紧急情况,如碰撞风险
- 可以覆盖所有其他指令
- 收到后车辆立即停止
2. SIGNAL (4):红绿灯指令,次高优先级
- 用于红绿灯控制
- 可以覆盖预警、绿灯和恢复指令
- 红灯时车辆停止,绿灯时可能恢复(取决于是否有更高优先级指令)
3. WARNING (3):预警指令,中等优先级
- 用于提前预警可能的风险
- 可以覆盖绿灯和恢复指令
- 收到后车辆减速或停止
4. GREEN (2):绿灯状态
- 系统内部状态,不是外部指令
- 可以覆盖恢复指令
- 只有在没有更高优先级指令时才生效
5. RESUME (1):恢复指令,最低优先级
- 用于恢复正常行驶
- 不能覆盖其他指令
- 只有在没有任何其他指令时才生效
### 5.1 优先级规则
1. 高优先级指令可以覆盖低优先级指令
2. 相同优先级的新指令可以覆盖旧指令
3. 低优先级指令不能覆盖高优先级指令
4. 恢复行驶需要满足两个条件:
- 收到 RESUME 指令
- 没有任何更高优先级的指令
### 5.2 状态转换
1. 收到告警指令 (ALERT)
- 立即停止
- 忽略所有低优先级指令
- 只能通过 RESUME 指令恢复(且无其他高优先级指令)
2. 收到红绿灯指令 (SIGNAL)
- 红灯:停止
- 绿灯如果没有更高优先级指令ALERT则恢复行驶
3. 收到预警指令 (WARNING)
- 减速或停止
- 可被告警或红灯指令覆盖
- 可通过绿灯或恢复指令解除(如无更高优先级指令)
4. 遇到绿灯 (GREEN)
- 如果没有 ALERT、SIGNAL 或 WARNING 指令,则恢复行驶
- 否则保持当前状态
5. 收到恢复指令 (RESUME)
- 检查是否有任何更高优先级指令
- 如果没有,则恢复正常行驶速度
- 如果有,则保持当前状态
### 5.3 使用示例
1. 告警指令覆盖其他指令:
```json
{
"vehicleId": "QN001",
"type": "ALERT",
"reason": "COLLISION_RISK",
"timestamp": 1733741411167
}
```
2. 红灯指令(但不会覆盖告警):
```json
{
"vehicleId": "QN001",
"type": "SIGNAL",
"reason": "TRAFFIC_LIGHT",
"signalState": "RED",
"timestamp": 1733741411167
}
```
3. 预警指令(可被告警和红灯覆盖):
```json
{
"vehicleId": "QN001",
"type": "WARNING",
"reason": "APPROACHING_INTERSECTION",
"timestamp": 1733741411167
}
```
4. 恢复指令(需要无更高优先级指令):
```json
{
"vehicleId": "QN001",
"type": "RESUME",
"reason": "RESUME_TRAFFIC",
"timestamp": 1733741411167
}
```
## 6. 使用示例
### 6.1 发送红绿灯指令
```bash
curl -X POST http://localhost:8081/api/vehicle/command \
-H "Content-Type: application/json" \
-d '{
"vehicleId": "QN001",
"type": "SIGNAL",
"reason": "TRAFFIC_LIGHT",
"timestamp": 1733741411167,
"signalState": "RED"
}'
```
### 6.2 发送碰撞预警指令
```bash
curl -X POST http://localhost:8081/api/vehicle/command \
-H "Content-Type: application/json" \
-d '{
"vehicleId": "QN001",
"type": "WARNING",
"reason": "AIRCRAFT_CROSSING",
"timestamp": 1733741411167,
"distance": 25.5
}'
```
### 6.3 发送恢复指令
```bash
curl -X POST http://localhost:8081/api/vehicle/command \
-H "Content-Type: application/json" \
-d '{
"vehicleId": "QN001",
"type": "RESUME",
"reason": "RESUME_TRAFFIC",
"timestamp": 1733741411167
}'
```
## 7. 启动服务
```bash
# 安装依赖
pip install flask
# 启动服务
python tools/mock_server.py
```
服务默认监听在:
- HTTP 服务:<http://localhost:8081>
## 8. 注意事项
1. 位置更新
- 位置更新频率1秒一次
- 坐标系统WGS84
- 速度单位km/h内部计算使用 m/s
2. 车辆控制
- 车辆收到停止指令后会立即停止位置更新
- 只有收到 RESUME 指令且没有更高优先级的指令时才会恢复运动
- 每个指令都必须包含时间戳
3. 错误处理
- 无效的车辆ID返回 404 错误
- 无效的指令格式:返回 400 错误
- 服务器内部错误:返回 500 错误

76
include/core/System.h Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <memory>
#include <thread>
#include <atomic>
#include <unordered_map>
#include <unordered_set>
#include <chrono>
#include "config/SystemConfig.h"
#include "config/IntersectionConfig.h"
#include "network/WebSocketServer.h"
#include "types/VehicleCommand.h"
#include "types/MovingObject.h"
class AirportBounds;
class ControllableVehicles;
class CollisionDetector;
class TrafficLightDetector;
class DataCollector;
class MovingObject;
struct CollisionRisk;
struct TrafficLightSignal;
namespace network {
struct TimeoutWarningMessage;
}
class System {
public:
System();
virtual ~System();
bool initialize();
void start();
void stop();
static System* instance() { return instance_; }
static void signalHandler(int signal);
const SystemConfig& getSystemConfig() const { return system_config_; }
const IntersectionConfig& getIntersectionConfig() const { return intersection_config_; }
// 广播相关函数
virtual void broadcastTimeoutWarning(const network::TimeoutWarningMessage& warning);
void broadcastPositionUpdate(const MovingObject& obj);
void broadcastCollisionWarning(const CollisionRisk& risk);
void broadcastVehicleCommand(const VehicleCommand& cmd);
void broadcastTrafficLightStatus(const TrafficLightSignal& signal);
private:
static System* instance_;
void processLoop();
std::atomic<bool> running_{false};
std::thread processThread_;
std::thread ws_thread_;
// 系统组件
std::unique_ptr<AirportBounds> airportBounds_;
std::unique_ptr<ControllableVehicles> controllableVehicles_;
std::unique_ptr<CollisionDetector> collisionDetector_;
std::unique_ptr<TrafficLightDetector> trafficLightDetector_;
std::unique_ptr<DataCollector> dataCollector_;
std::unique_ptr<network::WebSocketServer> ws_server_;
// 配置
SystemConfig system_config_;
IntersectionConfig intersection_config_;
// 记录车辆停止的时间
std::unordered_map<std::string, std::chrono::system_clock::time_point> vehicleStopTimes_;
// 记录上一次有风险的可控车辆列表
std::unordered_set<std::string> lastVehiclesWithRisk_;
};

View File

@ -12,7 +12,9 @@
#include "types/BasicTypes.h"
#include "config/WarnConfig.h"
#include "types/TrafficLightTypes.h"
#include "core/System.h"
// 前向声明
class System;
class DataCollector {
public:
@ -37,6 +39,16 @@ public:
dataSource_ = source;
}
// 获取数据的引用访问接口
const std::vector<Aircraft>& getAircraftRef() const {
std::lock_guard<std::mutex> lock(cacheMutex_);
return aircraftCache_;
}
const std::vector<Vehicle>& getVehicleRef() const {
std::lock_guard<std::mutex> lock(cacheMutex_);
return vehicleCache_;
}
private:
std::shared_ptr<DataSource> dataSource_;

View File

@ -23,12 +23,20 @@ IntersectionConfig IntersectionConfig::load(const std::string& configFile) {
info.name = item["name"].get<std::string>();
info.trafficLightId = item["trafficLightId"].get<std::string>();
// 加载位置信息
// 加载位置信息,检查是否为 null
if (item["position"]["longitude"].is_null() ||
item["position"]["latitude"].is_null() ||
item["position"]["altitude"].is_null()) {
throw std::runtime_error("Position values cannot be null for intersection: " + info.id);
}
info.position.longitude = item["position"]["longitude"].get<double>();
info.position.latitude = item["position"]["latitude"].get<double>();
info.position.altitude = item["position"]["altitude"].get<double>();
// 加载距离阈值
// 加载距离阈值,检查是否为 null
if (item["radius"].is_null() || item["stopDistance"].is_null()) {
throw std::runtime_error("Distance values cannot be null for intersection: " + info.id);
}
info.radius = item["radius"].get<double>();
info.stopDistance = item["stopDistance"].get<double>();

View File

@ -2,7 +2,7 @@
#include "utils/Logger.h"
#include <fstream>
SystemConfig SystemConfig::load(const std::string& filename) {
void SystemConfig::load(const std::string& filename) {
try {
std::ifstream file(filename);
if (!file.is_open()) {
@ -12,63 +12,59 @@ SystemConfig SystemConfig::load(const std::string& filename) {
nlohmann::json j;
file >> j;
SystemConfig config;
// 加载机场信息
config.airport.name = j["airport"]["name"];
config.airport.iata = j["airport"]["iata"];
config.airport.icao = j["airport"]["icao"];
config.airport.reference_point.latitude = j["airport"]["reference_point"]["latitude"];
config.airport.reference_point.longitude = j["airport"]["reference_point"]["longitude"];
airport.name = j["airport"]["name"];
airport.iata = j["airport"]["iata"];
airport.icao = j["airport"]["icao"];
airport.reference_point.latitude = j["airport"]["reference_point"]["latitude"];
airport.reference_point.longitude = j["airport"]["reference_point"]["longitude"];
// 加载数据源配置
config.data_source.host = j["data_source"]["host"];
config.data_source.port = j["data_source"]["port"];
config.data_source.aircraft_path = j["data_source"]["aircraft_path"];
config.data_source.vehicle_path = j["data_source"]["vehicle_path"];
config.data_source.traffic_light_path = j["data_source"]["traffic_light_path"];
config.data_source.refresh_interval_ms = j["data_source"]["refresh_interval_ms"];
config.data_source.timeout_ms = j["data_source"]["timeout_ms"];
config.data_source.read_timeout_ms = j["data_source"]["read_timeout_ms"];
data_source.host = j["data_source"]["host"];
data_source.port = j["data_source"]["port"];
data_source.aircraft_path = j["data_source"]["aircraft_path"];
data_source.vehicle_path = j["data_source"]["vehicle_path"];
data_source.traffic_light_path = j["data_source"]["traffic_light_path"];
data_source.refresh_interval_ms = j["data_source"]["refresh_interval_ms"];
data_source.timeout_ms = j["data_source"]["timeout_ms"];
data_source.read_timeout_ms = j["data_source"]["read_timeout_ms"];
// 加载 WebSocket 配置
config.websocket.port = j["websocket"]["port"];
config.websocket.max_connections = j["websocket"]["max_connections"];
config.websocket.ping_interval_ms = j["websocket"]["ping_interval_ms"];
config.websocket.position_update.aircraft_interval_ms = j["websocket"]["position_update"]["aircraft_interval_ms"];
config.websocket.position_update.vehicle_interval_ms = j["websocket"]["position_update"]["vehicle_interval_ms"];
websocket.port = j["websocket"]["port"];
websocket.max_connections = j["websocket"]["max_connections"];
websocket.ping_interval_ms = j["websocket"]["ping_interval_ms"];
websocket.position_update.aircraft_interval_ms = j["websocket"]["position_update"]["aircraft_interval_ms"];
websocket.position_update.vehicle_interval_ms = j["websocket"]["position_update"]["vehicle_interval_ms"];
// 加载碰撞检测配置
config.collision_detection.update_interval_ms = j["collision_detection"]["update_interval_ms"];
collision_detection.update_interval_ms = j["collision_detection"]["update_interval_ms"];
// 加载阈值配置
auto& thresholds = j["collision_detection"]["thresholds"];
config.collision_detection.thresholds.runway.aircraft_ground = thresholds["runway"]["aircraft_ground"];
config.collision_detection.thresholds.runway.vehicle = thresholds["runway"]["vehicle"];
config.collision_detection.thresholds.taxiway.aircraft_ground = thresholds["taxiway"]["aircraft_ground"];
config.collision_detection.thresholds.taxiway.vehicle = thresholds["taxiway"]["vehicle"];
config.collision_detection.thresholds.apron.aircraft_ground = thresholds["apron"]["aircraft_ground"];
config.collision_detection.thresholds.apron.vehicle = thresholds["apron"]["vehicle"];
config.collision_detection.thresholds.service.aircraft_ground = thresholds["service"]["aircraft_ground"];
config.collision_detection.thresholds.service.vehicle = thresholds["service"]["vehicle"];
collision_detection.thresholds.runway.aircraft_ground = thresholds["runway"]["aircraft_ground"];
collision_detection.thresholds.runway.vehicle = thresholds["runway"]["vehicle"];
collision_detection.thresholds.taxiway.aircraft_ground = thresholds["taxiway"]["aircraft_ground"];
collision_detection.thresholds.taxiway.vehicle = thresholds["taxiway"]["vehicle"];
collision_detection.thresholds.apron.aircraft_ground = thresholds["apron"]["aircraft_ground"];
collision_detection.thresholds.apron.vehicle = thresholds["apron"]["vehicle"];
collision_detection.thresholds.service.aircraft_ground = thresholds["service"]["aircraft_ground"];
collision_detection.thresholds.service.vehicle = thresholds["service"]["vehicle"];
// 加载日志配置
config.logging.level = j["logging"]["level"];
config.logging.file = j["logging"]["file"];
config.logging.max_size_mb = j["logging"]["max_size_mb"];
config.logging.max_files = j["logging"]["max_files"];
config.logging.console_output = j["logging"]["console_output"];
logging.level = j["logging"]["level"];
logging.file = j["logging"]["file"];
logging.max_size_mb = j["logging"]["max_size_mb"];
logging.max_files = j["logging"]["max_files"];
logging.console_output = j["logging"]["console_output"];
// 加载调试配置
config.debug.enable_mock_data = j["debug"]["enable_mock_data"];
config.debug.save_raw_data = j["debug"]["save_raw_data"];
config.debug.profile_performance = j["debug"]["profile_performance"];
debug.enable_mock_data = j["debug"]["enable_mock_data"];
debug.save_raw_data = j["debug"]["save_raw_data"];
debug.profile_performance = j["debug"]["profile_performance"];
// 加载告警配置
config.warning.warning_interval_ms = j["warning"]["warning_interval_ms"];
config.warning.log_interval_ms = j["warning"]["log_interval_ms"];
return config;
warning.warning_interval_ms = j["warning"]["warning_interval_ms"];
warning.log_interval_ms = j["warning"]["log_interval_ms"];
}
catch (const std::exception& e) {
Logger::error("Failed to load system config: ", e.what());

View File

@ -3,7 +3,23 @@
#include <string>
#include <nlohmann/json.hpp>
struct SystemConfig {
class System; // 前向声明
class SystemConfig {
public:
// 获取单例实例
static SystemConfig& instance() {
static SystemConfig instance;
return instance;
}
// 加载配置文件
void load(const std::string& filename);
// 删除拷贝构造和赋值操作
SystemConfig(const SystemConfig&) = delete;
SystemConfig& operator=(const SystemConfig&) = delete;
struct Airport {
std::string name;
std::string iata;
@ -38,6 +54,11 @@ struct SystemConfig {
struct CollisionDetection {
int update_interval_ms;
struct Prediction {
double time_window;
double vehicle_size;
double aircraft_size;
} prediction;
struct Thresholds {
struct Area {
double aircraft_ground;
@ -69,5 +90,7 @@ struct SystemConfig {
int log_interval_ms; // 日志记录间隔
} warning;
static SystemConfig load(const std::string& filename);
private:
SystemConfig() = default; // 私有构造函数
friend class System; // 允许 System 类访问私有成员
};

View File

@ -2,7 +2,7 @@
#include <typeinfo>
#include <chrono>
#include <cmath>
#include "core/System.h"
#include "System.h"
#include "utils/Logger.h"
#include "collector/DataCollector.h"
@ -29,15 +29,15 @@ void System::signalHandler(int signal) {
bool System::initialize() {
try {
// 加载系统配置
system_config_ = SystemConfig::load("config/system_config.json");
// 配置已在 main 中加载,这里直接使用
const auto& system_config = SystemConfig::instance();
// 加载路口配置
intersection_config_ = IntersectionConfig::load("config/intersections.json");
Logger::info("Loaded {} intersections", intersection_config_.getIntersections().size());
// 初始化 WebSocket 服务器
ws_server_ = std::make_unique<network::WebSocketServer>(system_config_.websocket.port);
ws_server_ = std::make_unique<network::WebSocketServer>(system_config.websocket.port);
ws_thread_ = std::thread([this]() {
ws_server_->start();
});
@ -46,31 +46,32 @@ bool System::initialize() {
airportBounds_ = std::make_unique<AirportBounds>("config/airport_bounds.json");
// 加载可控车辆配置
controllableVehicles_ = std::make_unique<ControllableVehicles>("config/vehicle_speed_limits.json");
controllableVehicles_ = std::make_unique<ControllableVehicles>("config/vehicle_control.json");
Logger::info("Loaded controllable vehicles configuration");
// 初始化冲突检测器
collisionDetector_ = std::make_unique<CollisionDetector>(*airportBounds_, *controllableVehicles_);
// 初始化红绿灯检测器
trafficLightDetector_ = std::make_unique<TrafficLightDetector>(intersection_config_, *controllableVehicles_);
trafficLightDetector_ = std::make_unique<TrafficLightDetector>(intersection_config_, *controllableVehicles_, *this);
// 创建数据采集器
dataCollector_ = std::make_unique<DataCollector>();
// 数据采集器初始化并启动
DataSourceConfig dataSourceConfig{
system_config_.data_source.host,
system_config_.data_source.port,
system_config_.data_source.aircraft_path,
system_config_.data_source.vehicle_path,
system_config_.data_source.traffic_light_path,
system_config_.data_source.refresh_interval_ms,
system_config_.data_source.timeout_ms
system_config.data_source.host,
system_config.data_source.port,
system_config.data_source.aircraft_path,
system_config.data_source.vehicle_path,
system_config.data_source.traffic_light_path,
system_config.data_source.refresh_interval_ms,
system_config.data_source.timeout_ms
};
WarnConfig warnConfig{
system_config_.warning.warning_interval_ms,
system_config_.warning.log_interval_ms
system_config.warning.warning_interval_ms,
system_config.warning.log_interval_ms
};
return dataCollector_->initialize(dataSourceConfig, warnConfig);
@ -135,6 +136,7 @@ void System::processLoop() {
while (running_) {
try {
auto now = std::chrono::steady_clock::now();
const auto& system_config = SystemConfig::instance();
auto last_data_collection = now;
Logger::debug("开始获取数据...");
@ -148,7 +150,7 @@ void System::processLoop() {
// 检查航空器更新
auto aircraft_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - last_aircraft_update).count();
if (aircraft_elapsed >= system_config_.websocket.position_update.aircraft_interval_ms) {
if (aircraft_elapsed >= system_config.websocket.position_update.aircraft_interval_ms) {
bool has_new_aircraft = false;
int64_t max_timestamp = last_aircraft_timestamp;
@ -179,46 +181,84 @@ void System::processLoop() {
// 检查车辆更新
auto vehicle_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - last_vehicle_update).count();
if (vehicle_elapsed >= system_config_.websocket.position_update.vehicle_interval_ms) {
if (vehicle_elapsed >= system_config.websocket.position_update.vehicle_interval_ms) {
bool has_new_vehicles = false;
int64_t max_timestamp = last_vehicle_timestamp;
Logger::debug("开始检查车辆数据更新,当前时间戳: ", last_vehicle_timestamp);
for (const auto& veh : vehicles) {
Logger::debug("车辆 ", veh.vehicleNo, " 时间戳: current=", veh.timestamp, " last=", last_vehicle_timestamp);
if (veh.timestamp > last_vehicle_timestamp) { // 改为大于比较
has_new_vehicles = true;
Logger::debug("车辆位置更新检查开始 >>>>>>>>>>>>>>>>>");
Logger::debug("当前系统时间: ", std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()).count());
Logger::debug("上次更新时间: ", std::chrono::duration_cast<std::chrono::milliseconds>(
last_vehicle_update.time_since_epoch()).count());
Logger::debug("距离上次更新的时间间隔: ", vehicle_elapsed, "ms");
Logger::debug("配置的更新间隔: ", system_config.websocket.position_update.vehicle_interval_ms, "ms");
Logger::debug("上次时间戳: ", last_vehicle_timestamp);
Logger::debug("收到车辆数量: ", vehicles.size());
// 如果是第一次更新last_vehicle_timestamp == 0则广播所有车辆位置
if (last_vehicle_timestamp == 0 && !vehicles.empty()) {
has_new_vehicles = true;
for (const auto& veh : vehicles) {
if (veh.timestamp > max_timestamp) {
max_timestamp = veh.timestamp;
}
Logger::debug("发现新数据: ", veh.vehicleNo, " (新时间戳: ", veh.timestamp, ")");
Logger::debug("首次更新,广播车辆: ", veh.vehicleNo);
}
} else {
// 正常的更新检查
for (const auto& veh : vehicles) {
Logger::debug("处理车辆: ", veh.vehicleNo);
Logger::debug(" - 位置: (", veh.geo.longitude, ", ", veh.geo.latitude, ")");
Logger::debug(" - 速度: ", veh.speed, "m/s");
Logger::debug(" - 时间戳: ", veh.timestamp);
Logger::debug(" - 时间差: ", veh.timestamp - last_vehicle_timestamp);
if (veh.timestamp > last_vehicle_timestamp) {
has_new_vehicles = true;
if (veh.timestamp > max_timestamp) {
max_timestamp = veh.timestamp;
}
Logger::debug(" - 发现新数据!");
} else {
Logger::debug(" - 数据未更新");
}
}
}
if (has_new_vehicles) {
Logger::debug("广播 ", vehicles.size(), " 辆车辆位置, 时间戳更新: ", last_vehicle_timestamp, " -> ", max_timestamp);
Logger::debug("发现新数据,准备广播...");
Logger::debug("更新时间戳: ", last_vehicle_timestamp, " -> ", max_timestamp);
for (const auto& veh : vehicles) {
broadcastPositionUpdate(veh);
}
last_vehicle_timestamp = max_timestamp;
Logger::debug("广播完成");
} else {
Logger::debug("没有新的车辆数据,当前时间戳: ", last_vehicle_timestamp);
Logger::debug("没有新数据需要广播");
}
last_vehicle_update = now;
Logger::debug("车辆位置更新检查结束 <<<<<<<<<<<<<<<");
}
// 检查冲突更新
auto collision_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - last_collision_update).count();
if (collision_elapsed >= system_config_.collision_detection.update_interval_ms) {
if (collision_elapsed >= system_config.collision_detection.update_interval_ms) {
// 只有当有新的数据时才更新冲突检测
if (last_aircraft_timestamp > last_collision_timestamp ||
last_vehicle_timestamp > last_collision_timestamp) {
// 更冲突检测器
// 更<EFBFBD><EFBFBD>冲突检测器
collisionDetector_->updateTraffic(aircraft, vehicles);
auto collisions = collisionDetector_->detectCollisions();
if (!collisions.empty()) {
Logger::debug("检测到 {} 个碰撞风险", collisions.size());
for (const auto& risk : collisions) {
Logger::debug("碰撞风险详情: id1={}, id2={}, 距离={}m, 预测最小距离={}m, 风险等级={}, 区域类型={}",
risk.id1, risk.id2, risk.distance, risk.minDistance,
static_cast<int>(risk.level), static_cast<int>(risk.zoneType));
}
processCollisions(collisions);
}
@ -230,7 +270,7 @@ void System::processLoop() {
// 处理红绿灯信号
auto traffic_light_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - last_traffic_light_update).count();
if (traffic_light_elapsed >= system_config_.websocket.position_update.traffic_light_interval_ms) {
if (traffic_light_elapsed >= system_config.websocket.position_update.traffic_light_interval_ms) {
bool has_new_signals = false;
int64_t max_timestamp = last_traffic_light_timestamp;
@ -245,7 +285,7 @@ void System::processLoop() {
Logger::debug("发现新数据: ", signal.trafficLightId, " (新时间戳: ", signal.timestamp, ")");
// 广播红绿灯状态更新
broadcastTrafficLightUpdate(signal);
broadcastTrafficLightStatus(signal);
// 处理红绿灯信号并检查是否需要停车
trafficLightDetector_->processSignal(signal, vehicles);
@ -261,7 +301,7 @@ void System::processLoop() {
}
// 计算下一次数据采集前的等待时间
auto next_collection = last_data_collection + std::chrono::milliseconds(system_config_.data_source.refresh_interval_ms);
auto next_collection = last_data_collection + std::chrono::milliseconds(system_config.data_source.refresh_interval_ms);
auto wait_time = std::chrono::duration_cast<std::chrono::milliseconds>(next_collection - now).count();
if (wait_time > 0) {
@ -275,29 +315,110 @@ void System::processLoop() {
}
}
void System::processCollisions(const std::vector<CollisionRisk>& collisions) {
if (!collisions.empty()) {
Logger::info("检测到 ", collisions.size(), " 个冲突风险");
void System::processCollisions(const std::vector<CollisionRisk>& risks) {
// 记录当前有风险的可控车辆
std::unordered_set<std::string> currentVehiclesWithRisk;
const auto& config = SystemConfig::instance().collision_detection;
// 记录需要发送恢复指令的车辆
std::unordered_set<std::string> vehiclesToResume;
for (const auto& risk : risks) {
// 只处理可控车辆
if (!controllableVehicles_->isControllable(risk.id1)) {
continue;
}
currentVehiclesWithRisk.insert(risk.id1);
for (const auto& risk : collisions) {
// 发送冲突警告到 Unity 客户端
broadcastCollisionWarning(risk);
// 根据风险等级处理
switch (risk.level) {
case RiskLevel::CRITICAL: {
// 危险区域:立即发送告警指令
VehicleCommand cmd;
cmd.vehicleId = risk.id1;
cmd.type = CommandType::ALERT;
cmd.reason = risk.id2.substr(0, 2) == "AC" ?
CommandReason::AIRCRAFT_CROSSING :
CommandReason::SPECIAL_VEHICLE;
cmd.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
// 设置目标位置(冲突对象的位置)
const MovingObject* target = findVehicle(risk.id2);
if (target) {
cmd.latitude = target->geo.latitude;
cmd.longitude = target->geo.longitude;
}
broadcastVehicleCommand(cmd);
controllableVehicles_->sendCommand(risk.id1, cmd);
Logger::warning("发送告警指令到车辆: ", risk.id1,
" 当前距离: ", risk.distance, "m",
" 预测最小距离: ", risk.minDistance, "m",
" 相对速度: ", risk.relativeSpeed, "m/s");
break;
}
case RiskLevel::WARNING: {
// 预警区域:发送预警指令
VehicleCommand cmd;
cmd.vehicleId = risk.id1;
cmd.type = CommandType::WARNING;
cmd.reason = risk.id2.substr(0, 2) == "AC" ?
CommandReason::AIRCRAFT_CROSSING :
CommandReason::SPECIAL_VEHICLE;
cmd.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
// 设置目标位置
const MovingObject* target = findVehicle(risk.id2);
if (target) {
cmd.latitude = target->geo.latitude;
cmd.longitude = target->geo.longitude;
}
broadcastVehicleCommand(cmd);
controllableVehicles_->sendCommand(risk.id1, cmd);
Logger::info("发送预警指令到车辆: ", risk.id1,
" 当前距离: ", risk.distance, "m",
" 预测最小距离: ", risk.minDistance, "m",
" 相对速度: ", risk.relativeSpeed, "m/s");
break;
}
default:
break;
}
// 广播碰撞预警消息
broadcastCollisionWarning(risk);
}
// 检查之前有风险但现在没有风险的可控车辆
for (const auto& vehicleId : lastVehiclesWithRisk_) {
if (currentVehiclesWithRisk.find(vehicleId) == currentVehiclesWithRisk.end()) {
vehiclesToResume.insert(vehicleId);
}
}
// 更新上一次有风险的可控车辆列表
lastVehiclesWithRisk_ = std::move(currentVehiclesWithRisk);
// 对于所有当前车辆,如果是可控车辆且不在风险列表中,考虑发送恢复指令
auto vehicles = dataCollector_->getVehicleData();
for (const auto& vehicle : vehicles) {
if (controllableVehicles_->isControllable(vehicle.vehicleNo) &&
currentVehiclesWithRisk.find(vehicle.vehicleNo) == currentVehiclesWithRisk.end()) {
// 根据风险等级选择不同的日志级别
switch (risk.level) {
case RiskLevel::CRITICAL:
Logger::warning("高度冲突风险: ", risk.id1, "", risk.id2,
", 距离: ", risk.distance, "",
", 相对速度: ", risk.relativeSpeed, "m/s");
break;
case RiskLevel::WARNING:
Logger::warning("低度冲突风险: ", risk.id1, "", risk.id2,
", 距离: ", risk.distance, "",
", 相对速度: ", risk.relativeSpeed, "m/s");
break;
case RiskLevel::NONE:
break;
// 只有当车辆之前有风险或速度为0时才发送恢复指令
if (vehiclesToResume.find(vehicle.vehicleNo) != vehiclesToResume.end() ||
vehicle.speed == 0) {
VehicleCommand cmd;
cmd.vehicleId = vehicle.vehicleNo;
cmd.type = CommandType::RESUME;
cmd.reason = CommandReason::RESUME_TRAFFIC;
cmd.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
broadcastVehicleCommand(cmd);
controllableVehicles_->sendCommand(cmd.vehicleId, cmd);
Logger::debug("发送恢复指令到无风险车辆: ", cmd.vehicleId);
}
}
}
@ -339,21 +460,36 @@ void System::broadcastPositionUpdate(const MovingObject& obj) {
" timestamp=", msg.timestamp);
}
void System::broadcastTrafficLightUpdate(const TrafficLightSignal& signal) {
void System::broadcastTrafficLightStatus(const TrafficLightSignal& signal) {
if (!ws_server_) {
return;
}
// 查找路口信息
const Intersection* intersection = intersection_config_.findByTrafficLightId(signal.trafficLightId);
nlohmann::json j = {
{"type", "traffic_light_update"},
{"type", "traffic_light_status"},
{"id", signal.trafficLightId},
{"status", static_cast<int>(signal.status)},
{"timestamp", signal.timestamp}
};
// 添加路口信息
if (intersection) {
j["intersection"] = intersection->id;
j["position"] = {
{"longitude", intersection->position.longitude},
{"latitude", intersection->position.latitude}
};
}
ws_server_->broadcast(j.dump());
Logger::debug("广播红绿灯状态: id=", signal.trafficLightId,
" status=", static_cast<int>(signal.status),
" intersection=", intersection ? intersection->id : "",
" position=(", intersection ? intersection->position.longitude : 0.0, ",",
intersection ? intersection->position.latitude : 0.0, ")",
" timestamp=", signal.timestamp);
}
@ -370,6 +506,7 @@ void System::broadcastCollisionWarning(const CollisionRisk& risk) {
return;
}
// 构造冲突预警消息
nlohmann::json j = {
{"type", "collision_warning"},
{"id1", risk.id1},
@ -380,7 +517,12 @@ void System::broadcastCollisionWarning(const CollisionRisk& risk) {
{"timestamp", std::chrono::system_clock::now().time_since_epoch().count()}
};
// 广播冲突预警消息
ws_server_->broadcast(j.dump());
Logger::debug("广播冲突预警: id1=", risk.id1, " id2=", risk.id2,
" distance=", risk.distance, "m",
" relativeSpeed=", risk.relativeSpeed, "m/s",
" level=", getRiskLevelString(risk.level));
}
void System::broadcastTimeoutWarning(const network::TimeoutWarningMessage& warning) {
@ -396,4 +538,75 @@ void System::broadcastTimeoutWarning(const network::TimeoutWarningMessage& warni
warning.elapsed_ms, "ms without response");
}
}
}
void System::broadcastVehicleCommand(const VehicleCommand& cmd) {
if (!ws_server_) {
return;
}
nlohmann::json j = {
{"type", "vehicle_command"},
{"vehicleId", cmd.vehicleId},
{"commandType", [&]() {
switch (cmd.type) {
case CommandType::SIGNAL: return "SIGNAL";
case CommandType::ALERT: return "ALERT";
case CommandType::WARNING: return "WARNING";
case CommandType::RESUME: return "RESUME";
default: return "UNKNOWN";
}
}()},
{"reason", [&]() {
switch (cmd.reason) {
case CommandReason::TRAFFIC_LIGHT: return "TRAFFIC_LIGHT";
case CommandReason::AIRCRAFT_CROSSING: return "AIRCRAFT_CROSSING";
case CommandReason::SPECIAL_VEHICLE: return "SPECIAL_VEHICLE";
case CommandReason::AIRCRAFT_PUSH: return "AIRCRAFT_PUSH";
case CommandReason::RESUME_TRAFFIC: return "RESUME_TRAFFIC";
default: return "UNKNOWN";
}
}()},
{"timestamp", cmd.timestamp}
};
// 添加可选字段
if (cmd.type == CommandType::SIGNAL) {
j["signalState"] = cmd.signalState == SignalState::RED ? "RED" : "GREEN";
j["intersectionId"] = cmd.intersectionId;
}
// 添加目标位置(对于所有非 RESUME 类型的指令)
if (cmd.type != CommandType::RESUME) {
j["targetLatitude"] = cmd.latitude;
j["targetLongitude"] = cmd.longitude;
}
ws_server_->broadcast(j.dump());
}
const MovingObject* System::findVehicle(const std::string& vehicleId) const {
if (!dataCollector_) {
return nullptr;
}
// 获取数据引用注意DataCollector 内部会加锁)
const auto& aircrafts = dataCollector_->getAircraftRef();
const auto& vehicles = dataCollector_->getVehicleRef();
// 在航空器中查找
for (const auto& aircraft : aircrafts) {
if (aircraft.flightNo == vehicleId) {
return &aircraft;
}
}
// 在车辆中查找
for (const auto& vehicle : vehicles) {
if (vehicle.vehicleNo == vehicleId) {
return &vehicle;
}
}
return nullptr;
}

View File

@ -4,6 +4,7 @@
#include <thread>
#include <string>
#include <atomic>
#include <unordered_set>
#include "types/BasicTypes.h"
#include "detector/CollisionDetector.h"
#include "detector/TrafficLightDetector.h"
@ -33,7 +34,8 @@ public:
virtual void broadcastTimeoutWarning(const network::TimeoutWarningMessage& warning);
void broadcastPositionUpdate(const MovingObject& obj);
void broadcastCollisionWarning(const CollisionRisk& risk);
void broadcastTrafficLightUpdate(const TrafficLightSignal& signal);
void broadcastVehicleCommand(const VehicleCommand& cmd);
void broadcastTrafficLightStatus(const TrafficLightSignal& signal);
const SystemConfig& getSystemConfig() const { return system_config_; }
const IntersectionConfig& getIntersectionConfig() const { return intersection_config_; }
@ -42,8 +44,6 @@ private:
void processLoop();
void processCollisions(const std::vector<CollisionRisk>& collisions);
std::atomic<bool> running_{false};
std::thread processThread_;
@ -64,4 +64,10 @@ private:
IntersectionConfig intersection_config_;
static System* instance_;
// 记录上一次有风险的车辆列表
std::unordered_set<std::string> lastVehiclesWithRisk_;
// 辅助函数
const MovingObject* findVehicle(const std::string& vehicleId) const;
};

View File

@ -1,34 +1,80 @@
#include "detector/CollisionDetector.h"
#include "utils/Logger.h"
#include "config/SystemConfig.h"
#include <cmath>
#include <format>
CollisionDetector::CollisionDetector(const AirportBounds& bounds, const ControllableVehicles& controllableVehicles)
: airportBounds_(bounds)
, vehicleTree_(bounds.getAirportBounds(), 8) // 使用机场总边界初始化四叉树
, controllableVehicles_(&controllableVehicles)
{
, controllableVehicles_(&controllableVehicles) {
// 记录初始化信息
const auto& airportBounds = bounds.getAirportBounds();
Logger::debug(
"碰撞检测器初始化: 机场边界=(",
airportBounds.x, ",", airportBounds.y, ") - (",
airportBounds.x + airportBounds.width, ",", airportBounds.y + airportBounds.height, ")"
);
}
void CollisionDetector::updateTraffic(const std::vector<Aircraft>& aircraft,
const std::vector<Vehicle>& vehicles) {
// 记录更新前的状态
Logger::debug(
"更新交通数据: 航空器数量=", aircraft.size(),
", 车辆数量=", vehicles.size()
);
// 更新航空器数据
aircraftData_ = aircraft;
// 更新车辆四叉树
vehicleTree_.clear();
size_t validVehicles = 0;
for (const auto& vehicle : vehicles) {
vehicleTree_.insert(vehicle);
// 验证车辆位置是否在机场边界内
const auto& bounds = airportBounds_.getAirportBounds();
if (vehicle.position.x >= bounds.x && vehicle.position.x <= (bounds.x + bounds.width) &&
vehicle.position.y >= bounds.y && vehicle.position.y <= (bounds.y + bounds.height)) {
vehicleTree_.insert(vehicle);
++validVehicles;
} else {
Logger::warning(
"车辆位置超出机场边界: id=", vehicle.vehicleNo,
", 位置=(", vehicle.position.x,
",", vehicle.position.y, ")"
);
}
}
// 记录更新后的状态
auto allVehicles = vehicleTree_.queryRange(vehicleTree_.getBounds());
Logger::debug(
"交通数据更新完成: 有效车辆数量=", validVehicles,
", 四叉树中的车辆数量=", allVehicles.size()
);
// 验证数据一致性
if (validVehicles != allVehicles.size()) {
Logger::error(
"车辆数据不一致: 有效车辆数=", validVehicles,
", 四叉树中的车辆数量=", allVehicles.size()
);
}
}
std::vector<CollisionRisk> CollisionDetector::detectCollisions() {
std::vector<CollisionRisk> risks;
// 获取配置参数
const auto& predictionConfig = SystemConfig::instance().collision_detection.prediction;
// 获取所有车辆
auto allVehicles = vehicleTree_.queryRange(vehicleTree_.getBounds());
// 过滤出可控车辆
// 可控车辆
std::vector<Vehicle> controlVehicles;
for (const auto& vehicle : allVehicles) {
if (controllableVehicles_->isControllable(vehicle.vehicleNo)) {
@ -38,92 +84,120 @@ std::vector<CollisionRisk> CollisionDetector::detectCollisions() {
// 检测可控车辆与航空器的碰撞
for (const auto& aircraft : aircraftData_) {
const auto& areaConfig = getCollisionParams(aircraft.position);
for (const auto& vehicle : controlVehicles) {
// 计算平面距离的平方
// 计算当前距离
double dx = aircraft.position.x - vehicle.position.x;
double dy = aircraft.position.y - vehicle.position.y;
double distanceSquared = dx*dx + dy*dy;
double threshold = areaConfig.aircraftGroundRadius;
double thresholdSquared = threshold * threshold;
double currentDistance = std::sqrt(dx*dx + dy*dy);
if (distanceSquared < thresholdSquared) {
// 只在必要时计算精确距离
double distance = std::sqrt(distanceSquared);
// 计算预测阈值
double maxSpeed = std::max(aircraft.speed, vehicle.speed);
double predictionDistance = maxSpeed * predictionConfig.time_window;
double baseThreshold = getCollisionParams(aircraft.position).aircraftGroundRadius;
double predictionThreshold = std::max(predictionDistance, baseThreshold * 2.0);
// 如果在预测距离内,进行轨迹预测
if (currentDistance <= predictionThreshold) {
// 获取预测结果
auto prediction = predictTrajectoryCollision(
aircraft.position, aircraft.speed, aircraft.heading,
vehicle.position, vehicle.speed, vehicle.heading,
predictionConfig.aircraft_size,
predictionConfig.vehicle_size,
predictionConfig.time_window
);
// 计算相对运动
MovementVector av(aircraft.speed, aircraft.heading);
MovementVector vv(vehicle.speed, vehicle.heading);
double vx = av.vx - vv.vx;
double vy = av.vy - vv.vy;
// 评估风险等级
auto [level, zoneType] = evaluateRisk(
currentDistance,
aircraft.position,
true, // aircraft
false, // vehicle
prediction.willCollide
);
// 计算相对速度大小
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
// 记录调试信息
Logger::debug("航空器与车辆相对速度计算: ", aircraft.flightNo, " vs ", vehicle.vehicleNo,
", 航空器: speed=", aircraft.speed, "m/s, heading=", aircraft.heading, "°",
", 车辆: speed=", vehicle.speed, "m/s, heading=", vehicle.heading, "°",
", 相对速度: vx=", vx, "m/s, vy=", vy, "m/s, magnitude=", relativeSpeed, "m/s");
// 计算风险等级
RiskLevel level = calculateRiskLevel(distance, aircraft.position, true, false);
// 添加碰撞风险信息
risks.push_back({
aircraft.flightNo,
vehicle.vehicleNo,
level,
distance,
relativeSpeed,
{vx, vy}
});
// 如果存在风险,添加到结果中
if (level != RiskLevel::NONE) {
// 计算相对运动
MovementVector av(aircraft.speed, aircraft.heading);
MovementVector vv(vehicle.speed, vehicle.heading);
double vx = av.vx - vv.vx;
double vy = av.vy - vv.vy;
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
risks.push_back({
aircraft.flightNo,
vehicle.vehicleNo,
level,
currentDistance,
prediction.minDistance,
relativeSpeed,
{vx, vy},
zoneType
});
}
}
}
}
// 检测可控车辆与其他车辆的碰撞
// 检测可控车辆之间的碰撞
for (size_t i = 0; i < controlVehicles.size(); ++i) {
const auto& controlVehicle = controlVehicles[i];
const auto& areaConfig = getCollisionParams(controlVehicle.position);
// 检查与所有其他车辆的碰撞(包括可控和非可控)
const auto& vehicle1 = controlVehicles[i];
for (size_t j = i + 1; j < allVehicles.size(); ++j) {
const auto& otherVehicle = allVehicles[j];
const auto& vehicle2 = allVehicles[j];
// 计算平面距离
double dx = controlVehicle.position.x - otherVehicle.position.x;
double dy = controlVehicle.position.y - otherVehicle.position.y;
double distance = std::sqrt(dx*dx + dy*dy);
double threshold = areaConfig.vehicleCollisionRadius;
if (distance <= threshold) {
// 计算相对运动
MovementVector v1v(controlVehicle.speed, controlVehicle.heading);
MovementVector v2v(otherVehicle.speed, otherVehicle.heading);
double vx = v1v.vx - v2v.vx;
double vy = v1v.vy - v2v.vy;
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
// 计算当前距离
double dx = vehicle1.position.x - vehicle2.position.x;
double dy = vehicle1.position.y - vehicle2.position.y;
double currentDistance = std::sqrt(dx*dx + dy*dy);
// 计算预测阈值
double maxSpeed = std::max(vehicle1.speed, vehicle2.speed);
double predictionDistance = maxSpeed * predictionConfig.time_window;
double baseThreshold = getCollisionParams(vehicle1.position).vehicleCollisionRadius;
double predictionThreshold = std::max(predictionDistance, baseThreshold * 2.0);
// 如果在预测距离内,进行轨迹预测
if (currentDistance <= predictionThreshold) {
// 获取预测结果
auto prediction = predictTrajectoryCollision(
vehicle1.position, vehicle1.speed, vehicle1.heading,
vehicle2.position, vehicle2.speed, vehicle2.heading,
predictionConfig.vehicle_size,
predictionConfig.vehicle_size,
predictionConfig.time_window
);
// 记录调试信息
Logger::debug("车辆间相对速度计算: ", controlVehicle.vehicleNo, " vs ", otherVehicle.vehicleNo,
", 车辆1: speed=", controlVehicle.speed, "m/s, heading=", controlVehicle.heading, "°",
", 车辆2: speed=", otherVehicle.speed, "m/s, heading=", otherVehicle.heading, "°",
", 相对速度: vx=", vx, "m/s, vy=", vy, "m/s, magnitude=", relativeSpeed, "m/s");
// 评估风险等级
auto [level, zoneType] = evaluateRisk(
currentDistance,
vehicle1.position,
false, // vehicle
false, // vehicle
prediction.willCollide
);
// 计算风险等级
RiskLevel level = calculateRiskLevel(distance, controlVehicle.position, false, false);
// 添加碰撞风险信息
risks.push_back({
controlVehicle.vehicleNo,
otherVehicle.vehicleNo,
level,
distance,
relativeSpeed,
{vx, vy}
});
// 如果存在风险,添加到结果中
if (level != RiskLevel::NONE) {
// 计算相对运动
MovementVector v1v(vehicle1.speed, vehicle1.heading);
MovementVector v2v(vehicle2.speed, vehicle2.heading);
double vx = v1v.vx - v2v.vx;
double vy = v1v.vy - v2v.vy;
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
risks.push_back({
vehicle1.vehicleNo,
vehicle2.vehicleNo,
level,
currentDistance,
prediction.minDistance,
relativeSpeed,
{vx, vy},
zoneType
});
}
}
}
}
@ -133,91 +207,320 @@ std::vector<CollisionRisk> CollisionDetector::detectCollisions() {
RiskLevel CollisionDetector::calculateRiskLevel(double distance, const Vector2D& position,
bool isAircraft1, bool isAircraft2) const {
// 获取当前区域的配置
const auto& areaConfig = getCollisionParams(position);
// 获取告警阈值
// 获取合适的阈值配置
auto thresholds = areaConfig.getThresholds(isAircraft1, isAircraft2);
double warningDistance = thresholds.warning;
double alertDistance = thresholds.critical;
// 直接比较距离和阈值
if (distance <= thresholds.critical) {
// 记录调试信息
Logger::debug(
"风险等级计算: 距离=", distance,
"m, 预警阈值=", warningDistance,
"m, 警报阈值=", alertDistance,
"m, 物体类型=",
isAircraft1 ? (isAircraft2 ? "航空器-航空器" : "航空器-车辆") : "车辆-车辆"
);
// 根据距离判断风险等级
if (distance <= alertDistance) {
return RiskLevel::CRITICAL;
} else if (distance <= thresholds.warning) {
} else if (distance <= warningDistance) {
return RiskLevel::WARNING;
}
return RiskLevel::NONE;
}
bool CollisionDetector::checkAircraftVehicleCollision(const Aircraft& aircraft,
const Vehicle& vehicle) const {
const auto& areaConfig = getCollisionParams(aircraft.position);
WarningZoneType CollisionDetector::determineWarningZone(double distance, double threshold) const {
// 获取警报和预警距离
double alertDistance = threshold * 0.5; // 警报距离为阈值的50%
double warningDistance = threshold; // 预警距离为阈值的100%
// 计算平面距离的平方
double dx = aircraft.position.x - vehicle.position.x;
double dy = aircraft.position.y - vehicle.position.y;
double distanceSquared = dx*dx + dy*dy;
// 记录调试信息
Logger::debug(
"预警区域判断: 当前距离=", distance,
"m, 警报距离=", alertDistance,
"m, 预警距离=", warningDistance, "m"
);
// 获取该区域的告警阈值
auto thresholds = areaConfig.getThresholds(true, false); // aircraft vs vehicle
double criticalThresholdSquared = thresholds.critical * thresholds.critical;
// 如果距离小于紧急阈值,直接报警
if (distanceSquared < criticalThresholdSquared) {
return true;
// 根据距离判断区域类型
if (distance <= alertDistance) {
return WarningZoneType::DANGER;
} else if (distance <= warningDistance) {
return WarningZoneType::WARNING;
}
// 如果距离在警告阈值范围内,检查相对运动
double warningThresholdSquared = thresholds.warning * thresholds.warning;
if (distanceSquared < warningThresholdSquared) {
// 计算相对运动
MovementVector av(aircraft.speed, aircraft.heading);
MovementVector vv(vehicle.speed, vehicle.heading);
double vx = av.vx - vv.vx;
double vy = av.vy - vv.vy;
// 计算相对运动
double relativeMotion = dx*vx + dy*vy;
return relativeMotion < 0;
}
return false;
return WarningZoneType::NONE;
}
bool CollisionDetector::checkVehicleCollision(const Vehicle& v1,
const Vehicle& v2) const {
const auto& areaConfig = getCollisionParams(v1.position);
// 添加一个新的辅助函数来统一处理风险等级和预警区域的判断
std::pair<RiskLevel, WarningZoneType> CollisionDetector::evaluateRisk(
double currentDistance,
const Vector2D& position,
bool isAircraft1,
bool isAircraft2,
bool willCollide) const {
// 计算平面距离
double dx = v1.position.x - v2.position.x;
double dy = v1.position.y - v2.position.y;
double distance = std::sqrt(dx*dx + dy*dy);
// 取区域配置
const auto& areaConfig = getCollisionParams(position);
auto thresholds = areaConfig.getThresholds(isAircraft1, isAircraft2);
// 获取该区域的告警阈值
auto thresholds = areaConfig.getThresholds(false, false); // vehicle vs vehicle
RiskLevel level = RiskLevel::NONE;
WarningZoneType zoneType = WarningZoneType::NONE;
// 如果距离小于紧急阈值,直接报警
if (distance < thresholds.critical) {
// 如果预测到碰撞或距离小于警报距离,设置为危险等级
if (willCollide || currentDistance <= thresholds.critical) {
level = RiskLevel::CRITICAL;
zoneType = WarningZoneType::DANGER;
}
// 如果距离在预警范围内,设置为预警等级
else if (currentDistance <= thresholds.warning) {
level = RiskLevel::WARNING;
zoneType = WarningZoneType::WARNING;
}
// 记录调试信息
Logger::debug(
"风险评估: 当前距离=", currentDistance,
"m, 预警阈值=", thresholds.warning,
"m, 警报阈值=", thresholds.critical,
"m, 预测碰撞=", willCollide ? "" : "",
", 风险等级=", static_cast<int>(level),
", 区域类型=", static_cast<int>(zoneType)
);
return {level, zoneType};
}
bool CollisionDetector::checkCollisionRisk(
const Vector2D& pos1, double speed1, double heading1, const std::string& id1,
const Vector2D& pos2, double speed2, double heading2, const std::string& id2,
bool isAircraft1, bool isAircraft2) const {
// 获取区域配置
const auto& areaConfig = getCollisionParams(pos1);
const auto& predictionConfig = SystemConfig::instance().collision_detection.prediction;
// 计算当前距离
double dx = pos1.x - pos2.x;
double dy = pos1.y - pos2.y;
double currentDistance = std::sqrt(dx*dx + dy*dy);
// 计算预测阈值
double maxSpeed = std::max(speed1, speed2);
double predictionDistance = maxSpeed * predictionConfig.time_window;
// 根据物体类型选择基准阈值
double baseThreshold = (isAircraft1 || isAircraft2) ?
areaConfig.aircraftGroundRadius :
areaConfig.vehicleCollisionRadius;
double predictionThreshold = std::max(predictionDistance, baseThreshold * 2.0);
// 如果当前距离超过预测阈值直接返回false
if (currentDistance > predictionThreshold) {
return false;
}
// 直接告警条件:距离小于阈值的一半
if (currentDistance < baseThreshold * 0.5) {
return true;
}
// 如果距离在警告阈值范围内,检查相对运动
if (distance < thresholds.warning) {
// 计算相对速度
double v1x = v1.speed * std::cos((90 - v1.heading) * M_PI / 180.0);
double v1y = v1.speed * std::sin((90 - v1.heading) * M_PI / 180.0);
double v2x = v2.speed * std::cos((90 - v2.heading) * M_PI / 180.0);
double v2y = v2.speed * std::sin((90 - v2.heading) * M_PI / 180.0);
double vx = v1x - v2x;
double vy = v1y - v2y;
// 获取预测结果
auto prediction = predictTrajectoryCollision(
pos1, speed1, heading1,
pos2, speed2, heading2,
isAircraft1 ? predictionConfig.aircraft_size : predictionConfig.vehicle_size,
isAircraft2 ? predictionConfig.aircraft_size : predictionConfig.vehicle_size,
predictionConfig.time_window
);
// 获取阈值配置
auto thresholds = areaConfig.getThresholds(isAircraft1, isAircraft2);
double alertDistance = thresholds.critical;
// 如果距离在阈值范围内,进行相对运动分析
bool hasCollisionRisk = false;
if (currentDistance < baseThreshold) {
// 使用 MovementVector 计算速度分量
MovementVector mv1(speed1, heading1);
MovementVector mv2(speed2, heading2);
// 计算相对运动
// 计算相对速度
double vx = mv1.vx - mv2.vx;
double vy = mv1.vy - mv2.vy;
// 计算相对运动(点积),判断是否在接近
double relativeMotion = dx*vx + dy*vy;
// 如果物体正在接近或相对静止,就报警
if (relativeMotion <= 0) {
return true;
// 如果相对运动小于等于0表示物体正在接近
hasCollisionRisk = (relativeMotion <= 0) || prediction.willCollide || currentDistance <= alertDistance;
}
if (hasCollisionRisk) {
// 使用 MovementVector 计算相对运动,用于日志记录
MovementVector mv1(speed1, heading1);
MovementVector mv2(speed2, heading2);
double vx = mv1.vx - mv2.vx;
double vy = mv1.vy - mv2.vy;
double relativeSpeed = std::sqrt(vx*vx + vy*vy);
std::string type1 = isAircraft1 ? "航空器" : "车辆";
std::string type2 = isAircraft2 ? "航空器" : "车辆";
Logger::debug(
"检测到碰撞风险: {}1={}, {}2={}, 当前距离={}m, 相对速度={}m/s, 预测碰撞={}",
type1, id1,
type2, id2,
currentDistance,
relativeSpeed,
prediction.willCollide ? "" : ""
);
}
return hasCollisionRisk;
}
bool CollisionDetector::checkAircraftVehicleCollision(const Aircraft& aircraft,
const Vehicle& vehicle) const {
return checkCollisionRisk(
aircraft.position, aircraft.speed, aircraft.heading, aircraft.flightNo,
vehicle.position, vehicle.speed, vehicle.heading, vehicle.vehicleNo,
true, false
);
}
bool CollisionDetector::checkVehicleCollision(const Vehicle& v1, const Vehicle& v2) const {
return checkCollisionRisk(
v1.position, v1.speed, v1.heading, v1.vehicleNo,
v2.position, v2.speed, v2.heading, v2.vehicleNo,
false, false
);
}
CollisionPrediction CollisionDetector::predictTrajectoryCollision(
const Vector2D& pos1, double speed1, double heading1,
const Vector2D& pos2, double speed2, double heading2,
double size1, double size2, double timeWindow) const {
CollisionPrediction result;
result.willCollide = false;
result.timeToCollision = std::numeric_limits<double>::infinity();
result.minDistance = std::numeric_limits<double>::infinity();
// 计算安全距离
double safeDistance = size1 + size2;
// 计算速度分量
MovementVector mv1(speed1, heading1);
MovementVector mv2(speed2, heading2);
// 计算相对速度
double dvx = mv1.vx - mv2.vx;
double dvy = mv1.vy - mv2.vy;
double relativeSpeed = std::sqrt(dvx*dvx + dvy*dvy);
// 计算相对位置
double dx = pos1.x - pos2.x;
double dy = pos1.y - pos2.y;
double currentDistance = std::sqrt(dx*dx + dy*dy);
// 记录初始状态
Logger::debug(
"轨迹预测初始状态: 当前距离=", currentDistance,
"m, 相对速度=", relativeSpeed,
"m/s, 安全距离=", safeDistance, "m"
);
// 如果物体静止相对于此,直接返回当前状态
if (relativeSpeed < 1e-6) {
result.minDistance = currentDistance;
result.willCollide = (currentDistance <= safeDistance);
if (result.willCollide) {
result.timeToCollision = 0.0;
// 根据物体尺寸计算碰撞点
double ratio = size1 / (size1 + size2);
result.collisionPoint.x = pos2.x + dx * ratio;
result.collisionPoint.y = pos2.y + dy * ratio;
}
return result;
}
// 计算相对运动方程的系数
double a = dvx * dvx + dvy * dvy;
double b = 2.0 * (dx * dvx + dy * dvy);
double c = dx * dx + dy * dy - safeDistance * safeDistance;
// 计算判别式
double discriminant = b * b - 4.0 * a * c;
// 如果判别式小于0不会发生碰撞
if (discriminant < 0) {
// 计算时间窗口内的最小距离
double t_min = -b / (2.0 * a);
t_min = std::clamp(t_min, 0.0, timeWindow);
// 计算最小距离时刻的位置
double x1_min = pos1.x + mv1.vx * t_min;
double y1_min = pos1.y + mv1.vy * t_min;
double x2_min = pos2.x + mv2.vx * t_min;
double y2_min = pos2.y + mv2.vy * t_min;
result.minDistance = std::sqrt(
std::pow(x1_min - x2_min, 2) +
std::pow(y1_min - y2_min, 2)
);
Logger::debug(
"无碰撞可能: 最小距离=", result.minDistance,
"m, 发生时间=", t_min, "s"
);
return result;
}
// 计算可能的碰撞时间点
double t1 = (-b - std::sqrt(discriminant)) / (2.0 * a);
double t2 = (-b + std::sqrt(discriminant)) / (2.0 * a);
// 检查两个时间点
for (double t : {t1, t2}) {
if (t >= 0 && t <= timeWindow) {
// 计算t时刻的位置
double x1_t = pos1.x + mv1.vx * t;
double y1_t = pos1.y + mv1.vy * t;
double x2_t = pos2.x + mv2.vx * t;
double y2_t = pos2.y + mv2.vy * t;
// 计算t时刻的距离
double dist_t = std::sqrt(
std::pow(x1_t - x2_t, 2) +
std::pow(y1_t - y2_t, 2)
);
// 更新最小距离
if (dist_t < result.minDistance) {
result.minDistance = dist_t;
// 如果距离小于等于安全距离,记录碰撞信息
if (dist_t <= safeDistance && !result.willCollide) {
result.willCollide = true;
result.timeToCollision = t;
// 根据物体尺寸计算碰撞点
double ratio = size1 / (size1 + size2);
result.collisionPoint.x = x2_t + (x1_t - x2_t) * ratio;
result.collisionPoint.y = y2_t + (y1_t - y2_t) * ratio;
Logger::debug(
"预测到碰撞: 时间=", t,
"s, 距离=", dist_t,
"m, 位置=(", result.collisionPoint.x,
",", result.collisionPoint.y, ")"
);
}
}
}
}
return false;
return result;
}

View File

@ -5,15 +5,24 @@
#include "spatial/QuadTree.h"
#include "spatial/AirportBounds.h"
#include "vehicle/ControllableVehicles.h"
#include "config/SystemConfig.h"
#include <vector>
#include <utility>
#include <limits>
#include <utils/Logger.h>
// 碰撞风险等级
enum class RiskLevel {
NONE = 0, // 无风险
WARNING = 1, // 低风险:距离在阈值的 50%-100% 之间
CRITICAL = 2, // 中等风险:距离在阈值的 0%-50% 之间
WARNING = 1, // 预警:进入预警区域
CRITICAL = 2, // 告警:进入危险区域
};
// 预警区域类型
enum class WarningZoneType {
NONE = 0, // 无风险区域
WARNING = 1, // 预警区域
DANGER = 2 // 危险区域
};
// 碰撞风险信息
@ -21,8 +30,18 @@ struct CollisionRisk {
std::string id1, id2; // 碰撞物体的ID
RiskLevel level; // 风险等级
double distance; // 当前距离
double minDistance; // 预测的最小距离
double relativeSpeed; // 相对速度
Vector2D relativeMotion; // 相对运动向量
WarningZoneType zoneType; // 预警区域类型
};
// 轨迹预测碰撞结果
struct CollisionPrediction {
bool willCollide; // 是否可能发生碰撞
double timeToCollision; // 到碰撞点的时间(秒)
Vector2D collisionPoint; // 可能的碰撞点
double minDistance; // 最小距离
};
class CollisionDetector {
@ -36,6 +55,15 @@ public:
// 检测所有可能的碰撞
std::vector<CollisionRisk> detectCollisions();
// 基于轨迹预测的碰撞检测
CollisionPrediction predictTrajectoryCollision(
const Vector2D& pos1, double speed1, double heading1, // 物体1的位置、速度、航向
const Vector2D& pos2, double speed2, double heading2, // 物体2的位置、速度、航向
double size1, // 物体1的尺寸
double size2, // 物体2的尺寸
double timeWindow = 30.0 // 预测时间窗口(默认30秒)
) const;
private:
const AirportBounds& airportBounds_;
QuadTree<Vehicle> vehicleTree_;
@ -48,6 +76,12 @@ private:
return airportBounds_.getAreaConfig(areaType);
}
// 通用碰撞风险检测函数
bool checkCollisionRisk(
const Vector2D& pos1, double speed1, double heading1, const std::string& id1,
const Vector2D& pos2, double speed2, double heading2, const std::string& id2,
bool isAircraft1, bool isAircraft2) const;
// 检查航空器和车辆是否可能碰撞
bool checkAircraftVehicleCollision(const Aircraft& aircraft, const Vehicle& vehicle) const;
// 检查两辆车是否可能碰撞
@ -57,18 +91,28 @@ private:
RiskLevel calculateRiskLevel(double distance, const Vector2D& position,
bool isAircraft1, bool isAircraft2) const;
// 确定预警区域类型
WarningZoneType determineWarningZone(double distance, double threshold) const;
// 统一的风险评估函数
std::pair<RiskLevel, WarningZoneType> evaluateRisk(
double currentDistance,
const Vector2D& position,
bool isAircraft1,
bool isAircraft2,
bool willCollide) const;
// 计算相对运动
struct MovementVector {
double vx, vy;
MovementVector(double speed, double heading) {
// 航向角是以正北为0度顺时针增加
// 需要转换为数学坐标系以正东为0度逆时针增加
double radians = (90.0 - heading) * M_PI / 180.0;
// 标准方位角正北为0度顺时针增加
double radians = heading * M_PI / 180.0;
// 计算速度分量
vx = speed * std::cos(radians); // 东向分量
vy = speed * std::sin(radians); // 北向分量
vx = speed * std::sin(radians); // 东向分量
vy = speed * std::cos(radians); // 北向分量
// 记录调试信息
Logger::debug("速度分量计算: speed=", speed, "m/s, heading=", heading,

View File

@ -1,12 +1,15 @@
#include "detector/TrafficLightDetector.h"
#include "utils/Logger.h"
#include "types/BasicTypes.h"
#include "core/System.h"
#include <chrono>
TrafficLightDetector::TrafficLightDetector(const IntersectionConfig& intersectionConfig,
const ControllableVehicles& controllableVehicles)
const ControllableVehicles& controllableVehicles,
System& system)
: intersection_config_(intersectionConfig)
, controllable_vehicles_(controllableVehicles) {
, controllable_vehicles_(controllableVehicles)
, system_(system) {
}
void TrafficLightDetector::processSignal(const TrafficLightSignal& signal,
@ -18,58 +21,68 @@ void TrafficLightDetector::processSignal(const TrafficLightSignal& signal,
return;
}
// 保存当前处理的信号
current_signal_ = signal;
// 检查每个车辆
for (const auto& vehicle : vehicles) {
if (controllable_vehicles_.isControllable(vehicle.vehicleNo)) {
checkVehicleIntersectionDistance(vehicle, *intersection, signal.status);
}
}
}
void TrafficLightDetector::checkVehicleIntersectionDistance(const Vehicle& vehicle,
const Intersection& intersection,
SignalStatus status) {
// 创建 GeoPosition 用于距离计算
GeoPosition intersectionPos{
intersection.position.latitude,
intersection.position.longitude
};
// 计算车辆到路口的距离
double distance = MovingObject::calculateDistance(vehicle.geo, intersectionPos);
// 如果车辆在路口影响范围内
if (distance <= intersection.radius) {
switch (status) {
case SignalStatus::RED:
sendStopCommand(vehicle.vehicleNo);
break;
case SignalStatus::GREEN:
sendContinueCommand(vehicle.vehicleNo);
break;
default:
Logger::warning("未知的信号灯状态");
break;
// 根据信号灯状态发送指令
switch (signal.status) {
case SignalStatus::RED:
sendStopCommand(vehicle.vehicleNo);
break;
case SignalStatus::GREEN:
sendContinueCommand(vehicle.vehicleNo);
break;
default:
Logger::warning("未知的信号灯状态");
break;
}
}
}
}
void TrafficLightDetector::sendStopCommand(const std::string& vehicleNo) {
VehicleCommand cmd;
cmd.vehicleId = vehicleNo;
cmd.type = CommandType::SIGNAL;
cmd.reason = CommandReason::TRAFFIC_LIGHT;
cmd.signalState = SignalState::RED;
cmd.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
const_cast<ControllableVehicles&>(controllable_vehicles_).sendCommand(vehicleNo, cmd);
Logger::debug("发送停止指令到车辆: ", vehicleNo);
// 添加路口信息
const Intersection* intersection = intersection_config_.findByTrafficLightId(current_signal_.trafficLightId);
if (intersection) {
cmd.intersectionId = intersection->id;
cmd.latitude = intersection->position.latitude;
cmd.longitude = intersection->position.longitude;
}
if (const_cast<ControllableVehicles&>(controllable_vehicles_).sendCommand(vehicleNo, cmd)) {
system_.broadcastVehicleCommand(cmd);
}
Logger::debug("发送停止指令到车辆: ", vehicleNo, " 路口: ", cmd.intersectionId);
}
void TrafficLightDetector::sendContinueCommand(const std::string& vehicleNo) {
VehicleCommand cmd;
cmd.vehicleId = vehicleNo;
cmd.type = CommandType::SIGNAL;
cmd.reason = CommandReason::TRAFFIC_LIGHT;
cmd.signalState = SignalState::GREEN;
cmd.timestamp = std::chrono::system_clock::now().time_since_epoch().count();
const_cast<ControllableVehicles&>(controllable_vehicles_).sendCommand(vehicleNo, cmd);
Logger::debug("发送继续指令到车辆: ", vehicleNo);
// 添加路口信息
const Intersection* intersection = intersection_config_.findByTrafficLightId(current_signal_.trafficLightId);
if (intersection) {
cmd.intersectionId = intersection->id;
cmd.latitude = intersection->position.latitude;
cmd.longitude = intersection->position.longitude;
}
if (const_cast<ControllableVehicles&>(controllable_vehicles_).sendCommand(vehicleNo, cmd)) {
system_.broadcastVehicleCommand(cmd);
}
Logger::debug("发送继续指令到车辆: ", vehicleNo, " 路口: ", cmd.intersectionId);
}

View File

@ -6,23 +6,25 @@
#include "config/IntersectionConfig.h"
#include "vehicle/ControllableVehicles.h"
// 前向声明
class System;
class TrafficLightDetector {
public:
TrafficLightDetector(const IntersectionConfig& intersectionConfig,
const ControllableVehicles& controllableVehicles);
const ControllableVehicles& controllableVehicles,
System& system);
// 处理红绿灯信号
void processSignal(const TrafficLightSignal& signal, const std::vector<Vehicle>& vehicles);
private:
// 检查车辆与路口的距离,决定是否需要发送指令
void checkVehicleIntersectionDistance(const Vehicle& vehicle,
const Intersection& intersection,
SignalStatus status);
// 发送车辆控制指令
void sendStopCommand(const std::string& vehicleId);
void sendContinueCommand(const std::string& vehicleId);
const IntersectionConfig& intersection_config_;
const ControllableVehicles& controllable_vehicles_;
System& system_;
TrafficLightSignal current_signal_; // 当前处理的信号
};

View File

@ -21,7 +21,7 @@ LogLevel getLogLevelFromString(const std::string& level) {
return LogLevel::INFO; // 默认级别
}
int main() {
int main(int argc, char* argv[]) {
try {
// 设置信号处理
signal(SIGINT, signalHandler);
@ -31,12 +31,12 @@ int main() {
std::filesystem::create_directories("logs");
// 加载系统配置
auto config = SystemConfig::load("config/system_config.json");
SystemConfig::instance().load("config/system_config.json");
// 初始化日志系统
Logger::initialize(config.logging.file, getLogLevelFromString(config.logging.level));
Logger::initialize(SystemConfig::instance().logging.file, getLogLevelFromString(SystemConfig::instance().logging.level));
Logger::info("Starting system...");
Logger::debug("Log level set to: ", config.logging.level);
Logger::debug("Log level set to: ", SystemConfig::instance().logging.level);
// 初始化系统
System system;

109
src/network/HTTPClient.cpp Normal file
View File

@ -0,0 +1,109 @@
#include "network/HTTPClient.h"
#include "utils/Logger.h"
#include <sstream>
HTTPClient::HTTPClient() {
curl_global_init(CURL_GLOBAL_ALL);
curl_ = curl_easy_init();
if (!curl_) {
throw std::runtime_error("Failed to initialize CURL");
}
}
HTTPClient::~HTTPClient() {
if (curl_) {
curl_easy_cleanup(curl_);
}
curl_global_cleanup();
}
size_t HTTPClient::WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
size_t total_size = size * nmemb;
std::string* response = static_cast<std::string*>(userp);
response->append(static_cast<char*>(contents), total_size);
return total_size;
}
bool HTTPClient::sendCommand(const std::string& ip, int port, const VehicleCommand& command) {
if (!curl_) {
Logger::error("CURL not initialized");
return false;
}
// 构造请求URL
std::stringstream url;
url << "http://" << ip << ":" << port << "/api/vehicle/command";
// 构造请求体
nlohmann::json request = {
{"vehicleId", command.vehicleId},
{"type", [&]() {
switch (command.type) {
case CommandType::SIGNAL: return "SIGNAL";
case CommandType::ALERT: return "ALERT";
case CommandType::WARNING: return "WARNING";
case CommandType::RESUME: return "RESUME";
default: return "UNKNOWN";
}
}()},
{"reason", [&]() {
switch (command.reason) {
case CommandReason::TRAFFIC_LIGHT: return "TRAFFIC_LIGHT";
case CommandReason::AIRCRAFT_CROSSING: return "AIRCRAFT_CROSSING";
case CommandReason::SPECIAL_VEHICLE: return "SPECIAL_VEHICLE";
case CommandReason::AIRCRAFT_PUSH: return "AIRCRAFT_PUSH";
case CommandReason::RESUME_TRAFFIC: return "RESUME_TRAFFIC";
default: return "UNKNOWN";
}
}()},
{"timestamp", command.timestamp}
};
// 添加可选字段
if (command.type == CommandType::SIGNAL) {
request["signalState"] = command.signalState == SignalState::RED ? "RED" : "GREEN";
request["intersectionId"] = command.intersectionId;
}
if (command.type != CommandType::RESUME) {
request["targetPosition"] = {
{"latitude", command.latitude},
{"longitude", command.longitude}
};
}
std::string request_body = request.dump();
response_buffer_.clear();
// 设置CURL选项
curl_easy_setopt(curl_, CURLOPT_URL, url.str().c_str());
curl_easy_setopt(curl_, CURLOPT_POST, 1L);
curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, request_body.c_str());
curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response_buffer_);
// 设置请求头
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, headers);
// 发送请求
CURLcode res = curl_easy_perform(curl_);
curl_slist_free_all(headers);
if (res != CURLE_OK) {
Logger::error("Failed to send command: ", curl_easy_strerror(res));
return false;
}
// 检查响应状态码
long http_code = 0;
curl_easy_getinfo(curl_, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code == 200) {
Logger::debug("Command sent successfully: ", request_body);
return true;
} else {
Logger::error("Command failed with HTTP code: ", http_code, " response: ", response_buffer_);
return false;
}
}

20
src/network/HTTPClient.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <string>
#include <curl/curl.h>
#include "types/VehicleCommand.h"
#include "nlohmann/json.hpp"
class HTTPClient {
public:
HTTPClient();
~HTTPClient();
// 发送控制指令
bool sendCommand(const std::string& ip, int port, const VehicleCommand& command);
private:
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp);
CURL* curl_;
std::string response_buffer_;
};

View File

@ -56,6 +56,7 @@ void AirportBounds::loadConfig(const std::string& configFile) {
else if (key == "taxiway") type = AreaType::TAXIWAY;
else if (key == "gate") type = AreaType::GATE;
else if (key == "service") type = AreaType::SERVICE;
else if (key == "test_zone") type = AreaType::TEST_ZONE;
else continue;
// 检查必要的字段
@ -77,7 +78,9 @@ void AirportBounds::loadConfig(const std::string& configFile) {
areaConfigs_[type] = {
config["vehicle_collision_radius"].get<double>(),
config["aircraft_ground_radius"].get<double>(),
config["height_threshold"].get<double>()
config["height_threshold"].get<double>(),
config["warning_zone_radius"].get<double>(),
config["alert_zone_radius"].get<double>()
};
}

View File

@ -10,14 +10,17 @@ enum class AreaType {
RUNWAY, // 跑道
TAXIWAY, // 滑行道
GATE, // 停机位
SERVICE // 服务区
SERVICE, // 服务区
TEST_ZONE // 测试区
};
// 区域配置
struct AreaConfig {
double vehicleCollisionRadius; // 车辆间冲突检测半径
double aircraftGroundRadius; // 航空器与车辆冲突检测半径
double heightThreshold; // 高度阈值
double vehicleCollisionRadius = 0.0; // 车辆间冲突检测半径
double aircraftGroundRadius = 0.0; // 航空器与车辆冲突检测半径
double heightThreshold = 0.0; // 高度阈值
double warning_zone_radius = 0.0; // 预警区域半径
double alert_zone_radius = 0.0; // 警报区域半径
// 获取不同类型交通工具间的告警阈值
struct CollisionThresholds {
@ -27,14 +30,15 @@ struct AreaConfig {
// 计算两个交通工具之间的告警阈值
CollisionThresholds getThresholds(bool isAircraft1, bool isAircraft2) const {
// 获取基础安全距离
double baseRadius = isAircraft1 || isAircraft2 ?
aircraftGroundRadius : vehicleCollisionRadius;
// 如果没有配置预警和警报距离,使用碰撞半径作为默认值
double warningRadius = warning_zone_radius > 0 ? warning_zone_radius :
(isAircraft1 || isAircraft2 ? aircraftGroundRadius : vehicleCollisionRadius);
double alertRadius = alert_zone_radius > 0 ? alert_zone_radius :
(isAircraft1 || isAircraft2 ? aircraftGroundRadius * 0.5 : vehicleCollisionRadius * 0.5);
// 计算不同级别的阈值
return {
baseRadius, // 预警距离:为基础距离
baseRadius / 2.0 // 告警距离:为基础距离的一半
warningRadius, // 预警距离
alertRadius // 警报距离
};
}
};

View File

@ -95,9 +95,9 @@ void MovingObject::updateMotion(const GeoPosition& newPos, uint64_t newTime) {
// 计算速度和航向
if (positionHistory.size() >= 2) {
// 找到合适的历史点来计算速度和航向
// 使用最近的两个点来计算速度和航向
const auto& curr = positionHistory.back();
const auto& prev = positionHistory.front(); // 使用最早的历史
const auto& prev = positionHistory[positionHistory.size() - 2]; // 使用倒数第二个
// 计算距离和时间差
double distance = calculateDistance(prev.geo, curr.geo); // 单位:米
@ -109,16 +109,16 @@ void MovingObject::updateMotion(const GeoPosition& newPos, uint64_t newTime) {
"\n Distance=", distance, "m, TimeDiff=", timeDiff, "s");
// 只有当位置变化足够大且时间差足够长时才更新速度和航向
static const double MIN_DISTANCE = 0.5; // 最小位置变化阈值(米)
static const double MIN_TIME = 0.2; // 最小时间差阈值(秒)
static const double MIN_DISTANCE = 0.1; // 最小位置变化阈值(米)
static const double MIN_TIME = 0.05; // 最小时间差阈值(秒)
if (distance > MIN_DISTANCE && timeDiff > MIN_TIME) {
// 计算新的速度
double newSpeed = distance / timeDiff; // 米/秒
if (isValidSpeed(newSpeed)) {
// 使用指数移动平均来平滑速度
const double alpha = getSpeedSmoothingFactor();
// 使用指数移动平均来平滑速度,增大平滑因子以加快更新
const double alpha = 0.8; // 增大平滑因子
if (speed == 0) {
speed = newSpeed; // 第一次计算
} else {
@ -134,8 +134,8 @@ void MovingObject::updateMotion(const GeoPosition& newPos, uint64_t newTime) {
// 计算新的航向
double newHeading = calculateHeading(prev.geo, curr.geo);
// 使用指数移动平均来平滑航向
const double beta = 0.3; // 航向平滑因子
// 使用指数移动平均来平滑航向,增大平滑因子以加快更新
const double beta = 0.8; // 增大航向平滑因子
if (heading == 0) {
heading = newHeading; // 第一次计算
} else {

7
src/types/RiskLevel.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
enum class RiskLevel {
NONE, // 无风险
WARNING, // 预警
CRITICAL // 告警
};

View File

@ -13,6 +13,9 @@ struct TrafficLightSignal {
std::string trafficLightId; // 红绿灯设备 ID
SignalStatus status; // 信号灯状态
uint64_t timestamp; // 时间戳
std::string intersectionId; // 路口编号
double latitude; // 路口纬度
double longitude; // 路口经度
static SignalStatus parseStatus(const std::string& status) {
if (status == "red") return SignalStatus::RED;

View File

@ -6,9 +6,9 @@
// 指令类型
enum class CommandType {
SIGNAL, // 信号灯指令(最高优先级)
ALERT, // 告警指令(中等优先级)
WARNING, // 预警指令(最低优先级)
ALERT, // 告警指令(最高优先级)
SIGNAL, // 信号灯指令(次高优先级)
WARNING, // 预警指令(中等优先级)
RESUME // 恢复指令(最低优先级)
};
@ -28,22 +28,30 @@ enum class CommandReason {
};
struct VehicleCommand {
std::string vehicleId; // 车辆ID
CommandType type; // 命令类型
CommandReason reason; // 命令原因
SignalState signalState; // 信号灯状态(仅当 type 为 SIGNAL 时有效)
Vector2D targetPosition; // 目标位置(如交叉路口)
double speed{0.0}; // 目标速度
double distance{0.0}; // 与关键点的距离
uint64_t timestamp; // 时间戳
std::string vehicleId; // 车辆ID
CommandType type; // 指令类型
CommandReason reason; // 指令原因
uint64_t timestamp; // 时间戳
SignalState signalState; // 信号灯状态(仅当 type 为 SIGNAL 时有效)
std::string intersectionId; // 路口ID仅当 type 为 SIGNAL 时有效)
double latitude; // 目标位置纬度(路口/航空器/特勤车)
double longitude; // 目标位置经度(路口/航空器/特勤车)
VehicleCommand() :
type(CommandType::RESUME),
reason(CommandReason::RESUME_TRAFFIC),
timestamp(0),
signalState(SignalState::GREEN),
latitude(0),
longitude(0) {}
// 获取指令优先级(数字越大优先级越高)
int getPriority() const {
switch(type) {
case CommandType::SIGNAL: return 4;
case CommandType::ALERT: return 3;
case CommandType::WARNING: return 2;
case CommandType::RESUME: return 1;
case CommandType::ALERT: return 5; // 最高优先级
case CommandType::SIGNAL: return 4; // 次高优先级
case CommandType::WARNING: return 3; // 中等优先级
case CommandType::RESUME: return 1; // 最低优先级
default: return 0;
}
}

View File

@ -4,7 +4,8 @@
#include <fstream>
#include <stdexcept>
ControllableVehicles::ControllableVehicles(const std::string& configFile) {
ControllableVehicles::ControllableVehicles(const std::string& configFile)
: http_client_(std::make_unique<HTTPClient>()) {
if (!configFile.empty()) {
loadConfig(configFile);
}
@ -24,6 +25,7 @@ const ControllableVehicleConfig* ControllableVehicles::findVehicle(const std::st
}
bool ControllableVehicles::isControllable(const std::string& vehicleNo) const {
// 只检查是否在配置文件中
return findVehicle(vehicleNo) != nullptr;
}
@ -43,17 +45,33 @@ void ControllableVehicles::loadConfig(const std::string& configFile) {
config.ip = item["ip"].get<std::string>();
config.port = item["port"].get<int>();
vehicles_.push_back(config);
Logger::info("Added controllable vehicle: {}", config.vehicleNo);
}
Logger::info("Loaded {} controllable vehicles", vehicles_.size());
} catch (const std::exception& e) {
throw std::runtime_error("Failed to parse controllable vehicles config: " + std::string(e.what()));
}
}
}
void ControllableVehicles::sendCommand(const std::string& vehicleNo, const VehicleCommand& command) {
bool ControllableVehicles::sendCommand(const std::string& vehicleNo, const VehicleCommand& command) {
auto vehicle = findVehicle(vehicleNo);
if (vehicle) {
// TODO: 发送控制命令
if (!vehicle) {
Logger::error("Vehicle {} not found in controllable vehicles", vehicleNo);
return false;
}
try {
bool success = http_client_->sendCommand(vehicle->ip, vehicle->port, command);
if (success) {
Logger::info("Successfully sent command to vehicle {}: type={}, reason={}",
vehicleNo, static_cast<int>(command.type), static_cast<int>(command.reason));
} else {
Logger::error("Failed to send command to vehicle {}", vehicleNo);
}
return success;
} catch (const std::exception& e) {
Logger::error("Exception while sending command to vehicle {}: {}", vehicleNo, e.what());
return false;
}
}

View File

@ -4,6 +4,7 @@
#include <vector>
#include <memory>
#include "types/VehicleCommand.h"
#include "network/HTTPClient.h"
struct ControllableVehicleConfig {
std::string vehicleNo; // 车牌号
@ -25,10 +26,11 @@ public:
// 检查车辆是否可控
virtual bool isControllable(const std::string& vehicleNo) const;
// 发送控制命令
virtual void sendCommand(const std::string& vehicleNo, const VehicleCommand& command);
// 发送控制命令,返回是否发送成功
virtual bool sendCommand(const std::string& vehicleNo, const VehicleCommand& command);
private:
std::vector<ControllableVehicleConfig> vehicles_;
std::unique_ptr<HTTPClient> http_client_;
void loadConfig(const std::string& configFile);
};

View File

@ -62,7 +62,7 @@ TEST_F(CollisionDetectorTest, DetectControllableVehicleAircraftCollision) {
.WillRepeatedly(testing::Return(true));
Logger::info("Set mock expectation: VEH001 is controllable");
// 设置测试数<EFBFBD><EFBFBD><EFBFBD>
// 设置<EFBFBD><EFBFBD><EFBFBD>试数据
Aircraft aircraft;
aircraft.flightNo = "TEST001";
aircraft.position = {100, 100};
@ -251,7 +251,7 @@ TEST_F(CollisionDetectorTest, PerformanceTest) {
aircraft.push_back(a);
}
// 滑行道区域5架航空器
// 滑行道5架航空器
for (int i = 0; i < 5; ++i) {
Aircraft a;
a.flightNo = "TW" + std::to_string(i + 1);
@ -356,4 +356,359 @@ TEST_F(CollisionDetectorTest, PerformanceTest) {
// 验证性能要求
EXPECT_LT(duration.count(), 100000); // 期望处理时间小于100ms
}
// 测试轨迹预测的准确性
TEST_F(CollisionDetectorTest, TrajectoryPredictionAccuracy) {
// 设置 Mock 期望
EXPECT_CALL(*mockControllableVehicles_, isControllable(testing::_))
.WillRepeatedly(testing::Return(true));
// 测试场景1正面相遇碰撞
{
Vector2D pos1{100, 100}; // 第一个物体的位置
double speed1 = 10; // 第一个物体的速度 (m/s)
double heading1 = 90; // 第一个物体的航向正东90度
Vector2D pos2{300, 100}; // 第二个物体的位置
double speed2 = 10; // 第二个物体的速度 (m/s)
double heading2 = 270; // 第二个物体的航向正西270度
double size1 = 5; // 第一个物体的尺寸
double size2 = 5; // 第二个物体的尺寸
double timeWindow = 30; // 预测时间窗口
auto prediction = detector_->predictTrajectoryCollision(
pos1, speed1, heading1,
pos2, speed2, heading2,
size1, size2, timeWindow
);
// 验证结果:首先验证是否检测到碰撞
EXPECT_TRUE(prediction.willCollide) << "应该检测到碰撞";
if (prediction.willCollide) {
// 验证碰撞点位置允许1米的误差
EXPECT_NEAR(prediction.collisionPoint.x, 200.0, 1.0) << "碰撞点x坐标应该在中点附近";
EXPECT_NEAR(prediction.collisionPoint.y, 100.0, 1.0) << "碰撞点y坐标应该保持不变";
}
}
// 测试场景2平行路径不会碰撞
{
Vector2D pos1{100, 100};
double speed1 = 10;
double heading1 = 90; // 正东90度
Vector2D pos2{100, 120}; // 平行路径距20米
double speed2 = 10;
double heading2 = 90; // 正东90度
double size1 = 5;
double size2 = 5;
double timeWindow = 30;
auto prediction = detector_->predictTrajectoryCollision(
pos1, speed1, heading1,
pos2, speed2, heading2,
size1, size2, timeWindow
);
// 验证结果:不应该检测到碰撞
EXPECT_FALSE(prediction.willCollide) << "平行路径不应该碰撞";
// 验证最小距离允许1米的误差
EXPECT_NEAR(prediction.minDistance, 20.0, 1.0) << "平行路径应该保持20米的距离";
}
// 测试场景3垂直相交路径
{
Vector2D pos1{0, 100}; // 第一个物体从左开始
double speed1 = 10;
double heading1 = 90; // 正东90度
Vector2D pos2{200, 300}; // 第二个物体从上开始
double speed2 = 10;
double heading2 = 180; // 正南180度
double size1 = 5;
double size2 = 5;
double timeWindow = 30; // 30秒的预测窗口
Logger::info("垂直路径测试参数:");
Logger::info(" 物体1: 位置=(" + std::to_string(pos1.x) + ", " + std::to_string(pos1.y) +
"), 速度=" + std::to_string(speed1) + ", 航向=" + std::to_string(heading1));
Logger::info(" 物体2: 位置=(" + std::to_string(pos2.x) + ", " + std::to_string(pos2.y) +
"), 速度=" + std::to_string(speed2) + ", 航向=" + std::to_string(heading2));
// 计算速度分量用于调试
double heading1Rad = heading1 * M_PI / 180.0;
double heading2Rad = heading2 * M_PI / 180.0;
double v1x = speed1 * std::sin(heading1Rad); // 东向为x轴正方向
double v1y = speed1 * std::cos(heading1Rad); // 北向为y轴正方向
double v2x = speed2 * std::sin(heading2Rad);
double v2y = speed2 * std::cos(heading2Rad);
Logger::info("速度分量:");
Logger::info(" 物体1: vx=" + std::to_string(v1x) + ", vy=" + std::to_string(v1y));
Logger::info(" 物体2: vx=" + std::to_string(v2x) + ", vy=" + std::to_string(v2y));
auto prediction = detector_->predictTrajectoryCollision(
pos1, speed1, heading1,
pos2, speed2, heading2,
size1, size2, timeWindow
);
Logger::info("预测结果:");
Logger::info(" willCollide=" + std::to_string(prediction.willCollide));
Logger::info(" minDistance=" + std::to_string(prediction.minDistance));
if (prediction.willCollide) {
Logger::info(" 碰撞点=(" + std::to_string(prediction.collisionPoint.x) + ", " +
std::to_string(prediction.collisionPoint.y) + ")");
Logger::info(" 碰撞时间=" + std::to_string(prediction.timeToCollision));
// 计算理论碰撞点
// 物体1x = 0 + 10t, y = 100
// 物体2x = 200, y = 300 - 10t
// 碰撞时x1 = x2 = 200, y1 = y2
double collisionTime = 20.0; // t = 200/10 = 20秒
double expectedX = 200.0; // x = 0 + 10*20 = 200
double expectedY = 100.0; // y = 100 (物体1的y保持不变)
// 验证碰撞点位置允许5米的误差考虑到物体尺寸
EXPECT_NEAR(prediction.collisionPoint.x, expectedX, 5.0)
<< "碰撞点x坐标应该在交叉点附近";
EXPECT_NEAR(prediction.collisionPoint.y, expectedY, 5.0)
<< "碰撞点y坐标应该在交叉点附近";
// 验证碰撞时间允许1秒的误差
EXPECT_NEAR(prediction.timeToCollision, collisionTime, 1.0)
<< "碰撞时间应该接近20秒";
}
}
// 测试场景4静止物体
{
Vector2D pos1{0, 100}; // 第一个物体从远处开始
double speed1 = 10;
double heading1 = 90; // 正东90度
Vector2D pos2{200, 100}; // 静止物体在目标位置
double speed2 = 0; // 静止物体
double heading2 = 0; // 航向无关紧要,因为是静止的
double size1 = 5;
double size2 = 5;
double timeWindow = 30; // 30秒的预测窗口
Logger::info("静止物体测试参数:");
Logger::info(" 物体1: 位置=(" + std::to_string(pos1.x) + ", " + std::to_string(pos1.y) +
"), 速度=" + std::to_string(speed1) + ", 航向=" + std::to_string(heading1));
Logger::info(" 物体2: 位置=(" + std::to_string(pos2.x) + ", " + std::to_string(pos2.y) +
"), 速度=" + std::to_string(speed2) + ", 航向=" + std::to_string(heading2));
// 计算速度分量用于调试
double heading1Rad = heading1 * M_PI / 180.0;
double heading2Rad = heading2 * M_PI / 180.0;
double v1x = speed1 * std::sin(heading1Rad); // 东向为x轴正方向
double v1y = speed1 * std::cos(heading1Rad); // 北向为y轴正方向
double v2x = speed2 * std::sin(heading2Rad);
double v2y = speed2 * std::cos(heading2Rad);
Logger::info("速度分量:");
Logger::info(" 物体1: vx=" + std::to_string(v1x) + ", vy=" + std::to_string(v1y));
Logger::info(" 物体2: vx=" + std::to_string(v2x) + ", vy=" + std::to_string(v2y));
auto prediction = detector_->predictTrajectoryCollision(
pos1, speed1, heading1,
pos2, speed2, heading2,
size1, size2, timeWindow
);
Logger::info("预测结果:");
Logger::info(" willCollide=" + std::to_string(prediction.willCollide));
Logger::info(" minDistance=" + std::to_string(prediction.minDistance));
if (prediction.willCollide) {
Logger::info(" 碰撞点=(" + std::to_string(prediction.collisionPoint.x) + ", " +
std::to_string(prediction.collisionPoint.y) + ")");
Logger::info(" 碰撞时间=" + std::to_string(prediction.timeToCollision));
// 计算理论碰撞点
// 考虑物体尺寸:当两个物体中心点距离等于它们尺寸之和时就发生碰撞
double safeDistance = size1 + size2; // 10米
double expectedX = pos2.x - safeDistance; // 200 - 10 = 190米
double expectedY = pos2.y; // 100米
double collisionTime = expectedX / speed1; // 19秒
// 验证碰撞点位置允许5米的误差考虑到数值计算的精度
EXPECT_NEAR(prediction.collisionPoint.x, expectedX, 5.0)
<< "碰撞点应该在考虑物体尺寸后的位置";
EXPECT_NEAR(prediction.collisionPoint.y, expectedY, 5.0)
<< "碰撞点y坐标应该保持不变";
// 验证碰撞时间允许1秒的误差
EXPECT_NEAR(prediction.timeToCollision, collisionTime, 1.0)
<< "碰撞时间应该接近19秒";
}
}
// 测试场景5超出时间窗口的碰撞
{
Vector2D pos1{100, 100};
double speed1 = 10;
double heading1 = 90; // 向东
Vector2D pos2{400, 100};
double speed2 = 0;
double heading2 = 0; // 静止物体的航向可以是任意值
double size1 = 5;
double size2 = 5;
double timeWindow = 20; // 20秒的时间窗口不足以到达碰撞点
auto prediction = detector_->predictTrajectoryCollision(
pos1, speed1, heading1,
pos2, speed2, heading2,
size1, size2, timeWindow
);
// 验证结果:不应该检测到碰撞(因为超出时间窗口)
EXPECT_FALSE(prediction.willCollide) << "超出时间窗口应该报告碰撞";
EXPECT_GT(prediction.minDistance, 0) << "最小距离该大于0";
}
// 测试场景6飞机和车辆垂直相交
{
// 飞机尺寸波音737-800翼展35.8米长度39.5米
double aircraftSize = 40.0; // 使用较大的值以确保安全
// 车辆尺寸标准摆渡车长度12米宽度2.5米
double vehicleSize = 12.0;
// 飞机从西向东,车辆从南向北
Vector2D aircraftPos{0, 200}; // 飞机初始位置
double aircraftSpeed = 12; // 飞机速度
double aircraftHeading = 90; // 向东飞行
Vector2D vehiclePos{200, 100}; // 修改车辆初始位置,使其能与飞机相遇
double vehicleSpeed = 6; // 车辆速度
double vehicleHeading = 0; // 向北行驶
double timeWindow = 60; // 60秒的预测窗口考虑到较低的速度
Logger::info("飞机和车辆垂直相交测试参数:");
Logger::info(" 飞机: 位置=(" + std::to_string(aircraftPos.x) + ", " + std::to_string(aircraftPos.y) +
"), 速度=" + std::to_string(aircraftSpeed) + ", 航向=" + std::to_string(aircraftHeading));
Logger::info(" 车辆: 位置=(" + std::to_string(vehiclePos.x) + ", " + std::to_string(vehiclePos.y) +
"), 速度=" + std::to_string(vehicleSpeed) + ", 航向=" + std::to_string(vehicleHeading));
// 计算速度分量
double aircraftHeadingRad = aircraftHeading * M_PI / 180.0;
double vehicleHeadingRad = vehicleHeading * M_PI / 180.0;
double vax = aircraftSpeed * std::sin(aircraftHeadingRad); // 东向为x轴正方向
double vay = aircraftSpeed * std::cos(aircraftHeadingRad); // 北向为y轴正方向
double vvx = vehicleSpeed * std::sin(vehicleHeadingRad);
double vvy = vehicleSpeed * std::cos(vehicleHeadingRad);
Logger::info("速度分量:");
Logger::info(" 飞机: vx=" + std::to_string(vax) + ", vy=" + std::to_string(vay));
Logger::info(" 车辆: vx=" + std::to_string(vvx) + ", vy=" + std::to_string(vvy));
// 计算相对运动方程的系数
double dx = aircraftPos.x - vehiclePos.x;
double dy = aircraftPos.y - vehiclePos.y;
double dvx = vax - vvx;
double dvy = vay - vvy;
double safeDistance = aircraftSize + vehicleSize;
double a = dvx * dvx + dvy * dvy;
double b = 2.0 * (dx * dvx + dy * dvy);
double c = dx * dx + dy * dy - safeDistance * safeDistance;
Logger::info("二次方程系数:");
Logger::info(" 相对位置: dx=" + std::to_string(dx) + ", dy=" + std::to_string(dy));
Logger::info(" 相对速度: dvx=" + std::to_string(dvx) + ", dvy=" + std::to_string(dvy));
Logger::info(" 安全距离=" + std::to_string(safeDistance));
Logger::info(" a=" + std::to_string(a) + ", b=" + std::to_string(b) + ", c=" + std::to_string(c));
auto prediction = detector_->predictTrajectoryCollision(
aircraftPos, aircraftSpeed, aircraftHeading,
vehiclePos, vehicleSpeed, vehicleHeading,
aircraftSize, vehicleSize, timeWindow
);
Logger::info("预测结果:");
Logger::info(" willCollide=" + std::to_string(prediction.willCollide));
Logger::info(" minDistance=" + std::to_string(prediction.minDistance));
if (prediction.willCollide) {
Logger::info(" 碰撞点=(" + std::to_string(prediction.collisionPoint.x) + ", " +
std::to_string(prediction.collisionPoint.y) + ")");
Logger::info(" 碰撞时间=" + std::to_string(prediction.timeToCollision));
}
// 验证结果
EXPECT_TRUE(prediction.willCollide) << "应该检测到飞机和车的潜在碰撞";
if (prediction.willCollide) {
// 考虑安全距离的影响,碰撞点会在实际交叉点之前
// 飞机从(0,200)出发速度12m/s12.79秒到达x=164.22
// 车辆从(200,100)出发速度6m/s12.79秒到达y=194.63
EXPECT_NEAR(prediction.collisionPoint.x, 164.22, 5.0) << "碰撞点x坐标应该考虑安全距离的影响";
EXPECT_NEAR(prediction.collisionPoint.y, 194.63, 5.0) << "碰撞点y坐标应该考虑安全距离的影响";
// 碰撞时间应该是12.79秒左右
double expectedTime = 12.79; // 考虑安全距离后的预期碰撞时间
EXPECT_NEAR(prediction.timeToCollision, expectedTime, 2.0) << "碰撞时间应该接近预期值";
}
}
// 测试场景7斜向相交路径
{
// 第一个物体从西南向东北运动
Vector2D pos1{0, 0};
double speed1 = 10;
double heading1 = 45; // 东北方向45度
// 第二个物体从东南向西北运动
Vector2D pos2{200, 0};
double speed2 = 10;
double heading2 = 315; // 西北方向315度
double size1 = 5;
double size2 = 5;
double timeWindow = 30;
Logger::info("斜向相交路径测试参数:");
Logger::info(" 物体1: 位置=(" + std::to_string(pos1.x) + ", " + std::to_string(pos1.y) +
"), 速度=" + std::to_string(speed1) + ", 航向=" + std::to_string(heading1));
Logger::info(" 物体2: 位置=(" + std::to_string(pos2.x) + ", " + std::to_string(pos2.y) +
"), 速度=" + std::to_string(speed2) + ", 航向=" + std::to_string(heading2));
// 计算速度分量
double heading1Rad = heading1 * M_PI / 180.0;
double heading2Rad = heading2 * M_PI / 180.0;
double v1x = speed1 * std::sin(heading1Rad); // 东向为x轴正方向
double v1y = speed1 * std::cos(heading1Rad); // 北向为y轴正方向
double v2x = speed2 * std::sin(heading2Rad);
double v2y = speed2 * std::cos(heading2Rad);
Logger::info("速度分量:");
Logger::info(" 物体1: vx=" + std::to_string(v1x) + ", vy=" + std::to_string(v1y));
Logger::info(" 物体2: vx=" + std::to_string(v2x) + ", vy=" + std::to_string(v2y));
auto prediction = detector_->predictTrajectoryCollision(
pos1, speed1, heading1,
pos2, speed2, heading2,
size1, size2, timeWindow
);
// 验证结果
EXPECT_TRUE(prediction.willCollide) << "斜向相交路径应该检测到碰撞";
if (prediction.willCollide) {
// 考虑安全距离两个物体各5米碰撞检测会在实际交叉点之前触发
// 由于两个物体速度相同且对称,碰撞点应该在中点附近,但会略低于理想位置
EXPECT_NEAR(prediction.collisionPoint.x, 100.0, 5.0) << "碰撞点x坐标应该在预期位置";
EXPECT_NEAR(prediction.collisionPoint.y, 95.0, 5.0) << "碰撞点y坐标应该考虑安全距离的影响";
// 到达碰撞点的时间
// 物体1需要移动√((100-0)² + (95-0)²) ≈ 137.8米
// 速度为10m/s所以时间应该约为13.78秒
double expectedTime = 13.78;
EXPECT_NEAR(prediction.timeToCollision, expectedTime, 2.0) << "碰撞时间应该接近预期值";
}
}
}

View File

@ -207,8 +207,6 @@ TEST_F(DataCollectorTest, TrafficLightSignalsTest) {
EXPECT_EQ(signals[0].status, SignalStatus::RED); // RED = 0
EXPECT_EQ(signals[1].trafficLightId, "TL002");
EXPECT_EQ(signals[1].status, SignalStatus::GREEN); // GREEN = 1
EXPECT_EQ(signals[2].trafficLightId, "TL003");
EXPECT_EQ(signals[2].status, SignalStatus::YELLOW); // YELLOW = 2
}
}

396
tools/map_websocket.html Normal file
View File

@ -0,0 +1,396 @@
<!DOCTYPE html>
<html>
<head>
<title>机场车辆监控</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
}
.container {
display: flex;
gap: 20px;
}
#map {
height: 800px;
width: 60%;
border: 1px solid #ccc;
}
#messages {
width: 40%;
height: 800px;
overflow-y: auto;
border: 1px solid #ccc;
padding: 10px;
font-family: monospace;
}
.controls {
margin-top: 10px;
}
.error { color: red; }
.success { color: green; }
.info { color: blue; }
.position { color: #666; }
.warning { color: #f90; }
.command { color: #800080; }
.vehicle-icon {
width: 10px;
height: 10px;
background-color: black;
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
border: 2px solid white;
}
.aircraft-icon {
width: 50px;
height: 50px;
background-color: purple;
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
border: 2px solid white;
}
.special-vehicle-icon {
width: 10px;
height: 10px;
background-color: orange;
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
border: 2px solid white;
}
.intersection-icon {
width: 30px;
height: 30px;
background-color: #666;
clip-path: polygon(40% 0%, 60% 0%, 60% 40%, 100% 40%, 100% 60%, 60% 60%, 60% 100%, 40% 100%, 40% 60%, 0% 60%, 0% 40%, 40% 40%);
border: 2px solid white;
}
.traffic-light {
width: 10px;
height: 10px;
border-radius: 50%;
border: 1px solid white;
z-index: 1000;
}
.traffic-light-red {
background-color: red;
}
.traffic-light-green {
background-color: green;
}
.distance-label {
background: none;
border: none;
color: #666;
font-size: 12px;
text-align: center;
white-space: nowrap;
}
</style>
</head>
<body>
<h2>机场车辆监控系统</h2>
<div class="container">
<div id="map"></div>
<div id="messages"></div>
</div>
<div class="controls">
<button onclick="connect()">连接</button>
<button onclick="disconnect()">断开</button>
<button onclick="clearMessages()">清空日志</button>
</div>
<script>
let ws = null;
const messagesDiv = document.getElementById('messages');
// 初始化地图
const map = L.map('map').setView([36.361999, 120.088503], 17);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// 定义路口坐标
const WEST_INTERSECTION = {
latitude: 36.361999,
longitude: 120.086003
};
const EAST_INTERSECTION = {
latitude: 36.361999,
longitude: 120.089003
};
// 存储所有标记
const markers = new Map();
const trafficLights = new Map();
const intersections = new Map();
// 创建自定义图标
function createIcon(className) {
let size;
if (className.includes('aircraft')) {
size = [50, 50]; // 50米正方形
} else if (className.includes('vehicle')) {
size = [10, 10]; // 10米正方形
} else if (className.includes('traffic-light')) {
size = [10, 10]; // 10像素的红绿灯
} else {
size = [20, 20]; // 其他图标保持原样
}
return L.divIcon({
className: className,
iconSize: size,
iconAnchor: [size[0]/2, size[1]/2] // 设置图标锚点为中心
});
}
function log(message, type = 'info') {
const div = document.createElement('div');
div.className = type;
div.textContent = `${new Date().toLocaleTimeString()} - ${message}`;
messagesDiv.appendChild(div);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
function clearMessages() {
messagesDiv.innerHTML = '';
}
function updatePosition(data) {
const id = data.object_id;
const position = [data.position.latitude, data.position.longitude];
let iconClass;
// 根据ID前缀确定图标类型
if (data.object_type === 'aircraft') {
iconClass = 'aircraft-icon'; // 六形
} else if (id.startsWith('TQ')) {
iconClass = 'special-vehicle-icon'; // 正方形
} else {
iconClass = 'vehicle-icon'; // 三角形
}
let marker = markers.get(id);
if (!marker) {
// 创建新标记
marker = L.marker(position, {
icon: createIcon(iconClass)
}).addTo(map);
marker.bindTooltip(id); // 添加标签显示ID
markers.set(id, marker);
} else {
// 更新现有标记位置
marker.setLatLng(position);
}
// 更新标记旋转(根据航向)
if (data.heading !== undefined) {
marker.setRotationAngle(data.heading);
}
}
function updateTrafficLight(data) {
const id = data.id;
const position = [data.position.latitude, data.position.longitude];
const state = data.status === 0 ? 'red' : 'green';
let light = trafficLights.get(id);
if (!light) {
light = L.marker(position, {
icon: createIcon(`traffic-light traffic-light-${state}`)
}).addTo(map);
light.bindTooltip(id);
trafficLights.set(id, light);
} else {
light.setIcon(createIcon(`traffic-light traffic-light-${state}`));
}
}
function connect() {
if (ws) {
log('已经连接,请先断开', 'error');
return;
}
try {
ws = new WebSocket('ws://localhost:8010');
ws.onopen = () => {
log('连接成功', 'success');
};
ws.onclose = () => {
log('连接关闭', 'info');
ws = null;
};
ws.onerror = (error) => {
log('发生错误: ' + error, 'error');
};
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
const formattedData = JSON.stringify(data, null, 2);
// 根据消息类型使用不同的样式和处理方式
let type = 'info';
let message = '收到消息:\n' + formattedData;
switch (data.type) {
case 'position_update':
type = 'position';
updatePosition(data);
break;
case 'traffic_light_status':
updateTrafficLight(data);
break;
case 'collision_warning':
type = 'warning';
break;
case 'vehicle_command':
type = 'command';
// 为控制指令添加中文描述
const commandTypes = {
'SIGNAL': '信号灯指令',
'ALERT': '告警指令',
'WARNING': '预警指令',
'RESUME': '恢复指令'
};
const reasons = {
'TRAFFIC_LIGHT': '红绿灯控制',
'AIRCRAFT_CROSSING': '航空器交叉',
'SPECIAL_VEHICLE': '特勤车辆',
'AIRCRAFT_PUSH': '航空器推出',
'RESUME_TRAFFIC': '恢复通行'
};
message = `收到车辆控制指令:\n车辆: ${data.vehicleId}\n` +
`指令类型: ${commandTypes[data.commandType] || data.commandType}\n` +
`原因: ${reasons[data.reason] || data.reason}\n` +
(data.targetLatitude !== undefined ? `目标位置: (${data.targetLatitude}, ${data.targetLongitude})\n` : '') +
(data.signalState ? `信号灯状态: ${data.signalState}\n` : '') +
(data.intersectionId ? `路口ID: ${data.intersectionId}\n` : '') +
`时间戳: ${new Date(data.timestamp/1000000).toLocaleString()}`;
break;
}
log(message, type);
} catch (e) {
log('收到消息: ' + event.data, 'info');
}
};
} catch (error) {
log('连接失败: ' + error, 'error');
}
}
function disconnect() {
if (!ws) {
log('未连接', 'error');
return;
}
ws.close();
ws = null;
// 清除所有标记
markers.forEach(marker => map.removeLayer(marker));
markers.clear();
trafficLights.forEach(light => map.removeLayer(light));
trafficLights.clear();
}
// 添加道路刻度标记函数
function addRoadMarks(startPoint, endPoint, isLatitude = false) {
const start = isLatitude ? startPoint[0] : startPoint[1];
const end = isLatitude ? endPoint[0] : endPoint[1];
const fixed = isLatitude ? startPoint[1] : startPoint[0];
const step = 0.0005; // 约50米
const direction = start < end ? 1 : -1;
for (let i = 0; Math.abs(i) <= Math.abs(end - start); i += step * direction) {
const position = isLatitude ?
[start + i, fixed] :
[fixed, start + i];
// 添加刻度线
const markLine = isLatitude ?
[[position[0], position[1] - 0.0001], [position[0], position[1] + 0.0001]] :
[[position[0] - 0.0001, position[1]], [position[0] + 0.0001, position[1]]];
L.polyline(markLine, {
color: '#666',
weight: 2
}).addTo(map);
// 添加距离标签(以米为单位)
const distance = Math.abs(Math.round(i / step) * 50);
if (distance > 0) { // 只显示非零<E99D9E><E99BB6><EFBFBD>
const label = L.divIcon({
className: 'distance-label',
html: distance + 'm',
iconSize: [40, 20],
iconAnchor: [20, 10]
});
L.marker(position, {
icon: label,
interactive: false
}).addTo(map);
}
}
}
// 添加道路
// 东西向主路
const mainRoadEW = L.polyline([
[WEST_INTERSECTION.latitude, WEST_INTERSECTION.longitude - 0.002],
[EAST_INTERSECTION.latitude, EAST_INTERSECTION.longitude + 0.002]
], {
color: '#999',
weight: 8
}).addTo(map);
// 西路口南北向道路
const westRoadNS = L.polyline([
[WEST_INTERSECTION.latitude + 0.002, WEST_INTERSECTION.longitude],
[WEST_INTERSECTION.latitude - 0.002, WEST_INTERSECTION.longitude]
], {
color: '#999',
weight: 8
}).addTo(map);
// 东路口南北向道路
const eastRoadNS = L.polyline([
[EAST_INTERSECTION.latitude + 0.002, EAST_INTERSECTION.longitude],
[EAST_INTERSECTION.latitude - 0.002, EAST_INTERSECTION.longitude]
], {
color: '#999',
weight: 8
}).addTo(map);
// 添加刻度标记
// 西路口南北向刻度
addRoadMarks(
[WEST_INTERSECTION.latitude - 0.002, WEST_INTERSECTION.longitude],
[WEST_INTERSECTION.latitude + 0.002, WEST_INTERSECTION.longitude],
true
);
// 东路口南北向刻度
addRoadMarks(
[EAST_INTERSECTION.latitude - 0.002, EAST_INTERSECTION.longitude],
[EAST_INTERSECTION.latitude + 0.002, EAST_INTERSECTION.longitude],
true
);
// 东西向刻度
addRoadMarks(
[WEST_INTERSECTION.latitude, WEST_INTERSECTION.longitude - 0.002],
[EAST_INTERSECTION.latitude, EAST_INTERSECTION.longitude + 0.002],
false
);
</script>
</body>
</html>

View File

@ -1,11 +1,29 @@
from flask import Flask, jsonify
from flask import Flask, jsonify, request
import time
import math
import random
app = Flask(__name__)
# 坐标转换常数粗略计算1度约等于111km所以1米约等于0.000009度)
METERS_TO_DEG = 0.000009
# 地球半径(米)
EARTH_RADIUS = 6378137.0
COMMAND_PRIORITIES = {
"SIGNAL": 4,
"ALERT": 3,
"WARNING": 2,
"RESUME": 1
}
def meters_to_degrees(meters, latitude):
"""
将米转换为度考虑纬度的影响
"""
# 纬度方向1度 = 111,319.9米
meters_per_deg_lat = 111319.9
# 经度方向1度 = 111,319.9 * cos(latitude)米
meters_per_deg_lon = meters_per_deg_lat * math.cos(math.radians(latitude))
return meters / meters_per_deg_lat, meters / meters_per_deg_lon
# 距离配置(米)
DIST_150M = 150
@ -13,8 +31,8 @@ DIST_100M = 100
DIST_50M = 50
# 两个路口的位置
WEST_INTERSECTION = {"longitude": 120.088003, "latitude": 36.361999}
EAST_INTERSECTION = {"longitude": 120.088303, "latitude": 36.361999}
WEST_INTERSECTION = {"longitude": 120.086003, "latitude": 36.361999}
EAST_INTERSECTION = {"longitude": 120.089003, "latitude": 36.361999}
# 位置更新间隔(秒)
UPDATE_INTERVAL = 1.0
@ -23,7 +41,7 @@ UPDATE_INTERVAL = 1.0
aircraft_data = [
{
"flightNo": "AC001", # 航空器
"latitude": EAST_INTERSECTION["latitude"] - (DIST_150M * METERS_TO_DEG), # 东路口南150米
"latitude": EAST_INTERSECTION["latitude"] - (DIST_150M / 111319.9), # 东路口南150米
"longitude": EAST_INTERSECTION["longitude"],
"time": int(time.time() * 1000),
"direction": 1, # 1表示向北
@ -31,93 +49,425 @@ aircraft_data = [
}
]
# 添加默认速度常量
DEFAULT_VEHICLE_SPEED = 36.0 # km/h
EMERGENCY_BRAKE_DECELERATION = 0.8 # 紧急制动减速度 (每次更新减速 80%)
NORMAL_BRAKE_DECELERATION = 0.2 # 正常制动减速度 (每次更新减速 20%)
# 车辆数据
vehicle_data = [
{
"vehicleNo": "QN001", # 无人车1西路口
"latitude": WEST_INTERSECTION["latitude"] + (DIST_50M * METERS_TO_DEG), # 西路口北50米
"latitude": WEST_INTERSECTION["latitude"] + (DIST_50M / 111319.9), # 西路口北50米
"longitude": WEST_INTERSECTION["longitude"],
"time": int(time.time() * 1000),
"direction": 1, # 1表示向东
"speed": 36.0 # 36km/h
"direction": -1, # -1表示向南
"speed": DEFAULT_VEHICLE_SPEED, # 使用默认速度
"phase": 0 # 0: 南北移动, 1: 东西移动
},
{
"vehicleNo": "QN002", # 无人车2东路口
"latitude": EAST_INTERSECTION["latitude"],
"longitude": EAST_INTERSECTION["longitude"] - (DIST_150M * METERS_TO_DEG), # 东路口西150米
"longitude": EAST_INTERSECTION["longitude"] - (DIST_150M / (111319.9 * math.cos(math.radians(EAST_INTERSECTION["latitude"])))), # 东路口西150米
"time": int(time.time() * 1000),
"direction": 1, # 1表示向东
"speed": 36.0 # 36km/h
"speed": DEFAULT_VEHICLE_SPEED # 使用默认速度
},
{
"vehicleNo": "TQ001", # 特勤车(西路口)
"latitude": WEST_INTERSECTION["latitude"],
"longitude": WEST_INTERSECTION["longitude"] + (DIST_50M * METERS_TO_DEG), # 西路口东50米
"longitude": WEST_INTERSECTION["longitude"] + (DIST_50M / (111319.9 * math.cos(math.radians(WEST_INTERSECTION["latitude"])))), # 西路口东50米
"time": int(time.time() * 1000),
"direction": -1, # -1表示向西
"speed": 36.0 # 36km/h
"speed": DEFAULT_VEHICLE_SPEED # 使用默认速度
}
]
def update_vehicle_position(vehicle, elapsed_time):
"""更新车辆位置"""
# 计算一次更新的移动距离(度)
speed_mps = vehicle["speed"] * 1000 / 3600 # 速度转换为米/秒
distance = speed_mps * elapsed_time
distance_deg = distance * METERS_TO_DEG
# 添加车辆状态类
class VehicleState:
def __init__(self, vehicle_no):
self.vehicle_no = vehicle_no
self.is_running = True # 运行状态
self.current_command = None # 当前执行的指令
self.command_priority = 0 # 当前指令优先级
self.target_speed = DEFAULT_VEHICLE_SPEED # 目标速度
self.brake_mode = None # 制动模式:'emergency' 或 'normal'
self.command_reason = None # 指令原因
self.last_command_time = time.time() # 最后一次指令时间
def can_be_overridden_by(self, command_type):
# 指令优先级: ALERT(5) > SIGNAL(4) > WARNING(3) > GREEN(2) > RESUME(1)
priority_map = {
"ALERT": 5,
"SIGNAL": 4,
"WARNING": 3,
"GREEN": 2,
"RESUME": 1
}
new_priority = priority_map.get(command_type, 0)
# 如果当前没有指令,或者新指令优先级更高,或者是相同类型的指令,则允许覆盖
return (self.current_command is None or
new_priority >= self.command_priority or
command_type == self.current_command)
def update_command(self, command_type):
"""更新指令状态"""
priority_map = {
"ALERT": 5,
"SIGNAL": 4,
"WARNING": 3,
"GREEN": 2,
"RESUME": 1
}
self.command_priority = priority_map.get(command_type, 0)
self.current_command = command_type
print(f"更新车辆 {self.vehicle_no} 指令状态: command={command_type}, priority={self.command_priority}")
# 添加车辆状态管理
vehicle_states = {}
for vehicle in vehicle_data:
vehicle_states[vehicle["vehicleNo"]] = VehicleState(vehicle["vehicleNo"])
def calculate_distance_to_target(vehicle, target_lat, target_lon):
"""计算车辆到目标位置的距离(米)"""
dlat = target_lat - vehicle["latitude"]
dlon = target_lon - vehicle["longitude"]
# 使用 Haversine 公式计算距离
R = 6371000 # 地球半径(米)
a = math.sin(dlat/2) * math.sin(dlat/2) + \
math.cos(math.radians(vehicle["latitude"])) * math.cos(math.radians(target_lat)) * \
math.sin(dlon/2) * math.sin(dlon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return R * c
@app.route('/api/vehicle/command', methods=['POST'])
def handle_vehicle_command():
try:
data = request.json
vehicle_id = data.get("vehicleId")
command_type = data.get("type", "").upper()
reason = data.get("reason", "").upper()
print(f"收到车辆控制指令: vehicle_id={vehicle_id}, type={command_type}, reason={reason}")
# 检查车辆是否存在
vehicle_state = vehicle_states.get(vehicle_id)
if not vehicle_state:
return jsonify({
"status": "error",
"message": f"Vehicle {vehicle_id} not found"
}), 404
# 检查是否为特勤车辆
if vehicle_id.startswith("TQ"):
return jsonify({
"status": "ok",
"message": "Special vehicle ignores command"
})
# 检查指令优先级
if not vehicle_state.can_be_overridden_by(command_type):
return jsonify({
"status": "error",
"message": "Command priority too low"
}), 400
# 处理不同类型的指令
if command_type == "ALERT":
print(f"执行告警指令: vehicle_id={vehicle_id}")
vehicle_state.is_running = False
vehicle_state.target_speed = 0
vehicle_state.brake_mode = "emergency" # 告警紧急制动
# 立即更新车辆速度
for v in vehicle_data:
if v["vehicleNo"] == vehicle_id:
v["speed"] = 0
print(f"车辆 {vehicle_id} 速度已设置为0")
break
elif command_type == "WARNING":
vehicle_state.is_running = False
vehicle_state.target_speed = 0
vehicle_state.brake_mode = "normal" # 预警正常制动
elif command_type == "RESUME":
# 只有在没有更高优先级指令时才恢复
if vehicle_state.command_priority <= 1:
vehicle_state.is_running = True
vehicle_state.target_speed = DEFAULT_VEHICLE_SPEED
vehicle_state.brake_mode = None
# 更新车辆状态
vehicle_state.update_command(command_type)
vehicle_state.command_reason = reason
vehicle_state.last_command_time = time.time()
print(f"Vehicle {vehicle_id} state updated: running={vehicle_state.is_running}, "
f"command={command_type}, reason={reason}, priority={vehicle_state.command_priority}, "
f"target_speed={vehicle_state.target_speed}, brake_mode={vehicle_state.brake_mode}")
return jsonify({
"status": "ok",
"message": "Command executed successfully"
})
except Exception as e:
print(f"Error handling vehicle command: {str(e)}")
return jsonify({
"status": "error",
"message": str(e)
}), 500
def calculate_distance_to_intersection(vehicle, intersection):
"""计算车辆到路口的距离(米)"""
vehicle_lat = vehicle["latitude"]
vehicle_lon = vehicle["longitude"]
intersection_lat = intersection["latitude"]
intersection_lon = intersection["longitude"]
# 使用经纬度计算距离
lat_diff = (vehicle_lat - intersection_lat) * 111319.9
lon_diff = (vehicle_lon - intersection_lon) * (111319.9 * math.cos(math.radians(vehicle_lat)))
return math.sqrt(lat_diff * lat_diff + lon_diff * lon_diff)
def get_nearest_intersection(vehicle):
"""获取车辆最近的路口及其红绿灯状态"""
west_dist = calculate_distance_to_intersection(vehicle, WEST_INTERSECTION)
east_dist = calculate_distance_to_intersection(vehicle, EAST_INTERSECTION)
if west_dist <= east_dist:
return WEST_INTERSECTION, traffic_light_data[0], west_dist # TL001
else:
return EAST_INTERSECTION, traffic_light_data[1], east_dist # TL002
def get_front_traffic_light(vehicle, distance_to_west, distance_to_east):
"""获取车辆前方的红绿灯状态"""
# 根据车辆的位置和方向判断前方路口
if vehicle["vehicleNo"] == "QN001":
# 无人车1东西方向往返西路口
new_lon = vehicle["longitude"] + (distance_deg * vehicle["direction"])
if new_lon >= WEST_INTERSECTION["longitude"] + (DIST_50M * METERS_TO_DEG):
vehicle["direction"] = -1 # 向西
elif new_lon <= WEST_INTERSECTION["longitude"]:
vehicle["direction"] = 1 # 向东
vehicle["longitude"] = new_lon
elif vehicle["vehicleNo"] == "QN002":
# 无人车2东西方向往返东路口
new_lon = vehicle["longitude"] + (distance_deg * vehicle["direction"])
if new_lon >= EAST_INTERSECTION["longitude"] + (DIST_100M * METERS_TO_DEG):
vehicle["direction"] = -1 # 向西
elif new_lon <= EAST_INTERSECTION["longitude"] - (DIST_150M * METERS_TO_DEG):
vehicle["direction"] = 1 # 向东
vehicle["longitude"] = new_lon
elif vehicle["vehicleNo"] == "TQ001":
# 特勤车:先东西后南北,然后返回(西路口)
# 确保 phase 属性存在
if "phase" not in vehicle:
vehicle["phase"] = 0
# QN001 的路线:西路口北侧 -> 南 -> 东 -> 北
if vehicle["phase"] == 0: # 南北移动
if vehicle["direction"] == -1: # 向南
return traffic_light_data[0], distance_to_west # 西路口红绿灯
else: # 向北
return traffic_light_data[0], distance_to_west # 西路口红绿灯
else: # 东西移动
if vehicle["direction"] == 1: # 向东
return None, float('inf') # 已过西路口,无红绿灯
else: # 向西
return traffic_light_data[0], distance_to_west # 西路口红绿灯
elif vehicle["vehicleNo"] == "QN002":
if vehicle["direction"] == 1: # 向东
return traffic_light_data[1], distance_to_east # 东路口红绿灯
else: # 向西
return traffic_light_data[1], distance_to_east # 东路口红绿灯
elif vehicle["vehicleNo"] == "TQ001":
# 特勤车:先东西后南北
if "phase" not in vehicle:
vehicle["phase"] = 0
if vehicle["phase"] == 0: # 东西移动
new_lon = vehicle["longitude"] + (distance_deg * vehicle["direction"])
if vehicle["direction"] == 1: # 向东
return None, float('inf') # 已过西路口,无红绿灯
else: # 向西
return traffic_light_data[0], distance_to_west # 西路口红绿灯
else: # 南北移动
if vehicle["direction"] == 1: # 向北
return traffic_light_data[0], distance_to_west # 西路口红绿灯
else: # 向南
return None, float('inf') # 已过西路口,无红绿灯
return None, float('inf') # 默认返回无红绿灯
def update_vehicle_position(vehicle, elapsed_time):
"""更新车辆位置"""
# 获取车辆状态
vehicle_state = vehicle_states.get(vehicle["vehicleNo"])
if not vehicle_state:
return
# 如果车辆处于停止状态(由告警或其他指令触发),直接返回
if not vehicle_state.is_running or vehicle_state.target_speed == 0:
vehicle["speed"] = 0
print(f"车辆 {vehicle['vehicleNo']} 处于停止状态: command={vehicle_state.current_command}, "
f"brake_mode={vehicle_state.brake_mode}")
return
# 计算到两个路口的距离
distance_to_west = calculate_distance_to_intersection(vehicle, WEST_INTERSECTION)
distance_to_east = calculate_distance_to_intersection(vehicle, EAST_INTERSECTION)
# 获取前方红绿灯状态
traffic_light, distance = get_front_traffic_light(vehicle, distance_to_west, distance_to_east)
# 确保所有车辆都有 phase 属性
if "phase" not in vehicle:
vehicle["phase"] = 0
# 计算基础速度(米/秒)
if vehicle["vehicleNo"].startswith("TQ"): # 特勤车
base_speed_mps = DEFAULT_VEHICLE_SPEED * 1000 / 3600
if traffic_light:
if traffic_light["state"] == 0: # 红灯
if distance <= 5: # 在路口5米处停车
base_speed_mps = 0
vehicle["speed"] = 0
print(f"特勤车 {vehicle['vehicleNo']} 在路口5米处停车等待红灯")
return
elif distance <= 50: # 50米内减速
deceleration = (base_speed_mps * base_speed_mps) / (2 * (distance - 5))
base_speed_mps = max(0, base_speed_mps - deceleration * elapsed_time)
print(f"特勤车 {vehicle['vehicleNo']} 距路口 {distance:.1f}米,减速至 {base_speed_mps * 3.6:.1f}km/h")
else: # 绿灯
base_speed_mps = DEFAULT_VEHICLE_SPEED * 1000 / 3600
else: # 无人车
base_speed_mps = vehicle["speed"] * 1000 / 3600
if traffic_light:
if traffic_light["state"] == 0: # 红灯
if distance <= 50: # 在50米处或50米内紧急停车
base_speed_mps = 0
vehicle_state.is_running = False
print(f"无人车 {vehicle['vehicleNo']} 在50米处停车等待红灯")
elif distance <= 100: # 50-100米减速
deceleration = (base_speed_mps * base_speed_mps) / (2 * (distance - 50))
base_speed_mps = max(0, base_speed_mps - deceleration * elapsed_time)
print(f"无人车 {vehicle['vehicleNo']} 距路口 {distance:.1f}米,减速至 {base_speed_mps * 3.6:.1f}km/h")
else: # 绿灯
# 更新绿灯状态
if vehicle_state.current_command != "ALERT" and vehicle_state.current_command != "SIGNAL":
vehicle_state.update_command("GREEN")
vehicle_state.is_running = True
base_speed_mps = DEFAULT_VEHICLE_SPEED * 1000 / 3600
vehicle["speed"] = DEFAULT_VEHICLE_SPEED
print(f"无人车 {vehicle['vehicleNo']} 遇绿灯且无高优先级指令,恢复行驶")
else:
print(f"无人车 {vehicle['vehicleNo']} 遇绿灯但有高优先级指令({vehicle_state.current_command}),保持停止状态")
base_speed_mps = 0
vehicle["speed"] = 0
return
# 更新车辆速度(米/秒)
speed_mps = base_speed_mps
# 更新车辆速度km/h
vehicle["speed"] = speed_mps * 3600 / 1000
# 如果速度为0不更新位置
if speed_mps == 0:
return
# 计算移动距离
distance = speed_mps * elapsed_time
# 计算经纬度变化
dlat, dlon = meters_to_degrees(distance, vehicle["latitude"])
if vehicle["vehicleNo"].startswith("QN"):
# 无人车的路径更新逻辑
if vehicle["vehicleNo"] == "QN001":
# 无人车1先南北后东西往返
if vehicle["phase"] == 0: # 南北移动
new_lat = vehicle["latitude"] + (dlat * vehicle["direction"])
if vehicle["direction"] == -1 and new_lat <= WEST_INTERSECTION["latitude"]:
# 到达路口,检查红绿灯
if traffic_light and traffic_light["state"] == 0: # 红灯
# 停在路口等待
new_lat = WEST_INTERSECTION["latitude"]
else: # 绿灯
# 切换到东西移动
vehicle["phase"] = 1
vehicle["direction"] = 1 # 向东
elif vehicle["direction"] == 1 and new_lat >= WEST_INTERSECTION["latitude"] + (DIST_50M / 111319.9):
# 返回起点
vehicle["phase"] = 0
vehicle["direction"] = -1 # 向南
# 重置车辆状态,确保可以继续行驶
vehicle_state = vehicle_states.get(vehicle["vehicleNo"])
if vehicle_state:
vehicle_state.is_running = True
vehicle_state.target_speed = DEFAULT_VEHICLE_SPEED
vehicle_state.brake_mode = None
vehicle["latitude"] = new_lat
else: # 东西移动
new_lon = vehicle["longitude"] + (dlon * vehicle["direction"])
if vehicle["direction"] == 1 and new_lon >= WEST_INTERSECTION["longitude"] + (DIST_100M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
# 到达东端,开始返回
vehicle["direction"] = -1 # 向西
# 重置车辆状态,确保可以继续行驶
vehicle_state = vehicle_states.get(vehicle["vehicleNo"])
if vehicle_state:
vehicle_state.is_running = True
vehicle_state.target_speed = DEFAULT_VEHICLE_SPEED
vehicle_state.brake_mode = None
elif vehicle["direction"] == -1 and new_lon <= WEST_INTERSECTION["longitude"]:
# 返回路口,检查红绿灯
if traffic_light and traffic_light["state"] == 0: # 红灯
# 停在路口等待
new_lon = WEST_INTERSECTION["longitude"]
else: # 绿灯
# 切换到南北移动
vehicle["phase"] = 0
vehicle["direction"] = 1 # 向北
# 重置车辆状态,确保可以继续行驶
vehicle_state = vehicle_states.get(vehicle["vehicleNo"])
if vehicle_state:
vehicle_state.is_running = True
vehicle_state.target_speed = DEFAULT_VEHICLE_SPEED
vehicle_state.brake_mode = None
vehicle["longitude"] = new_lon
else: # QN002
# 无人车2西向往返东路口
new_lon = vehicle["longitude"] + (dlon * vehicle["direction"])
if new_lon >= EAST_INTERSECTION["longitude"] + (DIST_100M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
vehicle["direction"] = -1 # 向西
elif new_lon <= EAST_INTERSECTION["longitude"] - (DIST_150M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
vehicle["direction"] = 1 # 向东
vehicle["longitude"] = new_lon
elif vehicle["vehicleNo"].startswith("TQ"):
# 特勤车的路径更新逻辑
if vehicle["phase"] == 0: # 东西移动
new_lon = vehicle["longitude"] + (dlon * vehicle["direction"])
if vehicle["direction"] == -1 and new_lon <= WEST_INTERSECTION["longitude"]:
vehicle["phase"] = 1 # 切换到南北移动
vehicle["direction"] = -1 # 向南
elif vehicle["direction"] == 1 and new_lon >= WEST_INTERSECTION["longitude"] + (DIST_50M * METERS_TO_DEG):
elif vehicle["direction"] == 1 and new_lon >= WEST_INTERSECTION["longitude"] + (DIST_50M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
vehicle["direction"] = -1 # 向西
vehicle["longitude"] = new_lon
else: # 南北移动
new_lat = vehicle["latitude"] + (distance_deg * vehicle["direction"])
if new_lat <= WEST_INTERSECTION["latitude"] - (DIST_100M * METERS_TO_DEG): # 到达南端
new_lat = vehicle["latitude"] + (dlat * vehicle["direction"])
if new_lat <= WEST_INTERSECTION["latitude"] - (DIST_100M / 111319.9): # 到达南端
vehicle["direction"] = 1 # 向北
elif new_lat >= WEST_INTERSECTION["latitude"]: # 返回到路口
elif new_lat >= WEST_INTERSECTION["latitude"]: # 返回路口
vehicle["phase"] = 0 # 切换回东西移动
vehicle["direction"] = 1 # 向东
vehicle["direction"] = 1 # 向
vehicle["longitude"] = WEST_INTERSECTION["longitude"] # 重置到起始位置
vehicle["latitude"] = new_lat
# 更新时间戳
vehicle["time"] = int(time.time() * 1000)
def update_aircraft_position(aircraft, elapsed_time):
"""更新航空器位置"""
# 计算一次更新的移动距离(度)
# 计算一次更新的移动距离(
speed_mps = aircraft["speed"] * 1000 / 3600 # 速度转换为米/秒
distance = speed_mps * elapsed_time
distance_deg = distance * METERS_TO_DEG
new_lat = aircraft["latitude"] + (distance_deg * aircraft["direction"])
if new_lat >= EAST_INTERSECTION["latitude"] + (DIST_150M * METERS_TO_DEG):
# 计算经纬度变化
dlat, dlon = meters_to_degrees(distance, aircraft["latitude"])
new_lat = aircraft["latitude"] + (dlat * aircraft["direction"])
if new_lat >= EAST_INTERSECTION["latitude"] + (DIST_150M / 111319.9):
aircraft["direction"] = -1 # 向南
elif new_lat <= EAST_INTERSECTION["latitude"] - (DIST_150M * METERS_TO_DEG):
elif new_lat <= EAST_INTERSECTION["latitude"] - (DIST_150M / 111319.9):
aircraft["direction"] = 1 # 向北
aircraft["latitude"] = new_lat
@ -128,63 +478,105 @@ def update_traffic_light_for_aircraft():
aircraft = aircraft_data[0]
# 计算到东路口的距离(米)
lat_diff = abs(aircraft["latitude"] - EAST_INTERSECTION["latitude"]) / METERS_TO_DEG
lat_diff = abs(aircraft["latitude"] - EAST_INTERSECTION["latitude"]) * 111319.9
# 更新TL002东路口的状态
for light in traffic_light_data:
if light["id"] == "TL002":
if lat_diff <= 50.0: # 距离小于50米时为红灯
light["state"] = 0 # 红灯
light["state"] = 1 # 红灯
else:
light["state"] = 1 # 绿灯
break
# 红绿灯数据
traffic_light_data = [
{
"id": "TL001", # 西侧路口
"state": 1, # 0: 红灯, 1: 绿灯
"timestamp": int(time.time() * 1000)
# 定义路口信息
INTERSECTIONS = {
"TL001": {
"id": "INT001",
"name": "西路口",
"latitude": WEST_INTERSECTION["latitude"],
"longitude": WEST_INTERSECTION["longitude"]
},
{
"id": "TL002", # 东侧路口
"state": 1, # 初始为绿灯
"timestamp": int(time.time() * 1000)
"TL002": {
"id": "INT002",
"name": "东路口",
"latitude": EAST_INTERSECTION["latitude"],
"longitude": EAST_INTERSECTION["longitude"]
}
]
}
last_update_time = time.time()
def generate_traffic_light_data():
"""生成红绿灯数据"""
traffic_light_data = []
# 生成两个固定路口的红绿灯数据
for tl_id, intersection in INTERSECTIONS.items():
signal = {
"id": tl_id,
"state": 1, # 0: RED, 1: GREEN测试时保持绿灯
"timestamp": int(time.time() * 1000),
"intersection": intersection["id"],
"position": {
"latitude": intersection["latitude"],
"longitude": intersection["longitude"]
}
}
traffic_light_data.append(signal)
return traffic_light_data
# 红绿灯数据
traffic_light_data = generate_traffic_light_data()
# 分别记录航空器和车辆的上次更新时间
last_aircraft_update_time = time.time()
last_vehicle_update_time = time.time()
last_light_switch_time = time.time()
@app.route('/api/getCurrentFlightPositions')
def get_flight_positions():
global last_update_time
global last_aircraft_update_time
current_time = time.time()
elapsed_time = current_time - last_update_time
elapsed_time = current_time - last_aircraft_update_time
# 只在达到更新间隔时更新位置
if elapsed_time >= UPDATE_INTERVAL:
for aircraft in aircraft_data:
update_aircraft_position(aircraft, UPDATE_INTERVAL)
aircraft["time"] = int(current_time * 1000)
last_update_time = current_time
last_aircraft_update_time = current_time
return jsonify(aircraft_data)
@app.route('/api/getCurrentVehiclePositions')
def get_vehicle_positions():
global last_update_time
global last_vehicle_update_time, last_light_switch_time
current_time = time.time()
elapsed_time = current_time - last_update_time
elapsed_time = current_time - last_vehicle_update_time
# 只在达到更新间隔时更新位置
if elapsed_time >= UPDATE_INTERVAL:
for vehicle in vehicle_data:
update_vehicle_position(vehicle, UPDATE_INTERVAL)
vehicle["time"] = int(current_time * 1000)
last_update_time = current_time
return jsonify(vehicle_data)
try:
# 更新红绿灯状态
elapsed_since_switch = current_time - last_light_switch_time
if elapsed_since_switch >= 1500: # 每15秒切换一次
traffic_light_data[0]["state"] = 1 if traffic_light_data[0]["state"] == 0 else 1
last_light_switch_time = current_time
print(f"西路口红绿灯状态切换为: {'绿灯' if traffic_light_data[0]['state'] == 1 else '红灯'}")
# 根据航空器位置更新东路口红绿灯
update_traffic_light_for_aircraft()
# 只在达到更新间隔时更新位置
if elapsed_time >= UPDATE_INTERVAL:
for vehicle in vehicle_data:
update_vehicle_position(vehicle, UPDATE_INTERVAL)
vehicle["time"] = int(current_time * 1000)
last_vehicle_update_time = current_time
return jsonify(vehicle_data)
except Exception as e:
print(f"Error in get_vehicle_positions: {str(e)}")
return jsonify({"error": str(e)}), 500
@app.route('/api/getTrafficLightSignals')
def get_traffic_light_signals():
@ -195,14 +587,28 @@ def get_traffic_light_signals():
for light in traffic_light_data:
light["timestamp"] = int(current_time * 1000)
# TL001西路口状态每15秒切换一次
# TL001西路口状态每15秒切换一次
elapsed_since_switch = current_time - last_light_switch_time
if elapsed_since_switch >= 15: # 每15秒切换一次
traffic_light_data[0]["state"] = 2 if traffic_light_data[0]["state"] == 0 else 0
if elapsed_since_switch >= 1500: # 每15秒切换一次
traffic_light_data[0]["state"] = 1 if traffic_light_data[0]["state"] == 0 else 1
last_light_switch_time = current_time
print(f"西路口红绿灯状态切换为: {'绿灯' if traffic_light_data[0]['state'] == 1 else '红灯'}")
# 根据航空器位置更新TL002东路口
update_traffic_light_for_aircraft()
if aircraft_data:
aircraft = aircraft_data[0]
# 计算到东路口的距离(米)
lat_diff = abs(aircraft["latitude"] - EAST_INTERSECTION["latitude"]) * 111319.9
# 更新TL002东路口的状态
old_state = traffic_light_data[1]["state"]
if lat_diff <= 50.0: # 距离小于50米时为红灯
traffic_light_data[1]["state"] = 1 # 红灯
else:
traffic_light_data[1]["state"] = 1 # 绿灯
if old_state != traffic_light_data[1]["state"]:
print(f"东路口红绿灯状态切换为: {'绿灯' if traffic_light_data[1]['state'] == 1 else '红灯'}")
return jsonify(traffic_light_data)

538
tools/mock_server.py.bak Normal file
View File

@ -0,0 +1,538 @@
from flask import Flask, jsonify, request
import time
import math
import random
app = Flask(__name__)
# 地球半径(米)
EARTH_RADIUS = 6378137.0
def meters_to_degrees(meters, latitude):
"""
将米转换为度考虑纬度的影响
"""
# 纬度方向1度 = 111,319.9米
meters_per_deg_lat = 111319.9
# 经度方向1度 = 111,319.9 * cos(latitude)米
meters_per_deg_lon = meters_per_deg_lat * math.cos(math.radians(latitude))
return meters / meters_per_deg_lat, meters / meters_per_deg_lon
# 距离配置(米)
DIST_150M = 150
DIST_100M = 100
DIST_50M = 50
# 两个路口的位置
WEST_INTERSECTION = {"longitude": 120.088003, "latitude": 36.361999}
EAST_INTERSECTION = {"longitude": 120.089003, "latitude": 36.361999}
# 位置更新间隔(秒)
UPDATE_INTERVAL = 1.0
# 航空器数据
aircraft_data = [
{
"flightNo": "AC001", # 航空器
"latitude": EAST_INTERSECTION["latitude"] - (DIST_150M / 111319.9), # 东路口南150米
"longitude": EAST_INTERSECTION["longitude"],
"time": int(time.time() * 1000),
"direction": 1, # 1表示向北
"speed": 50.0 # 滑行速度 50km/h
}
]
# 添加默认速度常量
DEFAULT_VEHICLE_SPEED = 36.0 # km/h
EMERGENCY_BRAKE_DECELERATION = 0.8 # 紧急制动减速度 (每次更新减速 80%)
NORMAL_BRAKE_DECELERATION = 0.2 # 正常制动减速度 (每次更新减速 20%)
# 车辆数据
vehicle_data = [
{
"vehicleNo": "QN001", # 无人车1西路口
"latitude": WEST_INTERSECTION["latitude"] + (DIST_50M / 111319.9), # 西路口北50米
"longitude": WEST_INTERSECTION["longitude"],
"time": int(time.time() * 1000),
"direction": -1, # -1表示向南
"speed": DEFAULT_VEHICLE_SPEED, # 使用默认速度
"phase": 0 # 0: 南北移动, 1: 东西移动
},
{
"vehicleNo": "QN002", # 无人车2东路口
"latitude": EAST_INTERSECTION["latitude"],
"longitude": EAST_INTERSECTION["longitude"] - (DIST_150M / (111319.9 * math.cos(math.radians(EAST_INTERSECTION["latitude"])))), # 东路口西150米
"time": int(time.time() * 1000),
"direction": 1, # 1表示向东
"speed": DEFAULT_VEHICLE_SPEED # 使用默认速度
},
{
"vehicleNo": "TQ001", # 特勤车(西路口)
"latitude": WEST_INTERSECTION["latitude"],
"longitude": WEST_INTERSECTION["longitude"] + (DIST_50M / (111319.9 * math.cos(math.radians(WEST_INTERSECTION["latitude"])))), # 西路口东50米
"time": int(time.time() * 1000),
"direction": -1, # -1表示向西
"speed": DEFAULT_VEHICLE_SPEED # 使用默认速度
}
]
# 添加车辆状态类
class VehicleState:
def __init__(self, vehicle_no):
self.vehicle_no = vehicle_no
self.is_running = True # 运行状态
self.current_command = None # 当前执行的指令
self.command_priority = 0 # 当前指令优先级
self.target_speed = DEFAULT_VEHICLE_SPEED # 目标速度
self.brake_mode = None # 制动模式:'emergency' 或 'normal'
def can_be_overridden_by(self, command_type):
# 指令优先级: SIGNAL(4) > ALERT(3) > WARNING(2) > RESUME(1)
priority_map = {
"SIGNAL": 4,
"ALERT": 3,
"WARNING": 2,
"RESUME": 1
}
new_priority = priority_map.get(command_type, 0)
# 如果当前没有指令,或者新指令优先级更高,或者是相同类型的指令,则允许覆盖
return (self.current_command is None or
new_priority >= self.command_priority or
command_type == self.current_command)
def update_command(self, command_type):
priority_map = {
"SIGNAL": 4,
"ALERT": 3,
"WARNING": 2,
"RESUME": 1
}
self.command_priority = priority_map.get(command_type, 0)
self.current_command = command_type
# 添加车辆状态管理
vehicle_states = {
"QN001": VehicleState("QN001"),
"QN002": VehicleState("QN002"),
"TQ001": VehicleState("TQ001")
}
def calculate_distance_to_target(vehicle, target_lat, target_lon):
"""计算车辆到目标位置的距离(米)"""
dlat = target_lat - vehicle["latitude"]
dlon = target_lon - vehicle["longitude"]
# 使用 Haversine 公式计算距离
R = 6371000 # 地球半径(米)
a = math.sin(dlat/2) * math.sin(dlat/2) + \
math.cos(math.radians(vehicle["latitude"])) * math.cos(math.radians(target_lat)) * \
math.sin(dlon/2) * math.sin(dlon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return R * c
@app.route('/vehicle/command', methods=['POST'])
def handle_vehicle_command():
try:
data = request.json
vehicle_id = data.get("vehicleId")
command_type = data.get("type", "").upper()
reason = data.get("reason", "").upper()
# 检查车辆是否存在
vehicle_state = vehicle_states.get(vehicle_id)
if not vehicle_state:
return jsonify({
"status": "error",
"message": f"Vehicle {vehicle_id} not found"
}), 404
# 检查是否为特勤车辆
if vehicle_id.startswith("TQ"):
return jsonify({
"status": "ok",
"message": "Special vehicle ignores command"
})
# 检查指令优先级
if not vehicle_state.can_be_overridden_by(command_type):
return jsonify({
"status": "error",
"message": "Command priority too low"
}), 400
# 获取目标位置
target_lat = data.get("latitude", 0.0)
target_lon = data.get("longitude", 0.0)
# 处理不同类型的指令
if command_type == "SIGNAL":
signal_state = data.get("signalState", "").upper()
if signal_state == "RED":
# 计算到路口的距离
distance = calculate_distance_to_target(
next(v for v in vehicles if v["vehicleNo"] == vehicle_id),
target_lat, target_lon
)
# 根据距离决定制动方式
if distance <= 50: # 已经在停止线内
vehicle_state.is_running = False
vehicle_state.target_speed = 0
vehicle_state.brake_mode = "emergency" # 紧急停车
elif distance <= 100: # 距离停止线100米内
vehicle_state.is_running = False
vehicle_state.target_speed = 0
vehicle_state.brake_mode = "normal" # 正常制动
elif signal_state == "GREEN":
vehicle_state.is_running = True
vehicle_state.target_speed = DEFAULT_VEHICLE_SPEED
vehicle_state.brake_mode = None
elif command_type == "ALERT":
vehicle_state.is_running = False
vehicle_state.target_speed = 0
vehicle_state.brake_mode = "emergency" # 告警紧急制动
elif command_type == "WARNING":
vehicle_state.is_running = False
vehicle_state.target_speed = 0
vehicle_state.brake_mode = "normal" # 预警正常制动
elif command_type == "RESUME":
vehicle_state.is_running = True
vehicle_state.target_speed = DEFAULT_VEHICLE_SPEED
vehicle_state.brake_mode = None
# 更新车辆状态
vehicle_state.command_type = command_type
vehicle_state.command_reason = reason
vehicle_state.command_priority = COMMAND_PRIORITIES.get(command_type, 0)
vehicle_state.last_command_time = time.time()
print(f"Vehicle {vehicle_id} state updated: running={vehicle_state.is_running}, "
f"command={command_type}, reason={reason}, priority={vehicle_state.command_priority}, "
f"target_lat={target_lat}, target_lon={target_lon}")
return jsonify({
"status": "ok",
"message": "Command executed successfully"
})
except Exception as e:
print(f"Error handling vehicle command: {str(e)}")
return jsonify({
"status": "error",
"message": str(e)
}), 500
def calculate_distance_to_intersection(vehicle, intersection):
"""计算车辆到路口的距离(米)"""
vehicle_lat = vehicle["latitude"]
vehicle_lon = vehicle["longitude"]
intersection_lat = intersection["latitude"]
intersection_lon = intersection["longitude"]
# 使用经纬度计算距离
lat_diff = (vehicle_lat - intersection_lat) * 111319.9
lon_diff = (vehicle_lon - intersection_lon) * (111319.9 * math.cos(math.radians(vehicle_lat)))
return math.sqrt(lat_diff * lat_diff + lon_diff * lon_diff)
def get_nearest_intersection(vehicle):
"""获取车辆最近的路口及其红绿灯状态"""
west_dist = calculate_distance_to_intersection(vehicle, WEST_INTERSECTION)
east_dist = calculate_distance_to_intersection(vehicle, EAST_INTERSECTION)
if west_dist <= east_dist:
return WEST_INTERSECTION, traffic_light_data[0], west_dist # TL001
else:
return EAST_INTERSECTION, traffic_light_data[1], east_dist # TL002
def get_front_traffic_light(vehicle, distance_to_west, distance_to_east):
"""获取车辆前方的红绿灯状态"""
# 根据车辆的位置和方向判断前方路口
if vehicle["vehicleNo"].startswith("QN"):
if vehicle["vehicleNo"] == "QN001":
# QN001 的路线:西路口北侧 -> 南 -> 东 -> 北
if vehicle["phase"] == 0: # 南北移动
if vehicle["direction"] == -1: # 向南
return traffic_light_data[0], distance_to_west # 西路口红绿灯
else: # 向北
return None, float('inf') # 没有红绿灯
else: # 东西移动
if vehicle["direction"] == 1: # 向东
return None, float('inf') # 没有红绿灯
else: # 向西
return traffic_light_data[0], distance_to_west # 西路口红绿灯
else: # QN002
# QN002 的路线:东西方向往返
if vehicle["direction"] == 1: # 向东
return traffic_light_data[1], distance_to_east # 东路口红绿灯
else: # 向西
return traffic_light_data[0], distance_to_west # 西路口红绿灯
elif vehicle["vehicleNo"].startswith("TQ"):
# 特勤车:先东西后南北
if vehicle["phase"] == 0: # 东西移动
if vehicle["direction"] == 1: # 向东
return None, float('inf') # 没有<E6B2A1><E69C89><EFBFBD>绿灯
else: # 向西
return traffic_light_data[0], distance_to_west # 西路口红绿灯
else: # 南北移动
return None, float('inf') # 南北方向没有红绿灯
return None, float('inf') # 默认返回无红绿灯
def update_vehicle_position(vehicle, elapsed_time):
"""更新车辆位置"""
# 计算到两个路口的距离
distance_to_west = calculate_distance_to_intersection(vehicle, WEST_INTERSECTION)
distance_to_east = calculate_distance_to_intersection(vehicle, EAST_INTERSECTION)
# 获取前方红绿灯状态
traffic_light, distance = get_front_traffic_light(vehicle, distance_to_west, distance_to_east)
# 计算基础速度(米/秒)
if vehicle["vehicleNo"].startswith("TQ"):
base_speed_mps = DEFAULT_VEHICLE_SPEED * 1000 / 3600
else:
vehicle_state = vehicle_states.get(vehicle["vehicleNo"])
if not vehicle_state or not vehicle_state.is_running:
return
base_speed_mps = vehicle["speed"] * 1000 / 3600
# 如果是无人车,还需要考虑制动模式
if vehicle_state.brake_mode:
current_speed_mps = base_speed_mps
target_speed_mps = vehicle_state.target_speed * 1000 / 3600
if vehicle_state.brake_mode == "emergency":
base_speed_mps = current_speed_mps * (1 - EMERGENCY_BRAKE_DECELERATION)
else: # normal
base_speed_mps = current_speed_mps * (1 - NORMAL_BRAKE_DECELERATION)
base_speed_mps = max(base_speed_mps, target_speed_mps)
# 根据红绿灯状态调整速度
if traffic_light and traffic_light["state"] == 0: # 红灯
if distance <= 50: # 已经在停止线内
speed_mps = 0 # 紧急停车
print(f"车辆 {vehicle['vehicleNo']} 在停止线内遇红灯,紧急停车")
elif distance <= 100: # 距离停止线100米内
# 计算减速度,使车辆在停止线前停下
deceleration = (base_speed_mps * base_speed_mps) / (2 * (distance - 50))
speed_mps = max(0, base_speed_mps - deceleration * elapsed_time)
print(f"车辆 {vehicle['vehicleNo']} 距红灯 {distance:.1f}米,减速至 {speed_mps * 3.6:.1f}km/h")
else:
speed_mps = base_speed_mps
else: # 绿灯或无红绿灯
speed_mps = base_speed_mps
# 更新车辆速度
vehicle["speed"] = speed_mps * 3600 / 1000 # 转回 km/h
# 计算移动距离
distance = speed_mps * elapsed_time
# 计算经纬度变化
dlat, dlon = meters_to_degrees(distance, vehicle["latitude"])
if vehicle["vehicleNo"].startswith("QN"):
# 无人车的路径更新逻辑
if vehicle["vehicleNo"] == "QN001":
# 无人车1先南北后东西往返
if "phase" not in vehicle:
vehicle["phase"] = 0
if vehicle["phase"] == 0: # 南北移动
new_lat = vehicle["latitude"] + (dlat * vehicle["direction"])
if vehicle["direction"] == -1 and new_lat <= WEST_INTERSECTION["latitude"]:
# 到达路口,切换到东西移动
vehicle["phase"] = 1
vehicle["direction"] = 1 # 向东
elif vehicle["direction"] == 1 and new_lat >= WEST_INTERSECTION["latitude"] + (DIST_50M / 111319.9):
# 返回起点
vehicle["phase"] = 0
vehicle["direction"] = -1 # 向南
vehicle["latitude"] = new_lat
else: # 东西移动
new_lon = vehicle["longitude"] + (dlon * vehicle["direction"])
if vehicle["direction"] == 1 and new_lon >= WEST_INTERSECTION["longitude"] + (DIST_100M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
# 到达东端,开始返回
vehicle["direction"] = -1 # 向西
elif vehicle["direction"] == -1 and new_lon <= WEST_INTERSECTION["longitude"]:
# 返回路口,切换到南北移动
vehicle["phase"] = 0
vehicle["direction"] = 1 # 向北
vehicle["longitude"] = new_lon
else: # QN002
# 无人车2东西方向往返东路口
new_lon = vehicle["longitude"] + (dlon * vehicle["direction"])
if new_lon >= EAST_INTERSECTION["longitude"] + (DIST_100M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
vehicle["direction"] = -1 # 向西
elif new_lon <= EAST_INTERSECTION["longitude"] - (DIST_150M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
vehicle["direction"] = 1 # 向东
vehicle["longitude"] = new_lon
elif vehicle["vehicleNo"].startswith("TQ"):
# 特勤车的路径更新逻辑
if "phase" not in vehicle:
vehicle["phase"] = 0
if vehicle["phase"] == 0: # 东西移动
new_lon = vehicle["longitude"] + (dlon * vehicle["direction"])
if vehicle["direction"] == -1 and new_lon <= WEST_INTERSECTION["longitude"]:
vehicle["phase"] = 1 # 切换到南北移动
vehicle["direction"] = -1 # 向南
elif vehicle["direction"] == 1 and new_lon >= WEST_INTERSECTION["longitude"] + (DIST_50M / (111319.9 * math.cos(math.radians(vehicle["latitude"])))):
vehicle["direction"] = -1 # 向西
vehicle["longitude"] = new_lon
else: # 南北移动
new_lat = vehicle["latitude"] + (dlat * vehicle["direction"])
if new_lat <= WEST_INTERSECTION["latitude"] - (DIST_100M / 111319.9): # 到达南端
vehicle["direction"] = 1 # 向北
elif new_lat >= WEST_INTERSECTION["latitude"]: # 返回到路口
vehicle["phase"] = 0 # 切换回东西移动
vehicle["direction"] = 1 # 向北
vehicle["longitude"] = WEST_INTERSECTION["longitude"] # 重置到起始位置
vehicle["latitude"] = new_lat
# 更新时间戳
vehicle["time"] = int(time.time() * 1000)
def update_aircraft_position(aircraft, elapsed_time):
"""更新航空器位置"""
# 计算一次更新的移动距离(米)
speed_mps = aircraft["speed"] * 1000 / 3600 # 速度转换为米/秒
distance = speed_mps * elapsed_time
# 计算经纬度变化
dlat, dlon = meters_to_degrees(distance, aircraft["latitude"])
new_lat = aircraft["latitude"] + (dlat * aircraft["direction"])
if new_lat >= EAST_INTERSECTION["latitude"] + (DIST_150M / 111319.9):
aircraft["direction"] = -1 # 向南
elif new_lat <= EAST_INTERSECTION["latitude"] - (DIST_150M / 111319.9):
aircraft["direction"] = 1 # 向北
aircraft["latitude"] = new_lat
def update_traffic_light_for_aircraft():
"""根据航空器位置更新东路口红绿灯状态"""
if not aircraft_data:
return
aircraft = aircraft_data[0]
# 计算到东路口的距离(米)
lat_diff = abs(aircraft["latitude"] - EAST_INTERSECTION["latitude"]) * 111319.9
# 更新TL002东路口的状态
for light in traffic_light_data:
if light["id"] == "TL002":
if lat_diff <= 50.0: # 距离于50米时为红灯
light["state"] = 0 # 红灯
else:
light["state"] = 1 # 绿灯
break
# 定义路口信息
INTERSECTIONS = {
"TL001": {
"id": "INT001",
"name": "西路口",
"latitude": WEST_INTERSECTION["latitude"],
"longitude": WEST_INTERSECTION["longitude"]
},
"TL002": {
"id": "INT002",
"name": "东路口",
"latitude": EAST_INTERSECTION["latitude"],
"longitude": EAST_INTERSECTION["longitude"]
}
}
def generate_traffic_light_data():
"""生成红绿灯数据"""
traffic_light_data = []
# 生成两个固定路口的红绿灯数据
for tl_id, intersection in INTERSECTIONS.items():
signal = {
"id": tl_id,
"state": random.randint(0, 1), # 0: RED, 1: GREEN
"timestamp": int(time.time() * 1000),
"intersectionId": intersection["id"],
"latitude": intersection["latitude"],
"longitude": intersection["longitude"]
}
traffic_light_data.append(signal)
return traffic_light_data
# 红绿灯<E7BBBF><E781AF><EFBFBD>
traffic_light_data = generate_traffic_light_data()
# 分别记录航空器和车辆的上次更新时间
last_aircraft_update_time = time.time()
last_vehicle_update_time = time.time()
last_light_switch_time = time.time()
@app.route('/api/getCurrentFlightPositions')
def get_flight_positions():
global last_aircraft_update_time
current_time = time.time()
elapsed_time = current_time - last_aircraft_update_time
# 只在达到更新间隔时更新位置
if elapsed_time >= UPDATE_INTERVAL:
for aircraft in aircraft_data:
update_aircraft_position(aircraft, UPDATE_INTERVAL)
aircraft["time"] = int(current_time * 1000)
last_aircraft_update_time = current_time
return jsonify(aircraft_data)
@app.route('/api/getCurrentVehiclePositions')
def get_vehicle_positions():
global last_vehicle_update_time
current_time = time.time()
elapsed_time = current_time - last_vehicle_update_time
# 只在达到更新间隔时更新位置
if elapsed_time >= UPDATE_INTERVAL:
for vehicle in vehicle_data:
update_vehicle_position(vehicle, UPDATE_INTERVAL)
vehicle["time"] = int(current_time * 1000)
last_vehicle_update_time = current_time
return jsonify(vehicle_data)
@app.route('/api/getTrafficLightSignals')
def get_traffic_light_signals():
global last_light_switch_time
current_time = time.time()
# 更新时间戳
for light in traffic_light_data:
light["timestamp"] = int(current_time * 1000)
# TL001西路口状态每15秒切换一次
elapsed_since_switch = current_time - last_light_switch_time
if elapsed_since_switch >= 15: # 每15秒切换一次
traffic_light_data[0]["state"] = 1 if traffic_light_data[0]["state"] == 0 else 0
last_light_switch_time = current_time
# 根据航空器位置更新TL002东路口
update_traffic_light_for_aircraft()
return jsonify(traffic_light_data)
@app.after_request
def add_cors_headers(response):
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
return response
if __name__ == '__main__':
app.run(host='localhost', port=8081, debug=True)

View File

@ -17,6 +17,7 @@
.info { color: blue; }
.position { color: #666; }
.warning { color: #f90; }
.command { color: #800080; } /* 紫色显示控制指令 */
</style>
</head>
<body>
@ -73,13 +74,42 @@
// 根据消息类型使用不同的样式
let type = 'info';
if (data.type === 'position_update') {
type = 'position';
} else if (data.type === 'collision_warning') {
type = 'warning';
let message = '收到消息:\n' + formattedData;
switch (data.type) {
case 'position_update':
type = 'position';
break;
case 'collision_warning':
type = 'warning';
break;
case 'vehicle_command':
type = 'command';
// 为控制指令添加中文描述
const commandTypes = {
'SIGNAL': '信号灯指令',
'ALERT': '告警指令',
'WARNING': '预警指令',
'RESUME': '恢复指令'
};
const reasons = {
'TRAFFIC_LIGHT': '红绿灯控制',
'AIRCRAFT_CROSSING': '航空器交叉',
'SPECIAL_VEHICLE': '特勤车辆',
'AIRCRAFT_PUSH': '航空器推出',
'RESUME_TRAFFIC': '恢复通行'
};
message = `收到车辆控制指令:\n车辆: ${data.vehicleId}\n` +
`指令类型: ${commandTypes[data.commandType] || data.commandType}\n` +
`原因: ${reasons[data.reason] || data.reason}\n` +
(data.targetLatitude !== undefined ? `目标位置: (${data.targetLatitude}, ${data.targetLongitude})\n` : '') +
(data.signalState ? `信号灯状态: ${data.signalState}\n` : '') +
(data.intersectionId ? `路口ID: ${data.intersectionId}\n` : '') +
`时间戳: ${new Date(data.timestamp/1000000).toLocaleString()}`;
break;
}
log('收到消息:\n' + formattedData, type);
log(message, type);
} catch (e) {
log('收到消息: ' + event.data, 'info');
}