Skip to content

Repository files navigation

RC-Joystick

ESP32-S3-based joystick emulation that reads ExpressLRS CRSF protocol from an RC receiver and presents as a USB HID gamepad (8 axes, 16-bit). Built with Rust, esp-hal, and embassy.

USB HID Specification

Attribute Value
Usage Game Pad (Generic Desktop)
Axes 8: X, Y, Z, Rx, Ry, Rz, Slider, Slider
Axis resolution 16-bit, logical range 0–65535
Center (neutral) 32767
Report size 16 bytes (8 × uint16 LE)
IN endpoint Interrupt, 16 bytes, 1 ms interval
VID:PID 0x303A:0x4001 (Espressif)
USB speed Full Speed (12 Mbps)
Polling rate Up to 1 kHz (matches CRSF frame rate)

Setup

Linux / macOS

# 1. Install Rust
curl --proto '=https' -sSf https://sh.rustup.rs | sh

# 2. Install ESP tooling
cargo install espup espflash

# 3. Install Xtensa Rust target + LLVM
espup install

# 4. Source environment (every new terminal)
. "$HOME/.cargo/env"
. "$HOME/export-esp.sh"

Windows (PowerShell)

# 1. Install Rust
# Download and run rustup-init.exe from https://rustup.rs

# 2. Install ESP tooling
cargo install espup espflash

# 3. Install Xtensa Rust target + LLVM
espup install

# 4. Source environment (every new terminal)
. $env:USERPROFILE\.cargo\env.ps1
. $env:USERPROFILE\export-esp.ps1

export-esp.sh / export-esp.ps1 is generated by espup install in your home directory. It sets LIBCLANG_PATH and Xtensa toolchain PATH variables.

WSL2

On Windows you can alternatively use WSL2 and follow the Linux instructions above. USB passthrough with usbipd may be needed for flashing.

VS Code

Open the project folder in VS Code and install these extensions:

The repo includes pre-configured files under .vscode/:

  • settings.json — toolbar buttons bound to Build (ESP), Flash & Monitor, and Test (host) tasks.
  • tasks.json — three tasks:
    • Build (ESP)cargo esp-build (bound to Ctrl+Shift+B)
    • Test (host)cargo test --lib
    • Flash & Monitorespflash flash --monitor (depends on Build)

Before building, source the ESP environment in the VS Code terminal first (e.g. . $HOME/export-esp.sh on Linux or . $env:USERPROFILE\export-esp.ps1 on Windows).

Build & Flash

# Build for ESP32-S3
cargo esp-build

# Flash and monitor
espflash flash --monitor target/xtensa-esp32s3-none-elf/release/rc-joystick

# Run unit tests on host
cargo test --lib

Board Pinout — ESP32-S3-Tiny

GPIO Function
4 UART1 RX — CRSF from RC receiver
5 UART1 TX — CRSF to RC receiver (reserved)
43 UART0 TX — debug console (115200 baud)
20 USB OTG D+
19 USB OTG D-

Debug console

Connect a UART adapter to GPIO43 (TX) at 115200 baud. Boot messages confirm firmware startup. The USB OTG port is dedicated to the HID gamepad, not serial.

Usage

Connect an ExpressLRS RC receiver to GPIO4 (RX) and GPIO5 (TX). The firmware automatically parses CRSF frames and sends HID axis reports.

Verify on the host:

  • Linux: evtest / jstest / lsusb -v
  • Windows: Game Controllers control panel (joy.cpl)
  • macOS: System Report → USB → Game Controller

Project Structure

rc-joystick/
├── Cargo.toml
├── .cargo/config.toml
├── src/
│   ├── main.rs        # embassy entry, main loop
│   ├── lib.rs         # library root (host-testable)
│   ├── crsf.rs        # CRSF parser + unit tests
│   ├── hid.rs         # HID gamepad descriptor
│   ├── pins.rs        # GPIO constant definitions
│   └── config.rs      # Project metadata

Stack

Layer Crate
HAL esp-hal
USB framework embassy-usb
HID descriptor usbd-hid
Async executor embassy-executor

License

SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only

Copyright (c) 2026 Richard C. L. Li

This project is dual-licensed under the GNU General Public License, version 2 or version 3. You may choose either license when using, modifying, or distributing this software.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages