-
-
Notifications
You must be signed in to change notification settings - Fork 40
Real time provider rpi
This page documents the rpi realtime I/O provider used by BDRealTime.
Current status:
- Working and currently the primary tested hardware path.
- Uses
gpiozerofor GPIO and MCP3008 ADC. - Uses
pigpiohardware PWM when available, with fallback togpiozero.PWMOutputDevice.
Implementation module: src/bdsim/blocks/io_rpi_gpio.py.
-
PWMOUTvia provider analog output. -
DIGITALOUTandDIGITALINon GPIO pins. -
ANALOGINusing MCP3008 channels 0-7.
Provider names accepted:
rpirpi_gpiogpiogpiozero
Recommended packages:
sudo apt update
sudo apt install -y python3-gpiozero python3-lgpio pigpio python3-pigpioIf you install with pip instead:
pip install gpiozero pigpioStart pigpio daemon for hardware PWM support:
sudo systemctl enable pigpiod
sudo systemctl start pigpiod
sudo systemctl status pigpiodIf pigpiod is not running, bdsim still runs but PWM falls back to software PWM.
For reliable hardware setup (especially PWM + SPI), check boot-time config.
Edit:
sudo nano /boot/firmware/config.txtRecommended settings:
# Enable SPI for MCP3008 (or other SPI ADCs)
dtparam=spi=on
# Free PWM channels used by onboard analog audio (important for GPIO18/19 PWM)
dtparam=audio=offThen reboot:
sudo rebootNotes:
-
dtparam=audio=offis important when you use hardware PWM on BCM18/19, since onboard analog audio uses the same PWM hardware resources. - If you need onboard analog audio, prefer PWM pins BCM12/13 for control output,
or disable hardware PWM per block with
io_options={"hardware_pwm": False}.
from bdsim.realtime import BDRealTime
rt = BDRealTime(io_provider="rpi", toolboxes=False)For rpi, channel values are physical pin/channel identifiers, not TOML device names.
- GPIO pins: integer BCM numbers (for example
18) or strings like"GPIO18","BCM18". - ADC channels: integer
0..7for MCP3008.
Examples:
clock = bd.clock(50, "Hz", name="clock") # 50 Hz control/sample clock
u = bd.PWMOUT(clock, channel=18, freq=10_000, name="u")
y = bd.ANALOGIN(clock, channel=1, name="y")
yref = bd.ANALOGIN(clock, channel=0, name="yref")PWMOUT writes a normalized duty command in [0, 1].
- Values below 0 clamp to 0.
- Values above 1 clamp to 1.
Hardware PWM is attempted on BCM pins:
- 12, 13, 18, 19
Use these pins if you want stable high-frequency PWM.
ANALOGIN with rpi expects MCP3008 (enabled on CS0) channel index 0..7.
Return value is normalized by gpiozero.MCP3008 in [0, 1].
If you need engineering units, add scaling in your diagram (GAIN, SUM, etc.).
Per block, pass backend options via io_options={...}.
Examples:
# Force software PWM even on hardware-capable pin
u = bd.PWMOUT(clock, channel=18, freq=5_000,
io_options={"hardware_pwm": False})
# Override active polarity
dout = bd.DIGITALOUT(clock, channel=23,
io_options={"active_high": True})
# Pull-up for digital input
din = bd.DIGITALIN(clock, channel=24,
io_options={"pull_up": True})
# Explicit ADC type (currently mcp3008 only)
y = bd.ANALOGIN(clock, channel=0,
io_options={"adc_type": "mcp3008"})#!/usr/bin/env python3
from bdsim.realtime import BDRealTime
rt = BDRealTime(io_provider="rpi", toolboxes=False)
bd = rt.blockdiagram()
clock = bd.clock(0.02, name="clock")
wave = bd.WAVEFORM(wave="square", freq=0.25, unit="Hz", min=0.25, max=0.75, name="u")
pwm = bd.PWMOUT(clock, channel=18, freq=10_000, name="pwm")
bd.connect(wave, pwm)
bd.compile()
rt.run(bd, tf=20)An LED on GPIO18 will alternate between 25% for 2 seconds and 75% brightness for 2 seconds. The LED is driven by a PWM pulse train at 10kHz.
- PWM LED demo: BCM18 (physical pin 12) plus resistor (470ohm) and LED to GND.
- MCP3008: wire SPI correctly (
MOSI,MISO,SCLK,CE0) and 3V3/GND. - Ensure SPI is enabled when using MCP3008:
sudo raspi-config
# Interface Options -> SPI -> EnableRpiGPIOProvider requires gpiozero to be installed
Install gpiozero in the Python environment used to run bdsim.
-
pigpioconnection not available
Start pigpiod service; otherwise software PWM fallback is used.
Detailed daemon checks:
# Service status
sudo systemctl status pigpiod --no-pager
# Start/restart and verify
sudo systemctl restart pigpiod
sudo systemctl is-active pigpiod
# Process check (should show pigpiod)
pgrep -a pigpiodIf pigpiod fails to start, inspect logs:
sudo journalctl -u pigpiod -n 100 --no-pagerCommon causes:
- Missing package (
pigpionot installed). - Conflicting GPIO service/process already holding resources.
- Stale daemon instance from manual launch.
Useful recovery sequence:
sudo systemctl stop pigpiod
sudo killall pigpiod 2>/dev/null || true
sudo systemctl start pigpiod
sudo systemctl status pigpiod --no-pager- Permission denied for GPIO access
- Quick check: run once with
sudoto confirm it is permission-related. - Then fix user permissions/groups according to your Raspberry Pi OS configuration.
- ADC channel error
ANALOGIN channel must be in 0..7 for MCP3008.
- How to confirm hardware PWM vs software fallback
The provider tries hardware PWM first (on BCM 12, 13, 18, 19) when
pigpiod is available. If that path is unavailable, it falls back to
software PWM.
Practical diagnostics:
# 1) Confirm daemon is alive
sudo systemctl is-active pigpiod
# 2) Observe GPIO function while diagram runs
sudo raspi-gpio get 18Typical interpretation while actively driving PWM on BCM18:
- Hardware PWM path: pin function usually shows an ALT mode (PWM function).
- Software fallback: pin typically remains plain OUTPUT.
Additional clues:
- Hardware PWM at high carrier rates (for example 10 kHz) remains stable with lower CPU load.
- Software PWM tends to show more jitter and higher CPU usage as frequency increases.
For A/B testing, force software path from the block:
u = bd.PWMOUT(clock, channel=18, freq=10_000,
io_options={"hardware_pwm": False})If behavior is unchanged when forcing software mode, you were likely already on fallback. If stability/CPU usage gets worse, hardware PWM was likely active before.
Use TELEMETRY exactly the same way as any provider.
telemetry = bd.TELEMETRY(clock, nin=3, endpoint="192.168.1.10:5001")On the desktop/laptop viewer:
telemetry-client --listen 0.0.0.0:5001- Raspberry Pi config.txt documentation: https://www.raspberrypi.com/documentation/computers/config_txt.html
- Raspberry Pi device tree overlays guide: https://www.raspberrypi.com/documentation/computers/configuration.html#device-tree-overlays
- gpiozero documentation: https://gpiozero.readthedocs.io/
- pigpio documentation: http://abyz.me.uk/rpi/pigpio/
Copyright (c) Peter Corke 2020-
- Home
- API reference (Sphinx)
- Block catalog
- Control Systems Magazine article
- Adding blocks to your model
- Block path
- Connecting blocks
- Compiling
- Running
- Watching a simulation variable
- Simulation results
- Runtime options
- Environment variables
- Discrete-time blocks
- Subsystems
- Figures
- Notebook animation
- Animation and movies
- PID control
- Coding patterns
- Block methods and attributes
- Time stepping: integration, animation & events
- Blocks, wires and plugs
- Graphics blocks
- Evaluation
- Runtimes and simulator state
- Creating a new block
- Related packages
Under development on feat/realtime branch, planned for release before end of 2026.