XIAO nRF52840 Sense not working with some Seeed_Arduino_LSM6DS3 examples

I am trying to use the FreeFallDetect example from Seeed-Studio/Seeed_Arduino_LSM6DS3 and it is not detecting freefall. The Pedometer example works.

Using Seeed nRF52 mbed-enabled Boards v2.9.1

The HighLevelExample program shows constantly changing Accel and Gyro data even when the device is sitting still on a table.

Hi Greglarious, Welcome…

That being said , Yea they are not 100% on working examples around here, It’s NOT really managed just kind of thrown on a wiki and rarely updated. The User’s here are EXCELLENT though. The support is responsive but not from an Engineering POV.
I managed to learn allot about the IMU here is the free fall template I tweaked and works VERY well with the Expansion Board, but also on the chip alone. (see Video)
here is the code and pics & bonus video if there’s no Cockpit issue’s/. You know Between the Keyboard and the floor :smile:

HTH
GL :slight_smile:

/*
Here is an example code that you can use to detect a light impact using the LSM6DS3 IMU 
and write the event information to the BLE characteristic value: , Check the comments for the values I've used successfully, You can WRITE them via the BLE connection and USE NRF connect to test. 
(best $10 bucs I ever spent) 
*/
// 
#include <ArduinoBLE.h>
#include <Arduino.h>
#include <LSM6DS3.h>
#include <Wire.h>
#include <U8x8lib.h>
LSM6DS3 IMU(I2C_MODE, 0x6A);  //I2C device address 0x6A  // IMU
#define int2Pin PIN_LSM6DS3TR_C_INT1
float aX, aY, aZ, gX, gY, gZ;
String timeDateStamp = (" __TIME____DATE__" );
float ftemperature = 25.0;
bool imuParked = false;
bool droppedFlag = false;
bool motionAlarm = true;
String imuOrientation = "upright";
double tapToOpen = true;
int numberOfTaps = 3;
const int appearance = (0x19);
int orientation = -1;                        // use -1 to indicate initial state
const int orientationUpdateInterval = 1000;  // update orientation every 5 seconds
unsigned long lastOrientationUpdate = 0;

// BLE Service and Characteristics
BLEService fallService("FDDA0001-7D3E-4988-B8E1-2E314F7A1D2A");
BLEStringCharacteristic fallCharacteristic("FDDA0002-7D3E-4988-B8E1-2E314F7A1D2A", BLERead | BLENotify, 20);
BLEFloatCharacteristic impactLevelCharacteristic("FDDA0003-7D3E-4988-B8E1-2E314F7A1D2A", BLERead | BLEWrite);

// Fall detection parameters
float impactThreshold = 1.5;  // G-force threshold for impact (default value) HEX 20 40 =10G, 20 41 =2.5 G, 10 40= 2.25G,80 3F 1.0G,C0 3F = 1.5G
const int impactTime = 250;   // Time (ms) to wait for impact
bool impactDetected = false;
unsigned long impactTimestamp;
unsigned long lastReadTimestamp = 0;
const int readInterval = 50; // Time interval (ms) to read acceleration data

//Create a instance of class
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* clock=*/PIN_WIRE_SCL, /* data=*/PIN_WIRE_SDA, /* reset=*/U8X8_PIN_NONE);  // OLEDs without Reset of the Display

void setup() {
   Serial.begin(9600);
  delay(3000);  //relax...Get Ready for serial port
  Serial.println();
  Serial.println("Power ON ");  // Let's BEGIN!!
  Serial.println("Test program compiled on " __DATE__ " at "__TIME__);
  Serial.println();
  IMU.begin();
  initdisplay();       // Sets Font and clears screen.

  if (!BLE.begin()) {
    Serial.println("Starting BLE failed!");
    while (1);
  }
  testimu();           //sets begin and reads Temps to verify alive
 
  BLE.setLocalName("FallDetector");
  BLE.setAdvertisedService(fallService);
  fallService.addCharacteristic(fallCharacteristic);
  fallService.addCharacteristic(impactLevelCharacteristic);
  BLE.addService(fallService);
  fallCharacteristic.writeValue("No Impact");
  impactLevelCharacteristic.setValue(impactThreshold);
  BLE.advertise();
  Serial.println("BLE Fall Detector is ready");
}

void loop() {
  BLEDevice central = BLE.central();

  if (central) {
    Serial.print("Connected to central: ");
    Serial.println(central.address());
    impactDetected = false;

    while (central.connected()) {
      if (impactLevelCharacteristic.written()) {
        float newThreshold = impactLevelCharacteristic.value();
        if (newThreshold >= 0.5 && newThreshold <= 10.0) {
          impactThreshold = newThreshold;
          Serial.print("Updated impactThreshold to: ");
          Serial.println(impactThreshold);

        }
      }

      unsigned long currentMillis = millis();
      if (currentMillis - lastReadTimestamp >= readInterval) {
        lastReadTimestamp = currentMillis;
        // read the acceleration data
        aX = IMU.readFloatAccelX();
        aY = IMU.readFloatAccelY();
        aZ = IMU.readFloatAccelZ();
        float magnitude = sqrt(aX * aX + aY * aY + aZ * aZ);

        if (magnitude > impactThreshold && !impactDetected) {
          impactDetected = true;
          impactTimestamp = millis();
        }

        if (impactDetected && (millis() - impactTimestamp) > impactTime) {
          impactDetected = false;
          fallCharacteristic.writeValue("Impact Detected!");
          setLedRGB(true, false, false);  // Turn on RED LED
          Serial.println("Impact Detected!");
          u8x8.clearDisplay();
          u8x8.setCursor(5, 0);
          u8x8.print("Impact Detected!");

          delay(1000);
          fallCharacteristic.writeValue("No Impact");
          setLedRGB(false, false, false);  // Turn off any LED 's OFF
          Serial.println("No Impact");
          u8x8.clearDisplay();
          u8x8.setCursor(5, 0);
          u8x8.print("No Impact");
          getOrientation();

        }
      }
    }

    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
    getOrientation();
  }
}
//end of main loop

bool checkForFall() {
  bool impact = false;
  unsigned long currentMillis = millis();
  if (currentMillis - lastReadTimestamp >= readInterval) {
    lastReadTimestamp = currentMillis;

    float ax = IMU.readFloatAccelX();
    float ay = IMU.readFloatAccelY();
    float az = IMU.readFloatAccelZ();
    float magnitude = sqrt(ax * ax + ay * ay + az * az);

    if (magnitude > impactThreshold && !impactDetected) {
      impactDetected = true;
      impactTimestamp = millis();
    }

    if (impactDetected && (millis() - impactTimestamp) > impactTime) {
      impactDetected = false;
      impact = true;
    }
  }
  return impact;
}



void getOrientation() {
  // Check if it's time to update the orientation
  if (millis() - lastOrientationUpdate >= orientationUpdateInterval) {
    lastOrientationUpdate = millis();

    // read the acceleration data
    aX = IMU.readFloatAccelX();
    aY = IMU.readFloatAccelY();
    aZ = IMU.readFloatAccelZ();

    // determine the orientation
    int newOrientation;
    if (abs(aX) > abs(aY) && abs(aX) > abs(aZ)) {
      newOrientation = (aX > 0) ? 1 : 0;
    } else if (abs(aY) > abs(aZ)) {
      newOrientation = (aY > 0) ? 2 : 3;
    } else {
      newOrientation = (aZ > 0) ? 4 : 5;
    }

    // print the orientation if it changed
    if (newOrientation != orientation) {
      Serial.print("3D Position:-->");
      u8x8.clearLine(0);
      u8x8.setCursor(0, 0);

      orientation = newOrientation;
      switch (orientation) {
        //Serial.println (orientation);
        case 0:
          Serial.println("UPRIGHT");
          u8x8.print("UPRIGHT");
          break;
        case 1:
          Serial.println("Ass UP ");
          u8x8.print("Ass UP ");
          break;
        case 2:
          Serial.println("SIDEWAYS LEFT");
          u8x8.print("SIDEWAYS LEFT");
          break;
        case 3:
          Serial.println("SIDEWAYS RIGHT");
          u8x8.print("SIDEWAYS RIGHT");
          break;
        case 4:
          Serial.println("TOP UP");
          u8x8.print("TOP UP");
          break;
        case 5:
          Serial.println("TOP DOWN");
          u8x8.print("TOP DOWN");
          break;
      }
    }
    orientation = -1;  // use -1 to indicate initial state
  }
}
void initdisplay() {
  pinMode(LEDR, OUTPUT);  // initialize the LED pin as an output:
  pinMode(LEDG, OUTPUT);  // initialize the LED pin as an output:
  pinMode(LEDB, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);  // initialize the LED pin as an output:
  u8x8.begin();
  u8x8.setFlipMode(1);  // set number from 1 to 3, the screen word will rotary 180
  u8x8.setFont(u8x8_font_8x13B_1x2_r);
  u8x8.clearDisplay();
  u8x8.setCursor(0, 0);
  u8x8.print("Power ON ");
}
void testimu() {
  if (IMU.begin() != 0) {  // Start IMU
    Serial.println("Device error");
    setLedRGB(false, true, false);  // Red
  } else {
    Serial.println("IMU GOOD");  //Serial.println("aX,aY,aZ,gX,gY,gZ");
    getOrientation();
    // //Thermometer
    Serial.print("Temperature: ");
    Serial.print((String) + IMU.readTempF() + "\u00b0");
    Serial.println();
  }
}
void setLedRGB(bool red, bool green, bool blue) {

  if (!blue) {
    digitalWrite(LEDB, HIGH);
  } else {
    digitalWrite(LEDB, LOW);
  }
  if (!green) {
    digitalWrite(LEDG, HIGH);
  } else {
    digitalWrite(LEDG, LOW);
  }
  if (!red) {
    digitalWrite(LEDR, HIGH);
  } else {
    digitalWrite(LEDR, LOW);
  }
}

https://youtu.be/stL80Iezyk4

Thanks for the welcome and the example.
Your code is looking at the raw Accel and Gyro values. That works for me but I am having difficulty using the higher level IMU functions such as LSM6DS3_ACC_GYRO_WAKE_UP_SRC

Hi there,
The default for the “Wake_UP_THS(5B)” is 000000, so it should always be awake?

Yes I loaded it up (seeeds example) it gives the “Device OK !” and the “Success to Configure!” message but that’s it, NOT a BYTE of data ? (thankyou seeed for verifying my previous comment)
Something seems not right here, the description says for “Grove”, not to mention “2015”
Everything else is blank but the “by www.seeedstudio.com” WTH? Talk about “Garbage” IMO.

If it where a company I owned or operated, "quality " would extend to the software and examples, I would have comments by testers with “Clear and concise Instructions” I mean that’s why it’s there to help user’s or potential “CUSTOMERS were you get your MONEY from” to figure if this is a good fit for your project and NOT waste their time in getting the “BASICS”
But hay that’s just me, having worked at companies and acidemia that care. BUT I digress, :crazy_face::slight_smile:
I don’t believe the register values being written are all correct, and I don’t get it’s just reading the register, no Interrupt , seems hokkie IMO.
One of the resident experts can chime in, I’ll look more too.
HTH
GL :slight_smile:

The point of having an IMU such as the LSM6DS3 versus just a raw accelerometer/gyro is to offload processing from the controller onto the IMU chip for detecting events such as free fall.

From my experience that requires 3 things:

  1. configuring the IMU to trigger interrupts based on raw inputs and the circumstances you want to detect
  2. listening to the interrupts from the IMU and gathering data
  3. examining the resulting data from the interrupt to interpret it (usually just drop it into a volatile variable as you don’t want to do real work inside of the interrupt function)

It is unclear to me which step is the issue I am having now. I will start modifying the LSM6DS3 library with debug code to find that out now.

Yep, In this case I’m sure it’s the first TWO :slight_smile:
If it’s just polling the register, then it won’t work unless the IMU is configured properly.
I like using the interrupts cleaner and easier, when it works, Like on the Double Tap demo I posted a while back. I 'll experiment more…
HTH
GL:-)

There could be several reasons why the FreeFallDetect example is not working. Here are a few troubleshooting steps you can try:

Check the sensitivity settings: The LSM6DS3 has a configurable threshold for freefall detection. Make sure that the sensitivity is set correctly in the FreeFallDetect example code.

Check the orientation of the board: The LSM6DS3 has a built-in orientation detection feature that affects the interpretation of the accelerometer readings. Make sure that the board is oriented correctly according to the code.

Check the wiring: Double-check that the board is wired correctly and that all connections are secure.

Update the firmware: Make sure that you have the latest firmware installed on the board. Check the Seeed Studio website for any firmware updates for the nRF52 board.

Check for interference: Other nearby devices or electrical noise can interfere with the accelerometer readings. Try moving the board to a different location to see if this makes a difference.

If none of these steps resolve the issue, you may need to reach out to Seeed Studio support for further assistance.

Regards,
Rachel Gomez