66 * @date 2025-06
77 */
88
9- #include " navigation.hpp"
9+ #include " navigation.hpp"
10+
11+ extern lv_obj_t *turnDistLabel;
12+ extern lv_obj_t *turnImg;
13+
14+ LV_IMG_DECLARE (straight);
15+ LV_IMG_DECLARE (slleft);
16+ LV_IMG_DECLARE (slright);
17+ LV_IMG_DECLARE (tleft);
18+ LV_IMG_DECLARE (tright);
19+ LV_IMG_DECLARE (uleft);
20+ LV_IMG_DECLARE (uright);
21+ LV_IMG_DECLARE (finish);
1022
1123 /* *
1224 * @brief Find the closest track point index to the user's current position.
4254 * @return The index of the closest point in the track within the search window or full track if needed.
4355 */
4456
45-
4657int findClosestTrackPoint (float userLat, float userLon, const std::vector<wayPoint>& track, int lastIdx)
4758{
48- // int window = 20;
49- // int start = std::max(0, lastIdx - window);
50- // int end = std::min((int)track.size() - 1, lastIdx + window);
51-
52- // int closestIdx = lastIdx;
53- // float minDist = calcDist(userLat, userLon, track[lastIdx].lat, track[lastIdx].lon);
54- // for (int i = start; i <= end; ++i) {
55- // float d = calcDist(userLat, userLon, track[i].lat, track[i].lon);
56- // if (d < minDist) {
57- // minDist = d;
58- // closestIdx = i;
59- // }
60- // }
61- // // Prevent small backward jumps on the track
62- // if (closestIdx < lastIdx && (lastIdx - closestIdx) < 5) {
63- // closestIdx = lastIdx;
64- // }
65- // return closestIdx;
66-
67- int window = 20 ;
59+ int window = 50 ;
6860 int n = (int )track.size ();
6961 int start = std::max (0 , lastIdx - window);
7062 int end = std::min (n - 1 , lastIdx + window);
@@ -74,14 +66,17 @@ int findClosestTrackPoint(float userLat, float userLon, const std::vector<wayPoi
7466 int closestIdx = lastIdx;
7567
7668 // Si la distancia al último punto es grande, busca en todo el track
77- if (minDist > 2 * window) { // o un umbral en metros, ej: 50m
69+ if (minDist > 2 * window)
70+ { // o un umbral en metros, ej: 50m
7871 start = 0 ;
7972 end = n - 1 ;
8073 }
8174
82- for (int i = start; i <= end; ++i) {
75+ for (int i = start; i <= end; ++i)
76+ {
8377 float d = calcDist (userLat, userLon, track[i].lat , track[i].lon );
84- if (d < minDist) {
78+ if (d < minDist)
79+ {
8580 minDist = d;
8681 closestIdx = i;
8782 }
@@ -93,174 +88,111 @@ int findClosestTrackPoint(float userLat, float userLon, const std::vector<wayPoi
9388 return closestIdx;
9489}
9590
96- /* *
97- * @brief Enhanced turn-by-turn navigation logic with "soft curve" detection for S-shaped and gentle bends.
98- *
99- * This function updates the navigation state and determines which instructions or alerts should be shown to the user.
100- * - It supports off-track detection.
101- * - The distance to the next turn is updated and shown dynamically ("live") on every cycle.
102- * - Introduces a "soft curve" warning for angles between 15 and 60 degrees, so S-shaped and gentle curves are not interpreted as straight.
103- * - The warning flags (warnedPreTurn, warnedTurn) are kept for possible unique actions (sound, vibration), but visual messages are refreshed every cycle.
91+ /* *
92+ * @brief Navegación simplificada: muestra solo el siguiente evento (recto, curva suave o fuerte) y únicamente lo avisa cuando quedan warnDist metros o menos.
10493 *
105- * @param userLat Current user latitude.
106- * @param userLon Current user longitude.
107- * @param userHeading Current heading of the user (degrees).
108- * @param speed_kmh Current user speed in km/h.
109- * @param track Vector of wayPoints representing the GPX track.
110- * @param turns Vector of TurnPoint, each representing a detected turn on the track.
111- * @param state Navigation state struct, updated persistently across function calls.
94+ * @param userLat Latitud del usuario.
95+ * @param userLon Longitud del usuario.
96+ * @param userHeading Rumbo del usuario (grados).
97+ * @param speed_kmh Velocidad del usuario (km/h).
98+ * @param track Vector de wayPoints del track GPX.
99+ * @param turns Vector de TurnPoint (giros detectados).
100+ * @param state Estado de navegación.
101+ * @param minAngleForCurve Umbral angular mínimo para considerar curva relevante (por defecto 15°).
102+ * @param warnDist Distancia (en metros) para mostrar el aviso del evento (por defecto 100).
112103 */
113104void updateNavigation (
114105 float userLat, float userLon, float userHeading, float speed_kmh,
115106 const std::vector<wayPoint>& track,
116107 const std::vector<TurnPoint>& turns,
117- NavState& state
118- ) {
119- float lookahead = 1000.0 ; // meters: how far ahead to consider upcoming turns
120- float umbralSeguirRecto = 200.0 ; // meters to show "go straight" or "soft curve"
121- float preWarnDist = speed_kmh > 11.0 ? 150.0 : 80.0 ; // meters for pre-turn warning
122- float warnDist = 50.0 ; // meters for final turn warning
123- float minAngleForCurve = 15.0 ; // degrees: minimum angle to consider as "curva suave"
108+ NavState& state,
109+ float minAngleForCurve,
110+ float warnDist
111+ )
112+ {
113+ const float minTurnDist = 5 .0f ; // Umbral para saltar turnpoints ya pasados o justo encima
124114
125115 int closestIdx = findClosestTrackPoint (userLat, userLon, track, state.lastTrackIdx );
126-
127116 float distToTrack = calcDist (userLat, userLon, track[closestIdx].lat , track[closestIdx].lon );
128117 if (distToTrack > 30.0 )
129118 {
130- // Pseudocode: show "off track" bitmap
131- // mostrarBitmap(LVGL_BITMAP_FUERA_RUTA);
132119 log_i (" ¡Fuera de ruta! Reincorpórate al track" );
133- state.warnedStraight = false ;
134- state.warnedTurn = false ;
135- state.warnedPreTurn = false ;
120+ state.lastTrackIdx = closestIdx;
136121 return ;
137122 }
138123
139- // --- Find the most relevant next turn within lookahead ---
140- int relevantTurnIdx = -1 ;
141- float distanceToRelevantTurn = std::numeric_limits<float >::max ();
124+ // Avanza el índice de turnpoint si ya lo hemos pasado (por índice)
125+ while (state.nextTurnIdx < (int )turns.size () && turns[state.nextTurnIdx ].idx <= closestIdx)
126+ state.nextTurnIdx ++;
127+
128+ // Busca el siguiente evento relevante (el primero con distancia suficiente)
129+ int nextEventIdx = -1 ;
130+ float distanceToNextEvent = std::numeric_limits<float >::max ();
142131 float abs_angle = 0.0 ;
143132 bool derecha = false ;
144133
145- // Scan all upcoming turns
146- for ( int i = state. nextTurnIdx ; i < ( int )turns. size (); ++i) {
134+ for ( int i = state. nextTurnIdx ; i < ( int ) turns. size (); ++i)
135+ {
147136 float turnLat = track[turns[i].idx ].lat ;
148137 float turnLon = track[turns[i].idx ].lon ;
149138 float distanceToTurn = calcDist (userLat, userLon, turnLat, turnLon);
150-
151- if (distanceToTurn < distanceToRelevantTurn) {
152- distanceToRelevantTurn = distanceToTurn ;
153- relevantTurnIdx = i;
154- abs_angle = fabs (turns[i]. angle ) ;
155- derecha = (turns[i]. angle > 0 ) ;
156- }
157- // stop search if the next turn is outside the lookahead window
158- if (distanceToTurn > lookahead) break ;
139+ // Si el evento está “demasiado cerca” (o ya pasado), sáltalo y sigue buscando
140+ if (distanceToTurn < minTurnDist)
141+ continue ;
142+
143+ distanceToNextEvent = distanceToTurn ;
144+ nextEventIdx = i ;
145+ abs_angle = fabs (turns[i]. angle );
146+ derecha = (turns[i]. angle > 0 );
147+ break ; // Encontrado el siguiente relevante, sal del bucle
159148 }
160149
161- // If no relevant turn in lookahead: show recto to the next turn (even if it is far)
162- if (relevantTurnIdx == -1 ) {
163- if (!turns.empty ()) {
164- // Still show "seguir recto" to the very next turn, even if > lookahead
165- float turnLat = track[turns[state.nextTurnIdx ].idx ].lat ;
166- float turnLon = track[turns[state.nextTurnIdx ].idx ].lon ;
167- float distanceToTurn = calcDist (userLat, userLon, turnLat, turnLon);
168- log_i (" Sigue recto durante %d m" , (int )distanceToTurn);
169- } else {
170- log_i (" Fin de ruta o sin más giros." );
171- }
172- state.warnedStraight = false ;
173- state.warnedTurn = false ;
174- state.warnedPreTurn = false ;
175- state.lastTrackIdx = closestIdx;
176- return ;
177- }
178-
179- // Update state.nextTurnIdx if we've passed a turn
180- while (state.nextTurnIdx < (int )turns.size () && turns[state.nextTurnIdx ].idx <= closestIdx)
181- state.nextTurnIdx ++;
182-
183- // --- Nueva lógica de avisos para el giro relevante ---
184- if (distanceToRelevantTurn > umbralSeguirRecto)
150+ // Si no queda ningún evento relevante
151+ if (nextEventIdx == -1 )
185152 {
186- if (abs_angle > minAngleForCurve && abs_angle < 60 ) {
187- // Soft curve
188- if (derecha)
189- log_i (" Curva suave a la DERECHA en %d m" , (int )distanceToRelevantTurn);
190- else
191- log_i (" Curva suave a la IZQUIERDA en %d m" , (int )distanceToRelevantTurn);
192- } else {
193- // Go straight
194- log_i (" Sigue recto durante %d m" , (int )distanceToRelevantTurn);
195- }
196- state.warnedStraight = true ;
197- state.warnedPreTurn = false ;
198- state.warnedTurn = false ;
153+ lv_img_set_src (turnImg, &finish);
199154 state.lastTrackIdx = closestIdx;
200155 return ;
201156 }
202157
203- // --- Pre-turn warning: dynamically update distance ---
204- if (distanceToRelevantTurn < preWarnDist && distanceToRelevantTurn > warnDist) {
205- if (abs_angle < 60 && abs_angle >= minAngleForCurve) {
206- if (derecha)
207- log_i (" Preaviso: curva suave a la DERECHA en %d m" , (int )distanceToRelevantTurn);
208- else
209- log_i (" Preaviso: curva suave a la IZQUIERDA en %d m" , (int )distanceToRelevantTurn);
210- } else if (abs_angle < 60 ) {
158+ // Mostrar solo cuando falten <= warnDist metros
159+ if (distanceToNextEvent <= warnDist)
160+ {
161+ if (abs_angle >= minAngleForCurve && abs_angle < 60 )
162+ {
211163 if (derecha)
212- log_i ( " Preaviso: giro leve a la DERECHA en %d m " , ( int )distanceToRelevantTurn );
164+ lv_img_set_src (turnImg, &slright );
213165 else
214- log_i ( " Preaviso: giro leve a la IZQUIERDA en %d m " , ( int )distanceToRelevantTurn );
166+ lv_img_set_src (turnImg, &slleft );
215167 }
216- else if (abs_angle < 120 ) {
168+ else if (abs_angle >= 60 )
169+ {
217170 if (derecha)
218- log_i ( " Preaviso: giro medio a la DERECHA en %d m " , ( int )distanceToRelevantTurn );
171+ lv_img_set_src (turnImg, &tright );
219172 else
220- log_i (" Preaviso: giro medio a la IZQUIERDA en %d m" , (int )distanceToRelevantTurn);
173+ lv_img_set_src (turnImg, &tleft);
174+
221175 }
222- else {
223- if (derecha)
224- log_i (" Preaviso: giro cerrado a la DERECHA en %d m" , (int )distanceToRelevantTurn);
225- else
226- log_i (" Preaviso: giro cerrado a la IZQUIERDA en %d m" , (int )distanceToRelevantTurn);
176+ // else if (abs_angle > 3.0)
177+ // {
178+ // log_i("Desvío leve a la %s en %d m (%.1f° en idx %d)",
179+ // derecha ? "DERECHA" : "IZQUIERDA",
180+ // (int)distanceToNextEvent,
181+ // abs_angle,
182+ // turns[nextEventIdx].idx
183+ // );
184+ // }
185+ else
186+ {
187+ lv_img_set_src (turnImg, &straight);
227188 }
228- state.warnedPreTurn = true ;
229- state.warnedStraight = false ;
230189 }
231- // --- Final turn warning: dynamically update distance ---
232- if (distanceToRelevantTurn <= warnDist) {
233- if (abs_angle < 60 && abs_angle >= minAngleForCurve) {
234- if (derecha)
235- log_i (" ¡Curva suave a la DERECHA en %d m!" , (int )distanceToRelevantTurn);
236- else
237- log_i (" ¡Curva suave a la IZQUIERDA en %d m!" , (int )distanceToRelevantTurn);
238- } else if (abs_angle < 60 ) {
239- if (derecha)
240- log_i (" ¡Giro leve a la DERECHA en %d m!" , (int )distanceToRelevantTurn);
241- else
242- log_i (" ¡Giro leve a la IZQUIERDA en %d m!" , (int )distanceToRelevantTurn);
243- }
244- else if (abs_angle < 120 ) {
245- if (derecha)
246- log_i (" ¡Giro medio a la DERECHA en %d m!" , (int )distanceToRelevantTurn);
247- else
248- log_i (" ¡Giro medio a la IZQUIERDA en %d m!" , (int )distanceToRelevantTurn);
249- }
250- else {
251- if (derecha)
252- log_i (" ¡Giro cerrado a la DERECHA en %d m!" , (int )distanceToRelevantTurn);
253- else
254- log_i (" ¡Giro cerrado a la IZQUIERDA en %d m!" , (int )distanceToRelevantTurn);
255- }
256- state.warnedTurn = true ;
257- state.warnedStraight = false ;
258- }
259- // Reset warnings if moving away from turn
260- if (distanceToRelevantTurn > preWarnDist)
190+ else
261191 {
262- state.warnedTurn = false ;
263- state.warnedPreTurn = false ;
192+ lv_img_set_src (turnImg, &straight);
264193 }
194+
195+ lv_label_set_text_fmt (turnDistLabel, " %4d" , (int )distanceToNextEvent);
196+
265197 state.lastTrackIdx = closestIdx;
266198}
0 commit comments