Maker.io main logo

Building an Analog-Style CPU Meter

2024-07-23 | By Maker.io Staff

License: See Original Project

finished

Monitoring CPU utilization while performing demanding tasks or running custom programs can ‎give you crucial insights into the necessary processing power. Establishing baseline ‎measurements is vital for optimizing source code to run more efficiently on the target platform. ‎

While command-line tools offer precise performance indicators, they are not engaging and are ‎often overly complicated to review for many applications for determining if a CPU core is ‎consistently maxed out or if operating at partial utilization suffices. This project employs analog-‎style voltmeters to give you an engaging, stunning, and practical readout of your Raspberry Pi's ‎CPU load.‎

Required Components

While you can adapt this project to run on any Raspberry Pi, I recommend using one of the later ‎models with a quad-core CPU. The more modern CPUs are more difficult to max out, meaning ‎the meters have more values to display than just 0% or full utilization. Further, employing four ‎analog voltmeters — one for each CPU core — makes for a more intriguing effect than using a ‎single voltmeter that displays the average utilization.‎

Besides a Raspberry Pi, if you wish to recreate this build, you will need four analog-style ‎voltmeters with an appropriate voltage range. All newer Raspberry Pi models output a maximum ‎of 3.3V through their GPIO pins, so a meter like this one that goes from 0V to +3V is perfect for ‎this application.‎

Wiring the Voltmeters

Connecting the voltmeters to the Pi requires only a few jumper wires with a female end that can ‎plug right into the GPIO pins. Usually, the other end of the wire gets secured using screw ‎terminals attached to the panel-mount voltmeters.‎

meter_back

The screw terminals for measuring the voltage and the mounting screws are positioned as ‎shown above.

Each meter requires two connections: a positive wire that can be connected to any digital output ‎pin and a GND wire. You can choose whether to connect the other terminal of each voltmeter to ‎a separate GND pin on the GPIO or combine all the wires, depending on whether you need to ‎preserve some free ground pins for other external parts.‎

 

The schematic diagram of this project. Source: Scheme-it

Installing the Required Libraries‎

The application requires you to install the psutil library using pip:‎

Copy Code
pip install psutil

Translating CPU Utilization Values to Voltages

A simple background program must read the current CPU load and translate it to a voltage ‎between 0V for an idling core and 3.3V when it runs at full steam. The Raspberry Pi doesn't have ‎analog outputs, so the program can only send high or low states via the Pi's GPIO pins. However, ‎using pulse-width modulation (PWM), the program can average the output voltage so that the ‎meter still displays the desired value.‎

PWM can generate analog-like signals by varying the duty cycle of a digital square wave. The ‎duty cycle represents the ratio of time the signal is on to the total period of the signal. So, for ‎example, a 50% duty cycle means that the output signal is high for 50% of its period, leading to ‎an average output of 1.5V. Adjusting the duty cycle allows you to control the average voltage to ‎mimic an analog output's behavior.

Copy Code
import psutil
import RPi.GPIO as GPIO
import time

pin_numbers = [17, 18, 27, 22]
pwm_pins = []
pwm_frequency = 5000

# Set up GPIO mode and pins for PWM
GPIO.setmode(GPIO.BCM)

for i in range(0, len(pin_numbers)):
pin = pin_numbers[i]
GPIO.setup(pin, GPIO.OUT)
pwm_pin = GPIO.PWM(pin, pwm_frequency)
pwm_pin.start(0) # Start with a duty cycle of 0%
pwm_pins.append(pwm_pin)

try:
while True:
# Read CPU load per core
cpu_loads = psutil.cpu_percent(percpu=True)
# Update PWM duty cycle based on CPU load
for i, load in enumerate(cpu_loads):
pwm_pins[i].ChangeDutyCycle(load)
time.sleep(0.25)
except KeyboardInterrupt:
pass
finally:
for i in range(0, len(pwm_pins)):
pwm_pins[i].stop()
GPIO.cleanup()

The program first imports the previously installed libraries necessary to read the current CPU ‎utilization and communicate with the GPIO pins. The program stores the pin numbers in a list to ‎make it easy to access them using only an index. The next line sets the PWM frequency to 5 ‎kHz. A sufficiently fast signal ensures the voltmeter’s needle doesn’t fluctuate erratically. The ‎script then sets the GPIO driver’s mode to use the BCM pin numbering scheme.‎

Next, the script initializes all PWM pins using a for-loop that iterates over all the previously ‎defined pin numbers. Using a list of numbers and their indices saves repeating numerous lines of ‎code and makes the program easier to adapt for platforms with more than four processing cores. ‎The program stores the created PWM objects in a new list.‎

The program defines an endless while loop that runs until you exit the program manually. Within ‎the loop, the script reads the CPU utilization per core in percent ranging from 0 to 100 and then ‎changes the duty cycle of each output pin to correspond to the readout value. Finally, the ‎program waits a quarter of a second before repeating the loop. The very last loop in the program ‎stops the PWM output and frees the GPIO hardware resource when you decide to exit the ‎program using the keyboard interrupt command (CTRL + C).‎

The following command runs the program as a background process:‎

Copy Code
python3 cpu_meter_firmware.py &

Building a Case

You can get creative when making a case for your analog-style CPU utilization monitor. I ‎decided to go for a steampunk look by gluing some copper pipes and fittings from the hardware ‎store. I then drilled holes in the pipes and mounted a thin plywood sheet using nuts and bolts:‎

finished_3

The steampunk look was the inspiration for this assembled case.‎‎

The plywood sheet has mounting holes for the voltmeters, which are held in place by the screws ‎that came with them. I then tucked away the wires and attached the pipe construction to a ‎wooden base with space for the Raspberry Pi:‎

back

With the wiring in place, the Raspberry Pi sits on the base plate.‎

Summary

This beginner-friendly project doesn’t require soldering, as the wires plug right into the Raspberry ‎Pi’s GPIO pins on one side and get attached to the analog voltmeter using built-in screw ‎terminals.‎

example

The needles move independently of each other.

The firmware for this project reads the CPU utilization per core and translates those values to a ‎voltage level between 0V, which indicates an idling core, and 3.3V, which corresponds to a ‎maxed-out processing core. The program uses PWM to mimic an analog output by altering the ‎square wave signal’s duty cycle, which works well with voltmeters that are slow to respond.‎

Using only a few cheap components, you can create a visually stunning CPU utilization readout ‎that is functional and acts as an impressive centerpiece or conversation starter.

制造商零件编号 SC0193(9)
RASPBERRY PI 4 B 2GB
Raspberry Pi
制造商零件编号 3989
LARGE 3V ANALOG PANEL METER
Adafruit Industries LLC
制造商零件编号 1954
JUMPER WIRE M TO F 6" 28AWG
Adafruit Industries LLC
制造商零件编号 FIT0714
CASE ALUM BLK 4.724"LX3.543"W
DFRobot
制造商零件编号 SC1158
27W USB-C PSU UL(US), BLACK
Raspberry Pi
Add all DigiKey Parts to Cart
TechForum

Have questions or comments? Continue the conversation on TechForum, DigiKey's online community and technical resource.

Visit TechForum