The Verdict: Why the pigs and raspi-gpio Commands Rule Hardware Control
If you are trying to achieve low-jitter hardware control on a Raspberry Pi, the most reliable raspberry pi command for the job is pigs (the command-line client for the pigpio daemon), not the legacy raspi-gpio utility or the deprecated Python RPi.GPIO library. While raspi-gpio is excellent for inspecting pin muxing and debugging device tree overlays, pigs bypasses the Linux kernel's scheduling latency by talking directly to the hardware via DMA, giving you true hardware PWM and microsecond-accurate pulse timing.
This guide targets the Raspberry Pi 5 (4GB and 8GB variants) running Raspberry Pi OS (Bookworm or later, 64-bit). The Pi 5 uses the RP1 southbridge chip, which changed how GPIO memory is mapped. Older versions of pigpio failed on the Pi 5, but versions 1.79 and later fully support the RP1 architecture. We will use these command-line tools and their Python API to build, debug, and scale a 12V PWM cooling fan controller.
Project Build: 12V PWM Fan Controller via Command Line
Parts List & Spec Sheet
| Component | Exact Model / Variant | Estimated Cost | Notes |
|---|---|---|---|
| Microcontroller | Raspberry Pi 5 (4GB) | $60.00 | Requires active cooler; RP1 southbridge. |
| PWM Fan | Noctua NF-A12x25 12V PWM | $30.00 | 25kHz PWM frequency requirement. |
| MOSFET | 2N7000 N-Channel (TO-92) | $0.50 | Logic-level gate threshold (Vgs ~2.0V). |
| Resistors | 1kΩ (Gate) & 10kΩ (Pull-down) | $0.10 | 1/4W carbon film or metal film. |
| Power Supply | 12V 2A DC Wall Adapter | $8.00 | Do NOT power 12V fans from the Pi 5V pin. |
Pin Mapping Table
| Pi 5 Physical Pin | BCM GPIO | Function | Wiring Destination |
|---|---|---|---|
| Pin 6 | GND | System Ground | Common GND rail (Pi + 12V PSU + MOSFET Source) |
| Pin 12 | GPIO 18 | Hardware PWM0 | 1kΩ Resistor -> 2N7000 Gate |
| N/A | N/A | 12V VCC | 12V PSU (+) -> Fan Pin 2 (VCC) |
| N/A | N/A | Fan PWM | Fan Pin 4 (PWM) -> 12V PSU (+) via 1kΩ pull-up* |
*Note: Standard 4-pin PC fans expect a 5V open-drain PWM signal. The 2N7000 pulls the fan's PWM line to ground. Ensure the fan's internal pull-up is sufficient, or add a 10kΩ resistor from the Fan PWM pin to the 12V line if the fan fails to spin at 100% duty cycle.
Wiring Steps
- De-energize everything. Unplug the Pi 5 and the 12V power supply before touching any wires.
- Establish a common ground. Connect the GND wire from the 12V PSU to the Pi 5 Pin 6 (GND). Safety Warning: Failing to share a common ground between the Pi and the external PSU will cause the PWM signal to float, potentially destroying the Pi's RP1 GPIO bank via back-voltage.
- Wire the MOSFET gate. Connect Pi 5 Pin 12 (GPIO 18) to a 1kΩ resistor, then to the Gate (middle pin) of the 2N7000. Connect a 10kΩ pull-down resistor from the Gate to GND to prevent the fan from spinning up during Pi boot.
- Wire the MOSFET drain/source. Connect the Source (right pin, facing flat side) to GND. Connect the Drain (left pin) to the Fan's PWM wire (Pin 4 on the fan connector).
- Apply power. Plug in the 12V PSU to the fan's VCC and GND, then boot the Raspberry Pi.
The Code: Python pigpio with Error Handling
While the pigs hp 18 25000 500000 bash command works for quick tests, a robust deployment requires a script. Below is a complete, executable Python script using the pigpio library. It includes explicit pin definitions, hardware initialization, and comprehensive error handling for daemon and hardware faults.
import pigpio
import time
import sys
# --- Pin & Hardware Definitions ---
PWM_PIN = 18 # BCM GPIO 18 (Physical Pin 12)
PWM_FREQ = 25000 # 25kHz standard for 4-pin PC fans
DUTY_CYCLE = 500000 # 50% duty cycle (pigpio range: 0 to 1,000,000)
def main():
pi = None
try:
# Initialize connection to the pigpio daemon
pi = pigpio.pi()
if not pi.connected:
raise ConnectionError('Failed to connect to pigpio daemon.')
# Configure hardware PWM
pi.set_PWM_frequency(PWM_PIN, PWM_FREQ)
pi.set_PWM_dutycycle(PWM_PIN, DUTY_CYCLE)
print(f'Success: Fan running at 50% duty cycle on GPIO {PWM_PIN}.')
# Keep script alive to maintain PWM signal
while True:
time.sleep(1)
except pigpio.error as e:
print(f'Hardware Error: {e}. Check if GPIO {PWM_PIN} is claimed by another overlay.')
except ConnectionError as e:
print(f'Daemon Error: {e}')
print('Fix: Start the daemon with sudo pigpiod or enable the systemd service.')
except KeyboardInterrupt:
print('\nInterrupt received. Stopping fan safely...')
finally:
# Cleanup: Ensure pin is turned off and connection closed
if pi is not None and pi.connected:
pi.set_PWM_dutycycle(PWM_PIN, 0)
pi.stop()
print('GPIO cleaned up and daemon disconnected.')
if __name__ == '__main__':
main()
Debugging: 'Connection Refused' and 'Not in Use' Errors
When working at the intersection of Linux and bare-metal hardware, you will encounter specific error strings. Here is how to diagnose the two most common failures when executing a raspberry pi command for GPIO control.
- Is the daemon actually running? Run
systemctl status pigpiod. If it's dead, your Python script andpigscommands will instantly fail. - Is the pin muxed correctly? Run
raspi-gpio get 18. If it saysGPIO 18: level=0 fsel=0 func=INPUT, the hardware PWM alt-function hasn't been claimed by the daemon yet. If it saysfunc=ALT5, the daemon has it. - Is the physical ground shared? If the software reports success but the fan doesn't spin, your 12V PSU ground and Pi GND are likely not bridged.
Error 1: socket error: connect: Connection refused
Exact Error String: socket error: connect: Connection refused (via pigs) or ConnectionError: Failed to connect to pigpio daemon (via Python).
Ranked Causes:
- pigpiod service is disabled/stopped. The daemon crashed or was never enabled on boot. Fix: Run
sudo systemctl enable pigpiod && sudo systemctl start pigpiod. - Port 8888 is blocked or in use. The daemon listens on TCP 8888. If another service claims it, the daemon fails silently. Fix: Check with
sudo lsof -i :8888. - RP1 Memory Mapping Failure (Pi 5 specific). You are using an outdated
pigpioversion (pre-1.79) that doesn't understand the Pi 5's RP1 chip. Fix: Update your OS viasudo apt update && sudo apt full-upgradeto pull the patched library.
Error 2: Failed to set GPIO 18 to mode ALT5
Exact Error String: Failed to set GPIO 18 to mode ALT5 (when using the raspi-gpio set 18 a5 command manually).
Ranked Causes:
- Device Tree Overlay Conflict. Another overlay (like an I2S audio DAC or SPI screen) has already claimed GPIO 18 in
/boot/firmware/config.txt. Fix: Remove conflictingdtoverlay=lines and reboot. - Insufficient Permissions. You are running the command without
sudoon an older OS version where thegpiogroup isn't properly mapped to the RP1 character device. Fix: Prependsudoor add your user to thegpiogroup.
Extending and Simplifying the Build
Depending on your end goal, you might want to strip this project down to its bare essentials or scale it up into a closed-loop thermal management system.
How to Simplify the Build
If wiring a TO-92 MOSFET and calculating pull-down resistors feels like unnecessary friction, eliminate the discrete components entirely. Purchase the Adafruit DC Motor + Stepper FeatherWing or a dedicated Raspberry Pi Motor HAT (approx. $25). These HATs use I2C PWM drivers (like the PCA9685) and handle the logic-level shifting, flyback diodes, and power routing on-board. You simply plug it into the 40-pin header and send I2C commands, trading a few dollars for hours of saved bench time.
How to Extend the Build
To turn this open-loop fan controller into a smart thermal regulator, add a Bosch BME280 I2C temperature/humidity sensor ($10). Wire the BME280 to the Pi 5's I2C1 bus (Pins 3 and 5). You can then write a PID control loop in Python that reads the ambient temperature via the smbus2 library and dynamically adjusts the DUTY_CYCLE variable in the pigpio script. This is the exact architecture used in custom 3D printer enclosure exhaust systems and network rack cooling deployments.
Raspberry Pi Command FAQ
How do I run a raspberry pi command for GPIO on boot without root?
Historically, accessing /dev/mem required root privileges. On modern Raspberry Pi OS (Bookworm and later), the kernel exposes GPIO via the pinctrl and gpiochip character devices. To run pigs or Python scripts without sudo, ensure your user is in the gpio and spi groups (sudo usermod -aG gpio $USER). Furthermore, configure the pigpiod systemd service to start on boot, and set the daemon's socket permissions to allow group access by editing /etc/systemd/system/pigpiod.service and adding -p 8888 to the ExecStart line.
What is the difference between the raspi-gpio and pigs raspberry pi commands?
Think of raspi-gpio as a diagnostic inspector and pigs as an active driver. The raspi-gpio command queries the kernel's device tree and pin muxing state; it tells you what the pin is configured to do (e.g., INPUT, OUTPUT, ALT0-ALT5). It is not designed for high-speed toggling. Conversely, pigs is the client for the pigpio daemon. It bypasses the kernel's standard GPIO subsystem to manipulate the hardware registers directly via DMA. Use raspi-gpio to debug why a pin isn't working, and use pigs to actually drive the pin with precise timing.
Which raspberry pi command shows the current pinout and alt functions?
To dump the entire state of the 40-pin header, including the currently assigned ALT functions (which indicate hardware PWM, I2C, or SPI routing), use the command raspi-gpio get. If you want to check a specific pin's muxing state and pull-up/down resistor configuration, use raspi-gpio get [pin_number] (e.g., raspi-gpio get 18). For a visual, color-coded pinout diagram directly in the terminal, install the pinout utility via pip3 install gpiozero and simply type pinout in your shell.






