Help!! I can’t seem to balance my robot. I’ve used several codes and several PID’s, but my Bot is still jittering.
Using arduino, mpu6050, drv8833, 6v motor, 6v power supply.
I need a tutor that can help me with my project.
#include <PID_v1.h>
#include <LMotorController.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
#define LOG_INPUT 0
#define MANUAL_TUNING 1
#define LOG_PID_CONSTANTS 0 //MANUAL_TUNING must be 1 to change
#define MOVE_BACK_FORTH 0
#define LOG_BT 0
#include<SoftwareSerial.h>
const int rxpin = 11; // pin used to receive (not used in this version)
const int txpin = 4; // pin used to send to LCD
SoftwareSerial blue(rxpin, txpin);
// for BT control
String content = "";
float d_speed = 0.1;
float rotate = 0;
float d_rot = 5;
#define MIN_ABS_SPEED 30
#define MIN_P 0
#define MAX_P 100000
#define MIN_I 0
#define MAX_I 50000
#define MIN_D 0
#define MAX_D 5000
//MPU
MPU6050 mpu;
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// orientation/motion vars
Quaternion q; // [w, x, y, z] quaternion container
VectorFloat gravity; // [x, y, z] gravity vector
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
//PID
#if MANUAL_TUNING
double kp , ki, kd;
double prevKp, prevKi, prevKd;
#endif
double originalSetpoint = 180 + 3.00;
double setpoint = originalSetpoint;
double movingAngleOffset = 0.3;
double input, output;
int moveState=0; //0 = balance; 1 = back; 2 = forth
#if MANUAL_TUNING
PID pid(&input, &output, &setpoint, 0, 0, 0, DIRECT);
#else
PID pid(&input, &output, &setpoint, 70, 240, 1.9, DIRECT);
#endif
//MOTOR CONTROLLER
#define ENA 10
#define IN1 8
#define IN2 12
#define ENB 9
#define IN3 6
#define IN4 7
LMotorController motorController(ENA, IN1, IN2, ENB, IN3, IN4, 1, 1);
//timers
long time1Hz = 0;
long time5Hz = 0;
volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high
void dmpDataReady()
{ mpuInterrupt = true;
}
void setup()
{ blue.begin(9600);
blue.setTimeout(10);
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
TWBR = 24; // 400kHz I2C clock (200kHz if CPU is 8MHz)
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
// initialize serial communication
Serial.begin(250000);
// initialize device
Serial.println(F("Initializing I2C devices..."));
mpu.initialize();
// verify connection
Serial.println(F("Testing device connections..."));
Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
// load and configure the DMP
Serial.println(F("Initializing DMP..."));
devStatus = mpu.dmpInitialize();
// supply your own gyro offsets here, scaled for min sensitivity
mpu.setXGyroOffset(220);
mpu.setYGyroOffset(76);
mpu.setZGyroOffset(-85);
mpu.setZAccelOffset(1788); // 1688 factory default
// make sure it worked (returns 0 if so)
if (devStatus == 0)
{ // turn on the DMP, now that it's ready
Serial.println(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
Serial.println(F("DMP ready! Waiting for first interrupt..."));
dmpReady = true;
// get expected DMP packet size for later comparison
packetSize = mpu.dmpGetFIFOPacketSize();
//setup PID
pid.SetMode(AUTOMATIC);
pid.SetSampleTime(10);
pid.SetOutputLimits(-255, 255);
}
else
{ // ERROR!
// 1 = initial memory load failed
// 2 = DMP configuration updates failed
// (if it's going to break, usually the code will be 1)
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}
}
void loop()
{ // if programming failed, don't try to do anything
if (!dmpReady) return;
// wait for MPU interrupt or extra packet(s) available
while (!mpuInterrupt && fifoCount < packetSize)
{ //no mpu data - performing PID calculations and output to motors
pid.Compute();
// motorController.move(output, MIN_ABS_SPEED);
motorController.move(output+rotate, output-rotate, MIN_ABS_SPEED);
unsigned long currentMillis = millis();
if (currentMillis - time1Hz >= 1000)
{ loopAt1Hz();
time1Hz = currentMillis;
}
if (currentMillis - time5Hz >= 5000)
{ loopAt5Hz();
time5Hz = currentMillis;
}
}
// reset interrupt flag and get INT_STATUS byte
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// get current FIFO count
fifoCount = mpu.getFIFOCount();
// check for overflow (this should never happen unless our code is too inefficient)
if ((mpuIntStatus & 0x10) || fifoCount == 1024)
{ // reset so we can continue cleanly
mpu.resetFIFO();
Serial.println(F("FIFO overflow!"));
// otherwise, check for DMP data ready interrupt (this should happen frequently)
}
else if (mpuIntStatus & 0x02)
{ // wait for correct available data length, should be a VERY short wait
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// read a packet from FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);
// track FIFO count here in case there is > 1 packet available
// (this lets us immediately read more without waiting for an interrupt)
fifoCount -= packetSize;
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
#if LOG_INPUT
// Serial.print("ypr\t");
// Serial.print(ypr[0] * 180/M_PI);
// Serial.print("\t");
Serial.print(ypr[1] * 180/M_PI);
Serial.print(",");
Serial.println(setpoint - originalSetpoint);
// Serial.print("\t");
// Serial.println(ypr[2] * 180/M_PI);
#endif
input = ypr[1] * 180/M_PI + 180;
}
if(blue.available())
{ content=blue.readString();
#if LOG_BT
Serial.print("content: ");Serial.print(content);
Serial.print(" - setpoint: "); Serial.print(setpoint);
Serial.print(" - rotation: "); Serial.println(rotate);
#endif
if(content[0]=='F')
{setpoint += d_speed; setpoint = constrain(setpoint, originalSetpoint-3, originalSetpoint+3);} // forward
else if(content[0]=='B')
{setpoint -= d_speed; setpoint = constrain(setpoint, originalSetpoint-3, originalSetpoint+3);} // backward
else if(content[0]=='L')
{rotate -= d_rot; rotate = constrain(rotate, -30, 30);} //left
else if(content[0]=='R')
{rotate += d_rot; rotate = constrain(rotate, -30, 30);} // right
}
}
void loopAt1Hz()
{
#if MANUAL_TUNING
setPIDTuningValues();
#endif
}
void loopAt5Hz()
{
#if MOVE_BACK_FORTH
moveBackForth();
#endif
}
//move back and forth
void moveBackForth()
{ moveState++;
if (moveState > 2) moveState = 0;
if (moveState == 0)
setpoint = originalSetpoint;
else if (moveState == 1)
setpoint = originalSetpoint - movingAngleOffset;
else
setpoint = originalSetpoint + movingAngleOffset;
}
//PID Tuning (3 potentiometers)
#if MANUAL_TUNING
void setPIDTuningValues()
{ readPIDTuningValues();
if (kp != prevKp || ki != prevKi || kd != prevKd)
{
#if LOG_PID_CONSTANTS
Serial.print(kp);Serial.print(", ");Serial.print(ki);Serial.print(", ");Serial.println(kd);
#endif
pid.SetTunings(kp, ki, kd);
prevKp = kp; prevKi = ki; prevKd = kd;
}
}
void readPIDTuningValues()
{ int potKp = analogRead(A0);
int potKi = analogRead(A1);
int potKd = analogRead(A2);
kp = map(potKp, 0, 1023, MIN_P, MAX_P) / 100.0;
ki = map(potKi, 0, 1023, MIN_I, MAX_I) / 100.0;
kd = map(potKd, 0, 1023, MIN_D, MAX_D) / 100.0;
}
#endif