servo-pwm-sysfs.sh

Banana Pi BPI-M2 Zero (Allwinner H2+ / H3) · File : servo-pwm-sysfs.sh · Language : Bash · Use case : Piloter un servo avec l'interface PWM du noyau (sysfs)

The Linux kernel PWM interface (sysfs) is identical on every board: 20 ms period, 0.5-2.5 ms pulse. This bash script sweeps a servo over 3 cycles then cuts power to stop the buzzing.

Hardware required

A Banana Pi BPI-M2 ZERO (Allwinner H2+, Pi Zero form factor) on an Armbian image, powered by its dedicated micro-USB power port, with its Raspberry-Pi-compatible 40-pin header. 1 hobby servo + external 5 V supply (never the board 5 V beyond a micro servo).

Wiring

Servo signal on the connector PWM pin (channel exposed in /sys/class/pwm once enabled), external supply, common grounds.

How it works

export creates the channel folder; period/duty_cycle are in nanoseconds. servo_angle converts the angle into a pulse; enable cleanly stops the signal. On Armbian: sudo apt install gpiod, then gpiodetect (gpiochip0 = banks PA-PE, gpiochip1 = PL) and gpioinfo to find the header lines (CON2-Pxx names).

Going further

Wrap the function in a small Python daemon (python3-pwmio or sysfs writes) for remote control.

servo-pwm-sysfs.sh

#!/bin/bash
# Servo d'angle via /sys/class/pwm (interface noyau standard).
# Exemple pour le canal PWM 0 du connecteur (a adapter a la carte :
# ls /sys/class/pwm/ apres activation du PWM dans le firmware/overlay).

PWM="/sys/class/pwm/pwmchip0"
CANAL=0

# Exporter le canal s'il n'existe pas.
if [ ! -d "$PWM/pwm$CANAL" ]; then
  echo $CANAL > "$PWM/export" 2>/dev/null || {
    echo "PWM $CANAL indisponible : activer le canal (overlay/device tree)"; exit 1; }
  sleep 1
fi

# Configuration : frequence 50 Hz = periode 20 000 000 ns.
echo 20000000 > "$PWM/pwm$CANAL/period"
echo 1500000  > "$PWM/pwm$CANAL/duty_cycle"   # 1,5 ms = 90 degres
echo 1        > "$PWM/pwm$CANAL/enable"

servo_angle() {  # $1 = angle 0..180
  local ns=$((500000 + $1 * 2000000 / 180))   # 0,5..2,5 ms en ns
  echo $ns > "$PWM/pwm$CANAL/duty_cycle"
}

for cycle in 1 2 3; do
  for a in $(seq 0 10 180); do servo_angle $a; sleep 0.1; done
  for a in $(seq 180 -10 0); do servo_angle $a; sleep 0.1; done
done
echo 0 > "$PWM/pwm$CANAL/enable"   # coupe l'alimentation du servo
# Penser a « echo $CANAL > $PWM/unexport » au propre.

← Back to the board