Arduino y el bajo consumo: Modo Sleep

por Ricardo Vega el 30/03/2017

Una problemática muy común cuando se lleva un tiempo jugando con Arduino es intentar alimentarlo con baterías / pilas. Existen miles de tutoriales en Internet sobre cómo crear un regulador de tensión de 5V por lo que no voy a volver a escribir una vez más sobre algo que creo que es ya fácil de encontrar. Hoy te quiero hablar del siguiente paso al que te enfrentas. Tu sistema tiene un consumo medianamente comedido de unos 20-25mA y si nuestra bateria es de 3000mAh, nos durarían unas 120 horas que son 5 días. Es decir, casi nunca nos valen estos número y queremos que nuestro sistema consuma mucho mucho menos. Este es el problema que vamos a ver hoy.

En primer lugar, decirte que si tu sistema emplea una comunicación permanente porque, por ejemplo, tiene que estar a la escucha de comunicaciones del exterior (caso de receptores MQTT o mini servidores HTTP), poco vas a poder hacer y este artículo no te aplica. De esta enseñanza también se extrae que si este es tu caso, seguramente tengas que pensar que tu sistema va a tener que estar conectado a la corriente si o si para mantenerlo con vida durante al menos un par de meses. Eso o usar baterías mucho más grandes (por ejemplo, para 60 días, necesitarías una batería de 36.000 mAh).

Supongamos que este no es tu caso y que tu sistema es un sensor que recibe información del entorno, la procesa (si tiene que hacerlo) y la envía por MQTT o HTTP al mundo exterior. Lo habitual es que esta medida la queramos conocer cada X tiempo, ¿verdad? Pongamos cada 5 minutos, es decir 300s. El tiempo que tardamos en medir y transmitir la medida puede ser, como máximo de 1s (realmente es mucho menos, pero bueno). En un caso así tendríamos 1s de "trabajo" y 299 segundos de consumo innecesario.

El rendimiento se suele calcular como un cociente entre lo que me cuesta hacer algo y lo que realmente aprovecho. En nuestro caso, consumimos 300s * 25mA = 7500mAs pero realmente sólo aprovechamos 1s * 25mA = 25mAs, así que nuestro rendimiento es del 0.33%. Vamos a mejorar esto, evitando consumir cuando no lo necesitamos.

La forma más habitual para reducir el consumo de un microcontrolador es trabajar con el modo "sleep" de éste. Dicho modo, reduce el consumo a costa de perder gran número de prestaciones. En nuestro caso, estamos empleando Arduino, cuya API no consta de órdenes específicas para trabajar con este modo "sleep". Sin embargo, debemos siempre tener presente que debajo de Arduino tenemos disponible toda la API de Atmel AVR ya que estos son los microcontroladores que emplea.

En este sentido debemos conocer perfectamente la existencia de 6 modos de energía diferentes que desactivan más o menos características para conseguir consumos más reducidos. De este modo, y de mayor a menor consumo, tenemos:

  • idle
  • adcNoiseReduction
  • powerDown
  • powerSave
  • powerStandby
  • standby
  • powerExtStandby

Tabla sobre el bajo consumo en Arduino.

Podemos manejar de forma manual todas estas características de bajo consumo en el sistema. Sin embargo, disponemos de una fantástica librería llamada Low Power y desarrollada por RocketStream que realmente facilita mucho esta tarea, ofreciéndonos una sencilla API desde la que manejar el modo sleep de nuestro Arduino.

Concretamente, debemos especificar los siguientes valores:

  • SLEEP_xS: Fija el tiempo que estará "dormido" usando para ello el Watchdog.
  • ADC_OFF: Apaga los convertidores Analógico a Digital.
  • BOD_OFF: Apaga el circuito de Brown Out Detection, que es un circuito que sirve como detector de niveles de tensión peligrosamente bajos que podrían incluso llegar dañar los circuitos.

En nuestro caso de uso, que creo puede ser un caso muy típico, vamos a apagar los convertidores Analógico-Digital y el circuito Brown Out Detection. Este último, aunque introducimos un riesgo en el circuito, realmente creo que compensa la reducción de consumo obtenida con su desactivación.

Eso si, ten en cuenta que estos elementos que apagamos en el modo sleep, están perfectamente disponibles al "despertar" nuestro Arduino.

En cuanto al parámetro SLEEP_xS, existe una limitación en la librería para su uso ya que esta función hace uso del Watchdog interno del microcontrolador lo cual establece un tiempo máximo de 8 segundos, correspondiente a SLEEP_8S.

Yo creo que en muchos casos, vamos a necesitar superar esa limitación y por eso, te voy a decir como he ampliado yo este tiempo. Tal vez no sea la forma más elegante del mundo (ni la más precisa) pero gracias a esta pequeña función vía código, se recibe cualquier valor en segundos y pone el Arduino en modo sleep con los convertidores Analógico-Digital y el circuito BOD apagados durante dicho tiempo.

A continuación, podemos ver dicho fragmento de código:

void sleep(int sec) {
  while (sec >= 8) {
    LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
    sec -= 8;
  }
  if (sec >= 4) {
    LowPower.powerDown(SLEEP_4S, ADC_OFF, BOD_OFF);
    sec -= 4;
  }
  if (sec >= 2) {
    LowPower.powerDown(SLEEP_2S, ADC_OFF, BOD_OFF);
    sec -= 2;
  }
  if (sec >= 1) {
    LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
    sec -= 1;
  }
  sendSignal();
}

Realmente, dicho código se encarga de controlar el tiempo haciendo breves comprobaciones sobre el tiempo transcurrido desde la última orden de entrada en modo sleep, haciendo uso de intervalos de 8 segundos para tiempos superiores a éste valor, e intervalos más pequeños a medida que nos acercamos a cero.

Aunque pueda parecer mentira, el consumo no se ve comprometido por esta práctica, ya que transcurren milésimas de segundo entre que despierta, se comprueba el tiempo transcurrido y se vuelve a dormir. Es más, el polímetro, ni siquiera aprecia un cambio en el consumo. Eso sí, estos ciclos despertar-dormir duran unos milisegundos que no son contabilizados por el contador, por lo que estamos introduciendo un pequeño error.

Anochecer de Invierno.

El consumo de corriente mientras el Arduino permanece dormido es de 0.55 mA. Volviendo al cálculo del rendimiento, en este caso particularizado con el uso del modo sleep, podemos ver como el resultado es el mismo (consumo empleado realmente en la transmisión 25mA * 1 seg) pero el total usado durante estos 5 minutos es 299 seg * 0.55mA + 1 seg * 25mA. En total, obtenemos un rendimiento del 13%. Además podemos calcular la duración de la batería para este caso, obteniendo 4750 horas, que son 197 días, o lo que es lo mismo, 6 meses y medio.

Como ves, haciendo uso de esta librería y este pequeño bucle, podemos dormir nuestro Arduino durante el tiempo que no estemos emitiendo de una forma sencilla. Esta acción nos permite ahorrar meses de batería y es que en el ejemplo que hemos ilustrado en este artículo, pasamos de 5 días a casi 200. Evidentemente, entre más tiempo pase entre envíos, más evidente va a ser este ahorro, pero creo que este ejemplo es bastante sintómatico de lo que podemos conseguir. Ten también en cuenta lo que se pierde (incapacidad total para comunicarse con el dispositivo durante este tiempo) y un pequeño "delay" en el "despertar" de Arduino, que puede significar que los conversores Analógico-Digital (y algunas librerías) no funcionen correctamente durante los primeros milisegundos tras el arranque.

En el próximo post, veremos como podemos completar este modo sleep para tener algo más de control sobre él.

Hasta entonces, puedes prácticar a implementar lo que hemos visto en esta entrada en tu propio proyecto. Estoy seguro que tus baterías te lo agradecerán.

¡Saludos!

Apoya al blog


Si te ha gustado este artículo, valora apoyarme económicamente a través de Patreon, una plataforma de Micro-mecenazgo con la que puedes hacerme un donativo que ayude a la continuidad del blog. Una pequeña ayuda significa mucho. 😃

Deja tu comentario!

Permanezcamos en contacto!


¿Quieres enterarte de todas las novedades del sector? ¿Te gustaría trabajar conmigo? ¡Puedes contactar conmigo de forma muy sencilla!