Hi, I'm working on my DIY arduino drone and recently ran into some problems. The thing is that I keep getting unexpected output from the PID and I don't know what is causing it. My guess is that it has something to do with the acelometer output and the PID. My code:
#include<Wire.h>
#include <SPI.h>
#include <RF24.h>
#include <nRF24L01.h>
#include <BME280I2C.h>
#define motor1 3 // left front - dopredu, dozadu kolem Z
#define motor2 5 // right front - doleva, doprava kolem Z
#define motor3 6 // right back - doleva, doprava kolem Z
#define motor4 9 // left back - dopredu, dozadu kolem Z
BME280I2C bme;
const int MPU_addr = 0x68;
RF24 radio(2, 10);
const byte address[10] = "sjSEmD3xK";
double seaLevelPres = 1013.25;
bool camera = false;
// radio input
int data[10];
//sensors
double pitchInput, rollInput, yawInput, altitudeInput;
//pid
double pitchKp = 1, pitchKi = 1 , pitchKd = 1;
double rollKp = 1, rollKi = 1, rollKd = 1;
double yawKp = 1, yawKi = 1, yawKd = 1;
double altitudeKp = 1, altitudeKi = 1, altitudeKd = 1;
double pitchSetpoint = 0, rollSetpoint = 0, yawSetpoint = 0, altitudeSetpoint = 0; //radio transmitter values
double pitchLastError, rollLastError, yawLastError, altitudeLastError;
double pitchIntegral, rollIntegral, yawIntegral, altitudeIntegral;
double pitchOutput, rollOutput, yawOutput, altitudeOutput;
unsigned long previousMillis;
unsigned long interval = 20;
//motor speeds
double sp1 = 0, sp2 = 0, sp3 = 0, sp4 = 0;
//functions initialization
void InitInput();
void GetRadio(double& yawSetpoint, double& rollSetpoint, double& pitchSetpoint, double& altitudeSetpoint, double& seaLevelPres, bool& camera);
void ReadSensors(double& pitchInput, double& rollInput, double& yawInput, double& altitudeInput);
double CalculatePID(double Input, double Kp, double Ki, double Kd, double Setpoint, double LastError, double Integral, unsigned long& previousMillis, unsigned long& interval);
void ControlMotors();
void setup() {
InitInput();
}
void loop() {
GetRadio(pitchInput, rollInput, yawInput, altitudeInput, seaLevelPres, camera);
ReadSensors(pitchInput, rollInput, yawInput, altitudeInput);
pitchOutput = CalculatePID(pitchInput, pitchKp, pitchKi, pitchKd, pitchSetpoint, pitchLastError, pitchIntegral, previousMillis, interval);
rollOutput = CalculatePID(rollInput, rollKp, rollKi, rollKd, rollSetpoint, rollLastError, rollIntegral, previousMillis, interval);
yawOutput = CalculatePID(yawInput, yawKp, yawKi, yawKd, yawSetpoint, yawLastError, yawIntegral, previousMillis, interval);
altitudeOutput = CalculatePID(altitudeInput, altitudeKp, altitudeKi, altitudeKd, altitudeSetpoint, altitudeLastError, altitudeIntegral, previousMillis, interval);
ControlMotors();
}
FUNCTIONS:
double CalculatePID(double Input, double Kp, double Ki, double Kd, double Setpoint, double LastError, double Integral, unsigned long& previousMillis, unsigned long& interval) {
unsigned long currentMillis = millis();
double timer = 0;
timer = double(currentMillis - previousMillis) / 1000;
if (timer <= interval) {
double error = Setpoint - Input;
Integral += error * timer;
double derivative = (error - LastError) / timer;
double Output = Kp * error + Ki * Integral + Kd * derivative;
LastError = error;
previousMillis = currentMillis;
return Output;
}
return 0;
}
void ControlMotors() {
sp1 = pitchOutput + altitudeOutput - yawOutput;
sp2 = -rollOutput + altitudeOutput + yawOutput;
sp3 = -pitchOutput + altitudeOutput - yawOutput;
sp4 = rollOutput + altitudeOutput + yawOutput;
sp1 = constrain(sp1, 0, 178);
sp2 = constrain(sp2, 0, 178);
sp3 = constrain(sp3, 0, 178);
sp4 = constrain(sp4, 0, 178);
Serial.println(sp1);
Serial.println(sp2);
Serial.println(sp3);
Serial.println(sp4);
/*
analogWrite(motor1, sp1);
analogWrite(motor2, sp2);
analogWrite(motor3, sp3);
analogWrite(motor4, sp4);
*/
}
void GetRadio(double& yawSetpoint, double& rollSetpoint, double& pitchSetpoint, double& altitudeSetpoint, double& seaLevelPres, bool& camera) {
if (radio.available()) {
radio.read(&data, sizeof(data));
altitudeSetpoint = map(data[0], 0, 1023, -50, 50);
yawSetpoint = map(data[1], 0, 1023, -180, 180);
rollSetpoint = map(data[2], 0, 1023, -45, 45);
pitchSetpoint = map(data[3], 0, 1023, -45, 45);
seaLevelPres = data[4];
if ( seaLevelPres == 0) {
seaLevelPres = 1013.25;
} camera = data[5];
/*
Serial.print("Altitude sea level pressure");
Serial.println(seaLevelPres);
Serial.print("altitudeSetpoint");
Serial.println(altitudeSetpoint);
Serial.print("pitchSetpoint");
Serial.println(pitchSetpoint);
Serial.print("rollSetpoint");
Serial.println(rollSetpoint);
Serial.print("yawSetpoint");
Serial.println(yawSetpoint);
*/
}
}
void InitInput() {
Serial.begin(115200);
radio.begin();
Wire.begin();
bme.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
radio.openReadingPipe(0, address);
radio.setPALevel(RF24_PA_MIN);
radio.startListening();
pinMode(motor1, OUTPUT);
pinMode(motor2, OUTPUT);
pinMode(motor3, OUTPUT);
pinMode(motor4, OUTPUT);
}
void ReadSensors(double& pitchInput, double& rollInput, double& yawInput, double& altitudeInput) {
//accelometer
int x, y, z;
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr, 14, true);
x = Wire.read() << 8 | Wire.read();
y = Wire.read() << 8 | Wire.read();
z = Wire.read() << 8 | Wire.read();
double x_Buff = float(x);
double y_Buff = float(y);
double z_Buff = float(z);
rollInput = RAD_TO_DEG * atan2(y_Buff, z_Buff);
pitchInput = RAD_TO_DEG * atan2(x_Buff, z_Buff);
yawInput = RAD_TO_DEG * atan2(x_Buff, y_Buff);
//altitudemeter
float temp(NAN), hum(NAN), pres(NAN);
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
BME280::PresUnit presUnit(BME280::PresUnit_Pa);
bme.read(pres, temp, hum, tempUnit, presUnit);
pres = pres / 100;
altitudeInput = ((pow((seaLevelPres / pres), 1 / 5.257) - 1) * (temp + 273.15)) / 0.0065;
bool setAltitudeZero = true;
double firstAltitudeInput;
if (setAltitudeZero == true) {
firstAltitudeInput = altitudeInput;
setAltitudeZero = false;
}
altitudeInput -= firstAltitudeInput;
altitudeInput = constrain(altitudeInput, -50, 50);
Serial.print("Pitch");
Serial.println(pitchInput);
Serial.print("Roll");
Serial.println(rollInput);
Serial.print("Yaw");
Serial.println(yawInput);
Serial.print("Altitude");
Serial.println(altitudeInput);
}