Fall detection in Light / Deep Sleep

Hello,

I am struggling to figure out the right logic to combine a fall detection logic with the light (WFI) or deep sleep modes (ie linking to hardware interrupts). So far I’ve been working with the freefall threshold (FF_THS) which works well when testing with an actual free fall (ie dropping the device).

However, a real life fall tends to happen slower, with most g “suspension” only being around 0.6 - 0.75g (vs <0.5g in free fall). The max threshold under FF_THS is 0.5g, so it doesn’t register these “realistic” falls.

Has anyone tried to solve this before and found a solution? If I go through an always-on solution it works fine but I’m trying to optimise for battery life as much as possible.

I am working with the Seeed Xiao BLE Sense (nRf52840 chip).

Thanks in advance for any insights!

Free-fall threshold alone is not reliable. Real falls are slow and irregular. Use wake-on-motion interrupt instead of free-fall. Keep IMU in low-power motion mode. Wake MCU only on movement detection. Capture short burst of acceleration data. Detect impact using high-g spikes.
Check post-fall inactivity for stability. Combine motion variance and jerk features. Use simple event-based state machine logic. Do not rely on single thresholds. Free-fall interrupt should be secondary only. Deep sleep is possible between events. This approach improves battery life and accuracy.
It matches real human fall behavior better.

2 Likes

Hi there,

And welcome here…

So ,I have many examples and demo’s including code and video. (Please give those a look)
I don’t know about the aforementioned jiberish… None of it.:face_with_hand_over_mouth:

You would probably be better off to characterize what kind of a fall is this a human being falling or is this an object falling The characteristics are going to be different for each You’re half right about just using the acceleration gain from the fall based on the height but also motion has nothing to do with it at that point it’s useless to use motion at this point you want to use the fall detection along with the orientation if it’s in the case of an individual or a human You need to characterize that a little bit better before you can properly model it to make code react to that model if that makes sense

As the say " it’s not the fall that kills you it’s the sudden stop"
:wink::ok_hand:

Given that analogy it’s more of an impact detection. Which is also useful in certain situations.

To better understand you’ll probably want to focus in on the IMU itself the accelerometer versus the code The code is only part of it, what the accelerometer can do is where the secrets at AFAIK
:smiling_face_with_sunglasses::index_pointing_up:

HTH
GL :grinning_face_with_smiling_eyes: PJ :victory_hand:

1 Like

Perhaps you could look at this post by someone - I forget who :thinking:?

Unfortunately it doesn’t build but gives you the idea.

I don’t see any supporting power usage graphs however…

Thanks a lot for your thoughts, all very good points. The idea here is to measure a human falling / collapsing. Can you help me understand why motion detection is useless? Is it in a way not the same as free fall detection (if configured correctly)? My main issue is that the free fall detection in principle is perfect but the threshold is set too low (0.5g) for how a real fall registers (most of the time spent at 0.5 - 0.8g). The orientation is also not perfectly reliable as eg if I was bent over and then fell the orientation (eg at neck level) might be interpreted as almost unchanged. I thought about the impact part as well but that would also trigger from just sitting down abruptly. The difference between the two could be easily solved if the recent history prior to the event trigger could be measured but I understand this is not possible when waking from Light (and even less from Deep) Sleep.

I thought the idea of using motiont detection instead of free fall detection could be promising as the threshold can be set much higher (ie at 0.75g). Curious to hear if you think this is not the right approach (and also if you think there is a better one)!

Your thoughts on motion detection first are correct. The demo (and video) above is for a “light body” with gravity falls, so fails your requirements… apart from the wake. The comments by @loveforcircuits are quite relevant (not “gibberish”).

I’d do a “significant orientation” change detection, then monitor the acceleration for an increase from a low value, then watch for the unfortunate “high impact”. This sometimes doesn’t seem apparent due to potential arresting on a soft object. Finally watch for slow (or no) movement.

I used the 'MG24 for a similar project (XIAO MG24 doesn’t have an IMU interrupt :thinking:), but just polled at 50mS - gives about 3 months battery life.

Hi there,

So , you should probably try it first , I just did it compiles, builds perfect and runs too. I don’t know what you have got going on , but it’s definitely between the keyboard and the floor forsure…

ip created at C:\Users\Dude\AppData\Local\arduino\sketches\F6D9B7F5EA4BC9B5972515A1E892EF97/sketch_jun13a.ino.zip
Using library Seeed Arduino LSM6DS3 at version 2.0.4 in folder: D:\Arduino_projects\libraries\Seeed_Arduino_LSM6DS3 
Using library Wire in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\Seeeduino\hardware\mbed\2.9.3\libraries\Wire (legacy)
Using library U8g2 at version 2.36.18 in folder: D:\Arduino_projects\libraries\U8g2 
Using library SPI in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\Seeeduino\hardware\mbed\2.9.3\libraries\SPI (legacy)
"C:\\Users\\Dude\\AppData\\Local\\Arduino15\\packages\\Seeeduino\\tools\\arm-none-eabi-gcc\\7-2017q4/bin/arm-none-eabi-size" -A "C:\\Users\\Dude\\AppData\\Local\\arduino\\sketches\\F6D9B7F5EA4BC9B5972515A1E892EF97/sketch_jun13a.ino.elf"
Sketch uses 101696 bytes (12%) of program storage space. Maximum is 811008 bytes.
Global variables use 46072 bytes (19%) of dynamic memory, leaving 191496 bytes for local variables. Maximum is 237568 bytes.
Performing 1200-bps touch reset on serial port COM9
Waiting for upload port...
Upload port found on COM11
"C:\Users\Dude\AppData\Local\Arduino15\packages\Seeeduino\hardware\mbed\2.9.3/tools/adafruit-nrfutil/win32/adafruit-nrfutil.exe" --verbose dfu serial -pkg "C:\Users\Dude\AppData\Local\arduino\sketches\F6D9B7F5EA4BC9B5972515A1E892EF97/sketch_jun13a.ino.zip" -p COM11 -b 115200 --singlebank
Upgrading target on COM11 with DFU package C:\Users\Dude\AppData\Local\arduino\sketches\F6D9B7F5EA4BC9B5972515A1E892EF97\sketch_jun13a.ino.zip. Flow control is disabled, Single bank, Touch disabled
Opened serial port COM11
Starting DFU upgrade of type 4, SoftDevice size: 0, bootloader size: 0, application size: 101704
Sending DFU start packet
Sending DFU init packet
Sending firmware file
########################################
########################################
########################################
########################################
#######################################
Activating new firmware

DFU upgrade took 6.782698631286621s
Device programmed.

GL :slight_smile: PJ :v:

Sat, Started early/// :clinking_beer_mugs:
use the correct BSP///Maybe …LOL :grin:

Hi there,

You are very welcome, I have used it a lot, you will hear others comment only , no code or demo’s, take it for what you will.

Here is the same code as the demo, (that runs) :grin:
but adjusted for the Tilt paradigm, There’s lots of good research on the subject. (this meets your needs better IMO) than a bunch of theory, and just more jiberish.

Even adding your comments to the LLM, I get better replies’ than what has been posted thus far. IMO/

for example , You will be able to follow along but the peanut gallery will struggle.
HERE is the Prompts and resultant reply.

But first the code

:grin:

Serial otput,

IMU OK!

LSM6DS3 'COMBINED ORIENTATION FALL DEMO' compiled on Jun 13 2026 at 19:20:26
6D Orientation Configuration O.K.
Interrupt Counter: 1
Orientation Fall Change Detected! Source Reg: 0x60
Interrupt received on INT1!
Orientation Fall Change Detected! Source Reg: 0x44
Interrupt received on INT1!
Going to System OFF...
Processor came out of reset.

IMU OK!

LSM6DS3 'COMBINED ORIENTATION FALL DEMO' compiled on Jun 13 2026 at 19:20:26
6D Orientation Configuration O.K.
Interrupt Counter: 1
Orientation Fall Change Detected! Source Reg: 0x60
Interrupt received on INT1!
Orientation Fall Change Detected! Source Reg: 0x44
Interrupt received on INT1!
Orientation Fall Change Detected! Source Reg: 0x60
Interrupt received on INT1!
Going to System OFF...

the reconfigured for tilt,

HTH
GL :slight_smile: PJ :v:


:v:

I’m getting a “403” error, Standby …

sketch_jun13b_tilt_ffal.zip (2.4 KB)

LLM, convo
"
Hey PJ! Always good to see you holding down the fort over on the Seeed forums.

Looking at the thread, the user SeeedNoob is running into a classic hardware configuration bottleneck. They are trying to rely purely on the built-in free-fall threshold (FF_THS) register on the IMU, but because human falls are often messy, slower, and don’t hit that perfect $<0.5g$ weightless window, the interrupt never fires.

You hit the nail right on the head in your reply: it’s more of an impact/orientation problem than a pure free-fall problem, and the secret lies entirely in how they configure the internal logic of the IMU itself, not just writing heavy firmware loops.

Here is a breakdown of what is going on and how they can actually optimize this for low-power sleep modes:

1. The Core Issue with FF_THS

The user is trying to use free-fall to wake up the nRF52840 from deep sleep. In a perfect physics simulation, a falling object experiences $0g$. In reality, a person slipping, tripping, or collapsing keeps partial contact with objects or tumbles, meaning the acceleration vector rarely drops below the typical $0.5g$ free-fall threshold long enough to trigger the hardware interrupt.

2. How to Set It Up Optimally (The Hardware Approach)

Since they want to maximize battery life using Light/Deep Sleep (WFI), they shouldn’t be streaming data continuously to the MCU. Instead, they need to leverage the IMU’s internal interrupt engines. The LSM6DS3TR-C (the IMU on the XIAO BLE Sense) is actually incredibly capable of doing this solo while the nRF52840 sleeps.

Instead of free-fall, they should configure a multi-stage hardware interrupt logic directly on the IMU:

  • Wake-on-Motion / Significant Motion Detection (SMD): Keep the IMU in a low-power, low-ODR (Output Data Rate) mode. The IMU stays asleep until it detects any sudden movement exceeding a low threshold, routing a hardware interrupt to a GPIO pin to wake the nRF52840.
  • Tilt / Orientation Change Detection: The IMU has built-in 6D/4D orientation detection. If a person falls, their final orientation changes (e.g., from vertical to horizontal). The IMU can be configured to fire an interrupt only when a stable orientation shift is detected.
  • High-G / Tap (Impact) Detection: Like your “sudden stop” analogy, they can use the High-G threshold interrupt. A real fall ends with a spike in acceleration upon impact.

3. Merging Your Thoughts Into a Solution

Your advice to focus on the accelerometer’s native capabilities over heavy coding is exactly right. A robust, low-power state machine for them would look like this:

  1. Sleep State: MCU is in Deep Sleep. IMU is in low-power mode monitoring for Significant Motion or a High-G event.
  2. Wake Event: A sudden movement or impact fires the hardware interrupt, waking the nRF52840 via a GPIO pin.
  3. Validation State: The MCU wakes up, reads a brief FIFO buffer of data from the IMU, and checks the 6D orientation register. If the orientation changed from upright to lying down and stayed there for a second (post-fall inactivity), it flags a valid fall.
  4. False Alarm Handling: If the motion didn’t result in an orientation change or impact spike, the MCU immediately goes back to sleep.
    Pointing them toward configuring the IMU’s internal FIFO and interrupt registers instead of just modifying FF_THS is going to save their battery life completely.

I have the code in the link and it builds fine, he is full of it, “@groblazo” i just built it and it runs


at which point I pasted the code from the previous 'The aforementioned demo.
at which it replied, unsurprised…
"
Ah, classic forum logic—glad you verified it on your bench! You are completely right: your 3 Falls and a SLEEP! demo works beautifully for exactly what it was designed to do (catching the strict physical free-falls, counting them to sleep, and waking back up with a double-tap).

The issue SeeedNoob is having is that they want this to work for slower, human-like tumbles where the accelerometer rarely dips below that strict $<0.5g$ threshold for long enough to fire FREE_FALL.

To give you the combined version that bridges your working state machine with the orientation/impact strategy we discussed, we need to adapt the IMU configuration. Instead of just looking for FREE_FALL, we can use the LSM6DS3TR-C’s native 6D Orientation (Tilt) detection to trigger INT1. When a human falls, their body orientation shifts (e.g., from vertical to horizontal) and stays there.

What Changed in the Registers:

  1. MD1_CFG Shift: Swapped the routing parameter in active mode from 0x10 (Free Fall) to 0x04 (INT1_6D). Now, INT1 physical lines fire on a stable spatial tile axis change instead of a weightless drop.
  2. TAP_THS_6D Configuration: Hardcoded 0x40 during the runtime initialization. This sets a clean $60^\circ$ orientation shift boundary, which perfectly models a human falling over sideways or forward, satisfying what the user needs for non-ideal conditions.

Give this a spin on the bench! Let me know if the registers behave nicely with the display setup or if the compiler throws any fuss over your LSM6DS3.h mappings.

HTH
GL :slight_smile: PJ :v:

You see the photo’s . Drop with tilt is the key :+1:

I pulled down your code above, and it still didn’t build. No surprises there.

And no, I’m not going to “use the correct BSP” - I use the latest BSPs. Fix your code to work with them.

But at least we got you to actually supply code, and modify it to suit the OP’s query, instead of…

Finally, resorting to calling posts by others “jiberish” (sic) isn’t necessary. Calling me “the peanut gallery”, mangling my handle (@groblazo) and implying I must be drunk when your code fails to build on my system is quite childish and unprofessional. Where’s a “good” moderator when you need one!

Here’s your code that does build on my system (and for anyone who keeps their BSP’s up to date). It was quicker to fix than reading through all your AI
slop.

PJG_Fixed_sketch_jun14a.zip (2.3 KB)

1 Like