/Fuzzy-Pi-Fan

Control raspberry pi fan speed using hardware PWM and fuzzy logic

Primary LanguageRust

Fuzzy Pi Fan

Short story!

I recently started using a Raspberry Pi 4 as my local file server. It didn't take many days to realize that it was suffering from high temperatures, which were leading to throttling. I immediately had to buy a fan and without much research I bought the official raspberry pi fan. Without further ado the rasbian os does not offer enough control on the fan operation. So I decided to make an app which will control the fan speed through fuzzy logic.

Raspberry Pi PWM

Hardware PWM must be enabled in order for this app to work.Activate it by adding an overlay in the /boot/config.txt. Main Raspberry Pi kernel documentation gives 2 possibilities. Either a single channel, either a dual channel. For our purpose we will activate only one PWM channel, which exposes the following GPIO pins

PWM GPIO Function Alt dtoverlay
PWM0 12 4 Alt0 dtoverlay=pwm,pin=12,func=4
PWM0 18 2 Alt5 dtoverlay=pwm,pin=18,func=2
PWM1 13 4 Alt0 dtoverlay=pwm,pin=13,func=4
PWM1 19 2 Alt5 dtoverlay=pwm,pin=19,func=2

Edit the /boot/config.txt file and add the dtoverlay line in the file. You need root privileges for this:

sudo nano /boot/config.txt

Save the file and reboot:

sudo reboot

After rebooting your Pi, you will have access to hardware PWM. A new sysfs directory will be shown uder the following route /sys/class/pwm/pwmchip{num}/pwm{num}, which operates much like the sysfs support for GPIO.

The numbers in brackets (pwmchip{num} , pwm{num}) correspond to values of the variables:

const  BB_PWM_CHIP:  u32  =  0;
const  BB_PWM_NUMBER:  u32  =  0;

Prerequisites

The app is developed using the Rust programming language and uses the following dependencies:

[dependencies]
sysfs-pwm = { git = "https://github.com/rust-embedded/rust-sysfs-pwm", branch = "master" }
rsfuzzy={git="https://github.com/auseckas/rsfuzzy",branch = "master"}
cpu-monitor = "0.1.1"

(Huge thanks to the creators ❤️)

Fuzzy Logic

The basic idea of this application is to use a fuzzy logic model in order to control the speed of the fan. The temperature of the pi processor is entered as a parameter in the model which then outputs the fan speed. The following plot shows the membership functions:

plot

You can easily edit the membership functions, by updating the following code section:

let soc_temp = rsfuzzy::fz_input_var![
        ("down", "cold", vec![30.0, 60.0]),
        ("triangle", "warm", vec![40.0, 60.0, 80.0]),
        ("up", "hot", vec![60.0, 90.0])
    ];

    f_engine.add_input_var("soc_temp", soc_temp, 30, 90);

    let cpu_usage = rsfuzzy::fz_input_var![
        ("down", "low", vec![0.0, 50.0]),
        ("triangle", "medium", vec![25.0, 50.0, 75.0]),
        ("up", "high", vec![50.0, 100.0])
    ];

    f_engine.add_input_var("cpu_usage", cpu_usage, 0, 100);

    let fan_speed = rsfuzzy::fz_output_var![
        ("down", "low", vec![0.0, 50.0]),
        ("triangle", "moderate", vec![25.0, 50.0, 75.0]),
        ("up", "high", vec![50.0, 100.0])
    ];
    f_engine.add_output_var("fan_speed", fan_speed, 0, 100);

The fuzzy relationship between input (soc_temp,cpu_usage) and output (fan_speed) is defined in the following rules:

let f_rules = vec![
        "if soc_temp is cold or cpu_usage is low then fan_speed is low",
        "if soc_temp is warm or cpu_usage is medium then fan_speed is moderate",
        "if soc_temp is hot or cpu_usage is high then fan_speed is high"
    ];

Finally we use Centroid method for the defuzzification:

f_engine.add_defuzz("centroid");

Run & Build

Use cargo in order to run and build the project. Be sure you have installed the appropriate rust compiler (toolchain)