CALENTAMIENTO DE LA RASPBERRY




¿Cómo resolver el problema de calentamiento de la RASPBERRY PI?

La respuesta es fácil: enfriando. Para ello precisaremos de un ventilador, de los muchos que se venden en el mercado, por ejemplo éste.

El problema de este sistema es que aumenta el consumo y hace un cierto ruido puesto que funciona siempre. 

Para evitarlo os proponemos un pequeño montaje que, junto a un software escrito en python, que es un lenguaje que lleva incorporada la Raspberry, provee un control variable del ventilador, funcionando solamente al régimen necesario para enfriar la Raspberry, sin necesidad de poner el ventilador a plena potencia, a no ser que estéis en un ambiente muy caliente.

Hardware

Haremos un circuito regulador con los componentes siguientes:

placa protoboard
1 resistencia de 470 ohmnios
1 diodo (cualquier tipo, incluido un LED)
1 transistor BC548 (sirve cualquier NPN)
1 ventilador
cable para conexión

El esquema es el siguiente




La señal de control del ventilador vendrá de uno de los pins del conector GPIO de la Raspberry. Sirve cualquiera, en nuestro caso hemos usado el pin GPIO17 que corresponde al terminal 11 del conector GPIO mientras que la alimentación (5v) proviene del pin 2 y la masa del pin 6. El pin GPIO puede ser cambiado por otro sin mayor dificultad, modificando la constante definida en el programa.

El funcionamiento es extremadamente simple:

Cuando en la entrada CTRL se aplica una tensión positiva, es decir un nivel alto, que en la RASPBERRY PI corresponde a 3.3 v el transistor se pone a conducir y el ventilador se activa. Cuando la tensión de control es 0v el transistor se bloquea y no conduce, y el ventilador se para.

A base de conducir y bloquear, rápidamente , se puede generar una señal de salida pulsada, con pulsos de anchura variable. Es decir, se puede generar, por software, un control de velocidad basado en variar la anchura de los pulsos. Por ejemplo, si trabajamos una frecuencia de 100 Hz (100 pulsos por segundo, con un período de período de 10 milisegundos ), si los pulsos son de anchura 10 ms estaremos alimentando al 100%, es decir a velocidad máxima, si los pulsos son 5 ms estaremos al 50% y así sucesivamente.

Así pues, implementaremos un control PWM por software.







Software

Hemos utilizado el lenguaje python3 porque ya viene instalado en la Raspberry, junto con el sistema operativo. Y dentro del programa, hemos querido utilizar “hilos” (“threads” en inglés) para practicar con la multitarea que nos permite python.

Código fuente (fan.py)

#!/usr/bin/python3

# librerias

from threading import Thread
from time import *
import RPi.GPIO as GPIO, atexit
from subprocess import getoutput

duty=0 # ciclo del PWM para ventilador valor inicial
ta=[] # fifo de temperaturas
lenfifo=4 # fifo de medidas de temperatura
PIN=17 # puede ser cualquier pin
frecuencia=100 # Veces que se actualiza la velocidad del ventilador.
# A más frecuencia mayor uso de CPU.
dutymin=15 # ciclo minimo. A determinar experimentalmente,
# a partir de qué valor el ventilador se para
tCenter=60 # temperatura central
tDelta=5 # semi intervalo de control
# parada ordenada del programa
def parada():
global Run,duty
duty=0
Run=False
GPIO.setup(PIN,GPIO.OUT)
GPIO.output(PIN,GPIO.LOW)
GPIO.cleanup()
return
#--------------------------------------------------
# gestión soft de la velocidad del ventilador mediante variación del ancho de pulso de tensión aplicada

def fan():
global duty
d=duty
GPIO.setup(PIN,GPIO.OUT)
while Run:
d=duty
if duty>100:
d=100
duty=100
if duty<dutymin:
d=0
if Run:
GPIO.output (PIN,GPIO.HIGH)
sleep(d/100/frecuencia)
if Run:
GPIO.output (PIN,GPIO.LOW)
sleep((100-d)/100/frecuencia)
GPIO.output (PIN,GPIO.LOW)
return

# leer temperatura CPU y GPU y retornar la mayor de las dos,
# promediado de n medidas (en fifo ta)
def get_temp():
global ta
# temperatura GPU
gpu_temp = float(getoutput('/opt/vc/bin/vcgencmd measure_temp' ).replace( 'temp=', '' ).replace( "'C", '' ))
# temperatura CPU
tempFile = open( "/sys/class/thermal/thermal_zone0/temp" )
t1=int(tempFile.read())/1000.0
tempFile.close()
# poner en fifo la mayor de las dos
ta.append(max(gpu_temp,t1))
if len(ta)>lenfifo:
ta=ta[1:]
# calcular la media de las últimas medidas
cpu_temp = 0
for i in range (len (ta)):
cpu_temp+=ta[i]
cpu_temp = cpu_temp/len(ta)
return cpu_temp

#determina el valor de duty en función de la temperatura
# si T< t0-dt duty =0
# si T> t0+dt duty =100
# si t0-dt<T< t0+dt duty: interpolacion lineal
def controlfan():
global duty
dmin=dutymin
t0=tCenter
dt=tDelta
while True:
t=get_temp()
if t<(t0-dt):
duty=0
elif t>=(t0+dt):
duty=100
else:
# lineal entre T0-dt (30%=cnf["FAN"]["DUTYMIN"]) i t0+dt(100%)
duty=(100-dmin)/2*(t-t0+dt)/dt+dmin
sleep (0.5)

#-------------------------------------
# Modulo principal


GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

atexit.register (parada)

# Inicialitzación variables y processos

Run=True
ventilador=Thread(target=fan,daemon=True)
ventilador.start()
controlven=Thread(target=controlfan,daemon=True)
controlven.start()

# bucle principal
while True:
try:
sleep (10)
except:
Run=False


Posibles modificaciones o ajustes

El programa está basado en dos procesos (threads) concurrentes. 

Uno (controlfan), mide la temperatura y determina el porcentaje del ciclo (duty) que estará ON y OFF, en función de la temperatura.

La temperatura se mide en la CPU y la GPU y se toma la mayor de las dos (caso más desfavorable)Ñ los valores se acumulan en una lista FIFO y se promedian. En nuestro caso se usan 4 valores (lenfifo) pero se puede aumentar el valor sin problemas. Esto evita que los cambios sean bruscos por variaciones puntuales o errores de medida. Es lo que podemos llamar un filtro pasa-bajo.Tampoco es conveniente ponerlo muy grande porque hace que la respuesta a una variación de temperatura sea más lenta.

Si el valor de la temperatura esta por debajo de tCentral-tDelta (en nuestro caso serían 55º) el ventilador está parado. Al pasar de este punto el ventilador empieza a funcionar. El arranque no se hace desde cero puesto que, por la inercia del motor se requiere un poco más de par para poder arrancar. Así pues, duty parte de 15 (dutymin), valor que se puede determinar experimentalmente y que es tanto menor como alta es la frecuencia. 

Aquí aparece otro factor, la frecuencia. Si la frecuencia es muy alta, la regulación es mejor pero, se consume más recursos de CPU. Una frecuencia de 100 Hz da buenos resultados en todos los casos pero podéis probar con otros valores.

Entre tCentral-tDelta (55º) y tCentral+tDelta (65º) tenemos una regulación lineal. proporcional a la diferencia de temperatura respecto al mínimo (55 º). 

A partir de tCentral+tDelta (65º) el ventilador va al 100%, al màximo.

Los valores de tCentral y tDelta pueden ser modificados, experimentando como va la regulación y el ruido generado por el ventilador.


Puesta en marcha

El sistema se puede poner en marcha manualmente tecleando

python3 fan.py

en una terminal del sistema

Mejor solución es ejecutar-lo en background, tecleando

python3 fan.py &

Y mucho mejor incluirla en la tabla de cron, para que arranque automàticamente al arrancar el sistema. pero eso es otro tema ...


Resultados

La placa utilizada , en algunos casos había llegado a bloquearse por exceso de temperatura antes de poner el ventilador. 
Al poner un ventilador sin regulación, el problema desaparecía pero el ruido se hacía bastante molesto al cabo de un rato, sobre todo si se trabaja en un ambiente silencioso. Con este sistema quedan resueltos ambos problemas.

Espero vuestros comentarios




Comentarios

Entradas populares de este blog

RASPBERRY: Máquina de estados (I)

EL BLOG DE MI RASPBERRY