Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/persona/IntentEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void IntentEngine::begin() {
activeSpeechUntilMs_ = 0;
soundOrientUntilMs_ = 0;
lastEventAtMs_ = lastUpdateMs_;
demoEnabled_ = true;
demoEnabled_ = STACKCHAN_DEMO_ENABLED_AT_BOOT != 0;
reducedMotion_ = false;
soundAzimuthNorm_ = 0.0f;
lastEventStrength_ = 0.0f;
Expand Down
18 changes: 17 additions & 1 deletion src/persona/IntentEngine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@
#include "persona/SpeechPlanner.hpp"
#include "persona/StateMatrix.hpp"

// Demo mode injects a random mode change and a synthetic event every 2.5-6 s.
// That is useful on a bench when showing the face off, and actively harmful the
// rest of the time: it makes the character look random rather than responsive,
// and because every injected event counts as stimulus the robot can never
// accumulate enough drowsiness to fall asleep. The character design has him
// getting heavy-lidded at fatigue 0.45, yawning at 0.62 and asleep at 0.80 after
// roughly 8.5 idle minutes, and none of that can happen while demo mode runs.
//
// Every native test covering sleep, idle life, or character behaviour calls
// setDemoEnabled(false) first for exactly this reason, so the behaviour under
// test was never the shipped default. Boot with it off; `demo on` over serial
// still turns it on for a bench demonstration.
#ifndef STACKCHAN_DEMO_ENABLED_AT_BOOT
#define STACKCHAN_DEMO_ENABLED_AT_BOOT 0
#endif

namespace stackchan {

class IntentEngine {
Expand Down Expand Up @@ -74,7 +90,7 @@ class IntentEngine {
uint32_t activeSpeechUntilMs_ = 0;
uint32_t soundOrientUntilMs_ = 0;
uint32_t lastEventAtMs_ = 0;
bool demoEnabled_ = true;
bool demoEnabled_ = STACKCHAN_DEMO_ENABLED_AT_BOOT != 0;
bool reducedMotion_ = false;
float soundAzimuthNorm_ = 0.0f;
float lastEventStrength_ = 0.0f;
Expand Down
28 changes: 28 additions & 0 deletions test/test_native_logic/test_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,7 @@ void test_intent_engine_emits_deduped_speech_cue_on_external_event() {
void test_intent_engine_demo_can_be_disabled_and_resumed() {
IntentEngine engine;
engine.begin();
engine.setDemoEnabled(true, 0);
TEST_ASSERT_TRUE(engine.isDemoEnabled());

engine.setDemoEnabled(false, 0);
Expand Down Expand Up @@ -1280,6 +1281,32 @@ CharacterMode runUntilAsleep(IntentEngine& engine, uint32_t limitMs, uint32_t* a
return mode;
}

// Demo mode injects a synthetic event every 2.5-6 s, and every injected event is
// stimulus, so with it on the robot can never accumulate sleep pressure. Shipping
// it enabled meant the documented drowsiness ladder could not run on a real
// robot: one observed device stayed awake for 5.9 days.
void test_intent_engine_boots_with_demo_off_so_the_character_can_sleep() {
IntentEngine engine;
engine.begin();
TEST_ASSERT_FALSE(engine.isDemoEnabled());

// Left alone, nothing injects a mode change. With demo mode on this loop sees
// Think/Attend/React appear within the first few seconds.
for (uint32_t nowMs = 1000; nowMs <= 30000; nowMs += 1000) {
const RobotFrame frame = engine.update(nowMs);
TEST_ASSERT_EQUAL(static_cast<int>(CharacterMode::Idle), static_cast<int>(frame.mode));
}

// And drowsiness accumulates instead of being reset by injected stimulus, so
// he reaches sleep the way the character design describes. Every other sleep
// test has to call setDemoEnabled(false) first to get here; this one must not
// need to, because that is now the boot state.
uint32_t asleepAtMs = 0;
runUntilAsleep(engine, 900000u, &asleepAtMs);
TEST_ASSERT_TRUE(engine.isAsleep());
}


} // namespace

void test_sleep_pressure_builds_only_when_left_alone() {
Expand Down Expand Up @@ -9418,6 +9445,7 @@ int main() {
RUN_TEST(test_robot_frame_carries_character_mode_for_renderer);
RUN_TEST(test_robot_frame_carries_speech_cue_for_output_adapters);
RUN_TEST(test_intent_engine_emits_deduped_speech_cue_on_external_event);
RUN_TEST(test_intent_engine_boots_with_demo_off_so_the_character_can_sleep);
RUN_TEST(test_intent_engine_demo_can_be_disabled_and_resumed);
RUN_TEST(test_idle_life_breathing_moves_face_and_body_together);
RUN_TEST(test_persona_behavior_codegen_exposes_idle_life_tuning);
Expand Down