main.cpp
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>
#include <math.h>
 
#include "LSM6DSL.h"
#include "model.h"  // generated by train_model.py
 
LSM6DSL imu;
 
// LED setup (NeoPixel on GPIO3, 1 pixel)
#define NEOPIXEL_PIN   3
#define NEOPIXEL_COUNT 1
Adafruit_NeoPixel pixel(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
 
// sampling
const uint32_t SAMPLE_PERIOD_MS = 10; // ~100 Hz
uint32_t lastSampleMs = 0;
 
// ring buffer for accel magnitude
static float magBuf[WINDOW_SIZE];
static uint16_t magIndex = 0;
static uint16_t sampleCountSinceLastEval = 0;
 
float logistic(float x) {
    // sigmoid
    return 1.0f / (1.0f + expf(-x));
}
 
void setLED(bool shaking) {
    if (shaking) {
        // green
        pixel.setPixelColor(0, pixel.Color(0, 255, 0));
    } else {
        // off
        pixel.setPixelColor(0, pixel.Color(0, 0, 0));
    }
    pixel.show();
}
 
void computeFeatures(float &mean_mag, float &std_mag, float &p2p_mag) {
    // Use the WINDOW_SIZE most recent samples in magBuf,
    // assuming magIndex is the "next write" index.
    float tmp[WINDOW_SIZE];
    for (int i = 0; i < WINDOW_SIZE; i++) {
        // oldest -> newest reconstruction
        int idx = (magIndex + i) % WINDOW_SIZE;
        tmp[i] = magBuf[idx];
    }
 
    // mean
    float sum = 0.0f;
    float minv = tmp[0];
    float maxv = tmp[0];
    for (int i = 0; i < WINDOW_SIZE; i++) {
        float v = tmp[i];
        sum += v;
        if (v < minv) minv = v;
        if (v > maxv) maxv = v;
    }
    mean_mag = sum / WINDOW_SIZE;
 
    // stddev
    float varSum = 0.0f;
    for (int i = 0; i < WINDOW_SIZE; i++) {
        float d = tmp[i] - mean_mag;
        varSum += d * d;
    }
    std_mag = sqrtf(varSum / WINDOW_SIZE);
 
    // peak-to-peak
    p2p_mag = maxv - minv;
}
 
void setup() {
    Serial.begin(115200);
    delay(2000);
 
    if (!imu.begin()) {
        Serial.println("# ERROR: IMU init failed");
        while (true) { delay(1000); }
    }
 
    pixel.begin();
    pixel.show(); // init off
 
    // init magBuf
    for (int i = 0; i < WINDOW_SIZE; i++) {
        magBuf[i] = 1.0f; // ~1g stationary baseline
    }
 
    Serial.println("# Sparrow shake detector running.");
}
 
void loop() {
    uint32_t now = millis();
    if (now - lastSampleMs >= SAMPLE_PERIOD_MS) {
        lastSampleMs = now;
 
        // 1. read imu
        float ax, ay, az;
        if (imu.readAccelG(ax, ay, az)) {
            // magnitude
            float mag = sqrtf(ax*ax + ay*ay + az*az);
 
            // ring buffer write
            magBuf[magIndex] = mag;
            magIndex = (magIndex + 1) % WINDOW_SIZE;
 
            sampleCountSinceLastEval++;
 
            // 2. every STEP_SIZE samples, evaluate model
            if (sampleCountSinceLastEval >= STEP_SIZE) {
                sampleCountSinceLastEval = 0;
 
                float mean_mag, std_mag, p2p_mag;
                computeFeatures(mean_mag, std_mag, p2p_mag);
 
                // 3. logistic regression
                float decision =
                    ShakeModel::W0 +
                    ShakeModel::W1 * mean_mag +
                    ShakeModel::W2 * std_mag +
                    ShakeModel::W3 * p2p_mag;
 
                float prob_shake = logistic(decision);
 
                bool shaking = (prob_shake > 0.5f);
 
                // 4. act
                setLED(shaking);
 
                // debug
                Serial.print("mean=");
                Serial.print(mean_mag, 4);
                Serial.print(" std=");
                Serial.print(std_mag, 4);
                Serial.print(" p2p=");
                Serial.print(p2p_mag, 4);
                Serial.print(" prob=");
                Serial.print(prob_shake, 3);
                Serial.print(" -> ");
                Serial.println(shaking ? "SHAKE" : "IDLE");
            }
        }
    }
}
iothings/laboratoare/2025_code/lab6_4.txt · Last modified: 2025/10/28 15:24 by dan.tudose
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0