Skip to content

DanielKalicki/Xiaomi_CyberGear_Rust

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Xiaomi_CyberGear_Rust

Rust TWAI (Two-Wire Automotive Interface - concept conceived by Espressif, implements the CAN Bus) driver for Xiaomi CyberGear running on ESP32-S3 with esp-idf-hal.

This is a port of the C++ Arduino library to Rust for the ESP-IDF ecosystem.

Features

  • Full motor control API matching the original C++ implementation
  • Support for multiple control modes: Motion, Position, Speed, and Current
  • Comprehensive status feedback (position, speed, torque, temperature)
  • Type-safe Rust interface with proper error handling
  • Integrated with esp-idf-hal CAN/TWAI driver

Usage

Module imports

Include the CyberGear driver and types in your main.rs:

use xiaomi_cybergear::XiaomiCyberGearDriver;
use xiaomi_cybergear_defs::{CyberGearMode, CyberGearStatus};

CAN bus initialization

Set up the TWAI (CAN) interface with 1 Mbps baudrate:

let filter = can::config::Filter::standard_allow_all();
let timing = can::config::Timing::B1M;
let config = can::config::Config::new().filter(filter).timing(timing);
let mut can_driver = can::CanDriver::new(
    peripherals.can,
    peripherals.pins.gpio43, // TX - D6 on Xiao ESP32S3
    peripherals.pins.gpio44, // RX - D7 on Xiao ESP32S3
    &config,
).unwrap();
can_driver.start().unwrap();

Motor initialization

Create and initialize the motor driver:

const CYBERGEAR_CAN_ID: u8 = 0x7F;  // CAN ID of the CyberGear motor
const MASTER_CAN_ID: u8 = 0x00;     // ESP32S3 CAN ID

let mut cybergear = XiaomiCyberGearDriver::new(
    can_driver,
    CYBERGEAR_CAN_ID,
    MASTER_CAN_ID
);

// Optional: enable debug output
cybergear.set_serial_debug(true);

// Initialize motor in position mode
cybergear.init_motor(CyberGearMode::Position);
cybergear.set_limit_speed(10.0);      // max speed 10 rad/s
cybergear.set_limit_current(5.0);     // max current 5 A
cybergear.enable_motor();
cybergear.set_position_ref(0.0);      // set initial position to 0

Main control loop

In your main loop, send commands and receive status:

loop {
    FreeRtos::delay_ms(1000);

    // Send motor command (e.g., move to new position)
    cybergear.set_position_ref(target_position);

    // Receive and process CAN messages
    while let Ok(rx_frame) = cybergear.receive(0) {
        let raw_id = rx_frame.identifier();
        if ((raw_id & 0xFF00) >> 8) == CYBERGEAR_CAN_ID as u32 {
            cybergear.process_message(&rx_frame);
        }
    }

    // Read current motor status
    let status = cybergear.get_status();
    println!(
        "POS:{:.4} V:{:.4} T:{:.4} temp:{}",
        status.position, status.speed, status.torque, status.temperature
    );

    // Request fresh status from the motor
    cybergear.request_status();
}

API Overview

Lifecycle methods

  • init_motor(mode) - Initialize motor with specified control mode
  • enable_motor() - Power on the motor
  • stop_motor() - Stop and power off the motor

Limit configuration

  • set_limit_speed(speed) - Set maximum speed (rad/s)
  • set_limit_current(current) - Set maximum current (A)
  • set_limit_torque(torque) - Set maximum torque (Nm)

Motion mode (continuous control)

  • send_motion_control(cmd) - Send position, speed, torque, and gains

Position mode

  • set_position_kp(kp) - Set position loop proportional gain
  • set_position_ref(position) - Set target position reference

Speed mode

  • set_speed_kp(kp) - Set speed loop proportional gain
  • set_speed_ki(ki) - Set speed loop integral gain
  • set_speed_ref(speed) - Set target speed reference

Current mode

  • set_current_kp(kp) - Set current loop proportional gain
  • set_current_ki(ki) - Set current loop integral gain
  • set_current_filter_gain(gain) - Set current filter gain
  • set_current_ref(current) - Set target current reference

Status and feedback

  • request_status() - Request motor status from the bus
  • process_message(frame) - Process received CAN frame
  • get_status() - Get last known motor status (position, speed, torque, temperature)

Configuration

  • set_motor_can_id(id) - Change motor's CAN ID
  • get_motor_can_id() - Get current motor CAN ID
  • get_run_mode() - Get current motor control mode

CAN bus access

  • receive(timeout) - Receive a CAN frame (blocking with timeout)
  • read_alerts(timeout) - Read CAN bus alerts

Modes

Position mode (CyberGearMode::Position)

Control motor position with proportional feedback.

Speed mode (CyberGearMode::Speed)

Control motor speed with PI feedback.

Current mode (CyberGearMode::Current)

Control motor current (torque) directly.

Motion mode (CyberGearMode::Motion)

Advanced control with simultaneous position, speed, and torque commands with individual gains.

Example

See src/main.rs for a complete working example that:

  • Initializes the CAN bus
  • Sets up the motor in position mode
  • Oscillates the position reference between -10 and +10 radians
  • Continuously requests and displays motor status

Documentation

Xiaomi CyberGear technical drawing:

Hardware Setup

Tests were performed using:

Connections:

  • ESP32S3 GPIO43 (D6) → CAN transceiver TX
  • ESP32S3 GPIO44 (D7) → CAN transceiver RX
  • CAN transceiver → CyberGear motor CAN interface

Building and Running

  1. Ensure you have the ESP Rust environment set up: https://github.com/esp-rs/esp-idf-template
  2. Build the project:
    cd xiaomi_cybergear
    cargo build
  3. Flash to the device:
    cargo run

References

About

Rust library for Xiaomi CyberGear using TWAI interface on ESP32 uC

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages