Embedded Rust
Master async programming in resource-constrained environments
A learning journey into embedded Rust development - This project explores the Embassy async runtime framework to control a physical robot arm using a Raspberry Pi Pico microcontroller.
This is a hands-on learning project that combines:
The project uses the Embassy async runtime, which provides:
// Core Embassy setupuse embassy_rp::gpio::{Input, Output, Pull};use embassy_rp::pwm::Pwm;use embassy_time::{Duration, Timer};
// Servo control with PWMlet mut pwm = Pwm::new_output_a(pio, pin, config);pwm.set_duty(duty_cycle);# Install Rust with embedded targetrustup target add thumbv6m-none-eabi
# Install probe-rs for debuggingcargo install probe-rs --features cli
# Install elf2uf2 for UF2 binary creationcargo install elf2uf2# Build the project (automatically flashes if Pico is connected)cargo build
# Manual flash if neededcargo build --releaseelf2uf2 -d target/thumbv6m-none-eabi/release/robot-arm# Then copy the UF2 file to the Pico's RPI-RP2 drivePico GPIO 0-4 → Servo signal pinsPico GPIO 5-9 → Sensor inputs (optional)Pico GPIO 10-14 → LED indicators (optional)Pico GND → Common groundPico VBUS → 5V power for servosEmbedded Rust
Master async programming in resource-constrained environments
PWM Control
Learn pulse-width modulation for servo motor control
Real-time Systems
Understand timing-critical embedded applications
Hardware Abstraction
Work with HALs and device drivers
robot-arm/├── src/│ ├── main.rs # Embassy executor and task setup│ ├── servo.rs # Servo motor control abstraction│ ├── kinematics.rs # Robot arm mathematics│ └── web.rs # HTTP server (future)├── memory.x # Linker script for Pico├── rust-toolchain.toml # Specific Rust version└── .woodpecker.yaml # CI/CD pipeline#[embassy_executor::main]async fn main(spawner: Spawner) { // Initialize peripherals let p = embassy_rp::init(Default::default());
// Spawn async tasks spawner.spawn(servo_control_task(p.PWM_CH0)).unwrap(); spawner.spawn(sensor_reading_task(p.ADC)).unwrap();}// Configure PWM for servo (50Hz, 1-2ms pulse)let mut config = PwmConfig::default();config.top = 25000; // 50Hzconfig.compare_a = 1500; // 1.5ms (neutral position)
// Set servo position (0-180 degrees)fn set_servo_angle(pwm: &mut Pwm, angle: f32) { let duty = (angle / 180.0 * 1000.0 + 1000.0) as u16; pwm.set_duty(duty);}This is primarily a learning project, but contributions are welcome: