mecha10-core 4.2.2

Mecha10 core runtime and foundational types
Documentation
//! Example usage of RateConfig trait for config-driven node rates
//!
//! This example demonstrates how to use the RateConfig trait to make node
//! update rates configurable instead of hard-coded.

use mecha10::prelude::*;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CameraConfig {
    pub fps: f32,
    pub width: u32,
    pub height: u32,
    pub device: Option<String>,
}

impl RateConfig for CameraConfig {
    fn rate_hz(&self) -> f32 {
        self.fps
    }
}

#[derive(Debug)]
pub struct CameraNode {
    config: CameraConfig,
}

#[async_trait]
impl NodeImpl for CameraNode {
    type Config = CameraConfig;

    async fn init(config: Self::Config) -> Result<Self> {
        info!("Initializing camera at {} Hz", config.rate_hz());
        Ok(Self { config })
    }

    async fn run(&mut self, ctx: &Context) -> Result<()> {
        let mut interval = self.config.create_interval();

        info!(
            "Camera running at {} Hz (period: {:?})",
            self.config.rate_hz(),
            self.config.period()
        );

        loop {
            interval.tick().await;

            let image = self.capture_image();
            ctx.publish_to(mecha10_core::topics::sensor::CAMERA_RGB, &image).await?;
        }
    }
}

impl CameraNode {
    fn capture_image(&self) -> mecha10_core::types::Image {
        mecha10_core::types::Image {
            header: mecha10_core::types::Header {
                seq: 0,
                stamp: now_micros(),
                frame_id: "camera".to_string(),
            },
            width: self.config.width,
            height: self.config.height,
            encoding: "rgb8".to_string(),
            is_bigendian: false,
            step: self.config.width * 3,
            data: vec![0; (self.config.width * self.config.height * 3) as usize],
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SensorSuiteConfig {
    pub camera_fps: f32,
    pub lidar_hz: f32,
    pub imu_hz: f32,
}

#[derive(Debug, Clone)]
pub struct CameraRateConfig(f32);

impl RateConfig for CameraRateConfig {
    fn rate_hz(&self) -> f32 {
        self.0
    }
}

#[derive(Debug, Clone)]
pub struct LidarRateConfig(f32);

impl RateConfig for LidarRateConfig {
    fn rate_hz(&self) -> f32 {
        self.0
    }
}

fn main() {
    println!("RateConfig examples:");
    println!();
    println!("1. Camera config with 30 Hz:");
    let camera_config = CameraConfig {
        fps: 30.0,
        width: 640,
        height: 480,
        device: None,
    };
    println!("   Rate: {} Hz", camera_config.rate_hz());
    println!("   Period: {:?}", camera_config.period());
    println!();

    println!("2. High-speed camera config with 120 Hz:");
    let highspeed_config = CameraConfig {
        fps: 120.0,
        width: 1920,
        height: 1080,
        device: Some("/dev/video0".to_string()),
    };
    println!("   Rate: {} Hz", highspeed_config.rate_hz());
    println!("   Period: {:?}", highspeed_config.period());
    println!();

    println!("Benefits of RateConfig:");
    println!("- Standardized interface for rate-based configs");
    println!("- Less boilerplate (no manual Duration calculation)");
    println!("- Config-driven rates (easy to change without code changes)");
    println!("- Type-safe and ergonomic API");
}