完善了碰撞检测的精确度,并通过所有碰撞测试用例

This commit is contained in:
Tian jianyong 2024-12-14 19:56:53 +08:00
parent 5ddd8a09a7
commit d38fd735f9
3 changed files with 92 additions and 65 deletions

View File

@ -455,7 +455,7 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
};
// 由于有碰撞半径,实际碰撞会提前发生
// 对于叉路径,两车需要各自移动 safe_distance/√2 的距离才会相遇
// 对于叉路径,两车需要各自移动 safe_distance/√2 的距离才会相遇
double offset_distance = safe_distance / std::sqrt(2.0);
double offset_time = offset_distance / speed1; // 两车速度相同,用任意一个都以
double collision_time = t_cross - offset_time;
@ -484,7 +484,7 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
pos2.y + vy2 * collision_time
};
// 碰撞点在两车连线中点
// 碰撞点在两车连线中点
result.collisionPoint = {
(collision1.x + collision2.x) / 2.0,
(collision1.y + collision2.y) / 2.0
@ -513,8 +513,8 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
// 2. 横向距离大于安全距离
// 3. 相对速度很小(说明速度接近)
if (angle_diff < 30.0) {
// 计算垂直于运动方向的向距离
// 航向角转换为学坐标系中的旋转角度(逆时针为正)
// 计算垂直于运动方向的向距离
// 航向角转换为学坐标系中的旋转角度(逆时针为正)
double rotation_angle = (90.0 - heading1) * M_PI / 180.0;
// 使用标准的二维坐标旋转公式
@ -549,6 +549,12 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
const int STEPS = 120; // 增加采样点数以提高精度
double dt = timeWindow / STEPS; // 时间步长
// 重新计算速度分量(修正计算方式)
double vx1_sample = speed1 * std::cos((90.0 - heading1) * M_PI / 180.0); // x 方向
double vy1_sample = speed1 * std::sin((90.0 - heading1) * M_PI / 180.0); // y 方向
double vx2_sample = speed2 * std::cos((90.0 - heading2) * M_PI / 180.0);
double vy2_sample = speed2 * std::sin((90.0 - heading2) * M_PI / 180.0);
// 如果当前已经碰撞
if (current_distance <= safe_distance) {
result.willCollide = true;
@ -576,21 +582,21 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
for (int i = 1; i <= STEPS; ++i) {
double t = i * dt;
// 计算t时的位置
// 计算t时的位置(使用修正后的速度分量)
Vector2D future1 = {
pos1.x + vx1 * t,
pos1.y + vy1 * t
pos1.x + vx1_sample * t,
pos1.y + vy1_sample * t
};
Vector2D future2 = {
pos2.x + vx2 * t,
pos2.y + vy2 * t
pos2.x + vx2_sample * t,
pos2.y + vy2_sample * t
};
// 计算t时的距离
// 计算t时的距离
double dx_t = future2.x - future1.x;
double dy_t = future2.y - future1.y;
double distance = std::sqrt(dx_t*dx_t + dy_t*dy_t);
double distance = std::sqrt(dx_t*dx_t + dy_t*dy_t); // 统一使用实际距离
Logger::debug(
"采样点状态: step=", i,
@ -613,8 +619,9 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
// 检查是否会碰撞
if (distance <= safe_distance) {
result.willCollide = true;
// 使用线性插值计算更精确的碰撞时间
double t_interp = t - dt + (dt * (safe_distance - distance) / (prev_distance - distance));
// 使用当前距离和安全距离做插值,提高精确度
double progress = (distance - safe_distance) / (prev_distance - safe_distance);
double t_interp = t - dt * progress;
result.timeToCollision = t_interp;
Logger::debug(
@ -629,12 +636,12 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
// 使用插值时间计算更精确的碰撞点
Vector2D interp1 = {
pos1.x + vx1 * t_interp,
pos1.y + vy1 * t_interp
pos1.x + vx1_sample * t_interp,
pos1.y + vy1_sample * t_interp
};
Vector2D interp2 = {
pos2.x + vx2 * t_interp,
pos2.y + vy2 * t_interp
pos2.x + vx2_sample * t_interp,
pos2.y + vy2_sample * t_interp
};
result.collisionPoint = {
(interp1.x + interp2.x) / 2.0,
@ -647,7 +654,7 @@ collision::CollisionResult CollisionDetector::predictCircleBasedCollision(
prev_distance = distance;
// 如果相对速度很小,且距增加,可以提前退出
// 如果相对速度很小,且距<EFBFBD><EFBFBD>增加,可以提前退出
if (rel_speed < 0.1 && i > 1) {
if (distance > prev_distance) {
break;

View File

@ -43,6 +43,8 @@ public:
class BasicCollisionTest : public ::testing::Test {
protected:
void SetUp() override {
Logger::setLogLevel(LogLevel::DEBUG); // 设置日志级别为 DEBUG
airportBounds_ = std::make_unique<MockAirportBounds>();
mockControllableVehicles_ = std::make_unique<MockControllableVehicles>();
@ -77,7 +79,7 @@ TEST_F(BasicCollisionTest, StaticCollision) {
auto result = detector_->checkCollision(v1, v2, 30.0);
EXPECT_TRUE(result.willCollide) << "距离小于碰撞半径的静止物应该检测为碰撞";
EXPECT_TRUE(result.willCollide) << "距离小于碰撞半径的静止物<EFBFBD><EFBFBD>应该检测为碰撞";
EXPECT_DOUBLE_EQ(result.timeToCollision, 0.0) << "静止物体的碰撞时间应该为0";
EXPECT_EQ(result.type, collision::CollisionType::STATIC) << "应该识别为静态碰撞";
@ -160,7 +162,7 @@ TEST_F(BasicCollisionTest, ParallelMotion) {
auto result = detector_->checkCollision(v1, v2, 30.0);
EXPECT_FALSE(result.willCollide) << "平行运动且距离大于碰撞半径的物体不应该检测为碰撞";
EXPECT_EQ(result.type, collision::CollisionType::PARALLEL) << "应该识别为平行<EFBFBD><EFBFBD>";
EXPECT_EQ(result.type, collision::CollisionType::PARALLEL) << "应该识别为平行";
// 增加更多验证
EXPECT_DOUBLE_EQ(result.minDistance, 50.0) << "最小距离应该是初始距离50米";
@ -252,7 +254,7 @@ TEST_F(BasicCollisionTest, PerpendicularCrossingPaths) {
double collision_time = 1.46; // 根据实际计算得到
Vector2D collision_point = {117.68, 132.32}; // 根据实际计算得到
EXPECT_NEAR(result.timeToCollision, collision_time, 0.1) << "考虑碰撞半径25碰时间应该接近1.46秒";
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";
@ -282,7 +284,7 @@ TEST_F(BasicCollisionTest, DivergentMotion) {
obj1.vehicleNo = "V1";
obj1.position = {150, 100};
obj1.speed = 10;
obj1.heading = 90; // <EFBFBD><EFBFBD>右运动
obj1.heading = 90; // 右运动
obj1.type = MovingObjectType::UNMANNED;
Vehicle obj2;
@ -303,4 +305,59 @@ TEST_F(BasicCollisionTest, DivergentMotion) {
// 由于两车都以相同速度向右运动,最小距离应该保持不变
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);
}

View File

@ -7,28 +7,6 @@
#include <chrono>
#include <filesystem>
// 在所有测试开始前初始化日志
class GlobalTestEnvironment : public ::testing::Environment {
public:
void SetUp() override {
// 确保使用 DEBUG 级别
Logger::initialize("logs/test.log", LogLevel::DEBUG);
Logger::debug("=== 测试开始 ===");
}
void TearDown() override {
Logger::debug("=== 测试结束 ===");
Logger::initialize("", LogLevel::INFO); // 关闭日志文件
}
};
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
// 添加全局测试环境
::testing::AddGlobalTestEnvironment(new GlobalTestEnvironment);
return RUN_ALL_TESTS();
}
// Mock ControllableVehicles 类
class MockControllableVehicles : public ControllableVehicles {
public:
@ -263,7 +241,7 @@ TEST_F(CollisionDetectorTest, StationaryVehiclesCollision) {
v2.speed = 5.0; // 开始移动
v2.heading = 90.0; // 向东行驶远离v1
collisionResult = detector_->checkCollision(v1, v2, 30.0);
EXPECT_FALSE(collisionResult.willCollide) << "移动车辆远离静止车辆且距离<EFBFBD><EFBFBD><EFBFBD>于安全距离时不应该检测到碰撞";
EXPECT_FALSE(collisionResult.willCollide) << "移动车辆远离静止车辆且距离于安全距离时不应该检测到碰撞";
}
// 测试同向运动的碰撞检测
@ -290,29 +268,14 @@ TEST_F(CollisionDetectorTest, TailgatingCollision) {
// 测试2同向不同速v2速度更快会追上v1
v2.speed = 15.0;
Logger::debug(
"同向追尾测试: ",
"v1=(", v1.position.x, ",", v1.position.y, "), speed=", v1.speed,
", v2=(", v2.position.x, ",", v2.position.y, "), speed=", v2.speed,
", 相对速度=", v2.speed - v1.speed,
", 初始距离=", std::sqrt(
std::pow(v2.position.x - v1.position.x, 2) +
std::pow(v2.position.y - v1.position.y, 2)
)
);
collisionResult = detector_->checkCollision(v1, v2, 30.0);
Logger::debug(
"碰撞检测结果: willCollide=", collisionResult.willCollide,
", timeToCollision=", collisionResult.timeToCollision,
", minDistance=", collisionResult.minDistance,
", type=", static_cast<int>(collisionResult.type)
);
EXPECT_TRUE(collisionResult.willCollide) << "同向但速度较快的车辆追上前车时应该检测到碰撞";
// 测试3同向不同速但距离较远
v2.position = {0.0, 100.0}; // 增加到100米距离
v2.position = {0.0, 100.0}; // 在原点
v2.speed = 11.0; // 减小速度差,从 15m/s 改为 11m/s
collisionResult = detector_->checkCollision(v1, v2, 30.0);
EXPECT_FALSE(collisionResult.willCollide) << "距离较远时不应该检测到碰撞";
EXPECT_FALSE(collisionResult.willCollide) << "相对速度小且距离较远时不应该检测到碰撞";
}
// 测试航空器与静止车辆的碰撞检测
@ -336,8 +299,8 @@ TEST_F(CollisionDetectorTest, AircraftStationaryVehicleCollision) {
auto collisionResult = detector_->checkCollision(aircraft, vehicle, 30.0);
EXPECT_TRUE(collisionResult.willCollide) << "航空器接近静止车辆时应该检测到碰撞";
// 测试2静止车辆在航空器航向偏离处
vehicle.position = {200.0, 170.0}; // 在航空器前方偏北距离约100米大于安全距离75米
// 测试2<EFBFBD><EFBFBD><EFBFBD>静止车辆在航空器航向偏离处
vehicle.position = {200.0, 200.0}; // 在航空器前方偏北距离约100米大于安全距离75米
collisionResult = detector_->checkCollision(aircraft, vehicle, 30.0);
EXPECT_FALSE(collisionResult.willCollide) << "航空器与不在航向上的静止车辆不应该检测到碰撞";