Logotipo de sheen.bot

← Ideas y reflexiones

Por qué delay() arruina los proyectos de Arduino en el aula (y cómo enseñar millis() a los alumnos)

8 oct 2026·Sheen Robotics
Por qué delay() arruina los proyectos de Arduino en el aula (y cómo enseñar millis() a los alumnos)

El uso de delay() pone en suspensión el microcontrolador, cegando sensores y bloqueando motores. Así es como el modelo mental del cronómetro enseña temporización no bloqueante al alumnado de la Fase Senior.

La función delay() arruina los proyectos de Arduino en el aula porque detiene el microcontrolador por completo. Durante toda la duración de la pausa, el procesador no hace nada: no puede leer un sensor de choque, no puede comprobar la distancia de un sensor ultrasónico y no puede responder a un botón de parada. Si un robot con ruedas avanza y se topa con una pausa de dos segundos, conducirá a ciegas contra una pared durante dos segundos enteros antes de ejecutar su siguiente instrucción.

Para solucionar esto con alumnos de 7.º a 9.º curso, no hace falta enseñar hilos de ejecución (threading), interrupciones de temporizadores por hardware ni máquinas de estados orientadas a objetos. Solo se necesita un modelo mental sencillo y concreto: mirar el reloj de pulsera en vez de echarse una siesta.

Anatomía de un error habitual en el aula

En casi cualquier programación didáctica de iniciación a la robótica, la lección 1 es el clásico parpadeo de un LED:

digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);

Funciona, proporciona a los alumnos una satisfacción inmediata y siembra una trampa conceptual que explota tres semanas después. En la lección 4, cuando se les pide construir un paso de peatones (hacer parpadear una luz y detectar la pulsación de un botón) o un vehículo esquivaobstáculos (hacer girar motores y leer distancias), su código se desmorona.

El alumno escribe un bucle que comprueba el pulsador, enciende un zumbador y llama a delay(1000). Al pulsar el botón, la placa normalmente lo ignora. ¿Por qué? Porque el procesador estaba ocupado contando ciclos muertos dentro de la pausa. El dedo pulsó y soltó el interruptor durante el 99 % del ciclo del bucle en el que el chip estaba, funcionalmente, dormido.

En un microcontrolador ATmega328P con una frecuencia de reloj de 16 MHz, llamar a delay(1000) desperdicia 16 millones de ciclos de reloj ejecutando instrucciones vacías en ensamblador. El robot no está realizando multitarea; está congelado.

El modelo mental del reloj de pulsera

Antes de mostrar el código a los alumnos, aléjelos de las pantallas durante cinco minutos para hacer una demostración. Pida a un voluntario que realice una tarea: “Aplaude cada tres segundos, pero si se me cae este bolígrafo, atrápalo antes de que toque el suelo”.

Primero, pídale que simule delay(): dígale que, para contar tres segundos, debe cerrar los ojos y contar mentalmente hasta tres en silencio. Suelte el bolígrafo en el segundo dos. Fallará siempre. Sus sensores estaban desactivados mientras medía el tiempo.

A continuación, plantee el modelo no bloqueante: dígale que mantenga los ojos bien abiertos, mire el reloj de pared del aula (o un reloj digital de pulsera) y no pierda de vista su mano. Comprueba la hora: si han pasado tres segundos desde su último aplauso, aplaude. Si el bolígrafo se cae, reacciona al instante.

Esto transforma el concepto de temporización de una acción (“esperar dos segundos”) a una comparación (“¿ha pasado ya suficiente tiempo?”).

El patrón fundamental: tres preguntas

Una vez que el alumnado comprende el reloj de la pared, presente millis(). Explique que millis() es sencillamente un cronómetro interno que empezó a correr en el milisegundo exacto en que Arduino se conectó a la alimentación. Nunca se detiene y nunca pausa el código.

Cualquier evento no bloqueante puede reducirse a tres preguntas formuladas en un lenguaje cotidiano dentro del bucle continuo:

  • ¿Qué hora es ahora mismo? (Leer el cronómetro: currentTime = millis())
  • ¿Cuándo realicé esta acción por última vez? (Consultar el apunte guardado: previousTime)
  • ¿Ha transcurrido el tiempo necesario? (Hacer la resta: currentTime - previousTime >= interval)

Si la respuesta a la tercera pregunta es afirmativa, se ejecuta la acción y se actualiza el apunte: asignando previousTime = currentTime. Si la respuesta es negativa, se omite la acción y se continúa de inmediato. Como el bucle se completa en una fracción de milisegundo, la placa queda libre para leer sensores ultrasónicos, comprobar finales de carrera y consultar sensores siguelíneas miles de veces por segundo.

Cómo enseñar la sintaxis sin abrumar a los principiantes

Para los alumnos de 7.º y 8.º curso, el código auxiliar estándar (boilerplate) de C++ relativo a unsigned long suele generar sobrecarga cognitiva. En los centros educativos que aplican el currículo oficial de Programación y Robótica de la Fase Senior, el alumnado suele trabajar en entornos basados en bloques o editores híbridos.

Si enseña mediante bloques (como los entornos de Arduino basados en Scratch), la adaptación es directa: introduzca un bloque de “cronómetro” y una variable llamada last_time_checked. Evite por completo el bloque “esperar 1 segundo” una vez presentadas las entradas básicas.

Si enseña C++ de Arduino basado en texto, no les suelte en pantalla el ejemplo estándar BlinkWithoutDelay sin andamiaje previo. El ejemplo oficial de Arduino combina dos conceptos distintos a la vez: temporización no bloqueante y alternancia de estado (invertir una variable de estado del LED). Por eso los chicos se confunden.

Separe la comprobación temporal de la lógica. Utilice en su lugar esta secuencia:

  1. Demuestre el fallo: haga que ejecuten un parpadeo de LED con delay() mientras intentan accionar un botón de parada de emergencia. Observe la frustración cuando el botón no responde.
  2. Presente la variable del temporizador: muéstreles cómo imprimir millis() en el monitor serie para que vean cómo los números aumentan continuamente. Esto desmitifica la función: es simplemente un cuentakilómetros del tiempo.
  3. Escriba la estructura temporal: proporcione una plantilla con andamiaje en la que la lógica de la resta esté aislada del comportamiento del robot.
ApproachProcessor StateSensor ResponsivenessSuitability
delay(1000)Detenido en bucle de espera activaCompletamente ciego durante la pausaDemostraciones de tarea única, iniciación en 4.º-6.º curso
Comparación con millis()En ejecución continua a máxima velocidad de relojInstantánea (muestreo en submilisegundos)Robótica, vehículos móviles (rovers), sistemas interactivos

Cómo consolidarlo en los proyectos de clase

Cuando el alumnado pasa de robots móviles que se desplazan a ciegas a vehículos que sondean los sensores de forma continua, su experiencia de depuración cambia por completo. En lugar de preguntarse por qué un interruptor de choque no detuvo un motor de corriente continua, pueden rastrear la ejecución con claridad.

Si su centro educativo está estructurando una progresión de varios trimestres desde la lógica basada en bloques hasta la robótica física, contar con secuencias didácticas estructuradas y esquemas de hardware verificados elimina las incertidumbres. Nuestro equipo en Sheen Robotics for Schools colabora con los docentes para coordinar estos conceptos de sistemas embebidos con los horarios de clase, garantizando que los alumnos construyan modelos mentales sólidos antes de que arraiguen malos hábitos de programación.

Una vez que el alumno comprende que un ordenador nunca debe quedarse con los ojos cerrados contando segundos, cruza el umbral que separa la simple ejecución de scripts de la creación de software reactivo y aplicable al mundo real.

#arduino#educación en robótica#programación#pedagogía#stem

Más de Ideas y reflexiones