feat: Implement motion sway effects and enhance face sliding based on roll angle
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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) + "°</div></div>"
|
||||
"<div class='status-item'><div class='status-label'>Pitch</div>"
|
||||
"<div class='status-value'>" + String(motion.pitchDeg(), 1) + "°</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>"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user