feat: Implement motion sway effects and enhance face sliding based on roll angle

This commit is contained in:
Joshua King
2026-02-22 20:40:27 -05:00
parent 9decccdce5
commit 16b9471107
3 changed files with 34 additions and 2 deletions

View File

@@ -81,6 +81,23 @@ static uint8_t luxToContrast(float lux) {
return (uint8_t)value;
}
static int8_t motionSwayOffsetX(unsigned long nowMs) {
// 8-step loop for a clear side-to-side motion while the accelerometer reports movement.
static const int8_t kSway[] = {-8, -4, 0, 4, 8, 4, 0, -4};
const size_t steps = sizeof(kSway) / sizeof(kSway[0]);
size_t idx = (nowMs / 90UL) % steps;
return kSway[idx];
}
static int8_t rollToFaceSlideX(float rollDeg) {
// Map tilt to a larger screen slide so the face visibly shifts toward the tilted side.
float clamped = clampFloat(rollDeg, -35.0f, 35.0f);
int v = (int)lroundf((clamped / 35.0f) * 24.0f); // -24..+24 px
if (v < -24) v = -24;
if (v > 24) v = 24;
return (int8_t)v;
}
static void initRestartButton() {
pinMode(PIN_RESTART_BUTTON, INPUT_PULLUP);
bool raw = digitalRead(PIN_RESTART_BUTTON);
@@ -332,11 +349,13 @@ void App::loop() {
motion.loop();
if (motion.available()) {
face.setTiltEffects(0, 0); // disable old motion-based eye deformation
face.setFaceSlideX(motion.eyeOffsetX()); // roll -> slide whole face left/right
int8_t slideX = rollToFaceSlideX(motion.rollDeg()); // stronger roll -> face slide
(void)motion.consumePickupEvent(); // consume pickup events so they don't accumulate
if (motion.isMoving()) {
motionWakeUntilMs = millis() + MOTION_WAKE_MS;
slideX = motionSwayOffsetX(millis());
}
face.setFaceSlideX(slideX);
} else {
face.setTiltEffects(0, 0);
face.setFaceSlideX(0);

View File

@@ -99,6 +99,19 @@ void WebUI::begin(Settings& settings,
"</div>"
"</div>"
"<div class='card'>"
"<h2><i class='fas fa-wave-square' style='margin-right: 10px;'></i>Sensor Readings</h2>"
"<div class='status-grid'>"
"<div class='status-item'><div class='status-label'>Soil Moisture</div>"
"<div class='status-value'>" + String(moisture.percent()) + "% (" + String(moisture.raw()) + ")</div></div>"
"<div class='status-item'><div class='status-label'>Accelerometer</div>"
"<div class='status-value'>" + String(motion.available() ? "Detected" : "Not detected") + "</div></div>"
"<div class='status-item'><div class='status-label'>Roll</div>"
"<div class='status-value'>" + String(motion.rollDeg(), 1) + "&deg;</div></div>"
"<div class='status-item'><div class='status-label'>Pitch</div>"
"<div class='status-value'>" + String(motion.pitchDeg(), 1) + "&deg;</div></div>"
"</div>"
"</div>"
"<div class='card'>"
"<h2><i class='fas fa-wifi' style='margin-right: 10px;'></i>Wi-Fi Settings</h2>"
"<form method='POST' action='/wifi' id='wifiForm'>"
"<label for='ssid'>Network Name (SSID)</label>"

View File

@@ -66,7 +66,7 @@ void FaceRenderer::triggerSurprised(unsigned long durationMs) {
}
void FaceRenderer::setFaceSlideX(int8_t x) {
_faceSlideTargetX = clampInt(x, -12, 12);
_faceSlideTargetX = clampInt(x, -24, 24);
}
void FaceRenderer::begin(Display& display, Settings& settings) {