Trying to build a 2 axis balancing stick

Hello everyone, I'm trying to make a 2 axis balancing stick with the Arduino uno,adafruit motor shield , mpu6050 gyroscope and 2x 12v
300 rpm motors. The project works on the principle of angular momentum to prevent the stick from falling. I will paste a link at the end. The problem I'm having is controlling the motor speed so that they get enough power and can reverse the direction when the speed goes into the negetive.

#include <SoftwareSerial.h>
#include <Wire.h>
#include <AFMotor.h>
#include <MPU6050_light.h>
SoftwareSerial BTSerial(A0, A1);  // RX, TX pins for SoftwareSerial

AF_DCMotor xMotor(1);
AF_DCMotor yMotor(4);

const float Kp = 1.0;   // Proportional gain
const float Ki = 0.1;   // Integral gain
const float Kd = 0.01;  // Derivative gain
const float dt = 0.02;  // Time interval (adjust as needed)

float setpointX = 0.0;  // Initial vertical position along X-axis
float setpointY = 0.0;  // Initial vertical position along Y-axis
float currentAngleX = 0.0;
float currentAngleY = 0.0;
float prevErrorX = 0.0;
float prevErrorY = 0.0;
float integralX = 0.0;
float integralY = 0.0;

MPU6050 mpu(Wire);

void setup() {
  Serial.begin(9600);
  Wire.begin();
  BTSerial.begin(9600);

  // Initialize MPU6050
  byte status = mpu.begin(3, 0);
  Serial.print(F("MPU6050 status: "));
  Serial.println(status);
  while (status != 0) {}  // stop everything if could not connect to MPU6050

  /*while (!mpu.begin(3, 0)) {
    BTSerial.println("Failed to initialize MPU6050!");
    Serial.println("Failed to initialize MPU6050!");
    delay(1000);*/
  Serial.println(F("Calculating offsets, do not move MPU6050"));
  mpu.calcAccOffsets();
  mpu.calcGyroOffsets();
  delay(1000);

}

void loop() {
  mpu.update();
  // Measure current angles (replace this with your actual sensor reading)
  float gyroReadingX = mpu.getGyroX();                                            // Assuming X-axis for angular velocity
  float gyroReadingY = mpu.getGyroY();                                            // Assuming Y-axis for angular velocity
  currentAngleX = 0.98 * (currentAngleX + gyroReadingX * dt) + 0.02 * setpointX;  // Update current angle along X-axis
  currentAngleY = 0.98 * (currentAngleY + gyroReadingY * dt) + 0.02 * setpointY;  // Update current angle along Y-axis

  // PID control for X-axis
  float errorX = setpointX - currentAngleX;
  integralX += errorX * dt;
  float derivativeX = (errorX - prevErrorX) / dt;
  float outputX = Kp * errorX + Ki * integralX + Kd * derivativeX * 100;

  // Motor control for X-axis
  int xMotorSpeed = 100 - outputX;  // Adjust direction based on your motor setup
  xMotor.setSpeed(xMotorSpeed);

  // PID control for Y-axis
  float errorY = setpointY - currentAngleY;
  integralY += errorY * dt;
  float derivativeY = (errorY - prevErrorY) / dt;
  float outputY = Kp * errorY + Ki * integralY + Kd * derivativeY * 100;

  // Motor control for Y-axis
  int yMotorSpeed = 200 + outputY;  // Adjust direction based on your motor setup
  yMotor.setSpeed(yMotorSpeed);

  // Run motors
  xMotor.run(FORWARD);
  yMotor.run(FORWARD);

  // Update variables for the next iteration
  prevErrorX = errorX;
  prevErrorY = errorY;

  // Print data to BT
  BTSerial.print("Setpoint X: ");
  BTSerial.print(setpointX);
  BTSerial.print("\tCurrent Angle X: ");
  BTSerial.print(currentAngleX);
  BTSerial.print("\tOutput X: ");
  BTSerial.print(outputX);
  BTSerial.print("\tX Motor Speed: ");
  BTSerial.print(xMotorSpeed);

  BTSerial.print("\tSetpoint Y: ");
  BTSerial.print(setpointY);
  BTSerial.print("\tCurrent Angle Y: ");
  BTSerial.print(currentAngleY);
  BTSerial.print("\tOutput Y: ");
  BTSerial.print(outputY);
  BTSerial.print("\tY Motor Speed: ");
  BTSerial.println(yMotorSpeed);

  // send data to serial monitor
  Serial.print("Setpoint X: ");
  Serial.print(setpointX);
  Serial.print("\tCurrent Angle X: ");
  Serial.print(currentAngleX);
  Serial.print("\tOutput X: ");
  Serial.print(outputX);
  Serial.print("\tX Motor Speed: ");
  Serial.print(xMotorSpeed);

  Serial.print("\tSetpoint Y: ");
  Serial.print(setpointY);
  Serial.print("\tCurrent Angle Y: ");
  Serial.print(currentAngleY);
  Serial.print("\tOutput Y: ");
  Serial.print(outputY);
  Serial.print("\tY Motor Speed: ");
  Serial.println(yMotorSpeed);


  delay(20);
}

ignore the bluetooth module, its just for sending sensor data

It sounds like the motor shield is inadequate for your motors.

Choose a motor driver that can handle the start/stall current of the motors (check the motor data sheet). Pololu has the best selection.

the motor shield can provide enough power to the motors im just having problems with changing the direction of the motors without using 'motor.run(BACKWARD);' since i need it to be seamless

You have to reverse the direction at times.

Keep in mind that when abruptly reversed, the motors briefly draw twice the stall current.

If you want help with the hardware, post links to the motors, the motor shield and a complete wiring diagram (hand drawn is preferred, with pins and connections clearly labeled). Identify the batteries.

motors: https://robu.in/product/300rpm-12v-low-noise-dc-motor-with-metal-gears-grade-a/

can u elaborate?

I feel that this is more of a software problem

If you don't know how to reverse the motor direction, then yes, the software is one of the problems.

Start with the basics, and make sure that you can control the motor speed and direction. Forget the sensors and balancing code until you understand how to do that. The motor driver library should have documentation, and example code to try.

I do know how to change the direction but I want change the direction using the negetive motor speed

Does the motor library support that option?

If not, you have to change both the direction of motor rotation and the sign of the commanded speed. Some libraries do exactly that, internally.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.