Problemas Conocidos
Fecha de análisis: 2026-06-30
Última actualización: 2026-06-30
Total: 13 issues — 1 crítico, 4 moderados, 8 leves
Resumen por Prioridades
| Prioridad |
Cantidad |
Issues |
| 🔴 Críticos |
1 |
SW-01 |
| 🟡 Moderados |
4 |
HW-01, HW-03, CT-01, CT-02, EG-02 |
| 🟢 Leves |
8 |
HW-02, SW-02, SW-03, EG-01, MV-01, MV-02, MV-03 |
| TOTAL |
13 |
|
Correcciones Recientes ✅
| ID |
Fecha |
Descripción |
| — |
— |
— |
🔴 Críticos
Software / Arquitectura
SW-01 — Buffer overflow en ISR de USART
| Archivos | setup.c:98 |
| Descripción | El buffer de comandos static char command[8] se llena sin comprobación de límites en command[i++]. Si se envían más de 7 caracteres antes del \n, el buffer desborda y corrompe la pila (variables locales, dirección de retorno de la ISR). |
| Impacto | Alto — Puede causar crashes, comportamiento errático, o vulnerabilidad de seguridad. |
| Mitigación | Ninguna. Se asume que el host no envía comandos largos. |
| Solución | Añadir if (i < sizeof(command) - 1) antes de almacenar cada carácter, o implementar un timeout que descarte comandos incompletos. |
🟡 Moderados
Hardware
HW-01 — Discrepancia SYSCLK: 84 MHz vs 72 MHz real
| Archivos | config.h:7, setup.c:13 |
| Descripción | config.h declara SYSCLK_FREQUENCY_HZ 84000000 y CYCLE_COUNTER_PER_MICROSECONDS 84, pero setup_clock() llama a rcc_clock_setup_in_hse_8mhz_out_72mhz() que configura el PLL a 72 MHz. Como resultado, delay_us() calcula mal los ciclos de espera: usa 84 ciclos/µs cuando debería usar 72. Los delays en microsegundos son un ~14% más cortos de lo esperado. |
| Impacto | Medio — Timing incorrecto en delay_us(). Las frecuencias de PWM y encoder se derivan del reloj real (72 MHz), por lo que los valores documentados en código (basados en 84 MHz) no coinciden. |
| Mitigación | Ninguna. El código funciona porque 72 MHz es la frecuencia real. |
| Solución | Cambiar SYSCLK_FREQUENCY_HZ a 72000000 y CYCLE_COUNTER_PER_MICROSECONDS a 72. |
HW-03 — Timer prescaler documentado para frecuencia incorrecta
| Archivos | setup.c:152 |
| Descripción | El prescaler de TIM1/TIM2 es 4 (división por 5). Con 72 MHz reales, la frecuencia PWM es 72 MHz / 5 / 512 = 28.125 kHz. Con 84 MHz (como declara config.h) sería 32.8 kHz. La documentación del código no aclara qué frecuencia se pretendía. 28 kHz es adecuado para motores BLDC pequeños (por encima del rango audible). |
| Impacto | Medio — La frecuencia real de PWM es correcta, pero la discrepancia con la documentación puede confundir. |
| Mitigación | Ninguna necesaria. |
| Solución | Documentar la frecuencia real de PWM y ajustar las constantes de config.h para que coincidan. |
Control PID
CT-01 — Término derivativo del PID comentado (solo PI)
| Archivos | motors.c:65, motors.c:86 |
| Descripción | MOTOR_SPEED_KD está definido como 0.0 y el cálculo del término derivativo (left_error - motor_left_last_error) * MOTOR_SPEED_KD está comentado. El controlador opera como PI en lugar de PID. En control de velocidad de motores, el término D puede ayudar a amortiguar oscilaciones y mejorar la respuesta a cambios bruscos de carga. |
| Impacto | Medio — Respuesta transitoria subóptima. Posibles overshoots en cambios bruscos de consigna. |
| Mitigación | El término integral proporciona cierta capacidad de reacción, pero sin amortiguamiento. |
| Solución | Experimentar con KD bajo (0.5-2.0) y evaluar si mejora la respuesta sin amplificar ruido del encoder. |
CT-02 — Anti-windup asimétrico: integrador sin límite superior
| Archivos | motors.c:75-80, motors.c:96-101 |
| Descripción | La condición if (motor_left_speed_factor < 100 || left_error < 0) permite acumular error integral cuando speed_factor == 100 y error < 0 (el motor va más rápido de lo pedido). Esto es correcto para reducir la integral cuando se necesita frenar. Pero cuando speed_factor == 100 y error > 0 se deja de acumular — correcto. Sin embargo, el integrador no tiene límite superior (solo inferior en 0) ni back-calculation, así que si se acumula un valor muy alto durante una aceleración, tarda en bajar cuando se reduce la consigna. |
| Impacto | Medio — Posible overshoot al reducir bruscamente la velocidad objetivo desde máxima velocidad. |
| Mitigación | El clamping inferior (nunca < 0) evita windup negativo. |
| Solución | Añadir clamping superior al integrador (ej. 100 / MOTOR_SPEED_KI) correspondiente al máximo speed factor alcanzable. |
Encoders
EG-02 — Posible overflow en acumulador fixed-point del filtro de velocidad
| Archivos | encoders.c:164-167 |
| Descripción | La variable left_speed_smooth_fp (int32_t) acumula valores en formato fixed-point con el filtro IIR: speed_smooth_fp = (speed_smooth_fp << 4) - speed_smooth_fp + speed. Con 3 bits fraccionales, el rango efectivo es ±2²⁸ ≈ ±268M ticks/s. Aunque improbable en condiciones normales, con ruido extremo o spikes de encoder el acumulador podría desbordar silenciosamente. |
| Impacto | Medio — Overflow silencioso causaría lecturas de velocidad incorrectas. Poco probable en operación normal. |
| Mitigación | Los valores reales de velocidad están muy por debajo del límite de overflow (MAX_RPM = 900 genera ~150 ticks/diff). |
| Solución | Añadir clamping del valor filtrado al rango esperado o usar int64_t para el acumulador fixed-point. |
🟢 Leves
Hardware
HW-02 — Includes ADC/DMA no utilizados
| Archivos | setup.h:7-8 |
| Descripción | setup.h incluye <libopencm3/stm32/adc.h> y <libopencm3/stm32/dma.h>, pero no se configura ningún ADC ni DMA en setup.c. Código muerto que probablemente se añadió para una funcionalidad futura (sensor de corriente o tensión de batería). |
| Impacto | Bajo — Solo afecta al tiempo de compilación y claridad del código. |
| Mitigación | Ninguna necesaria. |
| Solución | Eliminar los includes o implementar la lectura de ADC. |
Software / Arquitectura
SW-02 — motor_right_inited no declarado volatile
| Archivos | motors.c:23 |
| Descripción | motor_right_inited se modifica en set_motor_right_inited(), llamada desde la ISR exti15_10_isr(). Sin embargo, no está declarado volatile, a diferencia de otras variables como motor_left_speed. El compilador podría optimizar lecturas si el flag llegara a usarse en el main loop. |
| Impacto | Bajo — Actualmente el flag no se lee desde el main loop (ver SW-03). Si se implementara su lectura, podría fallar sin volatile. |
| Mitigación | El flag no se usa, así que el bug está latente. |
| Solución | Declarar static volatile int motor_right_inited. |
SW-03 — Flags de inicialización por motor nunca consultados
| Archivos | motors.c:114-120 |
| Descripción | set_motor_left_inited() y set_motor_right_inited() son llamadas desde las ISRs de índice Z para marcar cada motor como inicializado. Sin embargo, estos flags (motor_left_inited, motor_right_inited) no se leen en ninguna parte del código. motors_move() solo comprueba el flag global inited. |
| Impacto | Bajo — Funcionalidad incompleta: no se puede saber si un encoder ha recibido su pulso de índice. Permitiría distinguir entre "encoder sin referencia de cero" y "encoder listo". |
| Mitigación | El flag global inited es suficiente para la operación actual. |
| Solución | Usar los flags para condicionar el modo de operación (open-loop hasta recibir índice, closed-loop después) o eliminar el código muerto. |
Encoders
EG-01 — Offsets de calibración hardcodeados sin documentación
| Archivos | encoders.c:71, encoders.c:77 |
| Descripción | Los valores left_total_ticks = 22 y right_total_ticks = -61 son offsets de calibración que corrigen la diferencia angular entre el pulso de índice Z y el cero eléctrico del motor. Estos valores son específicos del montaje mecánico de cada motor en UltiBot y no son reutilizables. No hay documentación sobre cómo se obtuvieron ni cómo recalibrar para otro robot. |
| Impacto | Bajo — La funcionalidad es correcta para el hardware actual, pero la mantenibilidad es deficiente. |
| Mitigación | Ninguna. |
| Solución | Mover los offsets a #defines con nombres descriptivos en config.h (ej. ENCODER_LEFT_INDEX_OFFSET, ENCODER_RIGHT_INDEX_OFFSET) y documentar el procedimiento de calibración. |
Movimiento
MV-01 — Uso de round() (doble precisión) en lugar de roundf()
| Archivos | motors.c:34 |
| Descripción | En fill_lookup(), se usa abs(round(value)) donde round() opera en double. En un Cortex-M3 sin FPU de doble precisión, esto implica emulación por software, añadiendo latencia significativa durante la inicialización. La LUT se genera una sola vez al arrancar. |
| Impacto | Bajo — Solo afecta al tiempo de inicialización (~360 llamadas a round()). |
| Mitigación | Ninguna. La inicialización ocurre una sola vez. |
| Solución | Cambiar a roundf() (float) o precalcular la LUT offline e incluirla como array constante en el código. |
MV-02 — Orden de fases asimétrico entre motores sin documentar
| Archivos | motors.c:161-163, motors.c:184-186 |
| Descripción | El motor izquierdo asigna fases en orden C→B→A a los canales PWM (CCR1/CCR2/CCR3), mientras que el motor derecho usa A→C→B. Además, los offsets de fase para velocidad positiva son +270° (izquierdo) y +90° (derecho). Esta asimetría es intencionada por la orientación física de los motores en UltiBot, pero no está documentada ni comentada en el código. |
| Impacto | Bajo — Si se reutiliza este código con otra orientación de motores, el sentido de giro será incorrecto o el motor no arrancará. |
| Mitigación | Ninguna. |
| Solución | Añadir comentarios explicando la orientación esperada y la relación entre orden de fases y sentido de giro. |
MV-03 — motor_right_speed inconsistente en tipo vs motor_left_speed
| Archivos | motors.c:8, motors.c:19 |
| Descripción | motor_left_speed está declarado como static volatile int, mientras que motor_right_speed es static volatile int. Ambos son correctos, pero motor_right_inited es static int (no volatile, ver SW-02). La inconsistencia sugiere que los calificadores se aplicaron sin criterio uniforme. |
| Impacto | Bajo — No causa bugs actualmente, pero indica falta de revisión sistemática. |
| Mitigación | Ninguna. |
| Solución | Auditar y unificar los calificadores de todas las variables compartidas con ISRs. |
Documento generado el 2026-06-30 tras auditoría exhaustiva del código fuente. Ver también el resto de secciones de la documentación para contexto de cada subsistema.