use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RobotConfig {
pub drive: DriveConfig,
pub camera: CameraConfig,
pub audio: AudioConfig,
pub sensors: SensorConfig,
pub safety: SafetyConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DriveConfig {
pub backend: String,
pub ros2_topic: String,
pub serial_port: String,
pub max_speed: f64,
pub max_rotation: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CameraConfig {
pub device: String,
pub width: u32,
pub height: u32,
pub vision_model: String,
pub ollama_url: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioConfig {
pub mic_device: String,
pub speaker_device: String,
pub whisper_model: String,
pub whisper_path: PathBuf,
pub piper_path: PathBuf,
pub piper_voice: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SensorConfig {
pub lidar_port: String,
pub lidar_type: String,
pub motion_pins: Vec<u8>,
pub ultrasonic_pins: Option<(u8, u8)>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SafetyConfig {
pub min_obstacle_distance: f64,
pub slow_zone_multiplier: f64,
pub approach_speed_limit: f64,
pub max_drive_duration: u64,
pub estop_pin: Option<u8>,
pub bump_sensor_pins: Vec<u8>,
pub bump_reverse_distance: f64,
pub confirm_movement: bool,
pub predict_collisions: bool,
pub sensor_timeout_secs: u64,
pub blind_mode_speed_limit: f64,
}
impl Default for RobotConfig {
fn default() -> Self {
Self {
drive: DriveConfig {
backend: "mock".to_string(),
ros2_topic: "/cmd_vel".to_string(),
serial_port: "/dev/ttyACM0".to_string(),
max_speed: 0.5,
max_rotation: 1.0,
},
camera: CameraConfig {
device: "/dev/video0".to_string(),
width: 640,
height: 480,
vision_model: "moondream".to_string(),
ollama_url: "http://localhost:11434".to_string(),
},
audio: AudioConfig {
mic_device: "default".to_string(),
speaker_device: "default".to_string(),
whisper_model: "base".to_string(),
whisper_path: PathBuf::from("/usr/local/bin/whisper-cpp"),
piper_path: PathBuf::from("/usr/local/bin/piper"),
piper_voice: "en_US-lessac-medium".to_string(),
},
sensors: SensorConfig {
lidar_port: "/dev/ttyUSB0".to_string(),
lidar_type: "mock".to_string(),
motion_pins: vec![17, 27],
ultrasonic_pins: Some((23, 24)),
},
safety: SafetyConfig {
min_obstacle_distance: 0.3, slow_zone_multiplier: 3.0, approach_speed_limit: 0.3, max_drive_duration: 30, estop_pin: Some(4), bump_sensor_pins: vec![5, 6], bump_reverse_distance: 0.15, confirm_movement: false, predict_collisions: true, sensor_timeout_secs: 5, blind_mode_speed_limit: 0.2, },
}
}
}
impl RobotConfig {
pub fn load(path: &std::path::Path) -> anyhow::Result<Self> {
let content = std::fs::read_to_string(path)?;
Ok(toml::from_str(&content)?)
}
pub fn save(&self, path: &std::path::Path) -> anyhow::Result<()> {
let content = toml::to_string_pretty(self)?;
std::fs::write(path, content)?;
Ok(())
}
}