Trouble displaying correct angle with Memsic 2125 accelerometer

Hello,

I am working on a project where I need to measure the angle of inclination for a solar panel mounting system. The panels will start at an angle of 0 and will need to measure all the way to 90 degrees. I have already found some code others have used for similar projects and have modified it a bit, but I am having issues displaying the correct angle to the serial monitor. For example when it should measure 0 degrees it outputs a negative angle and when it should display 90 degrees it measures about 70ish.

The sensor will only be allowed to move in one direction, specifically in the Xm direction as the attached image shows.
Here is the code:

#include <math.h>

int xPin = 2; // X input from accelerometer
int yPin = 3; // Y input accelerometer

int Xraw, Yraw;
double xGForce, yGForce, Xangle, Yangle;


void setup() {
  
  Serial.begin(9600);
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  Serial.print("Welcome to the Earthlab!");
  Serial.println();
  Serial.println();
  delay(2000);
  
}

void loop() {
  
  // read x and  y values..pulseIn returns length of pulse 
  //in microseconds or zero if no complete pulse was received 
  Xraw = pulseIn(xPin,HIGH);
  Yraw = pulseIn(yPin,HIGH);


  //Due to erroneous output of pulseIn();
  // when x and y are calculated together
  // pulseIn(); must be used twice.
  Xraw = pulseIn(xPin,HIGH);
  Yraw = pulseIn(yPin,HIGH);


  //Calculate G-force in milli g's
  xGForce = ((Xraw / 10) - 500) * 8;
//  yGForce = ((Yraw / 10) - 500) * 8;


  // Calculate angle (radians) for both -x and -y axis.
  Xangle = asin( xGForce / 1000.0  );
  //Yangle = asin ( yGForce / 1000.0 );
  

  // Convert radians to degrees.
    Xangle = Xangle * (360 / (2*M_PI));
  //Yangle = Yangle * (360 / (2*M_PI));

   
   
  Serial.print("The current angle of inclination is ");

  //Force angle to 0 if there is any negative value
 if(Xangle<0)
  {
    Xangle = 0;
  }

  // Print the angle with printDouble function
  printDouble (Xangle, 10);


  delay(500);
}



void printDouble( double val, unsigned int precision)
{
  
  Serial.print(int(val));
  Serial.print(".");
   
  unsigned int frac;
  
  if(val >= 0)
  {
     frac = (val - int(val)) * precision;
  }
  else
     frac = (int(val) - val ) * precision;

  int frac1 = frac;
  
  while(frac1 /= 10)
  {
     precision /= 10;
  }
  
  precision /= 10;
  
  while( precision /= 10)
  {
     Serial.print("0");
     
  }

  
   Serial.print(frac, DEC);
   Serial.print(" degrees");
   Serial.println();
   Serial.println();
   
}

Any help would be greatly appreciated!

Capture.JPG

The Memsic 2125 is old and outdated. Get a normal 3 axis accelerometer with analog or digital (I2C or SPI) interface. But not just any accelerometer, but one that is often used with Arduino and for which libraries are available. Start at Adafruit.com and Sparkfun.com.

The Memsic 2125 can run at 3.3V and also at 5V. Most sensors are 3.3V, so you have to be careful how to connect that to a 5V Arduino.

Which Arduino board are you using ?

Why is simple code not enough ? for example this : Accelerometer/Arduino_Accelerometer.pde at master · parkerboundy/Accelerometer · GitHub

You have to show more data with angles. Keep it in all directions and show the data. I don't have a Memsic 2125 and what you tell about the angles is not enough for me.

Koepel:
The Memsic 2125 is old and outdated. Get a normal 3 axis accelerometer with analog or digital (I2C or SPI) interface. But not just any accelerometer, but one that is often used with Arduino and for which libraries are available. Start at Adafruit.com and Sparkfun.com.

The Memsic 2125 can run at 3.3V and also at 5V. Most sensors are 3.3V, so you have to be careful how to connect that to a 5V Arduino.

Which Arduino board are you using ?

Why is simple code not enough ? for example this : Accelerometer/Arduino_Accelerometer.pde at master · parkerboundy/Accelerometer · GitHub

You have to show more data with angles. Keep it in all directions and show the data. I don't have a Memsic 2125 and what you tell about the angles is not enough for me.

Hey there! I'm using an Arduino uno and powering the sensor with 5V. Right now I have the circuit set up without any resistors..Would you just recommend to power the sensor with 3.3V and/or use resistors? This project is for my senior design class, were on a time crunch right now and this is the only sensor we purchased. I need to have this done by Monday night :o :o

The idea is that the sensor will measure the angle of tilt for the solar panel system. I took a look at the code and will test it out tomorrow morning. The code you posted returns acceleration, do you know how I would go on to converting that value to degrees? In my code I try to accomplish that, but I'm not getting the correct measurements. I've been busting my head trying to find the bug, but to no avail.

Edit:

How does the map function help me acquire the acceleration? The PulseIn returns a value in microseconds, while map simply assigns the smallest value of time acquired to zero and the highest to 500. How is this new value acceleration? I don't follow.. is there a chart somewhere that tells me what this number between 0-500 means?

The sensor works at 5V, keep everything at 5V.

Could you connect the Tout as well ? Perhaps you can test that, because you already know the room temperature.

The Arduino Uno is okay; pin 2 and 3 is okay; pulseIn() is okay. Somehow we should be able to make this sensor work.

Something is wrong, that means you have to print a lot more data to the serial monitor. You are only printing the result.
Your code is not okay. You mix integer with float, and the result of the calculation is not useable.
Print the raw values of pulseIn(), and move the sensor around in all directions. Do the values make sense ?

The acceleration is (almost) the same as the angle. When the sensor is not moving, the earth gravity is measured as being an acceleration pointing downwards.

Is the printDouble() function working code ? From where does it come from ? What is it used for ?
Don't use that function when something is wrong, because it brings in extra uncertainty in the sketch.

For your sketch, use 'float' as soon as possible, and print that float using the Serial functions.
The Arduino Uno uses 32-bit 'float'. When you have 'double' in the sketch, the compiler translates it to 'float'.

xGForce = ((Xraw / 10) - 500) * 8;

Xraw is an integer, which you divide by integer 10, and then substruct integer 500. At that moment you have converted Xraw into something useless.
Cast Xraw to float and do the calculation with floating point numbers.

xGForce = (( (float) Xraw / 10.0) - 500.0) * 8.0;

Please update your sketch. Use for example "360.0" instead of "360" so everyone can see that it is a floating point calculation. Print a lot more data to the serial port.

I did not look into the use of the map function yet. Can you give a new sketch first ?

(You don't have to quote what I wrote, because what I wrote is already there. Use the Reply button).

I used analogRead() to get a value from Tout, but I'm not seeing how this would help me. I ran the code only printing raw values of pulseIn() however not completely comprehending the data. PulseIn() returns the length of the pulse in microseconds or 0 if no pulse is completed before timeout (i.e the number of microseconds to wait for the pulse to be completed).

Currently, the sensor is resting on a flat surface and is displaying roughly the same value of 4900 for pulseIn() in the x and y direction. When I move the sensor only in the x direction the value increase to around 6000..What are these values telling me?

Honestly I didn't really look into the the printDouble() function..I found this code from another user since they were doing a similar project to mine. If I'm not mistaken I think all this function does is provide a more accurate angle result for Xangle. However, I don't think the printDouble() function is even needed I could just have a Serial.print(Xangle) because Xangle is already a float type.

Here is my updated sketch:

#include <math.h>

int xPin = 2; // X input from accelerometer
int yPin = 3; // Y input accelerometer

int Xraw, Yraw;
double xGForce, yGForce, Xangle, Yangle;


void setup() {
  
  Serial.begin(9600);
  pinMode(xPin, INPUT);
  pinMode(yPin, INPUT);
  Serial.print("Welcome to the Earthlab!");
  Serial.println();
  Serial.println();
  delay(2000);
  
}

void loop() {
  
  // read x and  y values..pulseIn returns length of pulse 
  //in microseconds or zero if no complete pulse was received 
  Xraw = pulseIn(xPin,HIGH);
 


  //Due to erroneous output of pulseIn();
  // when x and y are calculated together
  // pulseIn(); must be used twice.
  Xraw = pulseIn(xPin,HIGH);
 

  Serial.print("The pulseIn() value for X is ");
  Serial.print(Xraw);
  Serial.println();
  delay(1000);


  //Calculate G-force in milli g's
  xGForce = (( (float)Xraw / 10.0) - 500.0) * 8.0;
  


  Serial.print("The xGForce value is ");
  Serial.print(xGForce);
  Serial.println();
  delay(1000);

  // Calculate angle (radians) for both -x and -y axis.
  Xangle = asin( xGForce / 1000.0  );
 

  Serial.print("The Xangle in radians is ");
  Serial.print(Xangle);
  Serial.println();
  delay(1000);

  // Convert radians to degrees.
  Xangle = Xangle * (360.0 / (2*M_PI));
  

  Serial.print("The Xangle in degrees is ");
  Serial.print(Xangle);
  Serial.println();
  delay(1000);

   
  // Print the angle with printDouble function
  Serial.print("The current angle of inclination is ");
  Serial.print(double(Xangle));
  Serial.print(" degrees");
  Serial.println();
  Serial.println();

   delay(500);
}

I still have the sensor on a flat surface and this is the output I get from the serial monitor:

The pulseIn() value for X is 4894
The xGForce value is -84.80
The Xangle in radians is -0.08
The Xangle in degrees is -4.86
The current angle of inclination is -4.86 degrees

I need to have angle of 0 degrees, but I am not getting that as you can see. Could there be something wrong with the conversions?

Your conversion to g's is probably inaccurate, and the sin() function is not the best method to calculate inclination.

It is much better to use atan2(), which takes care of the conversion scale factors automatically. Assuming that X is approximately horizontal and Z is approximately down,

float angle = atan2(az, ax);  //angle in radians

Refer to equations 25 or 29 in this application note.

How would I implement atan2() in my case I can't think of a way to measure the displacement in the Z direction?

"X", "Y" and "Z" are just names.

Point the Y axis down and calculate atan2(ay, ax).