Skip to main content

gloamy_robot/
lib.rs

1//! # Gloamy Robot
2//!
3//! `gloamy-robot` is the standalone robot-control crate for Gloamy. It groups
4//! the robot-facing tool surface in one library so robot integrations can
5//! evolve without coupling every hardware concern into the root runtime.
6//!
7//! ## Included tool surfaces
8//!
9//! - [`DriveTool`]: movement commands for mock, serial, or ROS2-backed bases
10//! - [`LookTool`]: image capture plus optional Ollama-based vision description
11//! - [`ListenTool`]: offline speech-to-text using `arecord` and `whisper.cpp`
12//! - [`SpeakTool`]: Piper-based text-to-speech and canned sound playback
13//! - [`SenseTool`]: obstacle, distance, and motion reads
14//! - [`EmoteTool`]: lightweight LED and sound-driven expression output
15//! - [`SafetyMonitor`] and [`SafeDrive`]: movement gating and emergency-stop support
16//!
17//! ## Integration model
18//!
19//! This crate is a workspace member, but it is not auto-registered into the
20//! main `gloamy` tool factory. The expected pattern today is:
21//!
22//! 1. load or construct a [`RobotConfig`]
23//! 2. build tools with [`create_tools`] or [`create_safe_tools`]
24//! 3. optionally adapt this crate's [`Tool`] trait into the main runtime
25//!
26//! ## Quick start
27//!
28//! ```rust,ignore
29//! use gloamy_robot::{create_tools, RobotConfig};
30//!
31//! let config = RobotConfig::default();
32//! let tools = create_tools(&config);
33//!
34//! assert_eq!(tools.len(), 6);
35//! ```
36//!
37//! ## Safety model
38//!
39//! The control plane may request movement, but [`SafetyMonitor`] decides whether
40//! movement is allowed. That separation is intentional and keeps collision
41//! handling, watchdog behavior, and emergency-stop responses outside the LLM's
42//! decision loop.
43
44// TODO: Re-enable once the public API surface is documented end-to-end.
45// #![warn(missing_docs)]
46#![allow(missing_docs)]
47#![warn(clippy::all)]
48
49pub mod config;
50pub mod traits;
51
52pub mod drive;
53pub mod emote;
54pub mod listen;
55pub mod look;
56pub mod sense;
57pub mod speak;
58
59#[cfg(feature = "safety")]
60pub mod safety;
61
62#[cfg(test)]
63mod tests;
64
65// Re-exports for convenience
66pub use config::RobotConfig;
67pub use traits::{Tool, ToolResult, ToolSpec};
68
69pub use drive::DriveTool;
70pub use emote::EmoteTool;
71pub use listen::ListenTool;
72pub use look::LookTool;
73pub use sense::SenseTool;
74pub use speak::SpeakTool;
75
76#[cfg(feature = "safety")]
77pub use safety::{preflight_check, SafeDrive, SafetyEvent, SafetyMonitor, SensorReading};
78
79/// Version of the published crate.
80pub const VERSION: &str = env!("CARGO_PKG_VERSION");
81
82/// Build the standard robot tool set from a shared configuration.
83///
84/// The returned tools are standalone and do not wrap `drive` with a safety gate.
85pub fn create_tools(config: &RobotConfig) -> Vec<Box<dyn Tool>> {
86    vec![
87        Box::new(DriveTool::new(config.clone())),
88        Box::new(LookTool::new(config.clone())),
89        Box::new(ListenTool::new(config.clone())),
90        Box::new(SpeakTool::new(config.clone())),
91        Box::new(SenseTool::new(config.clone())),
92        Box::new(EmoteTool::new(config.clone())),
93    ]
94}
95
96/// Build the standard robot tool set with safety-enforced drive control.
97///
98/// This keeps the visible tool list the same while routing movement requests
99/// through [`SafeDrive`].
100#[cfg(feature = "safety")]
101pub fn create_safe_tools(
102    config: &RobotConfig,
103    safety: std::sync::Arc<SafetyMonitor>,
104) -> Vec<Box<dyn Tool>> {
105    let drive = std::sync::Arc::new(DriveTool::new(config.clone()));
106    let safe_drive = SafeDrive::new(drive, safety);
107
108    vec![
109        Box::new(safe_drive),
110        Box::new(LookTool::new(config.clone())),
111        Box::new(ListenTool::new(config.clone())),
112        Box::new(SpeakTool::new(config.clone())),
113        Box::new(SenseTool::new(config.clone())),
114        Box::new(EmoteTool::new(config.clone())),
115    ]
116}