Help with Motion Detection using Arduino Nano 33 BLE Sense

Hey everyone,

My university team and I are working on a project where we are working with Arduinos for the first time. For this project we are using the Arduino Nano 33 BLE Sense Rev2. We need to develop a mechanism that detects movements using the gyroscope and accelerometer for an app.

The idea is that the Arduino is held in the hand and moved randomly within short intervals in one of the following directions: left, right, up, down, or it is shaken. The goal is to accurately distinguish these movements.

We've already tried several codes with the help of ChatGPT. While they partially work, we are still facing issues where the movements are not always correctly detected and distinguished. For example:

  • A movement upwards is often mistakenly detected as a shake
  • Up and down movements, in particular, are not being detected correctly or are difficult to differentiate.

Does anyone have any tips on how to improve the accuracy of movement detection? Any help would be greatly appreciated!

Thanks in advance! :blush:

#include "Arduino_BMI270_BMM150.h"

float lastMovement = 0;
float threshold = 15.0;
float shakeThreshold = 4.0;
float accelX, accelY, accelZ;

unsigned long lastShakeTime = 0;
unsigned long lastMovementTime = 0;

float minAccelForMovement = 1.5;
unsigned long movementDuration = 1000;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  Serial.println("Accelerometer initialized");
  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU. accelerationSampleRate ());
  Serial.println(" Hz");
  Serial.println();
}

void loop() {
  if (IMU.accelerationAvailable()) {
    IMU. readAcceleration(accelX, accelY, accelZ) ;

    if (accelX > minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != 1) {
        Serial.println("Movement to the right detected!");
        lastMovement = 1;
        lastMovementTime = millis();
      }
    }
    else if (accelX < -minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != -1) {
        Serial.println("Movement to the left detected!");
        lastMovement = -1;
        lastMovementTime = millis ();
      }
    }

    else if (accelY > minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != 2) {
        Serial.println("Movement upwards detected!");
        lastMovement = 2;
        lastMovementTime = millis() ;
      }
    }

    else if (accelY < -minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != -2) {
        Serial.println("Movement downwards detected!");
        lastMovement = -2;
        lastMovementTime = millis ();
      }
    }
    float totalAccel = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ) ;
    if (totalAccel > shakeThreshold && (millis() - lastShakeTime) > 1500) {
      Serial.println("Shaking detected!");
      lastShakeTime = millis();
    }
  }
  delay(100);
}

HI @Ma4444 ,

welcome to the forum!

Please use code tags to post your sketch ... it makes things much easier for supporters.

It should look like this

#include "Arduino_BMI270_BMM150.h"

float lastMovement = 0;
float threshold = 15.0;
float shakeThreshold = 4.0;
float accelX, accelY, accelZ;

unsigned long lastShakeTime = 0;
unsigned long lastMovementTime = 0;

float minAccelForMovement = 1.5;
unsigned long movementDuration = 1000;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Started");

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  Serial.println("Accelerometer initialized");
  Serial.print("Accelerometer sample rate = ");
  Serial.print(IMU. accelerationSampleRate ());
  Serial.println(" Hz");
  Serial.println();
}

void loop() {
  if (IMU.accelerationAvailable()) {
    IMU. readAcceleration(accelX, accelY, accelZ) ;

    if (accelX > minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != 1) {
        Serial.println("Movement to the right detected!");
        lastMovement = 1;
        lastMovementTime = millis();
      }
    }
    else if (accelX < -minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != -1) {
        Serial.println("Movement to the left detected!");
        lastMovement = -1;
        lastMovementTime = millis ();
      }
    }

    else if (accelY > minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != 2) {
        Serial.println("Movement upwards detected!");
        lastMovement = 2;
        lastMovementTime = millis() ;
      }
    }

    else if (accelY < -minAccelForMovement && (millis() - lastMovementTime) > movementDuration) {
      if (lastMovement != -2) {
        Serial.println("Movement downwards detected!");
        lastMovement = -2;
        lastMovementTime = millis ();
      }
    }
    float totalAccel = sqrt(accelX * accelX + accelY * accelY + accelZ * accelZ) ;
    if (totalAccel > shakeThreshold && (millis() - lastShakeTime) > 1500) {
      Serial.println("Shaking detected!");
      lastShakeTime = millis();
    }
  }
  delay(100);
}

I used an OCR function to convert your sketch to text. After a little bit of editing it could be formatted and compiles, so I hope it's ok.

Just a hint: It's a good idea to read this first ...

https://forum.arduino.cc/t/how-to-get-the-best-out-of-this-forum/679966

:wink:

ec2021

For any movement regardless of the direction you can't move for minutes into the same direction. Certainly not an accelerated movement. And this means you have to deccelerate pretty quickly. Decceleration creates a accelerometer-signal with opposite sign.

You will have to define threshold values how long shall the movement into one direction be.
How much time is the signal allowed to be of reversed direction?
How much time will there be between one move and the next move?

Each move is an acceleration and and decceleration.
So it might be better to measure the signal of the whole movement.
Until the signal has been "low" for a minimum of time.

My experience with using AI is:
you have to input a very very precise description of what you want to have.

Any unprecise detail is an invitation for the AI to guess. To be able to write down it detailed enough you need a profound knowledge of the thing itself and often profound knowledge how to write code to correct things. And this means without much programming knowledge you can't describe it precise enough or find errors / bugs in AI generated code.

Thank you, I'm new here. I changed the the image to text. Appreciate the help :slight_smile:

The "top secret" of sound engineering is ...

  • Carry out repeatable measurements
  • Document the measurement conditions
  • Evaluate the results
  • Develop or improve your theory based on these results
  • Start over until your theory is confirmed

Trial'n error can also lead to results but this usually takes a lot of time and is not a reliable way to success ...

My suggestion:

  • Make several measurements of each use case
  • Evaluate the data (e.g. by spreadsheet and visualization)
  • Improve the algorithms

Good luck!
ec2021

[Edit] Don't know if you already searched the internet but there are several (possibly) interesting links available

https://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/s2010/ky237_zy49/ky237_zy49/index.html#:~:text=Hand%20motion%20is%20found%20by,as%20defined%20in%20previous%20sections.

https://www.hackster.io/news/how-to-do-gesture-identification-through-machine-learning-on-arduino-39c9f5f55092

https://www.instructables.com/3-axis-accelerometer-based-gesture-recognition/

https://docs.arduino.cc/tutorials/nano-33-ble-sense/gesture-sensor/