Tutorial · Principiante · 30 min
Por qué tu robot se reinicia cuando arrancan los motores
El reinicio que parece un fallo de software es de alimentación. Resistencia interna, presupuesto de corriente y el hueco que el detector de brown-out no cubre.
Introducción
El robot funciona en el banco. Lo pones en el suelo, los motores arrancan y todo se detiene: el monitor serie se reinicia desde el principio, la secuencia de LED empieza de nuevo y lo que el robot estaba haciendo se olvida.
El primer instinto de casi todo el mundo es buscar en el código. No hay nada en el código.
Lo que pasó es que arrancar los motores exigió más corriente de la que la batería podía entregar sin que cayera su tensión, la alimentación bajó por debajo de lo que necesita el microcontrolador y la placa se reinició. Esto es un brown-out, y es el fallo más común en un primer robot: este sitio lo dice en la ruta de control de motores, en casi cada página de componente y en la lista de solución de problemas de la mitad de sus proyectos. Esta es la página que lo explica.
Primero, establece que es un reinicio y no un cuelgue
Necesitan arreglos distintos, y se ven idénticos desde el otro lado de la sala.
Pon una línea distintiva al principio de setup():
void setup() {
Serial.begin(115200);
Serial.println(F("---- BOOT ----"));
}
Ahora haz funcionar el robot hasta que falle y mira el monitor:
---- BOOT ----aparece de nuevo → la placa se reinició. Es alimentación. Sigue leyendo.- La salida se detiene o repite una línea para siempre → la placa está atascada en un bucle o se ha colgado. Eso es un problema de código, y esta es la página equivocada.
- La salida se convierte en caracteres basura → la alimentación está cayendo pero no lo suficiente para reiniciar. También es alimentación, y aplican los mismos arreglos.
En placas AVR puedes ir un paso más allá y preguntar al chip por qué se reinició. MCUSR guarda la razón, pero main() se ejecuta mucho después de cuando habría que leerlo, así que captúralo en una función .init3 que se ejecuta primero:
uint8_t resetFlags __attribute__((section(".noinit")));
void captureReset(void) __attribute__((naked, used, section(".init3")));
void captureReset(void) {
resetFlags = MCUSR;
MCUSR = 0;
}
void setup() {
Serial.begin(115200);
if (resetFlags & _BV(BORF)) Serial.println(F("cause: BROWN-OUT"));
if (resetFlags & _BV(EXTRF)) Serial.println(F("cause: reset pin"));
if (resetFlags & _BV(PORF)) Serial.println(F("cause: power-on"));
if (resetFlags & _BV(WDRF)) Serial.println(F("cause: watchdog"));
}
Una advertencia sincera: un Uno con Optiboot hace que su gestor de arranque (bootloader) lea MCUSR y lo borre antes de que tu código lo vea, guardando el valor en el registro r2. Si todos los indicadores se leen como cero en tu placa, esa es la razón: recurre a la prueba de ---- BOOT ----, que no requiere nada y nunca miente.
Por qué se colapsa la tensión
Una batería no es una fuente de tensión ideal. Es una fuente de tensión en serie con una resistencia, y esa resistencia es lo que decide si tu robot funciona o no:
V_terminal = V_circuito_abierto − I × R_interna
R_interna es una propiedad de la química y del tamaño de la celda, y varía enormemente entre los distintos paquetes de baterías que guardas en el mismo cajón.
| Paquete | Circuito abierto | R_interna | En un pico de 2 A |
|---|---|---|---|
| 2×18650 Li-ion | 7,4 V | ≈ 0,10 Ω | 7,20 V |
| 4×AA NiMH | 4,8 V | ≈ 0,12 Ω | 4,56 V |
| 4×AA alcalinas | 6,0 V | ≈ 0,80 Ω | 4,40 V |
| Bloque 9 V PP3 | 9,0 V | ≈ 2,0 Ω | 5,00 V, y cayendo |
De esto se desprenden tres conclusiones que valen más que las cifras:
El bloque de nueve voltios es la peor batería que puedes poner en un robot. Tiene la tensión más alta impresa en su carcasa y apenas 500 mAh de capacidad tras dos ohmios de resistencia interna. Es una batería para un detector de humo.
Las pilas alcalinas no son rígidas. Su resistencia interna es aproximadamente seis veces la de una celda de NiMH, y aumenta a medida que se descargan: así que el robot funciona durante veinte minutos y luego comienza a reiniciarse, lo que parece un fallo intermitente pero es simplemente una batería agotada comportándose exactamente como debe.
Las recargables ganan en lo que realmente importa. NiMH y Li-ion son las químicas estándar en robótica no por ser recargables, sino porque sostienen su tensión bajo carga.
Presupuesta la corriente antes de elegir la batería
Suma lo que consume el robot, dos veces: una para lo que usa normalmente y otra para el peor instante.
| Componente | En marcha | Peor caso |
|---|---|---|
| Placa Arduino Uno | 45 mA | 45 mA |
| Motorreductor TT ×2 | 400 mA | 2000 mA (ambos bloqueados) |
| Matriz reflectiva IR | 100 mA | 100 mA |
| HC-SR04 | 15 mA | 15 mA |
| Servo SG90 | 150 mA | 700 mA (bloqueado) |
| Bluetooth HC-05 | 30 mA | 40 mA |
| ESP32 (Wi-Fi) | 80 mA | 250 mA (ráfaga de transmisión) |
Un seguidor de línea común —Uno, dos motores, matriz IR— consume unos 545 mA en marcha y 2,15 A en el peor instante. El peor instante suele ser breve; la excepción es un robot empujando al límite de su tracción, que se mantiene en corriente de bloqueo mientras dura el empuje. Dimensiona la batería según el primer número y la caída de tensión según el segundo, porque responden a preguntas distintas:
autonomía ≈ capacidad / corriente en marcha 2000 mAh / 545 mA ≈ 3,7 h ideal
caída de tensión = corriente en peor caso × R_interna
Espera una autonomía real de aproximadamente dos tercios de esa cifra. No descargarás la batería hasta cero, los picos demandan más que su promedio y las clasificaciones de capacidad se miden con tasas de descarga suaves.
El hueco que el detector de caídas de tensión (brown-out) no cubre
Cada AVR incluye un detector de brown-out que mantiene el chip en reset por debajo de una tensión determinada. En un Arduino Uno ese fusible viene configurado de fábrica a 2,7 V.
Un ATmega328P a 16 MHz no está especificado para funcionar a 2,7 V. Su clasificación de velocidad según la hoja de datos va de 4 MHz a 1,8 V hasta 20 MHz a 4,5 V, e interpolando a 16 MHz se obtiene un mínimo de aproximadamente 3,8 V.
Esto explica el síntoma que más cuesta creer: un robot que no se reinicia de forma limpia sino que simplemente se comporta de forma anómala cuando los motores giran. Variables corrompidas, un servo que da tirones, un sensor I²C que devuelve basura, una máquina de estados en un estado al que no tiene transición. En esa banda el microcontrolador ejecuta instrucciones fuera de sus condiciones garantizadas de operación, y “garantizadas” es precisamente la palabra clave.
Por tanto, no tomes “no se ha reiniciado” como prueba de que la alimentación está bien.
Un paquete de baterías, dos rieles de alimentación
La solución no consiste en poner dos baterías. Consiste en un único paquete alimentando dos vías separadas.
- La corriente del motor va directamente desde la batería al terminal de alimentación de motor del controlador: el
+12Vde un L298N, elVMde un TB6612FNG. Jamás pasa por el microcontrolador. - La corriente de la lógica procede de una línea regulada de 5 V: el regulador integrado del controlador de motores, un módulo reductor (buck) independiente o USB mientras estás desarrollando.
- Las masas (GND) deben estar unidas. Cada señal entre la placa y el puente H es una tensión medida respecto a tierra; sin una referencia compartida, los pines de dirección carecen de sentido. Este es el segundo fallo de cableado más común después del primero.
Nunca alimentes motores a través del pin de 5 V del Arduino o de su regulador del conector jack. El regulador del Uno es un pequeño componente lineal que disipa la diferencia entre entrada y salida como calor: a 7,4 V de entrada, 5 V de salida y 500 mA, eso representa (7,4 − 5) × 0,5 = 1,2 W en un encapsulado sin disipador. Se calentará, luego se apagará por protección térmica, y el robot se reiniciará por una razón ajena a la batería.
Lo que un condensador realmente soluciona
El consejo habitual es colocar un gran condensador electrolítico en paralelo con la alimentación del motor. El consejo es acertado, la razón que suele darse está equivocada, y el cálculo lo demuestra:
ΔV = I × Δt / C
Un condensador de 1000 µF obligado a sostener un pico de arranque de 2 A durante 10 ms sufriría una caída de 2 × 0,010 / 0,001 = 20 V. Es físicamente incapaz de hacer ese trabajo. Un condensador no sostiene el pico de arranque del motor; solo una batería con menor resistencia interna puede hacerlo.
Lo que sí amortigua son los fenómenos de alta frecuencia. A una frecuencia de conmutación PWM de 8 kHz el periodo es de 125 µs, por lo que el mismo condensador experimenta 2 × 0,000125 / 0,001 = 0,25 V de rizado: un trabajo que realiza con solvencia. También absorbe los picos inductivos de conmutación que los motores de escobillas devuelven a la línea de alimentación.
Coloca uno —de 470 a 1000 µF en los bornes de alimentación de motor, más un cerámico de 0,1 µF cerca del controlador— y cuenta con que limpie el ruido y estabilice sensores erráticos. No esperes que solucione un reinicio por caída sostenida. Si un condensador resolvió tu reinicio, la batería estaba en el límite crítico y has ganado un margen minúsculo.
Mídelo en lugar de especular
Diez minutos con un multímetro superan a una tarde entera de conjeturas:
- Pon el multímetro en voltios de CC y conéctalo en los bornes de la batería, no en el Arduino.
- Anota la tensión en reposo.
- Arranca los motores, idealmente bajo carga real con el robot en el suelo.
- Observa el valor medido.
Una caída de más de unas pocas décimas de voltio es tu respuesta. Para deducir R_interna a partir de ello, divide: un paquete de 6,0 V que cae a 4,4 V consumiendo unos 2 A arroja (6,0 − 4,4) / 2 = 0,8 Ω.
Repite la medición en el riel de 5 V mientras arrancan los motores. Esa es la tensión que el microcontrolador experimenta realmente, y si desciende hacia 3,8 V habrás encontrado el fallo sin necesidad de osciloscopio.
Los multímetros económicos promedian con demasiada lentitud para captar el fondo exacto de un bajón de pocos milisegundos, así que considera optimista lo que leas. La caída real es al menos así de pronunciada.
Soluciones, de menor a mayor coste
- Deja de alimentar motores a través de la placa. Gratis, y soluciona directamente una gran proporción de los problemas.
- Cambia el paquete de baterías. Alcalinas o 9 V → NiMH o 18650. Suele ser la solución completa.
- Une las masas. Gratis, y su ausencia causa fallos más desconcertantes que un brown-out.
- Añade el condensador de desacoplo de gran capacidad. Para eliminar ruido e irregularidades de sensores, no para evitar reinicios por colapso.
- Aplica una rampa de aceleración a los motores. Un perfil de movimiento reparte la corriente de arranque en el tiempo en lugar de exigirla de golpe: el mismo código que evita que las ruedas patinen.
- Dimensiona los motores adecuadamente. Si a un motor se le exige más par del debido, consumirá más corriente de la debida; el cálculo para dimensionar motorreductores precede a este dilema.
- Separa la regulación. Un pequeño convertidor reductor (buck) para el riel lógico lo aísla por completo de las fluctuaciones del motor.
Una vez saneada la línea de potencia, medirla por software es el siguiente paso: y leer una tensión con precisión es más engañoso de lo que parece, porque la referencia por defecto del ADC es la propia línea de alimentación.
Cuando algo sale mal
| Síntoma | Causa habitual |
|---|---|
| La salida serie se reinicia desde el principio al arrancar los motores | Brown-out (caída de tensión); revisa la batería antes del código |
| Funciona con USB, falla con la batería | La batería no entrega la sobrecorriente, el puerto USB sí |
| Funciona durante veinte minutos, luego se reinicia continuamente | La resistencia interna de las alcalinas sube al descargarse |
| Comportamiento errático pero sin un reinicio limpio | Alimentación en la banda de 2,7–3,8 V; fuera de norma sin llegar al corte |
| Los sensores devuelven valores absurdos solo al desplazarse | Ruido en la alimentación; condensador de desacoplo y rieles independientes |
| Los pines de dirección parecen no responder | Falta de masa común entre placa y controlador de motores |
| El regulador quema al tocarlo | Lógica alimentada mediante un regulador lineal con excesiva tensión de entrada |
| Un condensador lo arregló, pero el fallo reapareció | Batería al límite; el condensador dio milisegundos de margen, no amperios |
La alimentación es la capa que sostiene a todas las demás en un robot, razón por la cual una deficiencia aquí simula fallos en cualquier otra parte. Cuando empiece a suceder algo inexplicable en el momento justo en que los motores entran en acción, mide la batería primero: cuesta diez minutos y acierta con mayor frecuencia que cualquier otra suposición.
Explora el grafo
Forma parte de estos montajes
Proyectos y rutas de aprendizaje que incluyen este tutorial.
- ProyectoConstrucción de un rover autónomo por waypoints GPS
- ProyectoConstruya un robot mecanum omnidireccional con ESP32
- ProyectoConstruye un plóter de dibujo: dos ejes paso a paso
- ProyectoConstruye un robot de cobertura de área para limpiar suelos
- ProyectoConstruye un robot mini sumo: tracción, cuña y borde
- ProyectoConstruye un robot pick and place con agarre verificado
- Ruta de aprendizajeFundamentos de electrónica para robótica: ruta guiada
- Ruta de aprendizajeMovimiento de precisión con motores paso a paso
- Ruta de aprendizajeTracción holonómica: desplazamiento omnidireccional
Lecturas adicionales