vkgs-sim / tests /cpp /test_drive.cpp
kimjunhan's picture
Add files using upload-large-folder tool
4c75661 verified
Raw History Blame Contribute Delete
6.53 kB
// drive.hpp ์˜ ์ถฉ๋Œยทํ›„์ง„ ํšŒ๊ท€ ์‹œํ—˜ โ€” tests/test_drive_cpp.py ๊ฐ€ ์ปดํŒŒ์ผํ•ด ๋Œ๋ฆฐ๋‹ค.
#include "drive.hpp"
#include <cmath>
#include <cstdio>
using namespace vkgs;
int main(int, char** argv) {
ObstacleGrid og; og.load(argv[1]); Drivable road;
int fails = 0;
// 1) ์ถœ๋ฐœ ์ž์„ธ๊ฐ€ ๊ธฐ๋‘ฅ์— ๊ฑธ์นจ: ๊ทธ ์ž๋ฆฌ์—์„œ ์•ž์œผ๋กœ(๋น ์ ธ๋‚˜๊ฐ€๋Š” ๋ฐฉํ–ฅ) ๊ฐ€๋ฉด ๋ง‰ํžˆ์ง€ ์•Š๊ณ , ๋ฒฝ(x=10)์—์„œ๋Š” ๋ฉˆ์ถ˜๋‹ค
Vehicle car; car.x = 0; car.y = 0.5f; car.yaw = 0;
ContactInfo cur = vehicle_contact(car, og, road, false);
std::printf("start contact %d\n", cur.total());
// ์ „์ œ: ์ •๋ง๋กœ ๊ธฐ๋‘ฅ์— ๊ฑธ์นœ ์ฑ„ ์ถœ๋ฐœํ•ด์•ผ '๋น ์ ธ๋‚˜๊ฐ€๊ธฐ' ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์‹œํ—˜๋œ๋‹ค
if (cur.total() <= 0) { std::puts("FAIL start pose does not overlap the pillar"); ++fails; }
VehicleControl go; go.throttle = 1;
float maxx = 0; int blocked = 0;
for (int i = 0; i < 2000; ++i) {
Vehicle prev = car; car.step(go, 0.01f);
ContactInfo hit = vehicle_contact(car, og, road, false);
if (hit.total() > cur.total()) { car = prev; car.v = 0; ++blocked; } else cur = hit;
maxx = std::max(maxx, car.x + car.geom.front);
}
std::printf("front reached x=%.2f (wall at 10.0), blocked steps %d\n", maxx, blocked);
// ํ—ˆ์šฉ์น˜: obst_tol 0.1 + ์ƒ˜ํ”Œ ๊ฐ„๊ฒฉ 0.1
if (maxx > 10.25f || maxx < 9.8f) { std::puts("FAIL wall"); ++fails; }
// 2) ํ›„์ง„: ์ •์ง€ ์ƒํƒœ์—์„œ ๋ธŒ๋ ˆ์ดํฌ 5์ดˆ โ†’ -3 m/s ๊ทผ์ฒ˜, ์ˆ˜ m ์ด๋™
Vehicle r; VehicleControl back; back.brake = 1;
for (int i = 0; i < 500; ++i) r.step(back, 0.01f);
std::printf("reverse v=%.2f x=%.2f\n", r.v, r.x);
if (r.v > -2.9f || r.x > -5.0f) { std::puts("FAIL reverse"); ++fails; }
// 3) ํ›„์ง„ ์ค‘ ์œ„ ํ‚ค = ๋ธŒ๋ ˆ์ดํฌ โ†’ 0 ์—์„œ ๋ฉˆ์ท„๋‹ค๊ฐ€ ์ „์ง„
VehicleControl fwd; fwd.throttle = 1; int k = 0;
while (r.v < 0 && k < 300) { r.step(fwd, 0.01f); ++k; }
std::printf("stopped after %.2f s, v=%.2f\n", k * 0.01f, r.v);
if (k > 100) { std::puts("FAIL brake-from-reverse"); ++fails; }
// 4) ๊ธฐ๋ณธ ์น˜์ˆ˜ = Zoe
VehicleGeom g; std::printf("zoe geom rear %.2f front %.2f center %.2f\n", g.rear, g.front, g.center());
// drive.hpp ์˜ ๊ธฐ๋ณธ๊ฐ’ (Renault Zoe: ์ถ•๊ฑฐ 2.588 m, ๋’ค ์˜ค๋ฒ„ํ–‰ 0.65, ๊ธธ์ด 4.08 โ†’ ์•ž 3.43, ํญ 1.74)
if (std::fabs(g.wheelbase - 2.588f) > 1e-4f || std::fabs(g.rear + 0.65f) > 1e-4f ||
std::fabs(g.front - 3.43f) > 1e-4f || std::fabs(g.half_width - 0.87f) > 1e-4f ||
std::fabs(g.center() - 0.5f * (g.front + g.rear)) > 1e-5f) {
std::puts("FAIL zoe geom");
++fails;
}
// 5) ๋‹ค๋ฅธ ์ฐจ๋Ÿ‰(์žฅ๋ฉด ๊ฐ์ฒด ๋ฐ”๋‹ฅ ์‚ฌ๊ฐํ˜•): ์•ž ์ฐจ์— ๋ง‰ํžˆ๊ณ , 90ยฐ ๋Œ์•„๊ฐ„ ์ฐจ๋Š” ํญ ์ชฝ์—์„œ ๋ง‰ํžˆ๊ณ , ์˜† ์ฐจ์„  ์ฐจ๋Š” ์ง€๋‚˜๊ฐ„๋‹ค
auto drive_into = [&](const std::vector<Footprint>& others) {
Vehicle c; ObstacleGrid none; Drivable nr;
ContactInfo cc = vehicle_contact(c, none, nr, false, 0.15f, 0.1f, &others);
float mx = 0;
for (int i = 0; i < 1500; ++i) {
Vehicle prev = c; c.step(go, 0.01f);
ContactInfo h = vehicle_contact(c, none, nr, false, 0.15f, 0.1f, &others);
if (h.total() > cc.total()) { c = prev; c.v = 0; if (h.kind != Contact::Vehicle) return -1.0f; } else cc = h;
mx = std::max(mx, c.x + c.geom.front);
}
return mx;
};
float f1 = drive_into({Footprint{12, 0, 0, 2.0f, 1.0f}}); // ๋’ค๋ x = 10
float f2 = drive_into({Footprint{12, 0, 1.5707963f, 2.0f, 1.0f}}); // ์˜†์œผ๋กœ ์„  ์ฐจ: ๊ฐ€๊นŒ์šด ๋ฉด x = 11
float f3 = drive_into({Footprint{12, 3.0f, 0, 2.0f, 1.0f}}); // ์˜† ์ฐจ์„  (y = 3)
std::printf("vehicle ahead stop %.2f (10), sideways %.2f (11), next lane %.2f (free)\n", f1, f2, f3);
if (f1 > 10.25f || f1 < 9.8f) { std::puts("FAIL vehicle ahead"); ++fails; }
if (f2 > 11.25f || f2 < 10.8f) { std::puts("FAIL vehicle sideways"); ++fails; }
if (f3 < 30.0f) { std::puts("FAIL next lane blocked"); ++fails; }
// 6) ๋น„์Šค๋“ฌํžˆ(17ยฐ) ๋ฒฝ์— ๋ฐ•์•„ ๋ง‰ํžŒ ๋’ค ํ›„์ง„์œผ๋กœ ๋น ์ ธ๋‚˜์˜จ๋‹ค โ€” ์  ์ˆ˜๋งŒ ๋น„๊ตํ•˜๋ฉด ํ›„์ง„ ์Šคํ…๋งˆ๋‹ค +1 ๋กœ ๋ง‰ํ˜€ ๊ฐ‡ํ˜”๋‹ค (2026-10-09)
{
Vehicle c; c.x = 3.0f; c.y = 4.0f; c.yaw = 0.3f;
ContactInfo cc = vehicle_contact(c, og, road, false);
auto step_blocked = [&](const VehicleControl& ctl) {
Vehicle prev = c; c.step(ctl, 0.01f);
ContactInfo h = vehicle_contact(c, og, road, false);
float dir = c.v > 0 ? 1.0f : c.v < 0 ? -1.0f : 0.0f;
if (h.depth(2) > cc.depth(2) && !escaping(c, dir, cc.depth(2), og, road, false, 0.15f, 0.1f, 2)) {
c = prev; c.v = 0; return true;
}
cc = h; return false;
};
int blocked = 0;
for (int i = 0; i < 600; ++i) blocked += step_blocked(go);
float x_hit = c.x;
VehicleControl back; back.brake = 1;
for (int i = 0; i < 300; ++i) step_blocked(back);
std::printf("angled wall: stopped x=%.2f (blocked %d, contact %d), after 3 s reverse x=%.2f\n", x_hit, blocked, cc.total(), c.x);
if (blocked == 0 || x_hit + c.geom.front * std::cos(0.3f) > 10.4f) { std::puts("FAIL angled wall not blocking"); ++fails; }
if (c.x > x_hit - 1.0f) { std::puts("FAIL stuck after angled hit (reverse)"); ++fails; }
}
// 7) ์™ธํ†จ์ด ํ•œ ์นธ์ด ์ฐจ์ฒด ์™ผ์ชฝ ๊ฐ€์žฅ์ž๋ฆฌ๋งŒ ์Šค์นœ๋‹ค (์ƒ˜ํ”Œ 2์  = graze): ๋ง‰ํžˆ์ง€ ์•Š๊ณ  ์ง€๋‚˜๊ฐ„๋‹ค. graze 0 ์ด๋ฉด ๋ง‰ํžŒ๋‹ค
for (int gz : {2, 0}) {
Vehicle c; c.x = -16.0f; c.y = 4.28f; c.yaw = 0; // ์™ผ์ชฝ ๋ ์ƒ˜ํ”Œ y = 4.28 + 0.77 = 5.05 (์นธ 5.0~5.2), ๊ทธ ์•ˆ์ชฝ ์ค„ 4.95 ๋Š” ๋ฐ–
ContactInfo cc = vehicle_contact(c, og, road, false);
int blocked = 0;
for (int i = 0; i < 400; ++i) {
Vehicle prev = c; c.step(go, 0.01f);
ContactInfo h = vehicle_contact(c, og, road, false);
float dir = c.v > 0 ? 1.0f : -1.0f;
if (h.depth(gz) > cc.depth(gz) && !escaping(c, dir, cc.depth(gz), og, road, false, 0.15f, 0.1f, gz)) {
c = prev; c.v = 0; ++blocked;
} else cc = h;
}
std::printf("graze %d: lone cell beside the car, x=%.2f blocked %d\n", gz, c.x, blocked);
if (gz == 2 && (blocked || c.x < -5.0f)) { std::puts("FAIL grazing a lone cell blocks the car"); ++fails; }
if (gz == 0 && !blocked) { std::puts("FAIL test setup: the lone cell does not touch the car"); ++fails; }
}
return fails;
}