Auto-levelling table

Hello everyone, I am developing a project which consists of leveling a table automatically by means of 4 electric pistons with DC motors controlled with L298N, plus a MPU6050 sensor to obtain the leveling angles, I would like to know what you think of the following code and what improvements could be included or change.
What the code does is to measure the angles with the MPU and then with trigonometry calculate the necessary displacement for the pistons, which have a displacement speed of 2.6mm/s, and do not have any feedback. then first move two pistons to level the X axis, and then the other two to level the Y axis, but I feel that it is not that efficient.

Here is the code.

#include "I2Cdev.h"
#include <MPU6050.h>
#include <Wire.h>

MPU6050 mpu;

// Pinout
const byte M1IN1 = 2; //motor 1
const byte M1IN2 = 3;
const byte M2IN3 = 4; //motor 2
const byte M2IN4 = 5;

const byte M3IN1 = 6; //motor 3
const byte M3IN2 = 7;
const byte M4IN3 = 8; //motor 4
const byte M4IN4 = 9;

//buttons
const byte buttonAdjust = 12;



// Constants of displacement (in mm)
const float DIST_PISTON1 = 1500; // 150 cm
const float DIST_PISTON2 = 925;  // 92.5 cm

int ax, ay, az;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  mpu.initialize();
  
  // Setup pins of motors as outputs
  pinMode(M1IN1, OUTPUT);
  pinMode(M1IN2, OUTPUT);
  pinMode(M2IN3, OUTPUT);
  pinMode(M2IN4, OUTPUT);
  pinMode(M3IN1, OUTPUT);
  pinMode(M3IN2, OUTPUT);
  pinMode(M4IN3, OUTPUT);
  pinMode(M4IN4, OUTPUT);


  // Setup buttons as INPUT
  pinMode(buttonAdjust, INPUT);


  digitalWrite(M1IN1, LOW);
  digitalWrite(M1IN2, LOW);
  digitalWrite(M2IN3, LOW);
  digitalWrite(M2IN4, LOW);
  digitalWrite(M3IN1, LOW);
  digitalWrite(M3IN2, LOW);
  digitalWrite(M4IN3, LOW);
  digitalWrite(M4IN4, LOW);

  
    if (mpu.testConnection()) {
    Serial.println("MPU6050 connected correctly");
  } else {
    Serial.println("Error connecting MPU6050");
  }
}

void loop() {
  int btnAdj = digitalRead(buttonAdjust);


    // Obtaining readings from the MPU6050
  mpu.getAcceleration(&ax, &ay, &az);

  
   float angleX = atan(ax/sqrt(pow(ay,2) + pow(az,2)))*(180.0/3.14);
   float angleY = atan(ay/sqrt(pow(ax,2) + pow(az,2)))*(180.0/3.14);
  
  
  if (btnAdj == HIGH) {
    float radAngleX = radians(angleX); // Desired angle X
    float radAngleY = radians(angleY);  // Desired angle Y

    // Calcular desplazamiento
    double displacementX = (tan(radAngleX) * DIST_PISTON1);
    double displacementY = (tan(radAngleY) * DIST_PISTON2); 

    //Calculate displacement time
    int TimeX = ((displacementX * 1000)/ 2.6); //The pistons have a displacement speed of 2.6mm/s
    int TimeY = ((displacementY * 1000)/ 2.6); 

    int TdispX = abs(TimeX);
    int TdispY = abs(TimeY);

  Serial.print("Inclination X: ");
  Serial.print(angleX); 
  Serial.print("Inclination Y:");
  Serial.println(angleY);
  
    Serial.println(displacementX);
    Serial.println(displacementY);
    Serial.println(TdispX);
    Serial.println(TdispY);
  
    delay(1000);

    Adjust(TdispX, TdispY, angleX, angleY);  
    }
}


void Adjust(int TdispX, int TdispY, float angleX, float angleY) {
  Serial.println("Adjusting X");
  float anX = angleX;
  if (anX > 0) {
    extendPistons(M3IN1, M3IN2, M4IN3, M4IN4, TdispX);
  } else if (anX < 0) {
    extendPistons(M1IN1, M1IN2, M2IN3, M2IN4, TdispX);
  }

  Serial.println("Ajust X completed");
  AdjustY(TdispY, angleY);
}

void AdjustY(int TdispY, float angleY) {
  Serial.println("Adjusting Y");
  float anY = angleY;
  if (angleY > 0) {
    extendPistons(M1IN1, M1IN2, M3IN1, M3IN2, TdispY);
  } else if (angleY < 0){
    extendPistons(M2IN3, M2IN4, M4IN3, M4IN4, TdispY);
  }

  Serial.println("Ajust Y completed");
  return;
}

void extendPistons(byte IN1, byte IN2, byte IN3, byte IN4, int TIME) {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
  
  delay(TIME);
  
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
}

And an image showing how I have the pistons arranged and the dimensions.
MESA

Have you built the mechanism? It is very difficult to constrain the ends of four pistons to always lie in a plane, as a stiff table top requires, and perhaps impossible for a DIY project, without using feedback.

One or the other of these equations is not valid for Euler tilt angles, and invalidates all subsequent calculations.

   float angleX = atan(ax/sqrt(pow(ay,2) + pow(az,2)))*(180.0/3.14);
   float angleY = atan(ay/sqrt(pow(ax,2) + pow(az,2)))*(180.0/3.14);

See this tutorial for one correct approach to measuring tilt angles, but keep in mind that there are twelve different definitions of Euler angles, and that the order of applying subsequent rotations must be correctly chosen and obeyed in your code.

1 Like

Spelling.

You are creating an oscillating mechanism because it has NO reference point. Make one leg as a constant and adjust the other three to match. You can still have 4 legs that are adjustable, but make one fixed for all your adjustments of the other three.

1 Like

I would tend to use linear-actuators in leveling applications

1 Like

Isn't that what is

means of 4 electric pistons

?

a7

Thanks for your comments, I already built the mechanism, and as you said it is difficult to adjust all the piston in the same plane, in the tests I always have 1 piston that is more retracted than the rest.

This is how is going.

Thanks for the tutorial I will check it and correct the calculations.

Thanks for your comments, could you please explain me how to do that? I’m not using any type of feedback sensors, could I do it anyways?
I’m very new at programming:(

I am using linear actuators

Your leveling sensor is your feedback sensor. But only adjust 3 of the 4 legs in your code, not all 4.

Nice work on the frame and mechanism. Do you allow for angular pivoting of the vertical components? They must move horizontally as the table corners are moved vertically.

The problem is that the linear actuator doesn’t have feedback, and I am not allowed to use any other sensor for this project.

Yes, I am using rod end on each piston so they have some degree of freedom.

Good design!

Let me write again, your leveling sensor is your feedback mechanism. Otherwise why do you have it?

1 Like

Oh ok I got it, you mean the MPU right? Yes that the only feedback that I have

Yes, the MPU is the only feedback you have and that is it's ONLY purpose. Your code has to determine which of the legs to move to make the table match the one leg not being moved.

But I cannot move 1 simple leg because all the structure is fixed, maybe I could move it but just a little. Is for that I’m moving 2 legs at the same time.

Face it, if you cannot move a single leg, then you cannot level the table. IT's a geometry problem.

Due to small manufacturing variations, no two brushed DC motors, like those in linear actuators, rotate at exactly the same speed. So extending two legs at the same time is very likely to violate the planarity constraint in short order, unless you use feedback speed control on each actuator.

This is why many people use three point support. Are you familiar with Stewart platforms? Examples for Arduino have been posted on the web.

So there’s nothing I could do ?

yes, I’ve heard about steward platform, I searched a lot of that. I’ll check the posts in the forum thanks

Sure there is, but with four legs you are faced with a serious challenge, which goes away completely when you have only three points of support.

Ok thank you, I’ll have that into consideration