Hi all, I've been developing a pid loop self balancing robot and im having trouble with the code (i think). Ive currently got an esp32 dev board hooked up to an mpu6050 for gyroscope angle reading, and 2 stepper motors which are connected through a4988 drivers.
The code runs well and does what i want it to do however the motor's max speed seem to be capped very low, nothing i change in the code increases the max speed. they are on 1/8 microstepping and can run much faster to the speed i need when i run them in a separate program outside a pid loop. I originally had an arduino nano in place of the esp32, but i thought it was possibly the processing power of the arduino nano that was slowing the loop down causing the motor to spin slower, but the issue hasnt gone away with the esp32.
Ive tried code with and without stepper motor libraries to get full control of the motors but its still not working as i want it. If anyone can recognise my issue I would greatly appreciate it.
here is my current code (with libraries)
#include <Wire.h>
#include <MPU6050_light.h>
#include <AccelStepper.h>
#include <PID_v1.h>
// Stepper motor pins
#define DIR_PIN 2
#define STEP_PIN 4
#define DIR_PIN2 12
#define STEP_PIN2 14
// MPU6050 object
MPU6050 mpu(Wire);
// Stepper objects
AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
AccelStepper stepper2(AccelStepper::DRIVER, STEP_PIN2, DIR_PIN2);
// PID variables
double setpoint = 0; // Desired angle of 0 degrees
double input, output;
// PID gain control
double Kp = 25.0;
double Ki = 0.0;
double Kd = 4.0;
// PID controller object
PID myPID(&input, &output, &setpoint, Kp, Ki, Kd, DIRECT);
void setup() {
Serial.begin(115200);
// Initialize MPU6050
Wire.begin();
byte status = mpu.begin();
if (status != 0) {
Serial.println("MPU6050 connection failed");
while (1); // Stop if connection fails
}
Serial.println("MPU6050 initialized successfully");
// Calibrate MPU6050
mpu.calcOffsets(true, true); // Calibrate gyro and accelerometer
// Initialize steppers
stepper.setMaxSpeed(7000);
stepper.setAcceleration(5000);
stepper2.setMaxSpeed(7000);
stepper2.setAcceleration(5000);
// Initialize PID controller
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(-1500, 1500); // Adjust output limits
}
void loop() {
delay(0.4);
// Update MPU6050 angle
mpu.update();
double angle = mpu.getAngleX(); // Get the Y-axis angle
// Update PID controller
input = angle;
myPID.Compute();
// Map PID output to motor speeds
int motorSpeed = (int)output;
stepper.setSpeed(motorSpeed); // Motor 1 speed
stepper2.setSpeed(motorSpeed); // Motor 2 speed
// Run the motors
stepper.runSpeed();
stepper2.runSpeed();
// Print angle and motor speed
Serial.print("Angle: ");
Serial.print(angle);
Serial.print(" Motor Speed: ");
Serial.println(motorSpeed);
}
here is my current code (without libraries)
#include <Wire.h>
#include <MPU6050_light.h>
// Stepper motor pins
#define DIR_PIN 2
#define STEP_PIN 4
#define DIR_PIN2 12
#define STEP_PIN2 14
// MPU6050 object
MPU6050 mpu(Wire);
// PID control variables
double Kp = 62.0; // Keep Kp low to ensure stability
double setpoint = 0.0; // Target angle (upright position)
double angle, error, speed;
// Variables for step timing
volatile long stepDelay; // Delay between steps in microseconds
unsigned long lastStepTime1 = 0;
unsigned long lastStepTime2 = 0;
void setup() {
Serial.begin(115200);
// Initialize MPU6050
Wire.begin();
byte status = mpu.begin();
if (status != 0) {
Serial.println("MPU6050 connection failed");
while (1); // Stop if connection fails
}
Serial.println("MPU6050 initialized successfully");
// Calibrate MPU6050
mpu.calcOffsets(true, true); // Calibrate gyro and accelerometer
// Set motor pins
pinMode(DIR_PIN, OUTPUT);
pinMode(STEP_PIN, OUTPUT);
pinMode(DIR_PIN2, OUTPUT);
pinMode(STEP_PIN2, OUTPUT);
}
void loop() {
mpu.update(); // Update MPU6050 angle
angle = mpu.getAngleX(); // Get X-axis angle
// Calculate error
error = angle - setpoint;
// Calculate speed based on proportional control
speed = Kp * error;
// Constrain speed to avoid overflow or hardware limits
speed = constrain(speed, -8000, 8000); // Adjust for your stepper motor and driver limits
// Determine motor directions
digitalWrite(DIR_PIN, speed >= 0 ? HIGH : LOW);
digitalWrite(DIR_PIN2, speed >= 0 ? HIGH : LOW);
// Calculate step delay (higher speed = shorter delay)
stepDelay = speed != 0 ? abs(1000000 / abs(speed)) : 1000000;
// Generate step pulses for Motor 1
if (micros() - lastStepTime1 >= stepDelay) {
lastStepTime1 = micros();
digitalWrite(STEP_PIN, HIGH);
delayMicroseconds(1); // Minimal HIGH pulse
digitalWrite(STEP_PIN, LOW);
}
// Generate step pulses for Motor 2
if (micros() - lastStepTime2 >= stepDelay) {
lastStepTime2 = micros();
digitalWrite(STEP_PIN2, HIGH);
delayMicroseconds(1); // Minimal HIGH pulse
digitalWrite(STEP_PIN2, LOW);
}
// Print angle and speed for debugging
Serial.print("Angle: ");
Serial.print(angle);
Serial.print(" Speed: ");
Serial.println(speed);
}