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

Difficulty: Intermediate (2/5) | Time: 45 minutes | Cost: ~$85

Parts List & Spec Sheet

ComponentExact Model / VariantEstimated CostNotes
MicrocontrollerRaspberry Pi 5 (4GB)$60.00Requires active cooler; RP1 southbridge.
PWM FanNoctua NF-A12x25 12V PWM$30.0025kHz PWM frequency requirement.
MOSFET2N7000 N-Channel (TO-92)$0.50Logic-level gate threshold (Vgs ~2.0V).
Resistors1kΩ (Gate) & 10kΩ (Pull-down)$0.101/4W carbon film or metal film.
Power Supply12V 2A DC Wall Adapter$8.00Do NOT power 12V fans from the Pi 5V pin.

Pin Mapping Table

Pi 5 Physical PinBCM GPIOFunctionWiring Destination
Pin 6GNDSystem GroundCommon GND rail (Pi + 12V PSU + MOSFET Source)
Pin 12GPIO 18Hardware PWM01kΩ Resistor -> 2N7000 Gate
N/AN/A12V VCC12V PSU (+) -> Fan Pin 2 (VCC)
N/AN/AFan PWMFan 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

  1. De-energize everything. Unplug the Pi 5 and the 12V power supply before touching any wires.
  2. 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.
  3. 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.
  4. 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).
  5. 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.

The First Three Things to Check When It Fails:
  1. Is the daemon actually running? Run systemctl status pigpiod. If it's dead, your Python script and pigs commands will instantly fail.
  2. Is the pin muxed correctly? Run raspi-gpio get 18. If it says GPIO 18: level=0 fsel=0 func=INPUT, the hardware PWM alt-function hasn't been claimed by the daemon yet. If it says func=ALT5, the daemon has it.
  3. 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:

  1. pigpiod service is disabled/stopped. The daemon crashed or was never enabled on boot. Fix: Run sudo systemctl enable pigpiod && sudo systemctl start pigpiod.
  2. 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.
  3. RP1 Memory Mapping Failure (Pi 5 specific). You are using an outdated pigpio version (pre-1.79) that doesn't understand the Pi 5's RP1 chip. Fix: Update your OS via sudo apt update && sudo apt full-upgrade to 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:

  1. 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 conflicting dtoverlay= lines and reboot.
  2. Insufficient Permissions. You are running the command without sudo on an older OS version where the gpio group isn't properly mapped to the RP1 character device. Fix: Prepend sudo or add your user to the gpio group.

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.