Core Electronics Forum

Mpu9250 inclination detecting code - need help in defining the default value

hi there, I need some help with my code, my project is about making a device that detects users’ posture and gives haptic feedback when they are slouched (20degree) or reclined back (40degrees). so what I want to is to detect forward tilt of 20 degrees and back-recline of 40 degrees (when the sensor is at 90 degrees default) and when the values are more than or equal to those front and back angles, the device will give notification with an output sensor. like how it is shown below:

this is the code:
#include <MPU9250.h>

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;
float ax0 = 0 ;
float ay0 = 0 ;
float az0 = 0 ;

void setup() {
// serial to display data
Serial.begin(115200);
while(!Serial) {}

// start communication with IMU
status = IMU.begin();
if (status < 0) {
Serial.println(“IMU initialization unsuccessful”);
Serial.println(“Check IMU wiring or try cycling power”);
Serial.print("Status: ");
Serial.println(status);
while(1) {}
}
ax0 = IMU.getAccelX_mss();
ay0 = IMU.getAccelY_mss();
az0 = IMU.getAccelZ_mss();

}
void loop() {
// read the sensor
IMU.readSensor();
float ax = IMU.getAccelX_mss();
float ay = IMU.getAccelY_mss();
float az = IMU.getAccelZ_mss();
//float inclination=180.0 acos(az/sqrt(ax ax+ay ay+az az))/M_PI;.
float inclination = 180.0 acos( (ax0 ax + ay0 ay + az0 az)/sqrt( (ax ax + ay ay + az az) (ax0 ax0 + ay0 ay0 + az0*az0)))/M_PI;
Serial.println (inclination);
delay(200);
}

At the moment the code reads the inclination value, but I am not quite sure which inclination it is whether it is Y-axis or x or z…

Because when I tilt the sensor forward and back it just gives the angle ( for e.g. When I tilt 20 forward and 20 backward, instead of displaying ‘70’ and ‘110’ it shows ‘20’ and ‘20’). So I think the starting angle value needs to be set at ’90’degrees in order to measure the correct back and forth inclinations. I cannot understand the formula (180.0acos( (ax0ax + ay0ay + az0az)/sqrt( (axax + ayay + azaz)(ax0ax0 + ay0ay0 + az0*az0)))/M_PI;) So I don’t know where I can fix to change the default value to 90. Could you please help me with these problems?

Thanks, heaps

Have tried to figure the formulae, but with out the values returned from the device I am a bit it the dark.
Suggestion:
Print the values as returned by the device before using them in the formulae, it might give an indication of how to detect one direction from the other.
eg:

float ax = IMU.getAccelX_mss();
float ay = IMU.getAccelY_mss();
float az = IMU.getAccelZ_mss();
Serial.println (ax, 10);
Serial.println (ay, 10);
Serial.println (az, 10);

The 10 in the print statement means show 10 decimal places. Helps if the numbers are greater than 2 decimal places. Without it print will only show 2 decimal places.

Regards
Jim

Hey Jinky,

Excellent idea for a project, I’d personally be using a ‘running’ variable called dir or similar, set to either zero, one, or negative one by a switch() {} which would ‘flip-flop’ about zero when the value passes a certain point which you can hardcode and then use float inclination = 90-(dir)(180acos(…) as an idea. Please let me know if you’re able to implement this one or if there’s anything else that we can do for you.

Bryce
Core Electronics | Support

The information I have shows very different formulae to get inclination information from 3-axis accelerometer data. Unsure what the formulae in your code is trying to achieve.
The pics are from Analog Devices application note AN-1057.

Regards
Jim

image

image

1 Like

I bought an Adafruit MPU6050 to experiment with. Been meaning to do it for a while. Not the same as what you have but the principle is the same.

The code you posted makes more sense now.
ax0, ay0 & az0 are the starting at rest positions when the micro starts up.
ax, ay & az are the deviation from the starting position in 3 axis.

The formulae: acos( (ax0*ax + ay0*ay + az0*az)/sqrt( (ax*ax + ay*ay + az*az)* (ax0*ax0 + ay0*ay0 + az0*az0))); calculates the amount of overall deviation from the starting position. 180 / M_PI converts this to degrees. It will always be positive as it takes no account of direction.

But you can easily determine the direction by checking the sign of AX, AY calculated from the following formulae.

  float AX = atan(ax/(sqrt(ay*ay + az*az))) * 180 /M_PI;
  float AY = atan(ay/(sqrt(ax*ax + az*az))) * 180 /M_PI;
  float AZ = atan((sqrt(ax*ax + ay*ay))/az) * 180 /M_PI;

Printout from my program.

At rest
AX = 7.87 AY = -1.13 AZ = 7.95
T = 0.10

Tilt forward
AX = 32.15 AY = 0.72 AZ = 32.16
T = 24.44

Tilt Back
AX = -22.02 AY = -2.70 AZ = 22.21
T = 29.85

Tilt Right
AX = 6.66 AY = -31.60 AZ = 32.46
T = 30.46

Tilt Left
AX = 3.78 AY = 35.17 AZ = 35.44
T = 36.43

T indicates there has been a change from rest, sign of AX and AY tells in which direction.

Cheers
Jim

1 Like

Hey James,

Excellent solution, it also may be worth putting your code up here if you feel comfortable with that so that we can dissect it use in the original project.

Bryce
Core Electronics | Support

1 Like

Happy to help Bryce.

The device and library is different but once the values are read the calculations are the same.
Setting the range and bandwidth would be different too.

Regards
Jim

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

float ax0 = 0;
float ay0 = 0;
float az0 = 0;

Adafruit_MPU6050 mpu;

//==================================
void setup(void) {
  Serial.begin(115200);
  Serial.println("--------------");
  Serial.println(" MPU6050 test ");
  Serial.println("--------------");

// initialise MPU6050
  if (!mpu.begin()) {
    Serial.println("MPU6050 not found");
    while (true) { }
  }
// Accelerometer:
//    MPU6050_RANGE_2_G  
//    MPU6050_RANGE_4_G  
//    MPU6050_RANGE_8_G
//    MPU6050_RANGE_16_G
// Gyro:
//    MPU6050_RANGE_250_DEG  
//    MPU6050_RANGE_500_DEG  
//    MPU6050_RANGE_1000_DEG  
//    MPU6050_RANGE_2000_DEG
// Filter Bandwidth
//    MPU6050_BAND_260_HZ  
//    MPU6050_BAND_184_HZ  
//    MPU6050_BAND_94_HZ  
//    MPU6050_BAND_44_HZ  
//    MPU6050_BAND_21_HZ  
//    MPU6050_BAND_10_HZ  
//    MPU6050_BAND_5_HZ
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  delay(2000);

// Read the initial position
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  ax0 = a.acceleration.x;
  ay0 = a.acceleration.y;
  az0 = a.acceleration.z;

  Serial.println("");
  delay(100);
}
//==================================
void loop() {

// Get new sensor events with the readings
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

// Get the raw values 
  float ax = a.acceleration.x;
  float ay = a.acceleration.y;
  float az = a.acceleration.z;

// Print raw values
  Serial.print("ax = ");
  Serial.print(ax);
  Serial.print(" ay = ");
  Serial.print(ay);
  Serial.print(", az = ");
  Serial.print(az);
  Serial.println(" m/s^2");

// Calculate the angles for the 3 axis
  float AX = atan(ax/(sqrt(ay*ay + az*az)));
  float AY = atan(ay/(sqrt(ax*ax + az*az)));
  float AZ = atan((sqrt(ax*ax + ay*ay))/az);

// Convert radians to degrees
  AX = AX * 180/M_PI;
  AY = AY * 180/M_PI;
  AZ = AZ * 180/M_PI;

// Print degrees
  Serial.print("AX = ");
  Serial.print(AX);
  Serial.print(" AY = ");
  Serial.print(AY);
  Serial.print(" AZ = ");
  Serial.println(AZ);

// Calculate the movement with respect to the initial position and all angles
  float t = acos((ax0*ax + ay0*ay + az0*az)/sqrt((ax*ax + ay*ay + az*az)*(ax0*ax0 + ay0*ay0 + az0*az0)));

// Convert radians to degrees
  t = t * 180.0/M_PI;

  Serial.print("T = ");
  Serial.println(t);

  Serial.println("");
  delay(2000);
}
2 Likes

Thank you so much for the code,I applied to the initial code that I had with yours, and the serial monitor is showing this:

17:33:00.321 -> ax = 3.46 ay = -7.50, az = AY = -55.60 AZ = 60.16
17:33:00.321 -> T = 114.65
17:33:00.321 ->
17:33:02.312 -> ax = -2.91 ay = 2.45, az = -9.23 m/s^2
17:33:02.312 -> AX = -16.93 AY = 14.22 AZ = -22.40
17:33:02.312 -> T = 26.95
17:33:02.312 ->

The code is this:

#include <Qduino.h>
#include <Wire.h>
#include <MPU9250.h>

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;
float ax0 = 0 ;
float ay0 = 0 ;
float az0 = 0 ;


void setup() {
  // serial to display data
  Serial.begin(115200);
  while(!Serial) {}

  // start communication with IMU 
  status = IMU.begin();
  if (status < 0) {
    Serial.println("IMU initialization unsuccessful");
    Serial.println("Check IMU wiring or try cycling power");
    Serial.print("Status: ");
    Serial.println(status);
    while(1) {}
  }
  ax0 = IMU.getAccelX_mss();
  ay0 = IMU.getAccelY_mss();
  az0 = IMU.getAccelZ_mss();
        
}
void loop() {
// read the sensor
  IMU.readSensor();
  float ax = IMU.getAccelX_mss();
  float ay = IMU.getAccelY_mss();
  float az = IMU.getAccelZ_mss();

// Print raw values
  Serial.print("ax = ");
  Serial.print(ax);
  Serial.print(" ay = ");
  Serial.print(ay);
  Serial.print(", az = ");
  Serial.print(az);
  Serial.println(" m/s^2");

// Calculate the angles for the 3 axis
  float AX = atan(ax/(sqrt(ay*ay + az*az)));
  float AY = atan(ay/(sqrt(ax*ax + az*az)));
  float AZ = atan((sqrt(ax*ax + ay*ay))/az);

// Convert radians to degrees
  AX = AX * 180/M_PI;
  AY = AY * 180/M_PI;
  AZ = AZ * 180/M_PI;

// Print degrees
  Serial.print("AX = ");
  Serial.print(AX);
  Serial.print(" AY = ");
  Serial.print(AY);
  Serial.print(" AZ = ");
  Serial.println(AZ);

// Calculate the movement with respect to the initial position and all angles
  float t = acos((ax0*ax + ay0*ay + az0*az)/sqrt((ax*ax + ay*ay + az*az)*(ax0*ax0 + ay0*ay0 + az0*az0)));

// Convert radians to degrees
  t = t * 180.0/M_PI;

  Serial.print("T = ");
  Serial.println(t);

  Serial.println("");
  delay(2000);
}

I think I am getting what I suppose to get in the serial monitor but there are a couple of things that i do not understand. So ‘T’ represents the angle/degree changes but which direction is it representing? x,y or z? (maybe i am not understanding it correctly). If i want to check the slouched posture+back reclined posture angle (forward tilt and back tilt) of the user, i will need to see the inclined angle of AX =… is this correct?

1 Like

I think the formulae in your original post is confusing things. I really don’t know what it it trying to show and you don’t need it to get what you want.

Below is some code I put together.
The y & z axis are ignored except for calculating the x axis angle.
When the device tilts forward past 70 degrees and back past 130 it displays the Beep message.

Cheers
Jim

//====================================================================
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

float x = 0;
float y = 0;
float z = 0;

int x_start = 0;
int x_now = 0;

Adafruit_MPU6050 mpu;
//====================================================================
void setup(void) {
  Serial.begin(115200);
  Serial.println("--------------");
  Serial.println(" MPU6050 test ");
  Serial.println("--------------");

// initialise MPU6050
  if (!mpu.begin()) {
    Serial.println("MPU6050 not found");
    while (true) { }
  }
  delay(200);

// Get sensor readings at rest
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  x = a.acceleration.x;
  y = a.acceleration.y;
  z = a.acceleration.z;

// Convert acceleration to angular movement in radians
  x = atan(x/(sqrt(y*y + z*z)));

// Convert radians to degrees and ignore the decimal point
  x_start = (int)(x * 180/M_PI);

  delay(100);
}
//====================================================================
void loop() {

// Get sensor readings now
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  x = a.acceleration.x;
  y = a.acceleration.y;
  z = a.acceleration.z;

// Convert acceleration to angular movement in radians
  x = atan(x/(sqrt(y*y + z*z)));

// Convert radians to degrees and ignore the decimal point
  x_now = (int)(x * 180/M_PI);

// Calculate tilt angle with respect to original at rest position
// and that Vertical = 90 degrees
  int x_tilt = x_now - x_start + 90;

// Beep 
  if ((x_tilt < 70) || (x_tilt > 130)) { 
    // beep function to make noise
    Serial.println("===================");
    Serial.println("     BEEP !!!!     ");
    Serial.println("===================");
  }
  Serial.print("x_tilt = ");
  Serial.println(x_tilt);
  
  delay(2000);
}
//====================================================================
1 Like

Thank you James I really appreciate your support, I got it working, my code now is this and serial monitor is showing the tilt & the “beep”
CODE:
#include <Qduino.h>
#include <Wire.h>
#include <MPU9250.h>

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;
float x0 = 0 ;
float y0 = 0 ;
float z0 = 0 ;
int x_start = 0;
int x_now = 0;

void setup() {
// serial to display data
Serial.begin(115200);
while(!Serial) {}

// start communication with IMU
status = IMU.begin();
if (status < 0) {
Serial.println(“IMU initialization unsuccessful”);
Serial.println(“Check IMU wiring or try cycling power”);
Serial.print("Status: ");
Serial.println(status);
while(1) {}
}
x0 = IMU.getAccelX_mss();
y0 = IMU.getAccelY_mss();
z0 = IMU.getAccelZ_mss();

}
void loop() {
// read the sensor
IMU.readSensor();
float x = IMU.getAccelX_mss();
float y = IMU.getAccelY_mss();
float z = IMU.getAccelZ_mss();

// Print raw values
Serial.print(“x = “);
Serial.print(x);
Serial.print(” y = “);
Serial.print(y);
Serial.print(”, z = “);
Serial.print(z);
Serial.println(” m/s^2”);

// Calculate the angles for the 3 axis
float X = atan(x/(sqrt(yy + zz)));
float Y = atan(y/(sqrt(xx + zz)));
float Z = atan((sqrt(xx + yy))/z);

// Convert acceleration to angular movement in radians
x = atan(x/(sqrt(yy + zz)));

// Convert radians to degrees and ignore the decimal point
x_now = (int)(x * 180/M_PI);

// Calculate tilt angle with respect to original at rest position
// and that Vertical = 90 degrees
int x_tilt = x_now - x_start + 90;

// Beep
if ((x_tilt < 160) || (x_tilt > 130)) {
// beep function to make noise
Serial.println("===================");
Serial.println(" BEEP !!! “);
Serial.println(”===================");
}
Serial.print("x_tilt = ");
Serial.println(x_tilt);

delay(2000);
}

S.MONITOR:
x = 6.13 y = -4.27, z = 6.34 m/s^2

 BEEP !!!!     

===================
x_tilt = 128

However, instead of defining the start value as ‘90’ degrees, like the previous code, I want the starting value to be at 0, so when the user wears the device in an upright sitting posture and turn on the device, the angle measurement can be starting from that point. (so wherever they place the device and doesn’t matter how the device is placed when the device is turned on, that has to be the starting point). Do I need to put this: float t = acos((ax0 ax + ay0 ay + az0 az)/sqrt((ax ax + ay ay + az az) (ax0 ax0 + ay0 ay0 + az0 az0))); code again? or is there another way to do it?

Moreover, I’m thinking of adding in the side inclination as well (30degrees on each side; y-axis), to do this should should the code be like:

#include <Qduino.h>
#include <Wire.h>
#include <MPU9250.h>

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;
float x0 = 0 ;
float y0 = 0 ;
float z0 = 0 ;
int x_start = 0;
int x_now = 0;
int y_start = 0;
int y_now = 0;
void setup() {
// serial to display data
Serial.begin(115200);
while(!Serial) {}

// start communication with IMU
status = IMU.begin();
if (status < 0) {
Serial.println(“IMU initialization unsuccessful”);
Serial.println(“Check IMU wiring or try cycling power”);
Serial.print("Status: ");
Serial.println(status);
while(1) {}
}
x0 = IMU.getAccelX_mss();
y0 = IMU.getAccelY_mss();
z0 = IMU.getAccelZ_mss();

}
void loop() {
// read the sensor
IMU.readSensor();
float x = IMU.getAccelX_mss();
float y = IMU.getAccelY_mss();
float z = IMU.getAccelZ_mss();

// Print raw values
Serial.print(“x = “);
Serial.print(x);
Serial.print(” y = “);
Serial.print(y);
Serial.print(”, z = “);
Serial.print(z);
Serial.println(” m/s^2”);

// Calculate the angles for the 3 axis
float X = atan(x/(sqrt(yy + zz)));
float Y = atan(y/(sqrt(xx + zz)));
float Z = atan((sqrt(xx + yy))/z);

// Convert acceleration to angular movement in radians
x = atan(x/(sqrt(yy + zz)));
y = atan(y/(sqrt(xx + zz)));
// Convert radians to degrees and ignore the decimal point
x_now = (int)(x * 180/M_PI);
y_now = (int)(y * 180/M_PI);
// Calculate tilt angle with respect to original at rest position
// and that Vertical = 90 degrees
int x_tilt = x_now - x_start + 90;
int y_tilt = y_now - y_start + 180;
// Beep
if ((x_tilt < 70) || (x_tilt > 130)) {
// beep function to make noise
Serial.println("===================");
Serial.println(" xBEEP !!! “);
Serial.println(”===================");
if ((y_tilt < 150) || (y_tilt > 210)) {
// beep function to make noise
Serial.println("===================");
Serial.println(" yBEEP !!! “);
Serial.println(”===================");
}
Serial.print("x_tilt = ");
Serial.println(x_tilt);
Serial.print("y_tilt = ");
Serial.println(y_tilt);
delay(2000);
}
}

like this?

(Sorry, my qduino is not showing up on the port again, it got turned off when i was just about to run this code above, so i couldn’t check. I need to work on the problem again. the light are on everything seems fine so I don’t know what went wrong just then. )

I thank you for your consideration in advance. Thank you so much!

This line shifts the 0 point to 90, remove the + 90 and it will be 0 again. -20 (forward) and +40 (back).

// Calculate tilt angle with respect to original at rest position
// and that Vertical = 90 degrees
  int x_tilt = x_now - x_start + 90;

Change the following line to look for the new values.

// Beep 
  if ((x_tilt < -20) || (x_tilt > 40)) { 
    // beep function to make noise

To check the y axis add the following at the appropriate places in the code.

Variable declaration.

int x_start = 0;
int y_start = 0;
int x_now = 0;
int y_now = 0;

In void setup(void)

// Convert acceleration to angular movement in radians
  x = atan(x/(sqrt(y*y + z*z)));
  y = atan(y/(sqrt(x*x + z*z)));

// Convert radians to degrees and ignore the decimal point
  x_start = (int)(x * 180/M_PI);
  y_start = (int)(y * 180/M_PI);

In void loop(void)

// Convert acceleration to angular movement in radians
  x = atan(x/(sqrt(y*y + z*z)));
  y = atan(y/(sqrt(x*x + z*z)));

// Convert radians to degrees and ignore the decimal point
  x_now = (int)(x * 180/M_PI);
  y_now = (int)(y * 180/M_PI);

// Calculate tilt angle with respect to original at rest position
  int x_tilt = x_now - x_start;
  int y_tilt = y_now - y_start;

// Beep 
  if ((x_tilt < -20) || (x_tilt > 40) || (y_tilt < -30) || (y_tilt > 30)) { 
    // beep function to make noise

Regards
Jim

Thank you, I have tried with this code, however for some reason, the starting value isn’t 0. When I open the serial monitor (tried a few times) it shows:

x_tilt = 74
y_tilt = 63
x = 9.70 y = 2.83, z = 0.21 m/s^2

 BEEP !!!!     

===================
x_tilt = 73
y_tilt = 65
x = 9.75 y = 2.78, z = 0.19 m/s^2

 BEEP !!!!     

===================

but I would like the values to start at 0 when i upload the code. Do you think my code has some problem?

The code: (tried on Arduino Uno)

#include <Wire.h>
#include <MPU9250.h>

// an MPU9250 object with the MPU-9250 sensor on I2C bus 0 with address 0x68
MPU9250 IMU(Wire,0x68);
int status;
float x = 0 ;
float y = 0 ;
float z = 0 ;
int x_start = 0;
int y_start = 0;
int x_now = 0;
int y_now = 0;;
void setup() {
// serial to display data
Serial.begin(115200);
while(!Serial) {}

// start communication with IMU
status = IMU.begin();
if (status < 0) {
Serial.println(“IMU initialization unsuccessful”);
Serial.println(“Check IMU wiring or try cycling power”);
Serial.print("Status: ");
Serial.println(status);
while(1) {}
}
x = atan(x/(sqrt(yy + zz)));
y = atan(y/(sqrt(xx + zz)));
x_start = (int)(x * 180/M_PI);
y_start = (int)(y * 180/M_PI);
}
void loop() {
// read the sensor
IMU.readSensor();
x = IMU.getAccelX_mss();
y = IMU.getAccelY_mss();
z = IMU.getAccelZ_mss();

// Print raw values
Serial.print(“x = “);
Serial.print(x);
Serial.print(” y = “);
Serial.print(y);
Serial.print(”, z = “);
Serial.print(z);
Serial.println(” m/s^2”);

// Convert acceleration to angular movement in radians
x = atan(x/(sqrt(yy + zz)));
y = atan(y/(sqrt(xx + zz)));

// Convert radians to degrees and ignore the decimal point
x_now = (int)(x * 180/M_PI);
y_now = (int)(y * 180/M_PI);

// Calculate tilt angle with respect to original at rest position
int x_tilt = x_now - x_start;
int y_tilt = y_now - y_start;

// Beep
if ((x_tilt < -20) || (x_tilt > 40) || (y_tilt < -30) || (y_tilt > 30)) {
// beep function to make noise
Serial.println("===================");
Serial.println(" BEEP !!! “);
Serial.println(”===================");

}
Serial.print("x_tilt = ");
Serial.println(x_tilt);
Serial.print("y_tilt = ");
Serial.println(y_tilt);
delay(2000);
}

Your code looks ok.
When my MPU6050 is sitting flat on the desk; x_start = 7, y_start = -1 approximately.
This represents the starting condition.
In the main loop() x_now & y_now should be the same (7, -1), therefore x_tilt & y_tilt should be zero.

Your code is printing x, y, z just after they have been read and the values you have listed are what would be expected; if the device is sitting flat. It should also be sitting flat when the program starts so the values in setup() are the same.

Start the device sitting flat and dont move it.
Try printing x_start, x_now and y_start, y_now after the calculation for x_tilt, y_tilt. They should be about the same.
Then move the device and see how much they change.

Possibly the device could be calibrated to return zero when it is sitting flat, at rest, but that is not necessary. The values will vary from device to device and probably with environmental changes such as temperature.

Regards
Jim

1 Like

Thanks for the reply, maybe I didnt make myself clear,

so in order to get 0 value the sensor needs to be flat in this case, but my intention is to actually make the initial point (when the device is turned on by the user) to be the starting point of measuring tilt angles. So when the user turns on the device, no matter how the device is placed/positioned it starts measuring the angles from that point.

Let’s say the user is sitting upright and turns on the device that is attached at their back. The device starts reading the angle tilts from the time they activates the device. So let’s say the upright posture value or the initial value is 0. Then, if the device gets front-tilted (20) or (20)+ degrees it beeps and when they recline backwards (-40) or (-40)+ degrees it beeps.

Is the code that I have doing that? or do I need a different formula for that?

secondly, you said the values will vary from device to device and probably with environmental changes such as temperature; how can the angle measures of movement be affected by the temperature?

Thank you

1 Like

Hey Jinky,

That’s interesting, I wonder whether you can set up a watchdog to keep the device on continuously, or a secondary system to verify the initial position, I’ll let James run you through the code for this one given he’s written that original script (of course @James46717 if you’d like me to have a look through it for you to see how it can be modded please let me know)

As for how the values may change with temperature, indoors I’d imagine the effect would be quite insignificant as you don’t have to worry too much about sunlight, rapid changes, or anything like that. But generally the biggest reason temperature affects measurements is because of how it changes the resistance of materials (most importantly the semiconductors inside sensors) which on a physical level, when not accounted for, will cause the values that are read to maintain their precision (generally) but to read uncalibrated values which are slightly off the real value, but 90% of the time, it won’t be significant. I hope that clears up your second question. :slightly_smiling_face:

Bryce
Core Electronics | Support

1 Like

Thank you for the reply,

The device doesn’t need to read the values after it gets turned off. When it gets turned on back again, the initial value is defined at that moment again, not considering the previous initial value.

1 Like

Also thank you for your answer to my second question! :slight_smile:

1 Like

Hey Jinkyung,

(Please let me know whether the name is right :sweat_smile:)

I’ve just gotten some advice on this project from one of my colleagues Michael who suggested looking into using Quartenions in 3D space which determine angle and a moment of rotation rather than simply reading the angle in order to determine the direction. I’m going to do a little more research on how this integrates with this MPU9250 and get back to you but that’s a great place to start looking.

Bryce
Core Electronics | Support

Yup, that is my name! :slight_smile:

Thank you so much! Please let me know about it, I would like to finish coding within this week so that i can solder the parts but it is ok if it is not figured out, I will try to do other things first.

Tested the MPU6050 at various starting angles with the code provided. Changed the board position, pressed reset on the UNO, tried to hold the board still till the first reading appeared.
In all cases it worked, x_tilt and y_tilt were zero or close to zero until the board is moved.
So the code will do what you want.

Reference to being flat on desk was to remove minor movements that would be introduced by holding it by hand.

The reading of the MPU6050 sensors and calculation of x_tilt and y_tilt takes about 3.6 milliseconds. You could simply reset the UNO if the MPU6050 was repositioned. But the UNO takes a little while longer to start. The addition of a switch on one of the digital pins could be used to reset the position. Pressing this switch would tell the program to get the new values for x_start and y_start. The following is the code that would need to be executed.

// Get sensor readings at rest
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  x = a.acceleration.x;
  y = a.acceleration.y;
  z = a.acceleration.z;

// Convert acceleration to angular movement in radians
  x = atan(x/(sqrt(y*y + z*z)));
  y = atan(y/(sqrt(x*x + z*z)));

// Convert radians to degrees and ignore the decimal point
  x_start = (int)(x * 180/M_PI);
  y_start = (int)(y * 180/M_PI); 

Every electronic device is subject to temperature changes as Bryce mentioned.
Most of these very sensitive device include a temperature monitor to allow minor programming changes if the temperature varies. It means the device can be extremely accurate when programmed correctly.
The manufacturing process is such that there will be minor changes in the ICs. It is impossible to make every one exactly the same. My device sitting flat produces x = 7, y = -1. It should produce zero as it is flat. If I was to purchase another device from Core Electronics it might return x = 2, y =1, etc.

Anyway, all the best.
Cheers
Jim

1 Like