| Crates.io | mecha10-controllers |
| lib.rs | mecha10-controllers |
| version | 0.1.48 |
| created_at | 2025-11-24 21:10:47.244221+00 |
| updated_at | 2026-01-25 23:05:51.744379+00 |
| description | Control algorithms and controllers for the Mecha10 robotics framework |
| homepage | |
| repository | https://github.com/mecha10/mecha10 |
| max_upload_size | |
| id | 1948676 |
| size | 200,532 |
Hardware controller abstractions for the Mecha10 framework.
The controllers package provides a composable layer between hardware drivers and nodes. Controllers wrap device SDKs/libraries and provide standardized interfaces for nodes to manage hardware.
┌─────────────────┐
│ Node │ (Business logic)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Controller │ (Device management + SDK abstraction)
└────────┬────────┘
│
▼
┌──────────────┐
│ Hardware SDK │ (realsense-rust, bno055, etc.)
└──────────────┘
Controller - Base traitAll controllers implement this trait providing:
use mecha10_controllers::{Controller, ControllerHealth};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MyControllerConfig::default();
let mut controller = MyController::init(config).await?;
controller.start().await?;
let health = controller.health_check().await;
assert_eq!(health, ControllerHealth::Healthy);
controller.stop().await?;
Ok(())
}
CameraController: For RGB, depth, and RGBD camerasImuController: For IMUs and orientation sensorsLidarController: For 2D and 3D LiDARsMotorController: For motors and actuatorsuse mecha10_controllers::{Controller, CameraController};
use mecha10_controllers::mock::MockCameraController;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize camera
let config = MockCameraConfig::default();
let mut camera = MockCameraController::init(config).await?;
// Start streaming
camera.start().await?;
// Capture frames
loop {
let frame = camera.capture_frame().await?;
match frame {
CameraFrame::Rgb(rgb) => {
println!("RGB frame: {}x{}", rgb.width, rgb.height);
}
CameraFrame::Rgbd { color, depth, .. } => {
println!("RGBD frame: {}x{}", color.width, color.height);
}
_ => {}
}
tokio::time::sleep(tokio::time::Duration::from_millis(33)).await;
}
Ok(())
}
use mecha10_controllers::{Controller, ImuController};
use mecha10_controllers::mock::MockImuController;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MockImuConfig::default();
let mut imu = MockImuController::init(config).await?;
imu.start().await?;
// Check calibration
let status = imu.calibration_status();
if !status.is_fully_calibrated() {
println!("Calibrating IMU...");
imu.calibrate().await?;
}
// Read IMU data
loop {
let data = imu.read_imu().await?;
println!("Orientation: roll={}, pitch={}, yaw={}",
data.roll, data.pitch, data.yaw);
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
}
Ok(())
}
use mecha10_controllers::{Controller, MotorController};
use mecha10_controllers::mock::MockMotorController;
use mecha10_core::actuator::Twist;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let config = MockMotorConfig::default();
let mut motors = MockMotorController::init(config).await?;
motors.start().await?;
// Send velocity commands
let twist = Twist {
linear: 0.5, // 0.5 m/s forward
angular: 0.1, // 0.1 rad/s rotation
};
motors.set_twist(twist).await?;
// Get encoder readings
let (left, right) = motors.get_encoders().await?;
println!("Encoders: left={}, right={}", left, right);
// Emergency stop
motors.emergency_stop().await?;
Ok(())
}
All controller traits have mock implementations for testing:
MockCameraController: Generates synthetic RGB/depth images with gradientsMockImuController: Generates synthetic IMU data with simulated motionMockLidarController: Generates synthetic laser scansMockMotorController: Simulates differential drive motors with encodersUse these in your tests:
#[cfg(test)]
mod tests {
use mecha10_controllers::mock::*;
use mecha10_controllers::{Controller, CameraController};
#[tokio::test]
async fn test_camera_capture() {
let config = MockCameraConfig::default();
let mut camera = MockCameraController::init(config).await.unwrap();
camera.start().await.unwrap();
let frame = camera.capture_frame().await.unwrap();
// Test your code with the mock frame
camera.stop().await.unwrap();
}
}
To create a controller for new hardware:
Controller traitCameraController, ImuController, etc.)Example skeleton:
use mecha10_controllers::{Controller, CameraController, ControllerCapabilities, ControllerHealth};
use async_trait::async_trait;
pub struct MyCustomCameraConfig {
pub device_path: String,
pub resolution: (u32, u32),
}
pub struct MyCustomCameraController {
config: MyCustomCameraConfig,
// Your SDK handle here
}
#[async_trait]
impl Controller for MyCustomCameraController {
type Config = MyCustomCameraConfig;
type Error = anyhow::Error;
async fn init(config: Self::Config) -> Result<Self, Self::Error> {
// Initialize your hardware SDK
Ok(Self { config })
}
async fn start(&mut self) -> Result<(), Self::Error> {
// Start data acquisition
Ok(())
}
async fn stop(&mut self) -> Result<(), Self::Error> {
// Stop gracefully
Ok(())
}
async fn health_check(&self) -> ControllerHealth {
// Check device health
ControllerHealth::Healthy
}
fn capabilities(&self) -> ControllerCapabilities {
ControllerCapabilities::new("camera", "my_custom_camera")
.with_vendor("MyCompany")
.with_feature("depth", false)
}
}
#[async_trait]
impl CameraController for MyCustomCameraController {
type Frame = CameraFrame;
async fn capture_frame(&mut self) -> Result<Self::Frame, Self::Error> {
// Capture frame from SDK
todo!()
}
// Implement other required methods...
}
Nodes should accept controllers via dependency injection:
use mecha10_controllers::{Controller, CameraController};
use mecha10_core::prelude::*;
pub struct VisionNode {
camera: Box<dyn CameraController<Frame = CameraFrame>>,
}
impl VisionNode {
pub async fn new(camera: Box<dyn CameraController<Frame = CameraFrame>>) -> Self {
Self { camera }
}
pub async fn run(&mut self, ctx: &Context) -> Result<()> {
self.camera.start().await?;
loop {
let frame = self.camera.capture_frame().await?;
// Process frame...
// Publish to topics...
}
}
}