Tutorial: Ventilador de velocidad variable para Raspberry Pi controlado por temperatura

Modificado por última vez hace 5 meses

¿Quieres, como yo, reducir el ruido del ventilador de la Raspberry Pi (o incluso eliminarlo)? Si es así, aquí te traigo la solución definitiva a nuestros problemas de ruido: el ventilador de velocidad variable para Raspberry Pi. Una solución fácil y barata (un par de euros).

Este tutorial va acompañado de un video, que te dejo más adelante, para que te resulte muy sencillo seguirlo.

Siguiendo este tutorial, vas a poder construir, con muy pocos componentes, un pequeño controlador para que la Raspberry Pi regule la velocidad de su ventilador dependiendo de su temperatura y lo completaremos con un pequeño programa en Python que haga el trabajo de supervisión y control.

Siempre que escribo un artículo en el blog mi máxima prioridad es que aporte valor para al lector, que realmente aporte conocimiento. No escribir artículos vacíos que simplemente tocan un tema por encima con información que ya está por todo internet.

¿Por qué he escrito este tutorial sobre cómo poner un ventilador de velocidad variable para Raspberry controlado por temperatura, cuando ya hay muchos por internet?

Porque los artículos que he encontrado me han parecido demasiado parciales, o no me parecía que explicaran bien las bases, de una forma entendible.

Además, me he encontrado que la mayoría de tutoriales para implementar control de velocidad por PWM basado en la temperatura en la Raspberry Pi NO LO HACEN BIEN (más adelante te explicaré por qué).

Este artículo (y los otros artículos a los que enlaza, y que he escrito como soporte de este tutorial), intentan abarcar el tema de una forma profunda pero comprensible, intentando que cualquiera pueda entenderlo fácilmente solo con leer el blog y sin preparación previa.
¡Espero que lo disfrutes!

Parece mentira lo mucho que ha costado, tanto el hardware como el software, hasta que ha todo ha funcionado perfectamente.

Que me haya costado más de lo esperado no me ha desanimado en absoluto, todo lo contrario. Esto quiere decir que el tema no es tan sencillo y que este artículo tendrá mucho valor.

La verdad es que he aprendido mucho por el camino. No esperaba que un tema tan, aparentemente, sencillo me fuera a dar tantos quebraderos de cabeza.

Tengo varias Raspberry Pi funcionando en casa para diferentes tareas. Son dispositivos pequeños, con poco consumo de energía y muy estables en su funcionamiento (pueden estar meses funcionando continuamente sin necesitar un reinicio).

He utilizado la Raspberry Pi original (la v1), la Raspberry Pi 2, la Raspberry Pi 3 y sus versiones «intermedias (con la «B» o el «+» añadidas) y la temperatura nunca ha sido un problema. Todas han funcionado estupendamente durante años sin problemas de calor.

La última que añadí, una Raspberry Pi 4, tiene mucha más potencia y rendimiento que las anteriores y eso conlleva que tenga unos requerimientos de refrigeración muy por encima de sus antecesoras. ¿Se puede usar una Raspberry Pi 4 sin ventilador? Si, pero no es recomendable hacer funcionar una Raspberry Pi 4 sin un ventilador que la refrigere.

Se supone que si ponemos una Raspberry Pi 4 es porque necesitamos su potencia en algunos momentos (si no, ¿para qué usar una Raspberry Pi 4?, mejor poner uno de los modelos anteriores, que son más baratos y consumen menos) y en este caso dotarla de un ventilador de refrigeración es casi imprescindible.

La desventaja de añadir un ventilador a la Raspberry Pi 4 es que deja de ser un dispositivo 100% silencioso para convertirse en una pequeña molestia (sobre todo en un dormitorio o despacho silencioso).

¿Cuánto ruido hace una Raspberry Pi 4?

La Raspberry Pi 4 en sí, no hace ruido, no tiene partes móviles, lo que hace ruido es su ventilador

El nivel de ruido de un ventilador de 5V para una Raspberry Pi 4 puede variar según el modelo y la marca del ventilador, así como su diseño y calidad de construcción. Sin embargo, en general, los ventiladores pequeños de 5V tienden a ser bastante silenciosos, sobre todo si los alimentamos a 3.3V (si, ventiladores de 5V alimentados a 3.3V para que giren más despacio y hagan menos ruido).

El nivel de ruido de un ventilador generalmente se mide en decibelios (dB), y los ventiladores pequeños de 5V diseñados para Raspberry Pi a menudo tienen un nivel de ruido de alrededor de 20 a 30 dB. Esto es relativamente silencioso y no debería ser molesto en la mayoría de las situaciones.

Es importante tener en cuenta que existen algunos factores que pueden influir en el nivel de ruido, como la velocidad a la que funcione el ventilador y la calidad del rodamiento del mismo. Si necesitas un funcionamiento especialmente silencioso, puedes optar por ventiladores con rodamientos de alta calidad, como los rodamientos de fluido o los rodamientos de bolas, que tienden a generar menos ruido que los rodamientos más simples.

En cualquier caso, si el ruido es una preocupación para ti, puedes buscar ventiladores diseñados específicamente para aplicaciones de bajo ruido o aquellos con opciones de control de velocidad para ajustar la velocidad del ventilador según sea necesario, lo que puede ayudarte a mantener un equilibrio entre la temperatura y el ruido.

Teniendo en cuenta todo lo anterior, podemos decir que el ruido del ventilador de una Raspberry Pi 4, una vez que hemos elegido el ventilador (mejor o peor, de mayor o menor calidad) y lo hemos conectado, siempre girará a la misma velocidad, refrigerará de la misma forma y hará el mismo ruido.

Si queremos reducir el ruido, aprovechando el ventilador esté siempre funcionando al máximo (de hecho, ni siquiera necesitamos que el ventilador esté siembre funcionando) la solución está en tener un ventilador velocidad variable para Raspberry Pi.

¿Por qué debería poner un ventilador a una Raspberry Pi 4?

Es bueno poner un ventilador en una Raspberry Pi 4 u otros dispositivos electrónicos similares por varias razones:

  1. Refrigeración: La Raspberry Pi 4 puede generar calor, especialmente cuando se ejecutan aplicaciones intensivas en términos de CPU o GPU. Un ventilador ayuda a disipar ese calor de manera más eficiente, lo que evita que la temperatura del dispositivo aumente demasiado. Un funcionamiento a temperaturas más bajas puede ayudar a prevenir el sobrecalentamiento, lo que puede afectar negativamente el rendimiento y la vida útil de la Raspberry Pi.
  2. Mayor rendimiento y estabilidad: Mantener la temperatura de la CPU y otros componentes a una temperatura más baja puede permitir que la Raspberry Pi funcione de manera más constante y sin ralentizaciones causadas por el sobrecalentamiento.
  3. Prevención de daños: El calor excesivo puede dañar los componentes electrónicos con el tiempo. Un ventilador puede prolongar la vida útil de la Raspberry Pi y prevenir daños a largo plazo.
  4. Rendimiento constante en cargas de trabajo intensivas: Si planeas utilizar tu Raspberry Pi para tareas intensivas, como emulación de videojuegos, aprendizaje automático o transcodificación de video, un ventilador puede ser esencial para mantener un rendimiento constante y evitar el estrangulamiento térmico.
  5. Reducción de la velocidad del ventilador y el ruido: No necesitas que el ventilador esté siempre a máxima velocidad. Puedes configurar el ventilador para que funcione solo cuando la temperatura alcance cierto umbral, lo que ayuda a reducir el ruido y el consumo de energía.

Todo lo anterior confirma lo que sospechábamos, poner un ventilador en una Raspberry Pi 4 es una buena idea si planeas utilizarla en tareas que generen calor o en entornos donde la temperatura ambiente sea alta. Ayudará a mantener la Raspberry Pi funcionando de manera eficiente y prolongará su vida útil al mantener las temperaturas bajo control.

Y ya que ponemos un ventilador, mejor que pongamos un ventilador velocidad variable para Raspberry Pi.

¿Cuál es el ventilador para Raspberry Pi 4 más silencioso?

Te puedo decir, sin temor a equivocarme, que el ventilador más silencioso es el ventilador apagado.

Podemos poner ventiladores de mejor calidad, a menor voltaje, de rodamientos de grafeno o Kryptonita, pero todos, sin excepción, hacen ruido.

Si queremos que un ventilador no haga ruido, lo mejor es apagarlo cuando no es necesario y ponerlo a la mínima velocidad que permita tener la temperatura de la Raspberry Pi 4 bajo control (tampoco es necesario que esté siempre «lo más fría posible«).

Ahora bien, si tengo algo que comentarte: Por regla general los ventiladores para Raspberry 4 son muy pequeños (lo normal es que sean de 40mm) y esto significa que, para que den una cantidad de aire importante tienen que girar muy deprisa.

Para mover la misma cantidad de aire, un ventilador más pequeño (como uno de 40 mm) debe girar aproximadamente 9 veces más rápido que un ventilador más grande (como uno de 120 mm).

La relación de velocidad se calcula de la siguiente manera:

Donde:

  • Dventilador grande​ es el diámetro del ventilador grande (en este caso, 120 mm).
  • Dventilador pequeño​ es el diámetro del ventilador pequeño (en este caso, 40 mm).

Si sustituimos los valores en la fórmula:

En resumen, si queremos tener el ventilador más silencioso posible, deberíamos fijarnos en:

  1. Apagar el ventilador cuando no sea necesario
  2. Ajustar la velocidad del ventilador al mínimo necesario en cada momento
  3. Montar el ventilador más grande que nos sea posible

El ventilador para la Raspberry Pi 4

Para nuestro ventilador de velocidad variable vamos a utilizar un pequeño ventilador de corriente continua de 5V (si tienes curiosidad, puedes ver pulsando aquí los diferentes tipos de ventilador que podemos usar en una Raspberry).

Se trata de un ventilador simple que lo único que tiene es un motor de motor de corriente continua que mueve las aspas. En este caso, su velocidad dependerá el voltaje con el que lo alimentamos.

Tiene solamente dos cables, el positivo y el negativo de alimentación (que, por cierto, puedes conectar al revés y el ventilador girará en sentido contrario).

Si quieres más detalles sobre por qué he elegido este tipo de ventilador, por qué he decidido variar su velocidad mediante PWM y muchos más detalles sobre el control de velocidad de ventiladores mediante PWM, el siguiente artículo del blog te gustará:

Aunque no es obligatorio leer este artículo, es interesante que lo hagas, ya que sienta las bases para lo que vamos a ver a continuación.

Si ves que te pierdes en las siguientes explicaciones, vuelve aquí y lee el artículo «Controlar la velocidad de un ventilador con PWM«.

¿Como vamos a regular la velocidad del ventilador de la Raspberry Pi 4?

Lo vamos a hacer generando una señal PWM y amplificándola, con un pequeño circuito, ya que la Raspberry Pi no puede suministrar directamente una señal PWM con la energía necesaria para mover un ventilador.

Para ello vamos a escribir un pequeño programa en Python que genere una señal de PWM que tenga un Ciclo de trabajo variable en función de lo rápido que necesite que gire el ventilador para refrigerar la Raspberry Pi 4.

Haremos que la Raspberry Pi 4 ejecute este programa automáticamente y que cada 15 segundos (configurable) el programa modifique, si es necesario, la señal PWM para subir o bajar la velocidad del ventilador.

Este programa tendrá un valor mínimo de Ciclo de trabajo de la señal PWM para asegurarnos de que el ventilador siempre se mueva y que nunca se bloquee por no tener energía suficiente para vencer la inercia y empezar a moverse.

Además, vamos a escribir un pequeño programa auxiliar que nos permitirá averiguar cuál es el Ciclo de trabajo mínimo para que el ventilador arranque y cuál es el Ciclo de trabajo mínimo para que el ventilador no se pare, una vez que está en movimiento (ambos Ciclos de trabajo no tienen por qué ser iguales, y no lo serán).

Para nuestra señal PWM vamos a utilizar los siguientes parámetros:

  • Amplitud: 3.3V
  • Ciclo de trabajo: Irá desde el mínimo que permita que el ventilador arranque (o no se pare, si ya está en movimiento) hasta el 100%.
  • Frecuencia: 25Khz

Solo con alimentar el ventilador con esta señal PWM, en vez de conectarlo directamente a 5V (o 3.3V), tendremos un ventilador velocidad variable en la Raspberry Pi.

El circuito electrónico de amplificación de señal PWM

El consumo normal de los pequeños ventiladores de 5V de 40x40mm es de aproximadamente 150mA.

La Raspberry Pi solamente puede proporcionar de manera segura 16mA, según la documentación oficial de la Raspberry Pi (y 50mA simultáneos, sumando todos sus pines).

Vamos a añadir a nuestra Raspberry Pi 4 un circuito electrónico muy sencillo, con un transistor que, con esa pequeña señal de control, de intensidad limitada, sea capaz de generar una señal igual pero que pueda llegar a un mínimo de 200 o 300mA.

Este tipo de circuitos se suelen llamar «drivers».

Hay dos formas principales de hacerlo (muy similares) y te voy a dejar las dos, para que elijas la que prefieras (aunque mi recomendación es que utilices la versión con MOSFET).

Driver PWM con transistor BJT

Este es el esquema de nuestro driver con transistor BJT:

Salvo que ya tengas los componentes (especialmente el transistor BJT), te recomiendo que construyas el driver PWM con transistor MOSFET que te dejo más abajo.

Este es el prototipo del driver con transistor BJT que construí para hacer las pruebas.

Como ves, la placa está muy sucia (digamos que está muy «trabajada»), debido al gran número de pruebas que hice con diferentes variaciones:

Transistores diferentes en configuración high-side y low-side, diferentes valores de resistencias, muchas mediciones, etc…

Aun utilizando componentes normales «through hole» (no de montaje en superficie), como ves quedó un tamaño muy compacto, para poderlo meter dentro de la caja de la Raspberry Pi 4.

En el siguiente artículo tienes toda la información sobre el driver PWM con transistor BJT:

Driver PWM con transistor MOSFET

Este es el tipo de driver que te recomiendo construir. Entre otras ventajas, su funcionamiento es más eficiente que el driver con transistor BJT y se calienta menos.

Este es el esquema de nuestro driver de señal PWM con transistor MOSFET:

Como ves es muy parecido al driver con transistor BJT que vimos antes.

En el siguiente artículo tienes toda la información sobre el driver PWM con transistor BJT:

El software de control del ventilador velocidad variable para la Raspberry Pi 4

Te dejo el video que he preparado para que te resulte más sencillo seguir este tutorial. Te recomiendo que lo veas a medida que lo lees.

Hacer estos videos lleva mucho trabajo. Si te gusta el video no te olvides de darle a «Me gusta» y suscribirte al canal. Eso me motivará a seguir haciendo más videos como este.

Aunque lo que vamos a hacer es muy sencillo y no debería causar ningún problema, el riesgo siempre está ahí, por lo que te recomiendo que hagas una copia de seguridad completa del contenido de tu Raspberry Pi 4 (te sugiero que, directamente, clones tu tarjeta Micro SD antes de tocar nada).

Generación de una señal PWM con la Raspberry Pi 4

La generación de señal PWM en la Raspberry Pi con Python no es difícil en absoluto, pero es importante saber cómo, porque, o yo estoy muy equivocado, o la inmensa mayoría de la información que hay en internet está mal.

Aquí te voy a contar por qué la mayoría de tutoriales para implementar control de velocidad por PWM basado en la temperatura en la Raspberry Pi que he visto en internet NO LO HACEN BIEN.

Inicialmente, hice todo este proyecto con la biblioteca RPi.GPIO (que es la recomendada, y con la que lo hace el 99% de gente en internet) y notaba ciertos ruidos en el ventilador y muy poca suavidad en su funcionamiento.

Atribuía los ruidos y la poca suavidad en el funcionamiento a que no era un ventilador de buena calidad, pero, haciendo pruebas con el osciloscopio, vi que algo no estaba bien…

La señal PWM generada era horrorosa, llena de ruido, en una frecuencia que no era la que yo había establecido y tanto los valores de frecuencia como de ciclo de trabajo eran muy inestables.

Lo más curioso era que el sistema funcionaba y si no hubiera hecho pruebas a fondo con el osciloscopio nunca habría sabido lo mal que estaba resultando. Seguramente hay millones de sistemas como este ‘funcionando’ en el mundo sin saber los problemas que tienen.

Me puse a investigar y encontré que la biblioteca RPi.GPIO no genera las señales PWM por hardware, sino por software (aunque utilices un pin hardware), y lo peor, es que tiene problemas con las señales de más de unos pocos kilohercios.

Utilizando una señal PWM con una frecuencia de 1Khz, por ejemplo, el sistema funcionaba, pero el ventilador hacía un ruido, perfectamente audible, que era peor que tenerlo funcionando a plena potencia.

Una desventaja adicional importante es que cuando la señal PWM se genera por software, es la CPU de la Raspberry Pi la que hace todo el trabajo (y es mucho, porque tiene que estar continuamente atendiendo y activando y desactivando el pin) con lo que el consumo de CPU puede ser alto.

Sigo documentando todo esto, haciendo pruebas, escribiendo y grabando videos para podértelo explicar bien. En breve incluiré la información.

La solución estaba en utilizar otra biblioteca, en lugar de la RPi.GPIO. Una que soporte la generación de la señal PWM por hardware.

Hay algunos proyectos (los que menos) que utilizan algún tipo de control PWM por hardware, pero la mayoría tienen problemas o limitaciones.

  • Se basan en proyectos obsoletos, o que por debajo los utilizan, o sin soporte como wiringPi
  • Necesitan un demonio corriendo (como pigpio), lo que complica la instalación y arquitectura

Generación de una señal hardware PWM con la Raspberry Pi 4

Puedes generar una señal PWM en un pin de una Raspberry Pi 4, de una forma muy fácil, utilizando Python y la biblioteca rpi-hardware-pwm.

Lo primero es preparar la Raspberry Pi para que sea capaz de utilizar los dos canales PWM hardware de los que dispone.

Tienes que editar el fichero /boot/config.txt e incluir la línea dtoverlay=pwm-2chan

Para ello, desde la consola ejecuta:

sudo nano /boot/config.txt

Y tras la última línea que empiece por dtoverlay (que posiblemente esté comentada, con una almohadilla ‘#’), incluye la línea:

dtoverlay=pwm-2chan

Esto habilitará el PWM por hardware en los GPIO por defecto: GPIO_18 para PWM0 y GPIO_19 para PWM1.

Si quieres, puedes utilizar (en vez de la línea anterior), la línea:

dtoverlay=pwm-2chan,pin=12,func=4,pin2=13,func2=4

Esto habilitará el PWM por hardware en los GPIO alternativos: GPIO_12 para PWM0 y GPIO_13 para PWM1.

Ahora reinicia la Raspberry Pi, para que los cambios tengan efecto, con:

sudo reboot

Cuando vuelva a arrancar la Raspberry Pi, entra de nuevo en la consola e instala la biblioteca rpi-hardware-pwm con:

sudo apt-get update
sudo pip3 install rpi-hardware-pwm

Programa de prueba y calibración de la señal PWM para el ventilador concreto

La Raspberry Pi ya está preparada para generar una señal PWM por hardware.

Ahora necesitamos un programa, que nos permita:

  • Probar de una forma fácil que, efectivamente, funciona.
  • Averiguar los ciclos de trabajo mínimos para que nuestro ventilador no se pare concreto (cada uno es diferente).

Para ello he creado un script muy sencillo, en el lenguaje de programación Python, hardware_pwm_generator.py, que nos permite llamarlo con tres parámetros en la línea de comandos de la Raspberry Pi:

  1. Un 0 para utilizar el canal PWM0 en GPIO_18 PWM0 y PWM1 en GPIO_19 (o PWM0 en GPIO_12 PWM0 y PWM1 en GPIO_13, si has elegido los pines alternativos en el fichero /boot/config.txt.
  2. La frecuencia en hertzios. Por ejemplo, 25000 para 25Khz.
  3. El ciclo de trabajo (un número entre 0 y 100).
import sys
from rpi_hardware_pwm import HardwarePWM

def set_pwm(pwm_channel, frequency, duty_cycle):
    pwm = HardwarePWM(pwm_channel, frequency)
    pwm.start(duty_cycle)
    input("Presiona Enter para detener el PWM...")
    pwm.stop()

if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Uso: python pwm_generator.py <canal_pwm> <frecuencia> <ciclo_de_trabajo>")
        sys.exit(1)

    pwm_channel = int(sys.argv[1])
    frequency = float(sys.argv[2])
    duty_cycle = float(sys.argv[3])

    try:
        set_pwm(pwm_channel, frequency, duty_cycle)
    except KeyboardInterrupt:
        pass

Guarda este programa en un archivo llamado «hardware_pwm_generator.py».

Puedes hacerlo ejecutando esta línea desde la consola:

sudo nano hardware_pwm_generator.py

Puedes ejecutar el programa con el siguiente comando:

python hardware_pwm_generator.py <canal_pwm> <frecuencia> <ciclo_de_trabajo>

Reemplaza:

  • <canal_pwm> Por el canal PWM que quieres usar (0 o 1). Por ejemplo, un 0 para utilizar el canal PWM0 del GPIO_18.
  • <frecuencia> Por la frecuencia en hertzios que quieres te tenga la señal PWM. Por ejemplo, 25000 para 25Khz.
  • <ciclo_de_trabajo> por el ciclo de trabajo que quieres, por ejemplo, «50» para un ciclo de trabajo del 50%.

Por ejemplo, para generar en el canal 0 de PWM (PWM0) en el GPIO_18 una señal a 25Khz con un ciclo de trabajo del 80%, tienes que ejecutar en la consola:

python hardware_pwm_generator.py 0 25000 80

Para salir y detener el PWM, solo tienes que pulsar [Enter].

También puedes interrumpir y salir del programa con Ctrl-C. En este caso la señal PWM no se detendrá.

El código es el siguiente:

Lectura de la temperatura de la CPU de la Raspberry Pi

Vamos a ver qué tenemos que hacer para leer la temperatura de la CPU de la Raspberry Pi de una forma sencilla, para ir poco a poco y que sea entendible. Más adelante veremos como modificar la señal PWM en base a la temperatura.

Para leer la temperatura de la CPU de una Raspberry Pi puedes utilizar la biblioteca psutil.

Asegúrate de tener la biblioteca psutil instalada en tu Raspberry Pi. Puedes instalar psutil con el siguiente comando:

sudo apt-get update
sudo pip install psutil

Ahora que tenemos la biblioteca instalada, podemos ver la temperatura ejecutando la siguiente línea:

vcgencmd measure_temp

Aquí tienes un programa simple en Python que utiliza la biblioteca psutil para leer la temperatura de la CPU y la imprime en la consola cada 5 segundos:

import psutil
import time

def get_cpu_temperature():
    try:
        temperature = psutil.sensors_temperatures()['cpu_thermal'][0].current
        return temperature
    except Exception as e:
        print(f"Error al obtener la temperatura de la CPU: {e}")
        return None

def main():
    try:
        while True:
            temperature = get_cpu_temperature()

            if temperature is not None:
                print(f"Temperatura de la CPU: {temperature}°C")

            time.sleep(5)

    except KeyboardInterrupt:
        pass

if __name__ == "__main__":
    main()

Puedes escribirlo en el fichero temperature_reader.py (como hicimos antes con hardware_pwm_generator.py), con:

sudo nano temperature_reader.py

Diferentes versiones de Raspberry Pi y de Linux pueden llamar al sensor de temperatura con un nombre diferente a ‘cpu_thermal’.

Ejecútalo desde la consola con la línea:

python temperature_reader.py

Si te da un error parecido a «Error al obtener la temperatura de la CPU: ‘cpu_thermal’» seguramente sea porque tu sensor no se llama ‘cpu_thermal’ y tendrás que averiguar su nombre.

Una vez sepas el nombre, tendrás que sustituir en la línea 6 el nombre ‘cpu_thermal’ por el nombre de tu sensor.

Por ejemplo, tanto en la Raspberry Pi 3 con la que empecé a hacer las pruebas como en la Raspberry Pi, este sensor se llamaba ‘cpu_thermal’.

Puedes utilizar este pequeño código para averiguarlo imprimiendo la lista de todos los sensores disponibles para entender qué nombres están presentes en tu sistema:

import psutil
import time

def get_cpu_temperature():
    try:
        sensors_data = psutil.sensors_temperatures()
        if 'coretemp' in sensors_data:
            temperature = sensors_data['cpu_thermal'][0].current
            return temperature
        else:
            print("No se encontraron datos del sensor 'cpu_thermal'. Sensores disponibles:", sensors_data.keys())
            return None
    except Exception as e:
        print(f"Error al obtener la temperatura de la CPU: {e}")
        return None

def main():
    try:
        while True:
            temperature = get_cpu_temperature()

            if temperature is not None:
                print(f"Temperatura de la CPU: {temperature}°C")

            time.sleep(5)

    except KeyboardInterrupt:
        pass

if __name__ == "__main__":
    main()

Este script imprimirá la lista de sensores disponibles en tu sistema si no puede encontrar el sensor ‘cpu_thermal’. Al ejecutar el script, podrás ver qué nombres de sensores están presentes, y podrás ajustar el código en consecuencia para leer la temperatura desde el sensor correcto.

Programa de lectura de la temperatura y ajuste de la velocidad del ventilador

Para leer la temperatura de la CPU de una Raspberry Pi 4 y generar una señal PWM con un ciclo de trabajo proporcional a la temperatura de la CPU, utilizaremos, como hemos visto antes, la biblioteca psutil para obtener la temperatura de la CPU y, de nuevo, la biblioteca rpi-hardware-pwm para generar la señal PWM.

#!/usr/bin/env python3

import configparser
from rpi_hardware_pwm import HardwarePWM
import psutil
import time
import sys
import atexit
import syslog
import os
import signal

#Inicializa las variables
canal_pwm = 0
frecuencia = 25000
ciclo_de_trabajo_anterior = 0
temperatura_anterior = 0
tiempo = 6
ciclo_de_trabajo = 0

pwm = HardwarePWM(canal_pwm, frecuencia)

def print_debug(mensaje):
    if debug and not as_a_service:
        print(mensaje)
    if debug and as_a_service:
        syslog.syslog(syslog.LOG_INFO, mensaje)
        
def inicializar_configuracion():
    # Valores predeterminados
    defaults = {
        'intervalo_de_prueba': 5,
        'canal_pwm': 0,
        'frecuencia': 25000,
        'temp_min': 45,
        'temp_max': 65,
        'ciclo_min': 60,
        'ciclo_max': 100,
        'histeresis': 2,
        'debug': False,
        'as_a_service': True
    }

    try:
        # Cargar configuración desde el archivo INI
        config = configparser.ConfigParser()
        config.read("temperature_pwm_controller.ini")

        # Desempaquetar la configuración o usar valores predeterminados
        intervalo_de_prueba = config.getint("config", "intervalo_de_prueba", fallback=defaults['intervalo_de_prueba'])
        canal_pwm = config.getint("config", "canal_pwm", fallback=defaults['canal_pwm'])
        frecuencia = config.getint("config", "frecuencia", fallback=defaults['frecuencia'])
        temp_min = config.getint("config", "temp_min", fallback=defaults['temp_min'])
        temp_max = config.getint("config", "temp_max", fallback=defaults['temp_max'])
        ciclo_min = config.getint("config", "ciclo_min", fallback=defaults['ciclo_min'])
        ciclo_max = config.getint("config", "ciclo_max", fallback=defaults['ciclo_max'])
        histeresis = config.getint("config", "histeresis", fallback=defaults['histeresis'])
        debug = config.getboolean("config", "debug", fallback=defaults['debug'])
        as_a_service = config.getboolean("config", "as_a_service", fallback=defaults['as_a_service'])

        return (intervalo_de_prueba, canal_pwm, frecuencia, temp_min, temp_max, ciclo_min, ciclo_max, histeresis, debug, as_a_service)

    except Exception as e:
        print(f"Error al cargar la configuración: {str(e)}")
        syslog.syslog(syslog.LOG_ERR, f"Error al cargar la configuración: {str(e)}")
        # Utiliza los valores predeterminados si hay un error al cargar la configuración
        return tuple(defaults.values())

def calcular_ciclo_de_trabajo(temp, temp_min, temp_max, ciclo_min, ciclo_max, ciclo_actual, hysteresis):
    try:
        if temp < temp_min:
            return 0
        elif temp > temp_max:
            return 100
        elif temp_min <= temp:
            if (temp > (temperatura_anterior + hysteresis)) or (temp < (temperatura_anterior - hysteresis)):
                print_debug(f"***Superada histéresis. Nueva temperatura: {temp:.2f}ºC. Nuevo ciclo de trabajo: {ciclo_de_trabajo:.0f}%. La temperatura anterior era {temperatura_anterior:.2f} °C. El ciclo anterior era de  {ciclo_de_trabajo_anterior:.0f}%")
                ciclo = (temp - temp_min) * (ciclo_max - ciclo_min) / (temp_max - temp_min) + ciclo_min
                ciclo = max(ciclo_min, min(ciclo, ciclo_max))
                return round(ciclo)
        return round(ciclo_actual)
    except Exception as e:
        print_debug(f"Error al calcular el ciclo de trabajo: {str(e)}")
        return round(ciclo_actual)
        
def parar_ventilador(signum, frame):
    try:
        syslog.syslog(syslog.LOG_INFO, "Parando salida PWM")
        pwm.stop();
        time.sleep(1)
        # Asegurarse de que todos los buffers estén vacíos antes de salir
        sys.stdout.flush()
        sys.stderr.flush() 
        sys.exit(0)
    except Exception as e:
        print_debug(f"Error al parar el servicio: {str(e)}")

try:
    # Llama a la función para inicializar la configuración
    (intervalo_de_prueba, canal_pwm, frecuencia, temp_min, temp_max, ciclo_min, ciclo_max, histeresis, debug, as_a_service) = inicializar_configuracion()

    script_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]
    syslog.openlog(ident=script_name, facility=syslog.LOG_USER)
    syslog.syslog(syslog.LOG_INFO, f"El servicio {script_name} se está ejecutando.")
    
    # Para que se detenga el ventilador al para el script
    signal.signal(signal.SIGTERM, parar_ventilador)

    pwm.start(100)
    time.sleep(1)
    pwm.change_duty_cycle(0)

    while True:
        temp = psutil.sensors_temperatures()['cpu_thermal'][0].current
        ciclo_de_trabajo = calcular_ciclo_de_trabajo(temp, temp_min, temp_max, ciclo_min, ciclo_max, ciclo_de_trabajo, histeresis)

        if tiempo >= intervalo_de_prueba and debug is True:
            mensaje = f"La temperatura de la CPU es {temp:.2f} °C. El ciclo de trabajo es de {ciclo_de_trabajo:.0f}%"
            print_debug(mensaje)
            mensaje = f"La temperatura anterior era {temperatura_anterior:.2f} °C. El ciclo anterior era de  {ciclo_de_trabajo_anterior:.0f}%"
            print_debug(mensaje)
            mensaje = f"--------------------------------------------------------------------------------------------"
            print_debug(mensaje)
            tiempo = 0
        else:
            tiempo += 1

        if ciclo_de_trabajo_anterior == 0 and ciclo_de_trabajo != 0:
            print_debug(f"Arrancando ventilador... (temperatura {temp:.2f}ºC)")
            pwm.change_duty_cycle(100)
            ciclo_de_trabajo_anterior = 100
            time.sleep(1)

        if ciclo_de_trabajo != ciclo_de_trabajo_anterior:
            pwm.change_duty_cycle(ciclo_de_trabajo)
            print_debug(f"Nueva temperatura: {temp:.2f}ºC. Nuevo ciclo de trabajo: {ciclo_de_trabajo:.0f}%")
            print_debug(f"Temperatura cambio anterior: {temperatura_anterior:.2f}ºC. Ciclo de trabajo anterior: {ciclo_de_trabajo_anterior:.0f}%")
            ciclo_de_trabajo_anterior = ciclo_de_trabajo
            temperatura_anterior = temp

        time.sleep(intervalo_de_prueba)

except Exception as e:
    print(f"Error general: {str(e)}")
    syslog.syslog(syslog.LOG_ERR, f"Error general: {str(e)}")

Puedes grabar el programa en un fichero con nombre temperature_pwm_controller.py mediante:

sudo nano temperature_pwm_controller.py

Este programa lee la temperatura de la CPU cada 5 segundos y ajusta el ciclo de trabajo del PWM de acuerdo con la temperatura.

Hay varios parámetros que puedes ajustar según tus necesidades y preferencias.

  • canal_pwm = 0: Te permite elegir el canal PWM que quieres utilizar.
  • frecuencia = 25000: La frecuencia de la señal PWM. Ten en cuenta que una señal de una frecuencia más baja provocará un ruido audible que puede ser molesto.
  • temp_min = 45: La temperatura por debajo de la cual el ventilador estará parado.
  • temp_max = 60: La temperatura que no quieres que se sobrepase. A partir de esta temperatura el ciclo de trabajo de la señal PWM será del 100%.
  • ciclo_min = 55: Ciclo de la señal PWM para tu ventilador y preferencias. No pongas una señal demasiado baja que pueda hacer que el ventilador no gire.
  • ciclo_max = 100: El ciclo de trabajo máximo al que quieres que se genere la señal PWM.
  • histeresis = 2: Para que el ventilador no esté continuamente parándose y poniéndose en marcha, este es el valor de «zona gris». La temperatura tendrá que variar más que este valor para que el ventilador cambie entre movimiento y parado.
python temperature_pwm_controller.py

El script leerá la temperatura y ajustará la señal PWM periódicamente.

Pulsa Ctrl-C para interrumpirlo.

Configuración del script

Si lo deseas puedes crear un fichero de configuración para que te resulte más fácil adaptar el programa a tus preferencias sin tener que modificar el script.

Este fichero es completamente opcional y si no lo creas (o falta cualquier línea) el script utilizará los valores por defecto que están definidos en el código.

Solo tienes que crear un fichero de texto, llamado temperature_pwm_controller.ini en la misma carpeta donde tengas el script (fichero temperature_pwm_controller.py).

Si quieres, puedes crearlo con:

sudo nano temperature_pwm_controller.ini

Dentro del archivo, solo tienes que incluir una primera línea, a modo de cabecera, con el texto [config] y a continuación incluir las líneas que desees de entre las que figuran arriba con los valores que quieras.

[config]
intervalo_de_prueba = 5
canal_pwm = 0
frecuencia = 25000
temp_min = 46
temp_max = 65
ciclo_min = 60
ciclo_max = 100
hysteresis = 2
debug = False

Instalar el script desde GitHub

Puedes encontrar todo código actualizado en mi repositorio de GitHub y lo puedes descargar a tu Raspberry Pi directamente desde allí.

Una vez en la consola te recomiendo que crees un directorio en el que clonar el repositorio, y lo clones:

git clone https://github.com/melkati/raspberry-fan.git

Ten en cuenta que tendrás que hacer los ajustes necesarios porque los scripts no estarán en /home/pi sino en /home/pi/raspberry-fan

El archivo temperature_pwm_controller.service estará ya configurado para funcionar desde /home/pi/raspberry-fan

Hacer que se inicie automáticamente al arrancar la Raspberry Pi 4

No tendría mucho sentido que cada vez que arrancásemos la Raspberry Pi tuviéramos que entrar en la consola y ejecutar un programa, de manera que lo vamos a automatizar.

Para que el script se ejecute automáticamente al arrancar la Raspberry Pi hay varias formas de hacerlo. Aquí vamos a ver cómo se hace con systemctl.

Ejecución automática con systemctl

Para ejecutar un script de Python en el arranque de una Raspberry Pi utilizando systemd, puedes seguir estos pasos.

En este ejemplo el nombre del script es temperature_pwm_controller.py y la ruta completa donde está es /home/pi/:

  1. Asegúrate de que el script sea ejecutable:
sudo chmod +x /home/pi/temperature_pwm_controller.py
  1. Crea un archivo de servicio para systemd:
    Crea un archivo de servicio en la ubicación /etc/systemd/system/. Puedes nombrarlo, por ejemplo, temperature_pwm_controller.service.

    sudo nano /etc/systemd/system/temperature_pwm_controller.service

    El contenido del archivo debe ser el siguiente:
# Este es un archivo de servicio para el controlador PWM basado en temperatura
# que se ejecutará automáticamente al arrancar la Raspberry Pi.

[Unit]
Description=Controlador de PWM basado en temperatura
After=multi-user.target

[Service]
ExecStartPre=sleep 30
ExecStart=/usr/bin/python3 /home/pi/temperature_pwm_controller.py
WorkingDirectory=/home/pi
StandardOutput=syslog
StandardError=syslog
Restart=always
User=pi

[Install]
WantedBy=multi-user.target

Puedes crear el archivo con el siguiente comando:

sudo nano /etc/systemd/system/temperature_pwm_controller.service

Una vez creado, asegurate de que tiene los permisos correctos. Puedes darle los permisos con la siguiente línea:

sudo chmod 777 /etc/systemd/system/temperature_pwm_controller.service

Asegúrate de reemplazar /home/pi/temperature_pwm_controller.py con la ruta completa de tu script de Python, si lo has modificado.

  1. Recarga systemd:
sudo systemctl daemon-reload
  1. Habilita e inicia el servicio:
sudo systemctl enable temperature_pwm_controller.service
sudo systemctl start temperature_pwm_controller.service

El servicio tiene un retraso antes de ejecutarse de 30 segundos para asegurarse de que la Raspberry Pi se haya iniciado por completo antes de poner en marcha el ventilador, por lo que tardará un tiempo en hacerlo.

Si en este punto reinicias la Raspberry Pi, el servicio arrancará automáticamente. Puedes hacerlo desde la consola con la línea:

sudo reboot
  1. Verifica el estado del servicio:
sudo systemctl status temperature_pwm_controller.service

Puedes parar el servicio con:

sudo systemctl stop temperature_pwm_controller.service

Puedes ejecutar el servicio con:

sudo systemctl start temperature_pwm_controller.service

Puedes ver el estado del servicio con:

   sudo systemctl status temperature_pwm_controller.service

Puedes ver el log del servicio con:

sudo journalctl -f -u temperature_pwm_controller.service

Fíjate en que no es necesario que ejecutemos el script cada quince segundos ya que realmente está siempre funcionando, realizando su trabajo cada 15 segundos.

Estos pasos deberían configurar tu script temperature_pwm_controller.py para ejecutarse automáticamente en el arranque de tu Raspberry Pi utilizando systemd. Asegúrate de ajustar las rutas y nombres de archivo según tus necesidades específicas.

Conexión del driver PWM a la Raspberry Pi 4 y puesta en marcha

Ya tenemos todo lo necesario y podemos unir las piezas, hardware y software, y poner en marcha nuestro ventilador de velocidad variable para Raspberry Pi.

Aunque tienes un tutorial de un driver PWM con MOSFET (y otro de un driver PWM con transistor BJT), he diseñado un driver PWM específico para la Raspberry Pi: El Mini HAT PWM:

Elección del pin de la Raspberry Pi 4 al que vamos a conectar el driver.

Todos los pines de salida de la Raspberry Pi 4 pueden sacar una señal PWM, pero hay que tener en cuenta que no todos los pines son iguales, a la hora de generar una señal PWM.

  • Pines PWM software: Generarán la señal por software. Será la CPU de la Raspberry Pi 4 la encargada de generar la señal y consumirá recursos de CPU, como cualquier otro programa.
  • Pines PWM hardware: Generarán la señal por hardware. La CPU de la Raspberry Pi 4 solo tendrá que pedirle a uno de sus «generadores hardware PWM» que genere la señal deseada y podrá desentenderse. El hardware especializado en generar señales PWM se ocupará de su generación y la CPU no tendrá que hacer nada, por lo que no consumirá recursos de la CPU dejando toda su capacidad y potencia para otros programas.
Fuente imagen: raspberry.org

Los pines 12/13 y 18/19 generan la señal PWM por hardware, mientras que todos los demás pines generan la señal PWM por software.

Fuente imagen: raspberry.org

Te recomiendo que utilices uno de los pines 12/13 y 18/19, salvo que tengas un buen motivo para no hacerlo, como el siguiente:

El hardware PWM y el jack de auriculares utilizan los mismos circuitos de la Raspberry Pi, por lo que no podrás utilizarlos al mismo tiempo. Dicho de otra manera: si usas el jack de auriculares de la Raspberry Pi 4 tendrás que utilizar PWM por software, con todas sus limitaciones.

IMPORTANTE: Si no utilizas el pin 18, recuerda actualizar el código con el pin que hayas decidido utilizar. Estos ejemplos están preparados para utilizar el GPIO 18 (pin 12 en el puerto de expansión de la Raspberry Pi 4)

Calibración de la señal PWM para tu ventilador

Como vimos en detalle en el artículo «Controlar la velocidad de un ventilador con PWM«, y hemos recordado anteriormente, en este mismo artículo, cada ventilador responde de una forma diferente a las señales PWM.

Cada ventilador tiene un Ciclo de trabajo mínimo para que el ventilador empiece a girar desde que está parado. En unos ventiladores puede ser el 30% y en otros el 90% por lo que es necesario que lo pruebes tú mismo con tu ventilador.

Cada ventilador tiene también un Ciclo de trabajo mínimo para que no se detenga cuando ya está en movimiento. No podrás bajar el Ciclo de trabajo a, digamos, un 5%, esperando que así el ventilador funcione muy despacio. Con tan poca energía se parará mucho antes de bajar hasta ese 5%.

Para que te hagas a la idea, el ventilador con el que estoy haciendo las pruebas ahora mismo se para cuando el ciclo de trabajo baja a un 60%, aproximadamente.

Tienes que tener presente que ambos Ciclos de trabajo no tienen por qué ser iguales (y no lo serán).

El ventilador necesita más energía (un Ciclo de trabajo más alto) para vencer la resistencia para ponerse en marcha y necesitará menos energía para mantenerse en movimiento, una vez que ya lo está.

Todo lo anterior significa que tendrás que calibrar tu ventilador concreto para encontrar esos dos valores del Ciclo de trabajo.

Podrás calibrar tu ventilador fácilmente utilizando el programa pwm_generator.py que te he dejado antes (puedes pichar aquí para ir a él).

Tendrás que, con el ventilador parado, ir ejecutando el programa varias veces, subiendo cada vez el Ciclo de trabajo, hasta que el ventilador se ponga en marcha. Una vez hayas encontrado ese «Ciclo de trabajo mínimo desde parado» puedes utilizar ese valor, aumentándolo un porcentaje como margen de seguridad (puedes probar con un 10%).

Luego, con el ventilador en marcha, tendrás ir ejecutando el programa varias veces, bajando cada vez el Ciclo de trabajo, hasta que el ventilador se detenga. Una vez hayas encontrado ese «Ciclo de trabajo mínimo desde en movimiento» puedes utilizar ese valor, aumentándolo un porcentaje como margen de seguridad (puedes probar con un 10%).

¿Y si mi Raspberry Pi no es la 4, que pasa con otros modelos?

La Raspberry Pi 5 es demasiado nueva y aún no la he usado, por lo que no te podré decir mucho sobre ella, pero si he tenido todos los modelos anteriores a la 4 y te puedo hablar sobre ellos.

Puedo decirte que, en los modelos anteriores de Raspberry Pi, 1, 2 3 y sus variaciones, el consumo de energía es mucho más bajo que en la Raspberry Pi 4 y nunca he necesitado utilizar un ventilador y su temperatura siempre se ha mantenido dentro de limites muy razonables.

Aun así, si quieres o necesitas añadir el ventilador en alguno de esos modelos, no te será difícil.

Yo lo he probado (y lo tengo funcionando) en la Raspberry Pi 3 y la Raspberry Pi 4, por lo que en estos modelos está bien probado.

Si lo quieres probar en otra versión, el software probablemente funcione tal cual, o con cambios mínimos.

Tola la investigación y el desarrollo lo ha hecho con una Raspberry Pi 3, solo cuando lo tenía terminado lo he instalado en la Raspberry Pi 4. El motivo es, simplemente, que la única Raspberry Pi 4 que tengo la tenía ocupada para cosas de la domótica de la casa, y no podía estar quitándola.

Si lo pruebas con otras versiones, especialmente si es con la Raspberry Pi 5, te pido que dejes un mensaje en los comentarios y así podré actualizar el artículo con esa información.

Raspberry Pi 4

El software está probado en la Raspberry Pi 4 y funciona sin problema.

Por cierto, en la Raspberry Pi 4 he montado una versión especial del Mini HAT PWM con componentes SMD y unos pines más largos para poderlo poner pegado a la caja por fuera. En mi opinión, ha quedado muy bien.

Raspberry Pi 3

Es el modelo en el que he hecho la investigación y el desarrollo por lo que está probado y debería funcionar sin problema.

Raspberry Pi 2

Cuando pueda lo probaré en esta versión, aunque no tiene mucha utilidad porque no se calienta y no necesita ventilador. No preveo que haya ningún problema.

No confundas hardware y software de tu Raspberry Pi

Lo que acabamos de ver es respecto al hardware de la Raspberry Pi, pero también el software puede ser diferente.

La versión concreta de sistema operativo que tenía instalada en la Raspberry Pi 3 era: «Raspbian GNU/Linux 11 (bullseye) armv71 (32bit) con user space de 32 bit.

El sistema operativo que tenía instalado en la Raspberry Pi 4 era: «Raspbian GNU/Linux 11 (bullseye) aarch64 (64bit) con user space de 32 bit.

Si has seguido el tutorial y encuentras algo diferente o que no te funciona no estaría de más de comprobaras tu versión.

Para ver la versión del sistema operativo instalada en tu Raspberry Pi, puedes utilizar el siguiente comando:

cat /etc/os-release

Este comando te mostrará el nombre y la versión del sistema operativo que se está ejecutando en tu dispositivo.

Si deseas saber si el sistema operativo es de 32 o 64 bits, puedes utilizar el siguiente comando:

uname -m

Este comando te mostrará la arquitectura del procesador de tu Raspberry Pi. Si la salida es armv7l, entonces estás utilizando un sistema operativo de 32 bits. Si la salida es aarch64, entonces estás utilizando un sistema operativo de 64 bits 12.

Para ver si el espacio de usuario de tu Raspberry Pi es de 32 o 64 bits, puedes utilizar el siguiente comando:

getconf LONG_BIT

Este comando te mostrará la arquitectura del procesador de tu Raspberry Pi. Si la salida es 32, entonces estás utilizando un espacio de usuario de 32 bits, si la salida es 64, entonces estás utilizando un espacio de usuario de 64 bits.

¿Y ahora qué?

En este artículo hemos visto lo que tenemos que hacer para controlar la velocidad del ventilador de la Raspberry Pi dependiendo de la temperatura de su CPU.

Si no lo has hecho, te sugiero que leas los siguientes artículos, donde se amplía la información sobre cada uno de los aspectos que hemos visto aquí, resumidos:

Deja un comentario