domingo, 11 de septiembre de 2011

Reducir el consumo de arduino

Hola querido lector,
si recuerdas la última entrada, expuse el proyecto de hacer un robot autónomo, y, como adelanto de la próxima entrega, hoy voy a hablarte, de manera breve (lo prometo, no muy extenso), sobre cómo reducir el consumo de arduino, concretamente, de los microcontroladores ATMega328 que montan las placas Duemillanova/Uno.
¿Por qué reducir el consumo? Si tienes tu arduino conectado a una toma de corriente, o un puerto usb, no será relevante, por supuesto, pero si pretendes montar un sistema alimentado por baterías (li-po, pilas, etc), el consmo pasa a ser crítico.
Un ejemplo práctico: el robot autónomo que estoy diseñando, agota una batería li-po de 2A en, aproximadamente, 36 horas.
No resulta especialmente crítico si puedes recargar la batería manualmente, pero después de unas pocas recargas, te darán ganas de tirarlo por la ventana.
Hay una solución, y es analizar el consumo energético de los componentes implicados.
En esta ocasión, voy a acotar el problema, y centrarme en la propia placa Duemillanova.

¿Por qué consume tanto?
Porque la placa no integra sólo el microcontrolador, sino un regulador de tensión, conversor Serie-USB, leds, condensadores, resistencias, cristal (marca los pulsos de reloj para hacer funcionar el microcontrolador a 16Mhz), diodos, etc.
Si juntamos todos los consumos, se dispara.
No cabe duda de que es una placa muy cómoda y sencilla de usar: enchufar y listo, si nos equivocamos con algún cable, los fusibles nos protegen, y l regulador de tensión se encarga de hacer el trabajo sucio si conectamos el arduino a un transformador.
Maravilloso, ¿verdad?
Pero es fácil perder de vista una cuestión clave: arduino se diseñó como una plataforma para facilitar el acceso a la computación física por parte de artistas, aficionados, etc... y ello supone un coste.
Si tienes curiosidad, puedes mirar el esquema de una placa duemillanova en http://arduino.cc/en/uploads/Main/arduino-duemilanove-schematic.pdf
Te adelanto que podemos reducir el esquema, y dejar sólo el microcontrolador.


Reducir el consumo
Antes de entrar en materia, y como ya dije, facilitar el acceso a la computación física tiene un coste, aunque por ahora, voy a centrarme en lo relativo al consumo eléctrico.

LO QUE VOY A COMENTAR A CONTINUACIÓN SE BASA EN MI EXPERIENCIA PERSONAL.
NO ME HAGO RESPONSABLE DE POSIBLES DAÑOS O CONTRATIEMPOS OCASIONADOS O DERIVADOS POR LA MANIPULACIÓN DE CUALQUIER COMPONENTE

El consumo de una placa duemillanova, como te dije, viene dado por la cantidad de componentes electrónicos que monta.
Si sabes un poquito de electrónica, reconocerás la función que desarrolla cada uno, pero si apenas tienes nociones, o no sabes nada, te hago un breve resumen.
Para alimentar el arduino a 16 Mhz, hace falta una fuente de alimentación que suministre 5V de manera estable (el puerto USB lo hace perfectamente), y según la cantidad de componentes que montemos en el circuito (sensores, leds, etc...), el consumo aumenta (necesitamos más amperios).
¿Cuál es el problema? El regulador de tensión, el adaptador USB-Serie, los leds, etc... consumen corriente, aunque no estén en funcionamiento.
Ojo, que depende de cada componente el pico de consumo: el regulador de tensión consumirá más cuando se le enchufe a un transformador, pero mientras, tiene un consumo mínimo.
Esta situación desencadena en alimentar una serie de componentes sin que tengan uso, siempre desde el punto de vista de un sistema autónomo alimentado por baterías.
Para ilustrar desde un punto de vista práctico el consumo, he montado el siguiente circuito:

Un circuito muy simple: arduino, led, alimentación (uso un portapilas con elevador de tensión para facilitar las medidas de corriente con el polímetro).
El código fuente lo tienes en los sketchs de ejemplo: Basic -> Blink
Midiendo con el polímetro, arroja un consumo de 29 mA.

Puede parecer poco, pero hagamos unas cuentas rápidas usando una batería de 2A:

(2000mA/Hora)/29mA = 69 horas

Es decir: tenemos una batería que suministra 2 amperios/hora (simplificando), y un circuito que demanda 29 miliamperios.
Convertimos amperios en miliamperios, dividimos y obtenemos un tiempo de vida aproximado de 69 horas.
Y digo aproximado, porque según se descargue la batería, el voltaje irá en descenso también (será más o menos lineal la caída de tensión), hasta no suministrar más corriente.
No está mal, ¿verdad? Podemos tener un led parpadeando durante, aproximadamente, 2 días y medio.
¡Pero se puede mejorar!
Antes comenté que la placa duemillanova funciona a 16 Mhz, una velocidad más que adecuada (todavía recuerdo mi i286 a 16 Mhz...), pero no necesariamente fija.
Si echas un ojo a las diferentes versiones de arduino, verás que hay placas que corren a 8 Mhz.
¿Por qué reducir la frecuencia del reloj e ir más lento? Porque consume menos.
Piensa: si procesas menos instrucciones por segundo, necesitas menos electricidad.
Es como el cuerpo humano: no es lo mismo andar, que ir corriendo, ¿verdad?
Habrán casos en los que se pueda sacrificar la capacidad de proceso (estamos basándonos en los ciclos de reloj), con tal de ganar batería.
Pero vayamos un paso más allá: como recordarás, el consumo de los componentes de la placa es constante, y créeme, elevado, para lo que es.
Vamos a hacer lo siguiente: pongamos el microcontrolador en una protoboard, sin nada más.
No voy a entrar en detalles, porque es una cuestión bien documentada en la página oficial: http://arduino.cc/en/Tutorial/ArduinoToBreadboard
Verás varias opciones: me voy a basar en Minimal Circuit (Eliminating the External Clock)
Aunque es un proceso muy bien detallado, NO LO HAGAS SI NO ESTÁS SEGURO.

DETALLE: el arduino que va a recibir el nuevo bootloader, EL QUE ESTÁ EN LA PROTOBOARD, debe tener un cristal de 16Mhz o no será capaz de cargar el código. NO hará falta de nuevo cuando hayas cargado el nuevo bootloader. Es un pequeño error en la documentación oficial.

El nuevo montaje queda asi:


Si te fijas, no hay cristal para microcontrolador, ni electrónica adicional.
Esto es muy peliagudo: si enchufamos mal la alimentación, podemos romper los componentes.
Y te refresco la memoria: estoy usando un portapilas con elevador de tensión, no pilas sin más.
Una vez más, vamos a medir la corriente consumida: 11 mA.
Hemos reducido el consumo en 18mA, no parece mucho, pero hablamos de más del 50%, una magnitud respetable, ¿verdad?

Y aún podemos ir un paso más allá reduciendo la frecuencia hasta 1 Mhz.

Lento pero seguro.
Una característica muy interesante de prescindir del cristal externo, es poder reducir la frecuencia del microcontrolador: 8Mhz es una velocidad interesante, pero dependiendo de las necesidades, podemos bajar hasta 1 Mhz.
¿Por qué no usar siempre esta frecuencia? Según la capacidad de cálculo que necesites, puede ser una velocidad muy muy lenta, pero para casos muy simples, puede ser más que suficiente.
Hay dos maneras de hacerlo: modificar el bootloader (complejo y requiere un grabador), o modificar el reloj del sistema dinamicamente. Si tienes un portátil, te sonará aunque sea de oídas: se modifica la frecuencia del procesador según demanda, economizando en batería.
Aquí vamos a hacerlo mismo, pero con un microcontrolador, claro.
Si quieres profundizar en esta cuestión, puedes leerte este post del foro de arduino: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1163418637/all

En esencia, la manera de modificar la frecuencia del reloj en un microcontrolador ATMega328, es insertar este código fuente en el programa allá donde querramos modificar la frecuencia:

CLKPR = (1<<CLKPCE);
CLKPR = B00000011;

La primera línea activa el escalado dinámico, y la segunda, indica la cifra por la que se divide el reloj interno (extraído de http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1163418637/all):

0000 - 1
0001 - 2
0010 - 4
0011 - 8
0100 - 16
0101 - 32
0110 - 64
0111 - 128
1000 - 256
Es decir: vamos a dividir por 8 la frecuencia interna del reloj, quedando en 1Mhz. OJO: no se puede incrementar la frecuencia, sólo dividirla. Para el caso que estamos manejado, con el parpadeo de un led, vamos a insertar este código en la función setup, antes de ejecutar nada. Tranquilo: puedes usar este código sin problema, no afecta al microcontrolador de manera permanente, es inocuo, y sólo funciona mientras funcione el programa en ejecución. Bien, cargamos el programa, ejecutamos y ... el led parpadea muy despacio, se mantiene mucho tiempo encendido. ¿Qué es esto?¿Se ha roto algo? Calma, está todo bien.
Como sabrás, hemos reducido la frecuencia del reloj, por lo cual, se ralentizan todas las funciones de entrada/salida, delay, etc...
Esto se deriva de las librerías de arduino: para facilitarnos el trabajo, encapsulan las llamadas al sistema, cálculos, etc ... dejando en nuestras manos un API muy sencillo.
Y me reitero: todo tiene un coste: en este caso, no poder controlar, aparentemente, la duración de dichas llamadas cuando se modifica la frecuencia del sistema.
¿O sí? Claro que sí.
Como dije, las librerías de arduino encapsulan la parte más compleja, y entre las abstracciones, está la de adecuar la velocidad de las llamadas de entrada/salida, y delay, a la frecuencia del sistema.
Esta frecuencia ha de definirse al compilar el código fuente, y si no indicamos al compilador que la nueva frecuencia es 1Mhz, tendremos unas llamadas que funcionan 8 veces más lentas (hemos pasado de 8Mhz a 1Mhz).
Cuidado con este baile de frecuencias: en este ejemplo tan simple, podemos ajustar la frecuencia a 8Mhz o 1Mhz, pero debes tener claro en qué momentos te conviene modificarla dinamicamente, y en qué va a afectar, o te volverás loco solucionando errores.
Hecha la aclaración, veamos donde indicar la nueva frecuencia del reloj del microcontrolador.
Editamos el fichero breadboard/breadboards.txt (recuerda leer el enlace donde se explica el proceso para usar un arduino en una protobard sin necesidad de cristal externo), y cambiamos la línea 18:

atmega328bb.build.f_cpu=8000000L


pasa a ser:
atmega328bb.build.f_cpu=1000000L


Compilamos, cargamos el código ... ¡et voilá! El led parpadea de manera correcta.
¿Y el consumo de corriente? ¿Ha variado? ¡Sí, y mucho! Ahora consume 5mA, un 50% menos que funcionando a 8Mhz, y un 17% menos que la placa duemillanova a 16 Mhz.
Impresionante, ¿verdad?

Aún se puede reducir más el consumo poniendo el microcontrolador en modo de reposo (sleep), aunque este modo implica no ejecutar ninguna instrucción (igual a cuando dejamos la tele en standby o el portátil durmiendo). Dejo para una próxima entrega la implementación y el análisis de consumos.
En resumen, para el ejemplo de parpadear un led:

Duemillanove 16Mhz: 29 mA
Protoboard 8Mhz: 11 mA
Protoboard 1Mhz: 5 mA

Me reitero en lo dicho: no hay una solución universal, todo depende de las necesidades que tengamos.
No es lo mismo manejar una matriz de leds, haciendo transiciones, o un motor de corriente contínua con las salidas PWM, que recopilar información de sensores a intervalos de tiempo, sin contar con la complejidad del código (más instrucciones, más ciclos y más tiempo procesando).
Hasta aquí esta entrega, espero que te haya resultado útil.
¡Hasta la próxima!