agentleFS
D-RoboticsD-Robotics/rdk-skills/skills/rdk-peripheral-cookbook/SKILL.md

rdk-peripheral-cookbook

Skill5 starsChanged 3 months agoApache-2.0View on GitHub

Hands-on peripheral driving on RDK boards — GPIO/I2C/SPI/UART/PWM, servos, DC/stepper/BLDC motors, LED/WS2812, audio (ALSA), and CAN (X5 SocketCAN vs S100/S600 MCU-domain CANHAL) — plus cross-platform pin/bus mapping and zero-driver diagnosis. Use whenever the user wants to actually light an LED, spin a motor, read a sensor, play/record audio, wire a servo, bring up CAN, or when a peripheral plugged into the board is "not detected / no driver". 触发词:点灯、GPIO 不工作、libgpiod、i2cdetect、PCA9685、舵机、步进电机、无刷、WS2812 灯带、ALSA 播放录音、aplay、CAN、SocketCAN、cansend、candump、S100 CAN、S600 自锁口、40PIN 接线、拨码开关、设备不识别没驱动. Routing — pure GPIO pin-number facts / per-board pinout tables → rdk-hardware (cite it when wiring); device error-code lookup / "板子报错" → rdk-board-knowledge; connector/cable/accessory part numbers → rdk-accessories.

  • Deletes or force-pushes
  • Installs packages

2 other projects use a version of this, 1 of them edited.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

11 rules. About 0 are common, 3 are distinctive, and 8 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Very specific:

    Use Hobot.GPIO: only when you need RPi-tutorial compatibility (its API copies RPi.GPIO).

    line 47
  2. Very specific:

    Real-time / <1ms jitter?: Call libgpiod from C, or on X5 use x5-hobot-io (C bindings, ~10× lower latency than Python Hobot.GPIO).

    line 48
  3. Very specific:

    S100/S600: start MCU1, build the /app/Can sample (make), edit the JSON config to the right IPC instance/channel for your CAN line, then …

    line 93
  4. Very specific:

    Answer template: ask for board model + interface (USB / 40PIN I2C / UART / MIPI) + device model → have the user run dmesg/lsusb/ls /dev and …

    line 110
  5. Very specific:

    No TROS needed — go straight to ALSA.

    line 125
  6. Distinctive:

    When answering from this skill, follow these rules — never fabricate facts, commands, or file paths:

    line 145
  7. Distinctive:

    No fabrication when tools are missing: If a script or reference doesn't exist, say "not found" — don't invent from memory.

    line 148
  8. Very specific:

    Preserve null/false/empty on failure: If a probe returns null or false, report that — don't substitute a plausible value.

    line 149
  9. Very specific:

    No substitution off-platform: If off_platform: true, say "probe didn't run on an RDK board" — don't guess what it would have returned.

    line 150
  10. Distinctive:

    Acknowledge sandbox limits: If you can't run a command, say so — don't pretend you did.

    line 152
  11. Very specific:

    Read-only boundary: Never modify the system — no dd, mkfs, rm -rf, apt install, reboot, or GPIO output without explicit user confirmation.

    line 153

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

RDK Peripheral Cookbook

Drive a real peripheral on an RDK board: GPIO, I2C, SPI, UART, PWM, servos, motors, LEDs, audio, and CAN. The single rule that prevents the most damage: never power a servo, motor, or LED strip from 40PIN Pin 2/4 (5V) — even one SG90 stall current can brown out the board and reboot it. Always use an external 5V/6V supply and share GND.

Sources: official D-Robotics docs (rdk_doc / rdk_s_doc 40pin user guide, rdk_x5/can.md, mcu_development/09_mcu_can.md), the x5-hobot-io toolchain, and standard cross-platform Linux peripheral practice. Every non-trivial board-specific claim is verified against the cited source; cross-platform Linux facts (libgpiod, ALSA, PCA9685) are standard and noted as such.

The one rule that matters most

A peripheral that needs current — servo, DC/stepper/BLDC motor, WS2812 strip — must NOT draw its power from the 40PIN 5V rail (Pin 2/4). Stall or full-load current pulls the rail down and reboots the board. Always: external 5V/6V supply for the load, signal line back to the board, common GND. This applies on RDK, Raspberry Pi, Jetson, and Rockchip alike — it is not RDK-specific.

Decision cheat-sheet (pick the right approach)

NeedFirst-choice approach
Cross-board GPIO / unsure of pin numberlibgpiod (gpiodetect / gpioinfo / gpiofind "GPIO17") — don't guess BCM numbers
Single servo (1–2 ch)On-board hardware PWM (50Hz / 20ms period, 1.0–2.0ms pulse), external supply
Multiple servos (≥3 ch)PCA9685 + I2C (default addr 0x40), servo power on PCA9685's V+ terminal
DC motorH-bridge (TB6612 / DRV8833 / BTS7960) + PWM speed + GPIO direction
Stepper motorDedicated driver (A4988 / DRV8825 / TMC2209 silent) + STEP/DIR
Brushless (BLDC)RC ESC (50Hz PWM, reuse PCA9685) or ODrive/VESC (UART/CAN closed-loop); on S100 use the MCU real-time domain
WS2812 RGB stripSPI MOSI emulating the 800kHz timing (run SPI at 2.4MHz, NeoPixel-SPI). RPi's rpi_ws281x does NOT work on RDK
Audio (no TROS)Standard ALSA (aplay -l / arecord / alsamixer); a USB sound card is the universal fallback
CANOnly X5 is Linux SocketCAN (TCAN4550): ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on + can-utils. S100/S600 CAN lives in the MCU domain — use CANHAL/IPC + /app/Can sample, NOT ip link. X3/Ultra have no on-board CAN. Full bringup: rdk-can-and-board-io.md

Safety rules (check before powering any peripheral)

  1. Never take 5V for servos/motors/WS2812 from 40PIN Pin 2/4. External 5V/6V supply, common GND with the board.
  2. Scan before you read/write. I2C: run i2cdetect -y <bus> and confirm the address appears first. PWM: start at low frequency / low duty.
  3. Persistent kernel/boot changes are the highest risk (/boot, device tree, MCU firmware). On RDK, don't touch them unless necessary.
  4. RDK-specific trap: a 40PIN pin may default to GPIO. On X-series, switch the function first via sudo srpi-config → 3 Interface Options → I3 Peripheral bus config (or the /app/40pin_samples/ scripts) before /dev/i2c-X or a pwmchip appears. S100 muxes I2C5/UART2 on the 40PIN with a dip switch (pick one). S600 has NO standard 40PIN — self-locking connectors, 1.8V digital IO; the 40PIN wiring in this cookbook does not apply to S600 (see rdk-can-and-board-io.md §4 and rdk-hardware).

Workflows

Workflow 1 — Cross-board GPIO (light an LED, read a button)

Use when: 点灯, GPIO 不工作, blink, button read, writing a script meant to run on more than one board.

  1. Enumerate, don't guess. gpiodetect → lists every gpiochip. gpioinfo gpiochip0 → shows each line's name.
  2. Operate by name for portability: gpioset $(gpiofind "GPIO17")=1. This is the only API common to RDK / RPi / Jetson / Rockchip.
  3. Use Hobot.GPIO only when you need RPi-tutorial compatibility (its API copies RPi.GPIO). It is system-Python only — import Hobot.GPIO inside conda/venv fails; use /usr/bin/python3.
  4. Real-time / <1ms jitter? Call libgpiod from C, or on X5 use x5-hobot-io (C bindings, ~10× lower latency than Python Hobot.GPIO).
  5. Verify — run bash scripts/gpio_probe.sh for structured JSON (gpio_lines, can_interfaces, can0_state). Confirm gpio_lines > 0 (or note the gpio_note if libgpiod is missing) before proceeding with GPIO operations.

Details and the cross-platform pin/bus mapping: hardware-notes.md.

验证: bash scripts/gpio_probe.sh returns gpio_lines > 0; gpioinfo gpiochip0 shows each line's name and consumer; gpioget $(gpiofind "GPIO17") reads the expected level (0 or 1).

Workflow 2 — Servos and motors

Use when: 舵机, 步进电机, 直流电机, 无刷, motor won't turn, robot joint.

  1. Single servo (1–2 ch): on-board hardware PWM. Signal = 50Hz (20ms period) + 1.0ms (0°) to 2.0ms (180°) pulse. Switch the pin to PWM mode first (srpi-config on X-series), then drive via /sys/class/pwm/pwmchipN/.
  2. ≥3 servos: PCA9685 + I2C (addr 0x40, 16ch, 12-bit). Servo power goes to PCA9685's V+ screw terminal, never the 40PIN rail.
  3. DC motor: H-bridge + PWM (speed) + GPIO (direction). TB6612FNG for a small 2-wheel car, BTS7960 for high current.
  4. Stepper: dedicated driver + STEP/DIR (2 GPIO, no PWM needed). TMC2209 if silence matters.
  5. BLDC: RC ESC (50Hz PWM like a servo) for open-loop; ODrive/VESC (UART/USB/CAN) for closed-loop. Bus servos (Feetech STS / Dynamixel) over USB-TTL are the standard for desktop arms / quadrupeds — one wire, many addressable servos.

Full wiring tables, code, and the PCA9685 troubleshooting steps: hardware-notes.md §Servos and §Motors.

验证: servo — cat /sys/class/pwm/pwmchipN/pwmX/enable shows 1 and the shaft holds position; PCA9685 — i2cdetect -y <bus> shows 0x40 and servos respond; motor — shaft turns and dmesg | tail shows no overcurrent warnings.

Workflow 3 — Audio without TROS (ALSA)

Use when: play/record audio and hobot_audio (TROS + official mic-array board) is not available.

  1. Probe: aplay -l / arecord -l list output/input cards. Nothing listed → kernel didn't see hardware → check lsusb and dmesg | grep -i snd.
  2. Play: aplay test.wav, or aplay -D plughw:1,0 test.wav for a specific card. MP3 needs mpg123 / sox first.
  3. Record: arecord -D plughw:1,0 -f S16_LE -r 16000 -c 1 -d 5 test.wav.
  4. Silent but a card exists? alsamixer → unmute (M), raise volume. Busy/"unable to open slave" → another process holds it (sudo fuser /dev/snd/*).
  5. Universal fallback: plug in a USB sound card — snd-usb-audio auto-loads and aplay -l shows it immediately. This is the only recommended path on Jetson (no on-board audio) and on RDK without an I2S HAT.

Command catalog and error table: hardware-notes.md §Audio.

验证: aplay -l lists the card; aplay test.wav plays sound; arecord -D plughw:1,0 -d 1 test.wav records and aplay test.wav plays it back; alsamixer shows the card unmuted.

Workflow 4 — CAN bringup

Use when: CAN, SocketCAN, cansend, candump, S100/S600 CAN.

  1. Identify the board first — this decides everything (scripts/can_mode.py <board> answers it deterministically):
    • X5 → Linux SocketCAN (TCAN4550 on SPI5). ip link + can-utils. Has a can0 network device.
    • S100 / S600 → CAN controller is in the MCU domain. Use CANHAL library + IPC + the /app/Can sample. There is no can0 — ip link set canX does not apply.
    • X3 / Ultra → no on-board CAN.
  2. X5 quick self-test (loopback): ip link set can0 type can bitrate 125000 → loopback on → up → candump can0 -L & → cansend can0 123#1122334455667788.
  3. X5 CAN FD: ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on; send an FD frame with ## (e.g. cansend can0 123##3...).
  4. S100/S600: start MCU1, build the /app/Can sample (make), edit the JSON config to the right IPC instance/channel for your CAN line, then ./canhal_get bypass & / ./canhal_send bypass <ch>. Terminate the bus with the right 120Ω element (X5 = switch, S100 = jumper, S600 = dip ON).

Full per-board CAN bringup, IPC channel maps, S100 dip mux, and S600 self-locking IO: rdk-can-and-board-io.md.

验证: X5 — ip link show can0 shows UP; candump can0 -L receives frames after cansend can0 123#1122334455667788; S100/S600 — ./canhal_get bypass prints received CAN frames without error; bus terminator is set (X5 switch / S100 jumper / S600 dip ON).

Workflow 5 — Zero-driver diagnosis (device not detected)

Use when: "I plugged in X but the board doesn't recognize it / no driver". Don't guess — run the 9 steps. Universal across RDK / RPi / Jetson / Rockchip.

dmesg | tail -50  →  lsusb  →  ls /dev/ (tty*/video*/i2c-*/spidev*/snd/)
→  i2cdetect -l && i2cdetect -y <bus>  →  v4l2-ctl --list-devices
→  aplay -l / arecord -l  →  lsmod | grep <kw>  →  modinfo/modprobe <mod>
→  cat /proc/device-tree/…

Answer template: ask for board model + interface (USB / 40PIN I2C / UART / MIPI) + device model → have the user run dmesg/lsusb/ls /dev and paste back → match the symptom table → give the smallest verifiable command → only then discuss ROS2-node wrapping / autostart.

Symptom→diagnosis table and the three orthogonal fix paths: hardware-notes.md §Zero-driver diagnosis.

验证: dmesg | tail -50 shows device enumeration (or explains why it's missing); ls /dev/ shows the expected device node (tty*/video*/i2c-/spidev/snd*); lsmod | grep <kw> shows the driver loaded.

Worked examples

Example 1 — "我在 S100 上敲 ip link set can0 type can bitrate 500000 不工作" That's the X5 path. S100's CAN is in the MCU domain — there is no can0 network device. Answer: "S100/S600 don't expose SocketCAN. The CAN controller lives in the MCU domain; Acore reaches it through CAN2IPC → IPC → the CANHAL library. Use the /app/Can sample: start MCU1, make the sample, set the IPC instance/channel in its JSON config (e.g. S100 CAN6 = instance 0 / channel 6), then ./canhal_get bypass & and ./canhal_send bypass 6. ip link, cansend, candump only work on X5." Point to rdk-can-and-board-io.md §2.

Example 2 — "想在 RDK X5 上接 4 个舵机,怎么接线?" Don't drive 4 servos from on-board PWM or the 40PIN rail. Answer: "Use a PCA9685 (I2C, default 0x40, 16 channels). Wire SDA/SCL/VCC/GND to the board; put the servo power on the PCA9685 V+ screw terminal from an external 5V/5A supply, common GND. Confirm with i2cdetect -y <bus> that 0x40 shows up before coding. If servos jitter, it's almost always supply, not signal." Point to Workflow 2.

Example 3 — "插了 USB 麦克风,想录音,没装 TROS" No TROS needed — go straight to ALSA. Answer: "arecord -l to find the card (e.g. card 1). Record with arecord -D plughw:1,0 -f S16_LE -r 16000 -c 1 -d 5 test.wav, play back with aplay test.wav. If nothing shows in arecord -l, check lsusb and dmesg | grep -i snd — a USB mic should auto-load snd-usb-audio." Point to Workflow 3.

Example 4 — "我接了个 WS2812 灯带,GPIO 拉高拉低控制不了" GPIO bitbang can't hold the WS2812 800kHz timing reliably. Answer: "Drive WS2812 from the SPI MOSI pin, emulating the timing: run SPI at ~2.4MHz and encode each WS2812 bit as 4 SPI bits, via Adafruit-CircuitPython-NeoPixel-SPI. RPi's rpi_ws281x does NOT work on RDK. And 30 LEDs at full white ≈ 1.8A — power the strip from an external 5V supply with common GND, never the 40PIN rail." Point to hardware-notes.md §LEDs.

Common pitfalls

❌ Don't✅ Do
Power servos/motors/WS2812 from 40PIN Pin 2/4External 5V/6V supply, common GND
Run ip link set can0 ... on S100/S600Use the MCU-domain CANHAL /app/Can sample (only X5 is SocketCAN)
Guess BCM numbers in a cross-board scriptUse libgpiod by line name (gpiofind "GPIO17")
Read I2C before confirming the addressi2cdetect -y <bus> first, then read/write
Expect /dev/i2c-X / pwmchip to exist by defaultSwitch the 40PIN function first (X5 srpi-config; S100 dip switch)
import Hobot.GPIO inside conda/venvUse system /usr/bin/python3 (bindings are system-only)
Drive WS2812 via GPIO bitbangSPI MOSI emulation at 2.4MHz (NeoPixel-SPI)
Assume S600 has a 40PINS600 uses 1.8V self-locking connectors (§4)

Anti-hallucination guardrails

When answering from this skill, follow these rules — never fabricate facts, commands, or file paths:

  1. Report only observed data. Quote what scripts/commands actually return, not what you remember. If the probe says board_id: X5, answer for X5 — even if the user insists it's an S100.
  2. No fabrication when tools are missing. If a script or reference doesn't exist, say "not found" — don't invent from memory. Route to the appropriate skill or doc instead.
  3. Preserve null/false/empty on failure. If a probe returns null or false, report that — don't substitute a plausible value. Empty output is data, not an error to "fix".
  4. No substitution off-platform. If off_platform: true, say "probe didn't run on an RDK board" — don't guess what it would have returned. Ask for on-board logs.
  5. No hand-editing JSON. Scripts emit structured JSON; never hand-craft output. If the contract says {ok,off_platform,reason,fields}, that's what goes to the user.
  6. Acknowledge sandbox limits. If you can't run a command, say so — don't pretend you did. Offer the command for the user to run.
  7. Read-only boundary. Never modify the system — no dd, mkfs, rm -rf, apt install, reboot, or GPIO output without explicit user confirmation.

Reference map

Read thisWhen
gpio-commands.mdQuick command/risk table for I2C / SPI / GPIO / pinmux probing
hardware-notes.mdDeep dives: cross-platform 40PIN pin/bus mapping, libgpiod, servos & PCA9685, motor paradigms, LEDs/WS2812, ALSA audio, zero-driver diagnosis SOP
rdk-can-and-board-io.mdCAN bringup (X5 SocketCAN / S100·S600 MCU-domain CANHAL), S100 I2C5↔UART2 dip mux, S600 self-locking IO (GPIO/UART6-7/SPI1)
scripts/can_mode.py <board>Deterministic "is this board SocketCAN or MCU-domain CAN?" lookup (X5/S100/S100P/S600/X3/Ultra)
scripts/gpio_probe.shLive GPIO/CAN probe — reads gpioinfo for GPIO line count + scans /sys/class/net/can* for CAN interfaces + checks can0 operstate (structured JSON {ok,off_platform,reason,fields}; non-board → {"ok":false,"off_platform":true,"reason":"not_on_rdk_board","fields":null}; board-but-no-libgpiod → reason="libgpiod not found")

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.