Overview
Peripherals implement thePeripheral trait, which provides:
- Connection management: Connect to hardware over serial, native GPIO, or network
- Tool exposure: Each peripheral exposes tools the agent can use
- Health monitoring: Check device connectivity and status
Supported Hardware
ZeroClaw supports multiple hardware platforms:Raspberry Pi GPIO
Native GPIO control via rppal (BCM pin numbering)
STM32 Nucleo
Serial-connected microcontrollers (Nucleo-F401RE, etc.)
Arduino
Arduino Uno and compatible boards
Arduino Uno Q
WiFi-connected Arduino via Bridge app
Step-by-Step Setup
[peripherals]
enabled = true
# Raspberry Pi GPIO (native)
[[peripherals.boards]]
board = "rpi-gpio"
transport = "native"
# STM32 Nucleo over serial
[[peripherals.boards]]
board = "nucleo-f401re"
transport = "serial"
path = "/dev/ttyACM0"
baud = 115200
# Arduino Uno over serial
[[peripherals.boards]]
board = "arduino-uno"
transport = "serial"
path = "/dev/ttyUSB0"
baud = 115200
# Arduino Uno Q over WiFi bridge
[[peripherals.boards]]
board = "uno-q"
transport = "bridge"
Configured peripherals:
rpi-gpio native (native)
nucleo-f401re serial /dev/ttyACM0
arduino-uno serial /dev/ttyUSB0
Raspberry Pi GPIO Example
Here’s how the Raspberry Pi GPIO peripheral is implemented (src/peripherals/rpi.rs):
GPIO Read Tool
GPIO Write Tool
Serial Peripheral Communication
For STM32 and Arduino boards, ZeroClaw uses a serial protocol to communicate with firmware:Protocol Format
Commands are JSON-based over serial:Serial Transport
Fromsrc/peripherals/serial.rs:
Arduino Uno Q (WiFi Bridge)
For wireless control, use the Arduino Uno Q Bridge:Setup Bridge
Bridge Configuration
Creating Custom Peripherals
use crate::peripherals::traits::Peripheral;
use crate::tools::{Tool, ToolResult};
use async_trait::async_trait;
pub struct MyCustomPeripheral {
device_path: String,
connected: bool,
}
impl MyCustomPeripheral {
pub fn new(device_path: String) -> Self {
Self {
device_path,
connected: false,
}
}
}
#[async_trait]
impl Peripheral for MyCustomPeripheral {
fn name(&self) -> &str {
"my-custom-peripheral"
}
fn board_type(&self) -> &str {
"custom"
}
async fn connect(&mut self) -> Result<()> {
// Initialize your hardware connection
self.connected = true;
Ok(())
}
async fn disconnect(&mut self) -> Result<()> {
self.connected = false;
Ok(())
}
async fn health_check(&self) -> bool {
self.connected
}
fn tools(&self) -> Vec<Box<dyn Tool>> {
vec![
Box::new(MyCustomTool),
]
}
}
struct MyCustomTool;
#[async_trait]
impl Tool for MyCustomTool {
fn name(&self) -> &str {
"custom_sensor_read"
}
fn description(&self) -> &str {
"Read data from custom sensor"
}
fn parameters_schema(&self) -> Value {
json!({
"type": "object",
"properties": {
"sensor_id": {
"type": "integer",
"description": "Sensor ID (0-7)"
}
},
"required": ["sensor_id"]
})
}
async fn execute(&self, args: Value) -> Result<ToolResult> {
let sensor_id = args["sensor_id"].as_u64()
.ok_or_else(|| anyhow::anyhow!("Missing sensor_id"))?;
// Read from your hardware
let value = read_sensor(sensor_id as u8).await?;
Ok(ToolResult {
success: true,
output: format!("Sensor {} = {}", sensor_id, value),
error: None,
})
}
}
Best Practices
Use appropriate transports
Use appropriate transports
- Serial: STM32, Arduino, ESP32 (reliable, wired)
- Native: Raspberry Pi GPIO (fastest, direct access)
- Bridge/Network: Wireless devices (flexible, may have latency)
Handle connection failures gracefully
Handle connection failures gracefully
Validate pin numbers and ranges
Validate pin numbers and ranges
Use blocking tasks for synchronous hardware APIs
Use blocking tasks for synchronous hardware APIs
Add firmware version checks
Add firmware version checks
Troubleshooting
Permission denied on /dev/ttyACM0 or /dev/ttyUSB0
Permission denied on /dev/ttyACM0 or /dev/ttyUSB0
Add your user to the
dialout group:GPIO access denied on Raspberry Pi
GPIO access denied on Raspberry Pi
Run with appropriate permissions or add user to gpio group:
Serial communication hangs
Serial communication hangs
Check baud rate, connection, and firmware:
Firmware not responding after flash
Firmware not responding after flash
Press reset button on the board after flashing:
Next Steps
Creating Tools
Learn how to create custom tools
Gateway Setup
Expose your agent via HTTP