I'm pretty new to Arduino. I am trying to build a Self-balancing robot. I am using A4988 drivers, ESP32 microcontroller, NEMA 17 motors and a 6050 MPU.
The problem is that, although the speed variable changes according to the position of the MPU. The motors rotate at a slow and constant speed, without varying according to the inclination of the robot.
Here is the code:
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <AccelStepper.h>
#define STEP_IZQ 26
#define DIR_IZQ 27
#define STEP_DER 12
#define DIR_DER 13
AccelStepper stepperizq(AccelStepper::FULL2WIRE,STEP_IZQ,DIR_IZQ);
AccelStepper stepperder(AccelStepper::FULL2WIRE,STEP_DER,DIR_DER);
Adafruit_MPU6050 mpu;
float kp = 20;
float ki = 0.5;
float kd = 30;
float angulo_grad, error,cumError,rateError,output,lastError;
float pid_error_temp, pid_i_mem, pid_setpoint, gyro_input, pid_output, pid_last_d_error;
int speed,outputAbs;
void setup(void) {
Serial.begin(115200);
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit MPU6050 test!");
// Try to initialize!
if (!mpu.begin()) {
Serial.println("Failed to find MPU6050 chip");
while (1) {
delay(10);
}
}
Serial.println("MPU6050 Found!");
mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
mpu.setGyroRange(MPU6050_RANGE_500_DEG);
mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);
pinMode(DIR_IZQ, OUTPUT);
pinMode(DIR_DER, OUTPUT);
stepperizq.setMaxSpeed(3000);
stepperder.setMaxSpeed(3000);
stepperizq.setAcceleration(1000); //1000
stepperder.setAcceleration(1000); //1000
}
void loop() {
/* Get new sensor events with the readings */
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
angulo_grad = atan((a.acceleration.x)/(a.acceleration.z))*(180/3.14); //0 to 90 degrees
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// pid
/////////////////////////////////////////////////////////////////////////////////////////////////
pid_error_temp = angulo_grad;
if((pid_error_temp > -2.0 )&&( pid_error_temp < 2.0)) pid_error_temp = 0.0;
pid_i_mem += ki * pid_error_temp; //Calculate the I-controller value and add it to the pid_i_mem variable
if(pid_i_mem > 800)pid_i_mem = 800; //Limit the I-controller to the maximum controller output
else if(pid_i_mem < -800)pid_i_mem = -800;
//Calculate the PID output value
pid_output = kp * pid_error_temp + pid_i_mem + kd * (pid_error_temp - pid_last_d_error);
if(pid_output > 5000)pid_output = 5000; //Limit the PI-controller to the maximum controller output
else if(pid_output < -5000)pid_output = -5000;
if(output < 50 && output > 50)output = 0;
pid_last_d_error = pid_error_temp;
////////////////////////////////////////////////////////////////////////////////////////////////////
//motors nema 17
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
outputAbs = (int)abs(pid_output);
speed = map(outputAbs,0,5000,0,3000);
stepperizq.setSpeed(speed);
stepperder.setSpeed(speed);
if(pid_output<0){
digitalWrite(DIR_IZQ,LOW);
digitalWrite(DIR_DER,HIGH);
}
else if(pid_output>0){
digitalWrite(DIR_IZQ,HIGH);
digitalWrite(DIR_DER,LOW);
}
stepperizq.runSpeed();
stepperder.runSpeed();
}
loop()
is running to slow for it to keep up with the necessary steps? If for example the sensor readings are taking too long (in the range of the period between two consecutive steps), then each execution ofrunSpeed()
would find, that it always was time to do a step, doing exactly one step and then exiting to the rest ofloop()
. That would limit your speed to one step perloop()
iteration, which probably has a constant duration. You could try to only get new measurements at set intervals (like every x ms)if (millis() - last > interval){...}
throttle.