Making the accelerometer useful: developing an algorithm to indicate when the device has been ‘stolen’

I managed to get the accelerometer to work and put in a sensitivity so it prints when the chip has been moved (i.e. does not print the raw data, just the statement “MOVED” when there has been movement.

However, for the bag movement alarm project I need it to tell for how long there has been movement, and only if there is movement for say 5 seconds does it trigger the “MOVED”… if it is moving for longer than 5 seconds then it has been stolen! The difficult part is that there may be moments in there where there is no movement, e.g. for a half second it may stop but then start moving again, and I don’t want that to ‘reset’ the movement time counter.

Here is what I thought of as a possible approach:

  1. I would store the ”moved” value in an array, shifting the new one in each time I take a reading.  Since I have the sensor reading at 1/3 of a second right now, to store the previous 5 seconds of “moved” would take 15 elements.  Each time I read a sensor value, I drop the oldest one, and add the newest one to the array.
  2. I would then look to see if there is a more than 5 second period between two moments of movement (i.e. it has been potentially been moving for more than 5 seconds).  I may need to have another criteria:  the number of seconds I am reviewing (e.g. may need to store the previous 10 seconds of data, and look at any more than 5 second period in that) but would need to think through if this is actually necessary given the second criteria.
  3. Then, I would loop through each element of the array and count how many are “moved” and how many are “not moved” between those two moments of movement, to see if it exceeds a threshold amount (say I allow 20% not movement).

This way, there would be two tests:

  1. Does the time between the oldest “moved” and the newest “moved” exceed 5 seconds? (i.e. it has potentially been moving for more that 5 seconds)
  2. If so, does “moved” exceed the threshold value for that time period? (i.e. it has actually been moving)

I can thus exclude the two events I want to exclude:

  1. Two blips more than 5 seconds apart, but with little movement in between (below the threshold).
  2. Movement (even 100% of the time) of say 4 seconds, and then stop.

I would only include it as “stolen” if:

  1. There are two blips of movement more than 5 second apart (with some maximum time period between moments of movement)
  2. AND there has been movement above the threshold in between those two blips (e.g. 80% of the time it has been moving)

After much back a forth, the following code was developed, which works.

// MPU-6050 MovementForXSeconds
// Arduino Ground –> MPU VCC
// Arduino 5V –> MPU VCC
// Arduino A4 (SDA) –> MPU SDA
// Arduino A5(SCL) –> MPU SCL

const int MPU=0x68; // I2C address of the MPU-6050
int AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
int OldAcX,OldAcY,OldAcZ,OldTmp,OldGyX,OldGyY,OldGyZ = 0;

const int AcSensitivity = 500;
boolean moved = false;

//———BELOW can change ————
const int maxMovementTime = 5000; //number of milliseconds. 5000 = 5 seconds.
const int maxStillnessThreshold = 20; // % threshold of stillness above which the thing is moving
const int readMPUinterval = 250; //number of milliseconds between checks of the accelerometer
//———ABOVE can change ————

//const int movedRecordLength = int((int(maxMovementTime / interval) * (100 + maxStillnessThreshold)) / 100);
const int maxMovementTimeArrayDifference = maxMovementTime / readMPUinterval;
const int movedRecordLength = maxMovementTimeArrayDifference * 2;
boolean movedRecord[movedRecordLength];

unsigned long previousMPUmillis = 0;

void setup(){
Serial.print(“MovedRecordLength: “);

} //end setup

void loop(){

unsigned long currentMillis = millis();
boolean isStolen = false;

if ((currentMillis – previousMPUmillis) > readMPUinterval){
// read the MPU and process the data
isStolen = checkIfStolen();
if (isStolen == true) {
} //end if stolen/
previousMPUmillis = currentMillis; //reset timer
} //end if
} //end loop

void intializeMovedRecord() {
for (int x = 0; x < movedRecordLength; x++) {
movedRecord[x] = false;
} //end for
} //end initializeMovedRecord

void printMovedRecord() {
for (int x = 0; x < movedRecordLength; x++) {
} //end for
} //end initializeMovedRecord

void beginMPUcommunications() {
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
} //end beginMPUcommunications

void readMPUrawvalues() {
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.requestFrom(MPU,14,true); // request a total of 14 registers<<8|; // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)<<8|; // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)<<8|; // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)<<8|; // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)<<8|; // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)<<8|; // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)<<8|; // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
} //end readMPUrawvalues

void checkPositionChangeAndShiftRecord() {
//Check to see if it has moved and add to the move record
if (abs(OldAcX – AcX) > AcSensitivity) { moved = true; }
if (abs(OldAcY – AcY) > AcSensitivity) { moved = true; }
if (abs(OldAcY – AcY) > AcSensitivity) { moved = true; }
//reset the values for next check
OldAcX = AcX;
OldAcY = AcY;
OldAcZ = AcZ;
moved = false;
} //end checkPositionChangeAndShiftRecord

void shiftMovedRecord(boolean movedValue) { //PURPOSE: shifts the movedRecord one to the left, and then adds the value of the most recent moved record the right
for (int x = 0; x < movedRecordLength; x++) { //step through the movedRecord
movedRecord[x] = movedRecord[x+1]; //for each record spot, shift it to the left. the first record gets lost.
if (x == (movedRecordLength-1)) { //if the last spot, add the new record from the most recent record
movedRecord [x] = movedValue;
} //end if
}//end for
} //end shiftMovedRecord

boolean checkIfStolen() {
//—————First test: is there movement more than 5 seconds apart
int firstMoved = movedRecordLength -1;
int lastMoved = 0;
boolean firstMovedSet = false;
boolean lastMovedSet = false;
boolean movedEnoughTime = false;

for (int x = 0; x < movedRecordLength; x++) { // get first moved
if (movedRecord[x] == true && firstMovedSet == false) {
firstMoved = x;
firstMovedSet = true;
} //end if
} //end for

for (int x = (movedRecordLength – 1); x >= 0; x–) { // get last moved
if (movedRecord[x] == true && lastMovedSet == false) {
lastMoved = x;
lastMovedSet = true;
} //end if
} //end for

if ((lastMoved – firstMoved) > maxMovementTimeArrayDifference){
movedEnoughTime = true;
//————-end First test —————————————–

//—————Second test: if there is movement over 5 seconds, is it more than the threshold

if (movedEnoughTime == true){
int trueCounter = 0;
for (int x = firstMoved; x <= lastMoved; x++) { //step through the movedRecord
if (movedRecord[x] == true) {
} //end if
} //end for

int movementPercent = map(trueCounter, 0, lastMoved – firstMoved + 1, 0, 100);
if (movementPercent > maxStillnessThreshold) {
return true;
} //end greater than maxStillnessThreshold
else {
return false;
} //end less than maxStillnessThreshold

} //end—————–Second test ——— if movement over difference in array

} //end checkIfStolen

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s