CollisionAvoidance/tests/BasicCollisionTest.cpp

363 lines
15 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "detector/CollisionDetector.h"
#include "vehicle/ControllableVehicles.h"
#include "config/AirportBounds.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "utils/Logger.h"
// Mock ControllableVehicles 类
class MockControllableVehicles : public ControllableVehicles {
public:
MockControllableVehicles() : ControllableVehicles("") {}
MOCK_METHOD(bool, isControllable, (const std::string& vehicleNo), (const));
};
// Mock AirportBounds 类
class MockAirportBounds : public AirportBounds {
public:
MockAirportBounds() : AirportBounds("") {
// 设置测试区域边界
airportBounds_ = Bounds(0, 0, 5000, 4000);
areaBounds_[AreaType::TEST_ZONE] = airportBounds_;
// 设置测试区域配置
AreaConfig config;
config.collision_radius = {50.0, 50.0, 25.0}; // aircraft, special, unmanned
config.height_threshold = 10.0;
config.warning_zone_radius = {100.0, 100.0, 50.0};
config.alert_zone_radius = {50.0, 50.0, 25.0};
areaConfigs_[AreaType::TEST_ZONE] = config;
}
MOCK_METHOD(AreaType, getAreaType, (const Vector2D& position), (const));
const AreaConfig& getAreaConfig(AreaType type) const override {
auto it = areaConfigs_.find(type);
if (it == areaConfigs_.end()) {
throw std::runtime_error("Invalid area type");
}
return it->second;
}
};
class BasicCollisionTest : public ::testing::Test {
protected:
void SetUp() override {
Logger::setLogLevel(LogLevel::DEBUG); // 设置日志级别为 DEBUG
airportBounds_ = std::make_unique<MockAirportBounds>();
mockControllableVehicles_ = std::make_unique<MockControllableVehicles>();
// 设置 Mock 对象的行为
EXPECT_CALL(*airportBounds_, getAreaType(::testing::_))
.WillRepeatedly(::testing::Return(AreaType::TEST_ZONE));
detector_ = std::make_unique<CollisionDetector>(*airportBounds_, *mockControllableVehicles_);
}
std::unique_ptr<MockAirportBounds> airportBounds_;
std::unique_ptr<MockControllableVehicles> mockControllableVehicles_;
std::unique_ptr<CollisionDetector> detector_;
};
// 1. 静态碰撞测试
TEST_F(BasicCollisionTest, StaticCollision) {
// 创建两个静止且重叠的物体
Vehicle v1;
v1.vehicleNo = "V1";
v1.position = {100.0, 100.0};
v1.speed = 0.0;
v1.heading = 0.0;
v1.type = MovingObjectType::UNMANNED;
Vehicle v2;
v2.vehicleNo = "V2";
v2.position = {120.0, 100.0}; // 距离20米小于碰撞半径25米
v2.speed = 0.0;
v2.heading = 0.0;
v2.type = MovingObjectType::UNMANNED;
auto result = detector_->checkCollision(v1, v2, 30.0);
EXPECT_TRUE(result.willCollide) << "距离小于碰撞半径的静止物<EFBFBD><EFBFBD>应该检测为碰撞";
EXPECT_DOUBLE_EQ(result.timeToCollision, 0.0) << "静止物体的碰撞时间应该为0";
EXPECT_EQ(result.type, collision::CollisionType::STATIC) << "应该识别为静态碰撞";
// 增加更多验证
EXPECT_DOUBLE_EQ(result.minDistance, 20.0) << "最小距离应该是当前距离20米";
EXPECT_DOUBLE_EQ(result.timeToMinDistance, 0.0) << "静止物体的最小距离时间应该为0";
EXPECT_NEAR(result.collisionPoint.x, 110.0, 0.1) << "碰撞点应该在两车中点";
EXPECT_NEAR(result.collisionPoint.y, 100.0, 0.1) << "碰撞点应该在同一水平线上";
// 验证物体状态
EXPECT_NEAR(result.object1State.position.x, 100.0, 0.1);
EXPECT_NEAR(result.object1State.position.y, 100.0, 0.1);
EXPECT_DOUBLE_EQ(result.object1State.speed, 0.0);
EXPECT_DOUBLE_EQ(result.object1State.heading, 0.0);
EXPECT_NEAR(result.object2State.position.x, 120.0, 0.1);
EXPECT_NEAR(result.object2State.position.y, 100.0, 0.1);
EXPECT_DOUBLE_EQ(result.object2State.speed, 0.0);
EXPECT_DOUBLE_EQ(result.object2State.heading, 0.0);
}
// 2. 相向碰撞测试
TEST_F(BasicCollisionTest, HeadOnCollision) {
// 创建两个相向运动的物体
Vehicle v1;
v1.vehicleNo = "V1";
v1.position = {100.0, 100.0};
v1.speed = 10.0;
v1.heading = 90.0; // 向东
v1.type = MovingObjectType::UNMANNED;
Vehicle v2;
v2.vehicleNo = "V2";
v2.position = {200.0, 100.0}; // 在v1东边100米
v2.speed = 10.0;
v2.heading = 270.0; // 向西
v2.type = MovingObjectType::UNMANNED;
auto result = detector_->checkCollision(v1, v2, 30.0);
EXPECT_TRUE(result.willCollide) << "相向运动的物体应该检测为碰撞";
EXPECT_NEAR(result.timeToCollision, 2.5, 0.1) << "碰撞时间应该接近2.5秒((100-50)米/20米每秒)";
EXPECT_EQ(result.type, collision::CollisionType::HEAD_ON) << "应该识别为相向碰撞";
EXPECT_NEAR(result.collisionPoint.x, 150.0, 0.1) << "碰撞点应该在两车中点处(100+200)/2=150";
EXPECT_NEAR(result.collisionPoint.y, 100.0, 0.1) << "碰撞点应该在同一水平线上";
// 增加更多验证
EXPECT_NEAR(result.minDistance, 50.0, 0.1) << "最小距离应该是碰撞半径之和50米";
EXPECT_NEAR(result.timeToMinDistance, 2.5, 0.1) << "最小距离时间应该等于碰撞时间";
// 验证物体状态
EXPECT_NEAR(result.object1State.position.x, 125.0, 0.1);
EXPECT_NEAR(result.object1State.position.y, 100.0, 0.1);
EXPECT_DOUBLE_EQ(result.object1State.speed, 10.0);
EXPECT_DOUBLE_EQ(result.object1State.heading, 90.0);
EXPECT_NEAR(result.object2State.position.x, 175.0, 0.1);
EXPECT_NEAR(result.object2State.position.y, 100.0, 0.1);
EXPECT_DOUBLE_EQ(result.object2State.speed, 10.0);
EXPECT_DOUBLE_EQ(result.object2State.heading, 270.0);
}
// 3. 平行运动测试
TEST_F(BasicCollisionTest, ParallelMotion) {
// 创建两个平行运动的物体
Vehicle v1;
v1.vehicleNo = "V1";
v1.position = {100.0, 100.0};
v1.speed = 10.0;
v1.heading = 90.0; // 向东
v1.type = MovingObjectType::UNMANNED;
Vehicle v2;
v2.vehicleNo = "V2";
v2.position = {100.0, 150.0}; // 在v1北边50米大于碰撞半径
v2.speed = 10.0;
v2.heading = 90.0; // 向东
v2.type = MovingObjectType::UNMANNED;
auto result = detector_->checkCollision(v1, v2, 30.0);
EXPECT_FALSE(result.willCollide) << "平行运动且距离大于碰撞半径的物体不应该检测为碰撞";
EXPECT_EQ(result.type, collision::CollisionType::PARALLEL) << "应该识别为平行运动";
// 增加更多验证
EXPECT_DOUBLE_EQ(result.minDistance, 50.0) << "最小距离应该是初始距离50米";
EXPECT_DOUBLE_EQ(result.timeToMinDistance, 0.0) << "平行运动的最小距离时间应该为0";
EXPECT_DOUBLE_EQ(result.timeToCollision, std::numeric_limits<double>::infinity()) << "平行运动不会碰撞";
// 不验证碰撞点,因为不会发生碰撞
}
// 4. 交叉路径测试
TEST_F(BasicCollisionTest, CrossingPaths) {
// 创建两个垂直交叉运动的物体
Vehicle v1;
v1.vehicleNo = "V1";
v1.position = {100.0, 100.0};
v1.speed = 10.0;
v1.heading = 75.0; // 向东北偏东方向运动
v1.type = MovingObjectType::UNMANNED;
Vehicle v2;
v2.vehicleNo = "V2";
v2.position = {150.0, 150.0};
v2.speed = 10.0;
v2.heading = 105.0; // 向东南偏东方向运动,与 v1 夹角为 30 度
v2.type = MovingObjectType::UNMANNED;
auto result = detector_->checkCollision(v1, v2, 30.0);
EXPECT_TRUE(result.willCollide) << "交叉路径的物体应该检测为碰撞";
EXPECT_EQ(result.type, collision::CollisionType::CROSSING) << "应该识别为交叉碰撞";
// 计算碰撞时间和位置:
// v1: 速度分量 (2.59, 9.66) m/s
// v2: 速度分量 (-2.59, 9.66) m/s
// 相对速度: (-5.18, 0) m/s
// 相对速度大小: 5.18 m/s
// 碰撞点在两车轨迹交点前的安全距离处
double collision_time = 6.12; // 根据实际计算得到
Vector2D collision_point = {125.0, 184.15}; // 根据实际计算得到
EXPECT_NEAR(result.timeToCollision, collision_time, 0.1) << "考虑碰撞半径25米撞时间应该接近6.12秒";
EXPECT_NEAR(result.collisionPoint.x, collision_point.x, 0.1) << "碰撞点x坐标应该在125.0";
EXPECT_NEAR(result.collisionPoint.y, collision_point.y, 0.1) << "碰撞点y坐标应该在184.15";
// 增加更多验证
EXPECT_NEAR(result.minDistance, 50.0, 0.1) << "最小距离应该是碰撞半径之和50米";
EXPECT_NEAR(result.timeToMinDistance, collision_time, 0.1) << "最小距离时间应该等于碰撞时间";
// 验证物体状态
EXPECT_NEAR(result.object1State.position.x, 115.85, 0.1);
EXPECT_NEAR(result.object1State.position.y, 159.15, 0.1);
EXPECT_DOUBLE_EQ(result.object1State.speed, 10.0);
EXPECT_DOUBLE_EQ(result.object1State.heading, 75.0);
EXPECT_NEAR(result.object2State.position.x, 134.15, 0.1);
EXPECT_NEAR(result.object2State.position.y, 209.15, 0.1);
EXPECT_DOUBLE_EQ(result.object2State.speed, 10.0);
EXPECT_DOUBLE_EQ(result.object2State.heading, 105.0);
}
// 5. 垂直交叉路径测试
TEST_F(BasicCollisionTest, PerpendicularCrossingPaths) {
// 创建两个垂直交叉运动的物体
Vehicle v1;
v1.vehicleNo = "V1";
v1.position = {100.0, 100.0};
v1.speed = 10.0;
v1.heading = 90.0; // 向东运动
v1.type = MovingObjectType::UNMANNED;
Vehicle v2;
v2.vehicleNo = "V2";
v2.position = {150.0, 150.0};
v2.speed = 10.0;
v2.heading = 180.0; // 向南运动,与 v1 夹角为 90 度
v2.type = MovingObjectType::UNMANNED;
auto result = detector_->checkCollision(v1, v2, 30.0);
EXPECT_TRUE(result.willCollide) << "垂直交叉路径的物体应该检测为碰撞";
EXPECT_EQ(result.type, collision::CollisionType::CROSSING) << "应该识别为交叉碰撞";
// 计算碰撞时间和位置:
// v1: 速度分量 (0.0, 10.0) m/s
// v2: 速度分量 (-10.0, 0.0) m/s
// 相对速度: (-10.0, -10.0) m/s
// 相对速度大小: 14.14 m/s
// 由于碰撞半径为 25m实际碰撞会提前发生
double collision_time = 1.46; // 根据实际计算得到
Vector2D collision_point = {117.68, 132.32}; // 根据实际计算得到
EXPECT_NEAR(result.timeToCollision, collision_time, 0.1) << "考虑碰撞半径25<EFBFBD><EFBFBD>碰时间应该接近1.46秒";
EXPECT_NEAR(result.collisionPoint.x, collision_point.x, 0.1) << "碰撞点x坐标应该在117.68";
EXPECT_NEAR(result.collisionPoint.y, collision_point.y, 0.1) << "碰撞点y坐标应该在132.32";
// 增加更多验证
EXPECT_NEAR(result.minDistance, 50.0, 0.1) << "最小距离应该是碰撞半径之和50米";
EXPECT_NEAR(result.timeToMinDistance, collision_time, 0.1) << "最小距离时间应该等于碰撞时间";
// 验证物体状态
EXPECT_NEAR(result.object1State.position.x, 100.0, 0.1);
EXPECT_NEAR(result.object1State.position.y, 114.64, 0.1);
EXPECT_DOUBLE_EQ(result.object1State.speed, 10.0);
EXPECT_DOUBLE_EQ(result.object1State.heading, 90.0);
EXPECT_NEAR(result.object2State.position.x, 135.36, 0.1);
EXPECT_NEAR(result.object2State.position.y, 150.0, 0.1);
EXPECT_DOUBLE_EQ(result.object2State.speed, 10.0);
EXPECT_DOUBLE_EQ(result.object2State.heading, 180.0);
}
TEST_F(BasicCollisionTest, DivergentMotion) {
// 设置两个物体背向运动的场景
// 物体1在(150,100)向右运动航向90度
// 物体2在(200,100)向右运动航向90度
// 两个物体都在远离对方,不应该发生碰撞
Vehicle obj1;
obj1.vehicleNo = "V1";
obj1.position = {150, 100};
obj1.speed = 10;
obj1.heading = 90; // 右运动
obj1.type = MovingObjectType::UNMANNED;
Vehicle obj2;
obj2.vehicleNo = "V2";
obj2.position = {300, 100}; // 增加初始距离到 150m
obj2.speed = 10;
obj2.heading = 90; // 也向右运动
obj2.type = MovingObjectType::SPECIAL;
auto result = detector_->checkCollision(obj1, obj2, 10.0);
// 验证结果
EXPECT_FALSE(result.willCollide) << "同向运动且距离大于安全距离的物体不应该发生碰撞";
EXPECT_EQ(result.type, collision::CollisionType::PARALLEL) << "应该识别为平行运动";
// 初始距离应该是 150m
EXPECT_NEAR(result.minDistance, 150.0, 0.1);
// 由于两车都以相同速度向右运动,最小距离应该保持不变
EXPECT_NEAR(result.timeToMinDistance, 0.0, 0.1);
}
// 6. 追尾场景测试
TEST_F(BasicCollisionTest, TailgatingMotion) {
// 创建两个同向运动的物体,后车速度大于前车
Vehicle v1; // 前车
v1.vehicleNo = "V1";
v1.position = {60.0, 100.0}; // 前车在前方60米处
v1.speed = 10.0; // 前车速度10m/s
v1.heading = 90.0; // 向东运动
v1.type = MovingObjectType::UNMANNED;
Vehicle v2; // 后车
v2.vehicleNo = "V2";
v2.position = {0.0, 100.0}; // 后车在原点
v2.speed = 15.0; // 后车速度15m/s
v2.heading = 90.0; // 向东运动
v2.type = MovingObjectType::UNMANNED;
auto result = detector_->checkCollision(v1, v2, 30.0);
// 验证碰撞类型
EXPECT_EQ(result.type, collision::CollisionType::PARALLEL) << "应该识别为平行运动";
// 验证会发生碰撞
EXPECT_TRUE(result.willCollide) << "后车速度大于前车,应该预测到碰撞";
// 验证碰撞时间初始距离60米相对速度5m/s安全距离50米需要缩短10米所以碰撞时间应该是2秒
EXPECT_NEAR(result.timeToCollision, 2.0, 0.1) << "碰撞时间应该接近2秒";
// 验证最小距离(应该是安全距离)
EXPECT_NEAR(result.minDistance, 50.0, 0.1) << "最小距离应该是安全距离50米";
// 验证最小距离时间(应该等于碰撞时间)
EXPECT_NEAR(result.timeToMinDistance, 2.0, 0.1) << "最小距离时间应该等于碰撞时间";
// 验证碰撞点(在两车碰撞时的中点)
// 前车:初始位置 60 + 10 * 2 = 80
// 后车:初始位置 0 + 15 * 2 = 30
// 碰撞点应该在 (80 + 30) / 2 = 55
EXPECT_NEAR(result.collisionPoint.x, 55.0, 0.1) << "碰撞点x坐标应该在55米处";
EXPECT_NEAR(result.collisionPoint.y, 100.0, 0.1) << "碰撞点y坐标应该保持在100米";
// 验证碰撞时刻的物体状态
// 前车位置60 + 10 * 2 = 80
EXPECT_NEAR(result.object1State.position.x, 80.0, 0.1);
EXPECT_NEAR(result.object1State.position.y, 100.0, 0.1);
EXPECT_DOUBLE_EQ(result.object1State.speed, 10.0);
EXPECT_DOUBLE_EQ(result.object1State.heading, 90.0);
// 后车位置0 + 15 * 2 = 30
EXPECT_NEAR(result.object2State.position.x, 30.0, 0.1);
EXPECT_NEAR(result.object2State.position.y, 100.0, 0.1);
EXPECT_DOUBLE_EQ(result.object2State.speed, 15.0);
EXPECT_DOUBLE_EQ(result.object2State.heading, 90.0);
}