/*************************************************************************** file : recovery4.cpp created : September 2026 copyright : (C) 2026 by Bernhard Wymann email : berniw@bluewin.ch ***************************************************************************/ /* This program is free software; you can redistribute it and/or modify it * under the GNU General Public License, version 2 or (at your option) any * later version. Distributed WITHOUT ANY WARRANTY, including MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See . */ #include #include #include #include "recovery4.h" static constexpr double STUCK_DELAY = 2.0; static constexpr double SLOW_SPEED = 1.0; static constexpr double ENTRY_ANGLE = 15.0; static constexpr double EXIT_ANGLE = 10.0; static constexpr double NEAR_BARRIER = 0.25; static constexpr double TURNING_SPACE = 0.8; BarrierClearance measureClearance(tCarElt* car) { BarrierClearance clearance; for (int i = 0; i < 4; ++i) { tTrkLocPos corner{}; RtTrackGlobal2Local(car->_trkPos.seg, car->_corner_x(i), car->_corner_y(i), &corner, TR_LPOS_TRACK); clearance.left = std::min(clearance.left, double(corner.toLeft)); clearance.right = std::min(clearance.right, double(corner.toRight)); const double space = std::min(corner.toLeft, corner.toRight); if (i == FRNT_LFT || i == FRNT_RGT) { clearance.front = std::min(clearance.front, space); } else { clearance.rear = std::min(clearance.rear, space); } } return clearance; } static tdble limitedSteering(double value) { return static_cast(std::max(-1.0, std::min(1.0, value))); } void moveSlowly(tCarElt* car, int direction, double steer) { car->ctrl = tCarCtrl{}; if (direction * car->_speed_x < -0.3) { car->ctrl.gear = car->_gear; car->ctrl.brakeCmd = 0.8f; return; } car->ctrl.steer = limitedSteering(steer); car->ctrl.gear = direction; if (std::hypot(car->_speed_x, car->_speed_y) > 3.0) { car->ctrl.brakeCmd = 0.3f; } else { car->ctrl.accelCmd = 0.3f; } } void Recovery::reset(double time) { mode = Mode::Driving; stuckTime = 0.0; previousTime = time; } bool Recovery::driveIfNeeded(tCarElt* car, tSituation* situation) { const double elapsed = std::max(0.0, situation->currentTime - previousTime); previousTime = situation->currentTime; double angle = RtTrackSideTgAngleL(&car->_trkPos) - car->_yaw; NORM_PI_PI(angle); const BarrierClearance clearance = measureClearance(car); const double speed = std::hypot(car->_speed_x, car->_speed_y); if (mode == Mode::Driving) { const bool misplaced = std::fabs(angle) > ENTRY_ANGLE * PI / 180.0 || clearance.minimum() < NEAR_BARRIER; if (situation->currentTime >= 0.0 && speed < SLOW_SPEED && misplaced) { stuckTime += elapsed; } else { stuckTime = 0.0; } if (stuckTime >= STUCK_DELAY) { const bool leftBarrier = clearance.left < clearance.right; const bool pointsOut = leftBarrier ? std::sin(angle) < 0.0 : std::sin(angle) > 0.0; mode = pointsOut ? Mode::Backing : Mode::MovingForward; } } if (mode != Mode::Driving) { if (mode == Mode::Backing && clearance.rear < 0.1 && clearance.front > clearance.rear + 0.2) { mode = Mode::MovingForward; } else if (mode == Mode::MovingForward && clearance.front < 0.1 && clearance.rear > clearance.front + 0.2) { mode = Mode::Backing; } const bool roomToTurn = clearance.minimum() >= TURNING_SPACE; const bool aligned = std::fabs(angle) < EXIT_ANGLE * PI / 180.0; if (roomToTurn && aligned) { mode = Mode::MovingForward; if (car->_speed_x >= -0.3) { mode = Mode::Driving; stuckTime = 0.0; } } if (mode != Mode::Driving) { int direction = mode == Mode::Backing ? -1 : 1; double steer = direction * angle / car->_steerLock; if (!roomToTurn) { steer = 0.0; if (std::fabs(std::sin(angle)) < 0.15) { const bool leftBarrier = clearance.left < clearance.right; const bool reverseSeparates = leftBarrier ? std::sin(angle) < -0.01 : std::sin(angle) > 0.01; if (mode == Mode::Backing && !reverseSeparates) { mode = Mode::MovingForward; } if (mode == Mode::MovingForward) { const double away = leftBarrier ? -0.1 : 0.1; steer = std::cos(angle) >= 0.0 ? away : -away; } } direction = mode == Mode::Backing ? -1 : 1; } moveSlowly(car, direction, steer); return true; } } return false; }