Skip to main content

ccf_core/
mbot.rs

1//! mBot2 reference sensor vocabulary.
2//!
3//! The [mBot2](https://www.makeblock.com/mbot2) is a programmable robot by Makeblock,
4//! retailing for around **$50–$80 USD**. It runs a CyberPi microcontroller with onboard
5//! light, sound, and motion sensors.
6//!
7//! This module provides a ready-to-use [`SensorVocabulary`] implementation for the mBot2's
8//! six onboard sensor dimensions. It is the vocabulary used in the CCF reference demo —
9//! the same robot that demonstrates emergent social behaviour through accumulated experience,
10//! entirely on-device with no cloud or ML model required.
11//!
12//! # Why this exists
13//!
14//! The mBot2 demo is the existence proof for what ccf-core makes possible: a sub-$100
15//! robot that develops genuine context-sensitive social behaviour. Not scripted. Not
16//! rule-based. The trust field accumulates through real interaction, and the robot's
17//! responses emerge from what it has actually experienced in each environment.
18//!
19//! This module ships as a concrete reference so you can see exactly what a production
20//! `SensorVocabulary` implementation looks like. Your own hardware vocabulary follows
21//! the same pattern — just swap in your sensor dimensions.
22//!
23//! # See also
24//!
25//! - `examples/mbot2.rs` — full simulated CCF loop for the mBot2
26//! - [`SensorVocabulary`] — the trait to implement for your own hardware
27
28use crate::vocabulary::{ContextKey, SensorVocabulary};
29
30/// mBot2 sensor vocabulary — 6-dimensional context for the CyberPi microcontroller.
31///
32/// Covers the six onboard sensor dimensions most relevant to social behaviour:
33/// ambient light, ambient sound, nearby presence, robot motion, orientation, and
34/// time of day (set by the host application).
35///
36/// ```rust
37/// use ccf_core::mbot::{MbotSensors, BrightnessBand, NoiseBand,
38///     PresenceSignature, MotionContext, Orientation, TimePeriod};
39/// use ccf_core::vocabulary::ContextKey;
40///
41/// let key = ContextKey::new(MbotSensors {
42///     brightness:  BrightnessBand::Bright,
43///     noise:       NoiseBand::Quiet,
44///     presence:    PresenceSignature::Close,
45///     motion:      MotionContext::Static,
46///     orientation: Orientation::Upright,
47///     time_period: TimePeriod::Day,
48/// });
49/// ```
50#[derive(Clone, Debug, PartialEq, Eq, Hash)]
51pub struct MbotSensors {
52    /// Ambient light level (CyberPi light sensor).
53    pub brightness: BrightnessBand,
54    /// Ambient sound level (CyberPi microphone).
55    pub noise: NoiseBand,
56    /// Nearby presence signature (proximity / IR sensor).
57    pub presence: PresenceSignature,
58    /// Robot motion context (derived from wheel encoders).
59    pub motion: MotionContext,
60    /// Robot orientation relative to starting heading (IMU).
61    pub orientation: Orientation,
62    /// Time of day period (set by host application or RTC).
63    pub time_period: TimePeriod,
64}
65
66/// Ambient light level — quantised from the CyberPi light sensor.
67#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
68pub enum BrightnessBand {
69    /// Very low ambient light (night, dark room).
70    Dark,
71    /// Moderate ambient light (indoor daytime, lamp).
72    Dim,
73    /// High ambient light (bright room, direct sunlight).
74    Bright,
75}
76
77/// Ambient sound level — quantised from the CyberPi microphone.
78#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
79pub enum NoiseBand {
80    /// Very low ambient noise (silent room).
81    Quiet,
82    /// Moderate ambient noise (background conversation, music).
83    Moderate,
84    /// High ambient noise (crowd, machinery, shouting).
85    Loud,
86}
87
88/// Nearby presence signature — person or object detection.
89#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
90pub enum PresenceSignature {
91    /// No person detected in sensor range.
92    Absent,
93    /// Person detected at a distance (outer detection zone).
94    Far,
95    /// Person detected in close proximity (inner detection zone).
96    Close,
97}
98
99/// Robot motion context — derived from wheel encoder state.
100#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
101pub enum MotionContext {
102    /// Robot is stationary (encoders at rest).
103    Static,
104    /// Robot is moving slowly (below speed threshold).
105    Slow,
106    /// Robot is moving quickly (above speed threshold).
107    Fast,
108}
109
110/// Robot orientation relative to its starting heading (IMU pitch/roll).
111#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
112pub enum Orientation {
113    /// Robot is upright — tilt within acceptable range.
114    Upright,
115    /// Robot is tilted beyond the upright threshold (picked up, on slope).
116    Tilted,
117}
118
119/// Time of day period — set by the host application or RTC.
120#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
121pub enum TimePeriod {
122    /// Daytime hours (context: active, well-lit environments typical).
123    Day,
124    /// Evening hours (context: winding down, lower light typical).
125    Evening,
126    /// Night-time hours (context: quiet, dark environments typical).
127    Night,
128}
129
130impl SensorVocabulary<6> for MbotSensors {
131    fn to_feature_vec(&self) -> [f32; 6] {
132        let b = match self.brightness {
133            BrightnessBand::Dark   => 0.0,
134            BrightnessBand::Dim    => 0.5,
135            BrightnessBand::Bright => 1.0,
136        };
137        let n = match self.noise {
138            NoiseBand::Quiet    => 0.0,
139            NoiseBand::Moderate => 0.5,
140            NoiseBand::Loud     => 1.0,
141        };
142        let p = match self.presence {
143            PresenceSignature::Absent => 0.0,
144            PresenceSignature::Far    => 0.5,
145            PresenceSignature::Close  => 1.0,
146        };
147        let m = match self.motion {
148            MotionContext::Static => 0.0,
149            MotionContext::Slow   => 0.5,
150            MotionContext::Fast   => 1.0,
151        };
152        let o = match self.orientation {
153            Orientation::Upright => 0.0,
154            Orientation::Tilted  => 1.0,
155        };
156        let t = match self.time_period {
157            TimePeriod::Day     => 0.0,
158            TimePeriod::Evening => 0.5,
159            TimePeriod::Night   => 1.0,
160        };
161        [b, n, p, m, o, t]
162    }
163}
164
165/// Type alias for the canonical mBot2 context key.
166pub type MbotContextKey = ContextKey<MbotSensors, 6>;