%% Referencias de código (no se renderizan en el PNG, solo para mantenimiento futuro) %% Fuente: src/python/src/navigation/planning/sign_router/ %% selección: SignRouter._active_sign_candidates() %% tabla de reglas por tramo/sentido: routing.py::ROUTING_TABLE %% consulta de la regla: routing.py::pass_side_lateral_axis() %% planificador de carril (LA RUTA QUE SE EJECUTA): planning/sign_lane.py::apply_sign_lanes() %% deformación por waypoint (SUPRIMIDA en config): sign_router/deformation.py %% anclaje opcional a la altura de la señal: SignRouter._pin_depth() %% - %% CORREGIDO 2026-09-10. Dos errores de fondo en la versión anterior: %% - %% 1) LA REGLA NO ES ABSOLUTA. Este diagrama decía "rojo siempre por afuera, %% verde siempre por adentro, sin importar el sentido". Es al revés: la regla %% (WRO 2026 9.19) es RELATIVA AL SENTIDO DE MARCHA -- el vehículo pasa a su %% PROPIA DERECHA de un pilar rojo y a su PROPIA IZQUIERDA de uno verde. Las %% 4 filas CLOCKWISE de ROUTING_TABLE son la NEGACIÓN de sus pares %% COUNTERCLOCKWISE, precisamente por eso. La tabla fue absoluta entre %% 2026-07-05 y 2026-09-03 (correcta en antihorario, al revés en TODA ronda %% horaria) y el error quedó oculto porque scenario_simulator/scoring.py %% juzgaba con la misma convención que el router conducía. Todo conteo de %% pass-side anterior a 2026-09-03 está medido con la regla equivocada. %% Corolario: sin dirección asentada la regla no es evaluable en absoluto %% (pass_side_lateral_axis devuelve None) -- ver esquiva-generica.mmd. %% - %% 2) LO QUE SE EJECUTA ES EL CARRIL, NO LA DEFORMACIÓN. El diagrama dibujaba %% _apply_deformation() como el mecanismo. En la config que embarca %% (src/config/navigation/signs/sign_router.toml) sign_lane_planner = true y %% sign_lane_suppress_deform = true, así que quien mueve la trayectoria es %% apply_sign_lanes(): un carril lateral con meseta plana y rampas, no un %% empujón de un único punto de paso. %% - %% Constantes (src/config/navigation/signs/sign_router.toml): %% activation_dist_m = 1.40 / passed_dist_m = 1.60 -- ventana de la maniobra %% sign_lane_ramp_m = 0.9 / sign_lane_hold_m = 0.25 -- forma del carril %% sign_lane_corner_entry_m = 0.5 -- arco de curva que el carril puede tomar %% sign_clearance_margin_m = 0.10 -- margen sobre semianchos chasis+señal %% commit_hysteresis = true -- una vez comprometida, se mantiene ESA señal %% - %% ADVERTENCIA DE ALCANCE (medido 2026-09-09, sobre bag de hardware): el carril %% está dimensionado para 1.40 m de anticipación y NUNCA la recibe. La cámara %% ve la señal a 0.66 m y el router se compromete a 0.38 m, así que la maniobra %% se ejecuta con una fracción del recorrido para el que fue diseñada. No es un %% fallo de la regla ni del carril: es falta de distancia. %% - %% Diagrama en TD (vertical) a propósito -- en LR la cadena de nodos quedaba %% demasiado ancha y el texto se veía borroso al escalar el PNG. %% El nodo con borde punteado (Pin) marca un paso opcional, no obligatorio. flowchart TD Sign["La cámara detecta
una señal de tránsito"] --> Active["Se elige la señal activa
más cercana que el robot
aún no ha pasado"] Active --> Commit["Una vez elegida, se mantiene ESA
señal hasta superarla, en vez de
recalcular la más cercana cada tick"] Commit --> Dir{"¿Está asentado el
sentido de la vuelta?"} Dir -- "No" --> NoRule(["La regla de paso NO es evaluable.
Se esquiva como obstáculo genérico
(ver esquiva-generica.mmd)"]) Dir -- "Sí" --> Lookup["Busca en la tabla de reglas
el tramo de la pista y el
sentido de la vuelta actuales"] Lookup --> Color{"¿De qué
color es?"} Color -- "ROJA" --> Right["Pasar por la DERECHA
del robot"] Color -- "VERDE" --> Left["Pasar por la IZQUIERDA
del robot"] Right --> Note>"La regla se define respecto al ROBOT,
no a la pista. Antihorario: su derecha
es la pared exterior. Horario: su derecha
es el cuadro central. Por eso la tabla
tiene filas opuestas para cada sentido"] Left --> Note Note --> Lane["Traza un CARRIL lateral hacia ese lado:
meseta plana de 0.25 m a la altura de la
señal, con rampas de 0.9 m a cada lado
que vuelven a la línea central"] Lane --> Taper["El carril se activa de forma progresiva
entre 1.40 m y 1.60 m de distancia,
para evitar cambios bruscos de dirección"] Taper --> Pin["Ancla el punto justo
a la altura de la señal"]:::optional Pin --> Steer["El carril se usa como
objetivo de dirección"] classDef optional stroke-dasharray: 5 5