# ADXL343 Speed Detection Implementation
Model: gemma-4-e4b-it
Created: 6/8/2026, 11:02:08 AM
Exported from: LM Studio 0.4.15+2

### User
hi can you add to this code so that it sends "TOO FAST" if the adxl 343 moves too fast? im doing wireless esp32c3 to esp32c3 comms. this is the sender code. i want it to always send the most recent state detected. either TOO FAST, movment detected, or moevemnt subsided. this is working code

/*
    MASTER SKETCH: Movement Detector Sender (ESP-NOW) - FINAL VERSION
*/



#include &lt;Wire.h&gt; // Required for I2C communication with most sensors
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_ADXL343.h&gt; 
#include &lt;esp_now.h&gt;
#include &lt;WiFi.h&gt;


// ===============================================================
// 1. GLOBAL CONFIGURATION & OBJECTS (Top of the file)
// ===============================================================


// --- Sensor Object Initialization ---
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345); 


// --- Movement Detection Variables ---
const float MOVEMENT_THRESHOLD = 1; // Tune this value! (Delta magnitude threshold)


// Tracking variables for the previous reading (MUST BE GLOBAL)
float last_accel_x = 0.0;
float last_accel_y = 0.0;
float last_accel_z = 0.0;


// State tracking flag (Controls if we print "DETECTED" or "SUBSIDED")
bool movement_detected_flag = false; 



// --- ESP-NOW MAC ADDRESS & STRUCTURES ---
uint8_t broadcastAddress[] = {0x94, 0xa9, 0x90, 0x6c, 0xd5, 0x9c};


typedef struct struct_message {
    char a[32]; // For status text ("Movement detected" or "Movement subsided")
    int b;      // Integer (e.g., scaled reading)
    float c;    // Float (e.g., magnitude or raw float data)
    bool d;     // Boolean (Movement Detected Flag)
} struct_message;


struct_message myData;


esp_now_peer_info_t peerInfo;



// --- SENSOR VARIABLES (Used by the main loop for calculation) ---
float accelX = 0.0, accelY = 0.0, accelZ = 0.0; // Global variables for sensor readings



// ===============================================================
// 2. CALLBACK FUNCTION (MUST BE GLOBAL)
// ===============================================================
void OnDataSent(const wifi_tx_info_t *txInfo, esp_now_send_status_t status) { 
    Serial.print("\r\n[ESP-NOW Status] Last Packet Send Status:\t");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}



// ===============================================================
// 3. SETUP FUNCTION (Initialization)
// ===============================================================
void setup() {
    // Initialize Serial Monitor
    Serial.begin(115200);
    
    // Set device as a Wi-Fi Station (Required for ESP-NOW)
    WiFi.mode(WIFI_STA);


    // --- Sensor Initialization ---
    Wire.begin(); // Initialize I2C bus for the sensor
    if(!accel.begin()) {
        Serial.println("ERROR: ADXL343 not found! Check wiring.");
    } else {
        accel.setRange(ADXL343_RANGE_16_G);
        Serial.println("ADXL343 Sensor Initialized Successfully.");
    }


    // 1. INITIALIZE ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }


    // 2. REGISTER SEND CALLBACK
    esp_now_register_send_cb(OnDataSent);
    
    // 3. CHANNEL SYNCHRONIZATION (CRITICAL FIX!)
    WiFi.setChannel(1); // &lt;-- Use the channel that works for your setup!



    // 4. REGISTER PEER INFO
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;  
    peerInfo.encrypt = false;
    
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("\n=========================================");
    Serial.println("Sender Setup Complete. Ready to transmit.");
    Serial.println("=========================================\n");
}



// ===============================================================
// 4. SENSOR READING FUNCTION (Replaces the simulation)
// ===============================================================
void readAccelerometerData() {
    sensors_event_t event;
    if (accel.getEvent(&event)) { // Check if reading was successful
        float current_x = event.acceleration.x;
        float current_y = event.acceleration.y;
        float current_z = event.acceleration.z;


        // Calculate the magnitude of acceleration (Total force vector)
        float current_magnitude = sqrt(current_x * current_x + current_y * current_y + current_z * current_z);


        // Calculate the change in magnitude since the last reading
        float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
        float delta_magnitude = abs(current_magnitude - last_magnitude);


        // Update the global variables used by the main loop() logic
        accelX = current_x;
        accelY = current_y;
        accelZ = current_z;
        
        // Return the calculated delta magnitude so we can use it in the loop() state machine
        Serial.printf("Sensor Read: X=%.2f, Y=%.2f, Z=%.2f | Delta Mag: %.2f\n", accelX, accelY, accelZ, delta_magnitude);


    } else {
        Serial.println("ERROR reading sensor data!");
    }
}



// ===============================================================
// 5. MAIN LOOP (State Machine & Sending)
// ===============================================================
void loop() {
    // --- STEP A: Read Sensor Data and Calculate Change ---
    // We must capture the delta magnitude here to use it for state detection
    float current_delta_magnitude;
    readAccelerometerData(); 


    // NOTE: Since readAccelerometerData now prints, we rely on its internal logic 
    // to calculate the necessary values. For simplicity in this final merge, 
    // we will re-calculate the delta here based on the global variables updated above.
    float current_magnitude = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ);
    float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
    current_delta_magnitude = abs(current_magnitude - last_magnitude);



    // --- STEP B: State Change Detection (The core logic) ---
    if (current_delta_magnitude &gt; MOVEMENT_THRESHOLD) {
        if (!movement_detected_flag) {
            // *** TRANSITION: From Still to Moving ***
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT DETECTED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");


            strcpy(myData.a, "Movement detected"); 
            myData.b = 1;                                     
            myData.c = current_magnitude;                      // Send the actual magnitude
            myData.d = true;                                   



        } else {
             // Already moving: just update payload without printing status text
             strcpy(myData.a, "Movement detected"); 
             myData.b = 1;
             myData.c = current_magnitude;
             myData.d = true;
        }


    } else {
        if (movement_detected_flag) {
            // *** TRANSITION: From Moving to Still ***
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT SUBSIDED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");


            strcpy(myData.a, "Movement subsided"); 
            myData.b = 0;                                     
            myData.c = current_magnitude;                      // Send the low magnitude
            myData.d = false;                                  
        } else {
             // Still still: just update payload without printing status text
             strcpy(myData.a, "Movement subsided"); 
             myData.b = 0;
             myData.c = current_magnitude;
             myData.d = false;
        }
    }


    // --- STEP C: Send Data (Network Transmission) ---
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    
    if (result == ESP_OK) {
        Serial.println("Data packet sent successfully."); 
    } else {
        Serial.println("ERROR: Failed to send data packet."); 
    }


    // --- STEP D: Update State for Next Cycle & Sensor History ---
    movement_detected_flag = (current_delta_magnitude &gt; MOVEMENT_THRESHOLD); // Set flag based on current detection
    last_accel_x = accelX;
    last_accel_y = accelY;
    last_accel_z = accelZ;


    // Wait for a short period to keep the loop responsive but not overwhelming.
    delay(500); 
}

### Assistant
This is a great request. To implement the "TOO FAST" state, we need to introduce a **second threshold** based on the *rate of change* of acceleration (the derivative), which is what you are currently calculating with `delta_magnitude`.

We will define a new constant for this speed threshold and modify the logic in Step B to check for three conditions:
1.  **TOO FAST:** If $\text{Delta Magnitude} &gt; \text{SPEED\_THRESHOLD}$
2.  **MOVEMENT DETECTED:** If $\text{MOVEMENT\_THRESHOLD} &lt; \text{Delta Magnitude} \le \text{SPEED\_THRESHOLD}$ (This handles normal movement)
3.  **SUBSIDED:** If $\text{Delta Magnitude} \le \text{MOVEMENT\_THRESHOLD}$

Since you want to *always* send the most recent state, we will structure the logic to prioritize "TOO FAST" over general "Movement Detected."

Here is the complete, modified code:

### Modified Sender Code (ESP32C3)

```cpp
/*
    MASTER SKETCH: Movement Detector Sender (ESP-NOW) - FINAL VERSION with Speed Check
*/

#include &lt;Wire.h&gt; // Required for I2C communication with most sensors
#include &lt;Adafruit_Sensor.h&gt;
#include &lt;Adafruit_ADXL343.h&gt; 
#include &lt;esp_now.h&gt;
#include &lt;WiFi.h&gt;


// ===============================================================
// 1. GLOBAL CONFIGURATION & OBJECTS (Top of the file)
// ===============================================================

// --- Sensor Object Initialization ---
Adafruit_ADXL343 accel = Adafruit_ADXL343(12345); 


// --- Movement Detection Variables ---
const float MOVEMENT_THRESHOLD = 0.8; // Tune this value! (Delta magnitude threshold for general movement)
const float SPEED_THRESHOLD = 5.0;    // *** NEW: Threshold for "TOO FAST" (Tune this!) ***

// Tracking variables for the previous reading (MUST BE GLOBAL)
float last_accel_x = 0.0;
float last_accel_y = 0.0;
float last_accel_z = 0.0;


// State tracking flag (Controls if we print "DETECTED" or "SUBSIDED")
bool movement_detected_flag = false; 



// --- ESP-NOW MAC ADDRESS & STRUCTURES ---
uint8_t broadcastAddress[] = {0x94, 0xa9, 0x90, 0x6c, 0xd5, 0x9c};


typedef struct struct_message {
    char a[32]; // For status text ("Movement detected", "TOO FAST", etc.)
    int b;      // Integer (e.g., scaled reading)
    float c;    // Float (e.g., magnitude or raw float data)
    bool d;     // Boolean (Movement Detected Flag - used for general state tracking)
} struct_message;


struct_message myData;


esp_now_peer_info_t peerInfo;



// --- SENSOR VARIABLES (Used by the main loop for calculation) ---
float accelX = 0.0, accelY = 0.0, accelZ = 0.0; // Global variables for sensor readings



// ===============================================================
// 2. CALLBACK FUNCTION (MUST BE GLOBAL)
// ===============================================================
void OnDataSent(const wifi_tx_info_t *txInfo, esp_now_send_status_t status) { 
    Serial.print("\r\n[ESP-NOW Status] Last Packet Send Status:\t");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}


// ===============================================================
// 3. SETUP FUNCTION (Initialization)
// ===============================================================
void setup() {
    // Initialize Serial Monitor
    Serial.begin(115200);
    
    // Set device as a Wi-Fi Station (Required for ESP-NOW)
    WiFi.mode(WIFI_STA);


    // --- Sensor Initialization ---
    Wire.begin(); // Initialize I2C bus for the sensor
    if(!accel.begin()) {
        Serial.println("ERROR: ADXL343 not found! Check wiring.");
    } else {
        accel.setRange(ADXL343_RANGE_16_G);
        Serial.println("ADXL343 Sensor Initialized Successfully.");
    }


    // 1. INITIALIZE ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }


    // 2. REGISTER SEND CALLBACK
    esp_now_register_send_cb(OnDataSent);
    
    // 3. CHANNEL SYNCHRONIZATION (CRITICAL FIX!)
    WiFi.setChannel(1); // &lt;-- Use the channel that works for your setup!


    // 4. REGISTER PEER INFO
    memcpy(peerInfo.peer_addr, broadcastAddress, 6);
    peerInfo.channel = 0;  
    peerInfo.encrypt = false;
    
    if (esp_now_add_peer(&peerInfo) != ESP_OK){
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("\n=========================================");
    Serial.println("Sender Setup Complete. Ready to transmit.");
    Serial.println("=========================================\n");
}


// ===============================================================
// 4. SENSOR READING FUNCTION (Replaces the simulation)
// ===============================================================
void readAccelerometerData() {
    sensors_event_t event;
    if (accel.getEvent(&event)) { // Check if reading was successful
        float current_x = event.acceleration.x;
        float current_y = event.acceleration.y;
        float current_z = event.acceleration.z;


        // Calculate the magnitude of acceleration (Total force vector)
        float current_magnitude = sqrt(current_x * current_x + current_y * current_y + current_z * current_z);


        // Calculate the change in magnitude since the last reading
        float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
        float delta_magnitude = abs(current_magnitude - last_magnitude);


        // Update the global variables used by the main loop() logic
        accelX = current_x;
        accelY = current_y;
        accelZ = current_z;
        
        // Print for debugging purposes (optional)
        Serial.printf("Sensor Read: X=%.2f, Y=%.2f, Z=%.2f | Delta Mag: %.2f\n", accelX, accelY, accelZ, delta_magnitude);


    } else {
        Serial.println("ERROR reading sensor data!");
    }
}


// ===============================================================
// 5. MAIN LOOP (State Machine & Sending)
// ===============================================================
void loop() {
    // --- STEP A: Read Sensor Data and Calculate Change ---
    readAccelerometerData(); 

    // Recalculate delta magnitude based on the updated global variables from readAccelerometerData()
    float current_magnitude = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ);
    float last_magnitude = sqrt(last_accel_x * last_accel_x + last_accel_y * last_accel_y + last_accel_z * last_accel_z);
    float current_delta_magnitude = abs(current_magnitude - last_magnitude);


    // --- STEP B: State Change Detection (The core logic) ---
    char status_string[32] = ""; // Buffer to hold the status message
    bool send_movement_flag = false;

    if (current_delta_magnitude &gt; SPEED_THRESHOLD) {
        // 1. TOO FAST STATE
        strcpy(status_string, "TOO FAST");
        send_movement_flag = true;
        
        if (!movement_detected_flag) {
            Serial.println("\n========================================");
            Serial.println("!!! SPEED EXCEEDED (TOO FAST) !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");
        }

    } else if (current_delta_magnitude &gt; MOVEMENT_THRESHOLD) {
        // 2. NORMAL MOVEMENT DETECTED STATE
        strcpy(status_string, "Movement detected");
        send_movement_flag = true;

        if (!movement_detected_flag) {
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT DETECTED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");
        }

    } else {
        // 3. SUBSIDED STATE (Below both thresholds)
        strcpy(status_string, "Movement subsided");
        send_movement_flag = false;

        if (movement_detected_flag) {
            Serial.println("\n========================================");
            Serial.println("!!! MOVEMENT SUBSIDED !!!"); // &lt;-- PRINT ON CHANGE
            Serial.println("========================================\n");
        }
    }


    // --- Populate Payload based on determined state ---
    if (send_movement_flag) {
        myData.a[0] = '\0'; // Clear status string buffer for safety
        strncpy(myData.a, status_string, 31); // Copy the correct status
        myData.b = 1;                               // Movement is active
        myData.c = current_magnitude;               // Send the actual magnitude
        myData.d = true;                             // Flag set to true
    } else {
        // Subsided or still state
        strcpy(myData.a, "Movement subsided"); // Always send this if not moving fast/moving
        myData.b = 0;                            // Movement is inactive
        myData.c = current_magnitude;            // Send the low magnitude
        myData.d = false;                         // Flag set to false
    }


    // --- STEP C: Send Data (Network Transmission) ---
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    
    if (result == ESP_OK) {
        Serial.printf("Data packet sent successfully. Status: %s\n", myData.a); 
    } else {
        Serial.println("ERROR: Failed to send data packet."); 
    }


    // --- STEP D: Update State for Next Cycle & Sensor History ---
    // The flag is now set based on the highest detected state (TOO FAST &gt; MOVEMENT &gt; STILL)
    if (current_delta_magnitude &gt; SPEED_THRESHOLD) {
        movement_detected_flag = true; // If too fast, we are definitely "moving"
    } else if (current_delta_magnitude &gt; MOVEMENT_THRESHOLD) {
        movement_detected_flag = true; // Normal movement
    } else {
        movement_detected_flag = false; // Subsided
    }

    // Update history for the next loop iteration
    last_accel_x = accelX;
    last_accel_y = accelY;
    last_accel_z = accelZ;


    // Wait for a short period to keep the loop responsive but not overwhelming.
    delay(100); // Reduced delay slightly to better capture rapid changes
}
```

### Key Changes and Explanations:

1.  **New Constant:**
    ```cpp
    const float SPEED_THRESHOLD = 5.0;    // *** NEW: Threshold for "TOO FAST" (Tune this!) ***
    ```
    I added `SPEED_THRESHOLD`. You **must tune this value** based on how fast you expect the device to move before it triggers a "TOO FAST" alert.

2.  **State Logic Overhaul (Step B):**
    The logic now uses an `if-else if-else` structure, which is crucial because we want the highest severity state to take precedence:
    *   **Check 1 (Highest Priority):** Is $\text{Delta Magnitude} &gt; \text{SPEED\_THRESHOLD}$? If yes, status is "TOO FAST".
    *   **Check 2:** Else if $\text{Delta Magnitude} &gt; \text{MOVEMENT\_THRESHOLD}$? If yes, status is "Movement detected".
    *   **Check 3 (Default):** Otherwise, the state is "Movement subsided".

3.  **Payload Population:**
    The payload population section was refactored to use a `status_string` buffer. This ensures that regardless of which condition triggered the send, the correct status text (`"TOO FAST"`, `"Movement detected"`, or `"Movement subsided"`) is copied into `myData.a`.

4.  **State Flag Update (Step D):**
    The `movement_detected_flag` update logic was updated to reflect the new hierarchy: if it's too fast, we consider it "moving," even if the general movement threshold wasn't crossed.

### How to Tune This Code:

*   **`MOVEMENT_THRESHOLD` (e.g., 0.8):** Controls when you report *any* noticeable change from rest.
*   **`SPEED_THRESHOLD` (e.g., 5.0):** Controls how much the acceleration magnitude must change in one cycle to trigger an emergency "TOO FAST" alert. This value should be significantly higher than your normal movement threshold.
*   **`delay(100)`:** I reduced this from `500ms` to `100ms`. Since you are detecting rapid changes, a shorter delay allows the system to react much faster to speed spikes.

### User
it worked thank you

### Assistant
That's fantastic news! I'm very glad it worked for you and that the state machine logic met your requirements.

If you run into any other issues—whether it's tuning the thresholds, optimizing power consumption, or integrating another sensor—feel free to ask! Happy coding!
