Hi I am making an drone using a Arduino Nano ESP32 as the FC.
I have the drone constructed and running this code:
#include <ESP32Servo.h>
#include <Wire.h>
float RatePitch, RateRoll, RateYaw;
float RateCalibrationPitch, RateCalibrationRoll, RateCalibrationYaw;
int RateCalibrationNumber;
uint32_t LoopTimer;
float DesiredRateRoll, DesiredRatePitch, DesiredRateYaw;
float ErrorRateRoll, ErrorRatePitch, ErrorRateYaw;
float InputRoll, InputThrottle, InputPitch, InputYaw;
float PrevErrorRateRoll, PrevErrorRatePitch, PrevErrorRateYaw;
float PrevItermRateRoll, PrevItermRatePitch, PrevItermRateYaw;
float PIDReturn[]={0, 0, 0};
float PRateRoll=0.4 ; float PRatePitch=PRateRoll; float PRateYaw=2;
float IRateRoll=3 ; float IRatePitch=IRateRoll; float IRateYaw=12;
float DRateRoll=0.03 ; float DRatePitch=DRateRoll; float DRateYaw=0;
float MotorInput1, MotorInput2, MotorInput3, MotorInput4;
#include "CRSFforArduino.hpp"
#define USE_SERIAL_PLOTTER 0
Servo ESC1;
Servo ESC2;
Servo ESC3;
Servo ESC4;
int servoPin1 = D9;
int servoPin2 = D10;
int servoPin3 = D11;
int servoPin4 = D12;
int channel1;
int channel2;
int channel3;
int channel4;
int throttleSafety;
int armHoverSwitch;
CRSFforArduino *crsf = nullptr;
int rcChannelCount = crsfProtocol::RC_CHANNEL_COUNT;
const char *rcChannelNames[] = {
"A",
"E",
"T",
"R",
"Aux1",
"Aux2",
"Aux3",
"Aux4",
"Aux5",
"Aux6",
"Aux7",
"Aux8",
"Aux9",
"Aux10",
"Aux11",
"Aux12"};
void onReceiveRcChannels(serialReceiverLayer::rcChannels_t *rcChannels);
void gyro_signals(void) {
Wire.beginTransmission(0x68);
Wire.write(0x1A);
Wire.write(0x05);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x1B);
Wire.write(0x08);
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x43);
Wire.endTransmission();
Wire.requestFrom(0x68,6);
int16_t GyroX=Wire.read()<<8 | Wire.read();
int16_t GyroY=Wire.read()<<8 | Wire.read();
int16_t GyroZ=Wire.read()<<8 | Wire.read();
RateRoll=(float)GyroX/65.5;
RatePitch=(float)GyroY/65.5;
RateYaw=(float)GyroZ/65.5;
}
void pid_equation(float Error, float P , float I, float D, float PrevError, float PrevIterm) {
float Pterm=P*Error;
float Iterm=PrevIterm+I*(Error+PrevError)*0.004/2;
if (Iterm > 400) Iterm=400;
else if (Iterm <-400) Iterm=-400;
float Dterm=D*(Error-PrevError)/0.004;
float PIDOutput= Pterm+Iterm+Dterm;
if (PIDOutput>400) PIDOutput=400;
else if (PIDOutput <-400) PIDOutput=-400;
PIDReturn[0]=PIDOutput;
PIDReturn[1]=Error;
PIDReturn[2]=Iterm;
}
void reset_pid(void) {
PrevErrorRateRoll=0; PrevErrorRatePitch=0; PrevErrorRateYaw=0;
PrevItermRateRoll=0; PrevItermRatePitch=0; PrevItermRateYaw=0;
}
void setup() {
Serial.begin(115200);
ESC3.attach(servoPin3,989,2000);
ESC4.attach(servoPin4,989,2000);
ESC1.attach(servoPin1,989,2000);
ESC2.attach(servoPin2,989,2000);
delay(2500);
pinMode(5, OUTPUT);
digitalWrite(5, HIGH);
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
Wire.setClock(400000);
Wire.begin();
delay(250);
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
for (RateCalibrationNumber=0; RateCalibrationNumber<2000; RateCalibrationNumber ++) {
gyro_signals();
RateCalibrationRoll+=RateRoll;
RateCalibrationPitch+=RatePitch;
RateCalibrationYaw+=RateYaw;
delay(1);
}
RateCalibrationRoll/=2000;
RateCalibrationPitch/=2000;
RateCalibrationYaw/=2000;
crsf = new CRSFforArduino();
if (!crsf->begin())
{
crsf->end();
delete crsf;
crsf = nullptr;
Serial.println("CRSF for Arduino initialisation failed!");
while (1)
{
delay(10);
}
}
rcChannelCount = rcChannelCount > crsfProtocol::RC_CHANNEL_COUNT ? crsfProtocol::RC_CHANNEL_COUNT : rcChannelCount;
crsf->setRcChannelsCallback(onReceiveRcChannels);
// Show the user that the sketch is ready.
Serial.println("RC Channels Example");
delay(1000);
Serial.println("Ready");
delay(1000);
while (channel3 < 980 || channel3 > 1050) {
crsf->update();
delay(4);
}
LoopTimer=micros();
}
void loop() {
gyro_signals();
RateRoll-=RateCalibrationRoll;
RatePitch-=RateCalibrationPitch;
RateYaw-=RateCalibrationYaw;
crsf->update();
DesiredRateRoll=0.15*(channel1-1500);
DesiredRatePitch=0.15*(channel2-1500);
InputThrottle=channel3;
DesiredRateYaw=0.15*(channel4-1500);
ErrorRateRoll=DesiredRateRoll-RateRoll;
ErrorRatePitch=DesiredRatePitch-RatePitch;
ErrorRateYaw=DesiredRateYaw-RateYaw;
pid_equation(ErrorRateRoll, PRateRoll, IRateRoll, DRateRoll, PrevErrorRateRoll, PrevItermRateRoll);
InputRoll=PIDReturn[0];
PrevErrorRateRoll=PIDReturn[1];
PrevItermRateRoll=PIDReturn[2];
pid_equation(ErrorRatePitch, PRatePitch, IRatePitch, DRatePitch, PrevErrorRatePitch, PrevItermRatePitch);
InputPitch=PIDReturn[0];
PrevErrorRatePitch=PIDReturn[1];
PrevItermRatePitch=PIDReturn[2];
pid_equation(ErrorRateYaw, PRateYaw,
IRateYaw, DRateYaw, PrevErrorRateYaw,
PrevItermRateYaw);
InputYaw=PIDReturn[0];
PrevErrorRateYaw=PIDReturn[1];
PrevItermRateYaw=PIDReturn[2];
if (InputThrottle > 1800) InputThrottle = 1800;
MotorInput1= 1.024*(InputThrottle-InputRoll-InputPitch-InputYaw);
MotorInput2= 1.024*(InputThrottle-InputRoll+InputPitch+InputYaw);
MotorInput3= 1.024*(InputThrottle+InputRoll+InputPitch-InputYaw);
MotorInput4= 1.024*(InputThrottle+InputRoll-InputPitch+InputYaw);
if (MotorInput1 > 2000)MotorInput1 = 1999;
if (MotorInput2 > 2000)MotorInput2 = 1999;
if (MotorInput3 > 2000)MotorInput3 = 1999;
if (MotorInput4 > 2000)MotorInput4 = 1999;
int ThrottleIdle=1180;
if (MotorInput1 < ThrottleIdle) MotorInput1 = ThrottleIdle;
if (MotorInput2 < ThrottleIdle) MotorInput2 = ThrottleIdle;
if (MotorInput3 < ThrottleIdle) MotorInput3 = ThrottleIdle;
if (MotorInput4 < ThrottleIdle) MotorInput4 = ThrottleIdle;
int ThrottleCutOff=1000;
if (channel3<1050) {
MotorInput1=ThrottleCutOff;
MotorInput2=ThrottleCutOff;
MotorInput3=ThrottleCutOff;
MotorInput4=ThrottleCutOff;
reset_pid();
}
if(throttleSafety == 2000)
{
ESC1.write(MotorInput1);
ESC2.write(MotorInput2);
ESC3.write(MotorInput3);
ESC4.write(MotorInput4);
}
else
{
ESC1.write(989);
ESC2.write(989);
ESC3.write(989);
ESC4.write(989);
}
while (micros() - LoopTimer < 4000);
LoopTimer=micros();
}
void onReceiveRcChannels(serialReceiverLayer::rcChannels_t *rcChannels)
{
if (rcChannels->failsafe == false)
{
/* Print RC channels every 100 ms. */
unsigned long thisTime = millis();
static unsigned long lastTime = millis();
/* Compensate for millis() overflow. */
if (thisTime < lastTime)
{
lastTime = thisTime;
}
if (thisTime - lastTime >= 100)
{
lastTime = thisTime;
channel2 = (crsf->rcToUs(crsf->getChannel(2)));
channel1 = (crsf->rcToUs(crsf->getChannel(1)));
channel4 = (crsf->rcToUs(crsf->getChannel(4)));
channel3 = (crsf->rcToUs(crsf->getChannel(3)));
channel3 = map(channel3, 989, 2017, 1000, 2000);
throttleSafety = (crsf->rcToUs(crsf->getChannel(5)));
armHoverSwitch = (crsf->rcToUs(crsf->getChannel(6)));
channel2 = map(channel2, 989, 2010, 1000, 2000);
channel1 = map(channel1, 989, 2010, 1000, 2000);
channel4 = map(channel4, 994, 2012, 1000, 2000);
if(channel1 > 2000)
{
channel1 = 2000;
}
else if(channel1 < 1000)
{
channel1 = 1000;
}
if(channel2 > 2000)
{
channel2 = 2000;
}
else if(channel2 < 1000)
{
channel2 = 1000;
}
if(channel4 > 2000)
{
channel4 = 2000;
}
else if(channel4 < 1000)
{
channel4 = 1000;
}
Serial.print("-------------------------------------------------");
Serial.println();
Serial.print(channel1);
Serial.println();
Serial.print(channel2);
Serial.println();
Serial.print(channel3);
Serial.println();
Serial.print(channel4);
Serial.println();
}
}
}
It has an ELRS receiver and a gyroscope. For now I copied the code for an PID controller from this video: https://www.youtube.com/watch?v=4vpgjjYizVU&list=PLeuMA6tJBPKsAfRfFuGrEljpBow5hPVD4&index=17
However whenever I try to take of the drone flips. If you want look at the video of what happens:
I know that the values of P, I and D play a big role in the vibrations and stuff, but I have no clue what to set them to.
Any help in resolving this issue is appreciated, because I have no clue for to stabilize the drone