How to record a desired position of accelerometer

Hi friends, I'm lack of knowledge in programming so hope anyone here could help me out with my idea.

I'm building a camera stabilizer with 3 servo motors and a MPU 6050 module with my Arduino Mega 2560. So far I can make it stabilize with PID controlling method, and now im thinking of improving my stabilizer, making its reference position(desired position) adjustable according to the user with just a single click of button.

The problem I am facing now is I do not know how to record just a single data/ angle value from an all time changing values of accelerometer at the moment the button is clicked. Can anyone help me with this or is anyone know another method to achieve the same result?

Thank you in advance.

Here is my code prior to the idea i just mentioned.

#include <Servo.h>
#include <Wire.h>
//Declaring some global variables
int gyro_x, gyro_y, gyro_z;
long gyro_x_cal, gyro_y_cal, gyro_z_cal;
boolean set_gyro_angles;

long acc_x, acc_y, acc_z, acc_total_vector;
float angle_roll_acc, angle_pitch_acc;

float angle_pitch, angle_roll;
int angle_pitch_buffer, angle_roll_buffer;
float angle_pitch_output, angle_roll_output;

long loop_timer;
int temp;

//variables for servo motor
byte PWMOutput;
long PID;
int P;
int I;
int D;
int Error;

Servo servo;

void setup() {
  Wire.begin();                                                        //Start I2C as master
  setup_mpu_6050_registers();                                          //Setup the registers of the MPU-6050 
  for (int cal_int = 0; cal_int < 1000 ; cal_int ++){                  //Read the raw acc and gyro data from the MPU-6050 for 1000 times
    read_mpu_6050_data();                                             
    gyro_x_cal += gyro_x;                                              //Add the gyro x offset to the gyro_x_cal variable
    gyro_y_cal += gyro_y;                                              //Add the gyro y offset to the gyro_y_cal variable
    gyro_z_cal += gyro_z;                                              //Add the gyro z offset to the gyro_z_cal variable
    delay(3);                                                          //Delay 3us to have 250Hz for-loop
    
  }

  // divide by 1000 to get avarage offset
  gyro_x_cal /= 1000;                                                 
  gyro_y_cal /= 1000;                                                 
  gyro_z_cal /= 1000;                                                 
  Serial.begin(115200);
  loop_timer = micros();                                               //Reset the loop timer
   servo.attach(9);
   servo1.attach(10);
}

void loop(){
  static int displayPrescaler = 0;

  read_mpu_6050_data();   
 //Subtract the offset values from the raw gyro values
  gyro_x -= gyro_x_cal;                                                
  gyro_y -= gyro_y_cal;                                                
  gyro_z -= gyro_z_cal;                                                
         
  //Gyro angle calculations . Note 0.0000611 = 1 / (250Hz x 65.5)
  angle_pitch += gyro_x * 0.0000611;                                   //Calculate the traveled pitch angle and add this to the angle_pitch variable
  angle_roll += gyro_y * 0.0000611;                                    //Calculate the traveled roll angle and add this to the angle_roll variable
  //0.000001066 = 0.0000611 * (3.142(PI) / 180degr) The Arduino sin function is in radians
  angle_pitch += angle_roll * sin(gyro_z * 0.000001066);               //If the IMU has yawed transfer the roll angle to the pitch angel
  angle_roll -= angle_pitch * sin(gyro_z * 0.000001066);               //If the IMU has yawed transfer the pitch angle to the roll angel
  
  //Accelerometer angle calculations
  acc_total_vector = sqrt((acc_x*acc_x)+(acc_y*acc_y)+(acc_z*acc_z));  //Calculate the total accelerometer vector
  //57.296 = 1 / (3.142 / 180) The Arduino asin function is in radians
  angle_pitch_acc = asin((float)acc_y/acc_total_vector)* 57.296;       //Calculate the pitch angle
  angle_roll_acc = asin((float)acc_x/acc_total_vector)* -57.296;       //Calculate the roll angle
  
  angle_pitch_acc -= 0.0;                                              //Accelerometer calibration value for pitch
  angle_roll_acc -= 0.0;                                               //Accelerometer calibration value for roll

  if(set_gyro_angles){                                                 //If the IMU is already started
    angle_pitch = angle_pitch * 0.9996 + angle_pitch_acc * 0.0004;     //Correct the drift of the gyro pitch angle with the accelerometer pitch angle
    angle_roll = angle_roll * 0.9996 + angle_roll_acc * 0.0004;        //Correct the drift of the gyro roll angle with the accelerometer roll angle
  }
  else{                                                                //At first start
    angle_pitch = angle_pitch_acc;                                     //Set the gyro pitch angle equal to the accelerometer pitch angle 
    angle_roll = angle_roll_acc;                                       //Set the gyro roll angle equal to the accelerometer roll angle 
    set_gyro_angles = true;                                            //Set the IMU started flag
  }
  
  //To dampen the pitch and roll angles a complementary filter is used
  angle_pitch_output = angle_pitch_output * 0.9 + angle_pitch * 0.1;   //Take 90% of the output pitch value and add 10% of the raw pitch value
  angle_roll_output = angle_roll_output * 0.9 + angle_roll * 0.1;      //Take 90% of the output roll value and add 10% of the raw roll value
 // Serial.print(" | Angle  = "); Serial.println(angle_pitch_output);
  //Serial.print(" | Angle2  = "); Serial.println(angle_roll_output);

  if(displayPrescaler++ >=100){
    displayPrescaler = 0;
   Serial.print(" | Angle  = "); Serial.println(angle_pitch_output);
  Serial.print(" | Angle2  = "); Serial.println(angle_roll_output);
  }

 while(micros() - loop_timer < 4000);                                 //Wait until the loop_timer reaches 4000us (250Hz) before starting the next loop
 loop_timer = micros();    //Reset the loop timer
 GetError();
 CalculatePID();
 servo.write(PWMOutput);
  
}

void GetError(void)
{
  byte i=0;
  word ActualPosition_roll = angle_pitch_output;    //due to setup of structure, roll direction  of MPU 
 6050 is my pitch direction
  Serial.print("ActPos_roll =");
  Serial.println(ActualPosition_roll,DEC);
  
  int DesiredPosition_roll = -3;
  Serial.print("DesPos_roll=");
  Serial.println(DesiredPosition_roll, DEC);

  Error = DesiredPosition_roll - ActualPosition_roll;
 
  }

 void CalculatePID(void)
 {
  P = 1.0;
  I = 1.0;
  D = 4.0;
  int dt = 0.1;
  
 
   int pre_error = 0;
 int derivative;
 int integral=0;
 int proportional = P*Error;
 integral = integral + Error*dt;
 derivative = (Error - pre_error)*dt;
 PID = proportional + I*integral + D*derivative;
 pre_error = Error;

  Serial.print("PID =");
  Serial.println(PID, DEC);

  if( PID >= 90 )
  PID = 90;

  if(PID <= -90)
  PID = -90;
 

  PWMOutput = 90+PID;
  
  Serial.print("PWMOutput=");
  Serial.println(PWMOutput,DEC);
 }
                          
}
if (digitalRead(theButtonPin) == LOW)
  {
    savedPosition = theAngle;
  }

Hi, thank you for answering my question. One thing to ask, is theAngle a fixed number here extracted from accelerometer? Will it change again if i move the MPU 6050 when the button state is still low? should i consider also what happen when the button satte is high?

Thanks.

is theAngle a fixed number here extracted from accelerometer?

theAngle is the name that I chose for the angle just to demonstrate the principle. In your code you need to substitute the real name of the variable holding the angle that you are interested in which has been read from the accelerometer.

Will it change again if i move the MPU 6050 when the button state is still low? should i consider also what happen when the button satte is high?

The answer to both of those questions depends on what you want to do. If you just read the button state with digitalRead() and save the angle then it will continuously update the save angle. If you want to you can write code to act when the button becomes pressed rather than when it is pressed. Look at the StateChangeDetection example in the IDE.

Either way, note that detecting the button press by checking the state of the pin depends on how you wire the switch. The easiest way is to connect one side of the switch to the pin and the other side to GND so that the pin is taken LOW when pressed. Use INPUT_PULLUP in the pinMode() for the switch pin to keep it HIGH when the button not pressed. Test for LOW on the pin to detect when the button is or becomes pressed.

If you just read the button state with digitalRead() and save the angle then it will continuously update the save angle.

What i want to do is just when the button is pressed once, update the angle, second press to save current angle and stop updating the save angle and use whatever saved angle value for my program to set it as reference point. Is my idea clear for you? Can this be done?

Thank you for your information on the buttonstate, i have read through and understand that.

If you want to do different things depending on how many times the button has become pressed then increment a counter each time you detect the button press and take action dependant on the value of the counter.

Did you look at the StateChangeDetection example in the IDE ?

Yes i have look into it and understand how StateChangeDetection works, appreciate that. Now the problem is i do not know how to write the code for saving current angle and stop updating the value of current angle. What kind of functions do i need to use to achieve this? Can you please help and guide me through? Thanks.

Some pseudo code for you

start of loop()
//your current code goes here
//part of which reads the current angle

if the button is now pressed and previously wasn't //see the example of how to determine this
save the current angle in a variable - this will only update if the button becomes pressed again
end if
end of loop()

Hi, thank you very much for your help. I've made it for the result that i want. Appreciate that. :slight_smile: