Problems with Esp32 wifi based Drone

High I'm working on a new project (Esp32 WiFi based Drone ). the drone is supposed to use the esp32 build in WiFi to connect with a mobile which works as a controller to drive the circuit. and i'm encountering three major problems. i'm encountering three major problems.

  1. The pin14 on my esp32 is high even when initialised to zero. I thought the problem was in the pin. so i tested it but the pin is working fine. i used the led blinking method.

  2. The motors on my drone are running without even uploading the code the moment i connect the battery or if i connect the esp with a USB the motors start running. i'm using SI302 MOSFET. i ruled out that the problem might be in the MOSFET, by replacing them with new ones "did not work".

  3. The third problem is that i'm building this project on a PCB and when i connect the esp32 (while mounted on the PCB) with the computer it does not show up on the computer. but does show up if not mounted on the PCB.

i"m using esp-Wroom-32. here is the schematic for the circuit.



WhatsApp_Image_2024-04-26_at_1.48.31_AM1

this is the code I'm working on.

#include <PID_v1.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <ESPAsyncWebServer.h>

Adafruit_MPU6050 mpu; 

const char *ssid = "Esp32";
const char *password = "123esp32";

const float THR_INCREMENT_FACTOR = 1.1;  // Exponential increment factor
const float THR_DECREMENT_FACTOR = 1.1;  // Exponential decrement factor
const float YAW_ROTATE_FACTOR =1.1;
const float beta = 0.98;  // Complementary filter constant
const float maxAngle = 30.0;  // Maximum allowed angle for pitch, roll
const float MAX_BATTERY_VOLTAGE = 4.2;  // Maximum battery voltage in volts (fully charged)
const float MIN_BATTERY_VOLTAGE = 3.3;  // Minimum battery voltage in volts (low battery)
const float MAX_ADC_VALUE = 1023.0;  // Maximum value from the ADC (10-bit)
const float LOW_BATTERY_THRESHOLD = 20.0;


double targetAngleRoll = 0;
double targetAnglePitch = 0;
double targetAngleYaw = 0;
double currentAngleRoll = 0;  
double currentAnglePitch = 0;  
double currentAngleYaw = 0;  

const int MOTOR_MIN = 1000;  // Minimum PWM value
const int MOTOR_MAX = 2000;  // Maximum PWM value
const int MOTOR_PINS[4] = {7, 13, 14, 23}; //change pins
const int MAX_UP_COMMANDS = 10;  // Number of "goUp()" commands to reach maximum THR
const int MAX_DOWN_COMMANDS = 10; // Number of "goDown()" commands to reach minimum THR
const int BATTERY_PIN = A0;  // Analog pin connected to the battery voltage divider
const int THROTTLE_REDUCTION_STEPS = 10;  // Number of steps to gradually reduce throttle
const int THROTTLE_INCREASE_STEPS = 10; // Number of steps to gradually increase throttle

int upCommandsCounter = 0;  // Counter for "goUp()" commands
int downCommandsCounter = 0; // Counter for "goDown()" commands
int yawRotateLeftCounter = 0;  
int yawRotateRightCounter = 0;
int throttleValue = 0; // Initialize throttle value
double rollOutputAngle=0, pitchOutputAngle=0, yawOutputAngle=0;
int pwmRollValue = 0;
int pwmPitchValue = 0;
int pwmYawValue = 0;
int throttleReductionStep = 0;  // Current step for gradual throttle reduction
int throttleincreasingStep = 0;  // Current step for gradual throttle increase

static uint16_t motor[4];
static uint16_t rcRollValue[4];
static uint16_t rcPitchValue[4];
static uint16_t rcYawValue[4];

double kpRoll = 1.0, kiRoll = 0.1, kdRoll = 0.0; //change kp, ki, kd
double kpPitch = 1.0, kiPitch = 0.1, kdPitch = 0.0; //change kp, ki, kd
double kpYaw = 1.0, kiYaw = 0.1, kdYaw = 0.0; //change kp, ki, kd

// PID objects for each axis
PID pidRoll(&currentAngleRoll, &rollOutputAngle, &targetAngleRoll, kpRoll, kiRoll, kdRoll, DIRECT);
PID pidPitch(&currentAnglePitch, &pitchOutputAngle, &targetAnglePitch, kpPitch, kiPitch, kdPitch, DIRECT);
PID pidYaw(&currentAngleYaw, &yawOutputAngle, &targetAngleYaw, kpYaw, kiYaw, kdYaw, DIRECT);

AsyncWebServer server(80);

enum DroneState {
    IDLE,
    TAKEOFF,
    FLIGHT,
    LANDING,
    EMERGENCY,
    LOW_BATTERY
};

DroneState currentDroneState = IDLE;

float getBatteryLevel() {
    // Read the analog value from the battery voltage divider
    int adcValue = analogRead(BATTERY_PIN);

    // Map the ADC value to the battery voltage range
    float batteryVoltage = (adcValue / MAX_ADC_VALUE) * (MAX_BATTERY_VOLTAGE - MIN_BATTERY_VOLTAGE) + MIN_BATTERY_VOLTAGE;

    // Calculate the battery level as a percentage
    float batteryPercentage = ((batteryVoltage - MIN_BATTERY_VOLTAGE) / (MAX_BATTERY_VOLTAGE - MIN_BATTERY_VOLTAGE)) * 100.0;

    return batteryPercentage;
}

bool isLowBattery() {
    // Implement a function to check if the battery level is below the threshold.
    float batteryLevel = getBatteryLevel();
    return (batteryLevel < LOW_BATTERY_THRESHOLD);
}

void initializeWiFi() 
{
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, password);

  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP);

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Hello, World!");
  });
  server.onNotFound([](AsyncWebServerRequest *request) {
    request->send(404, "text/plain", "Not found");
  });
  server.begin();
}

void read_MPU6050() 
{
   Wire.begin();
    Serial.begin(115200);

  if (!mpu.begin()) {
    Serial.println("Failed to initialize MPU6050!");
    while (1);
  }

  mpu.setAccelerometerRange(MPU6050_RANGE_2_G);
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);

  // Initialize PID controllers
  pidRoll.SetOutputLimits(-maxAngle, maxAngle);
  pidPitch.SetOutputLimits(-maxAngle, maxAngle);

   // Set the sample time (in milliseconds) for the PID controllers
  pidRoll.SetSampleTime(10);
  pidPitch.SetSampleTime(10);
  pidYaw.SetSampleTime(10);

  // Set PID modes to AUTOMATIC
  pidRoll.SetMode(AUTOMATIC);
  pidPitch.SetMode(AUTOMATIC);
  pidYaw.SetMode(AUTOMATIC);
}

void motorState() 
{
  pinMode(MOTOR_PINS[0], OUTPUT);
  pinMode(MOTOR_PINS[1], OUTPUT);
  pinMode(MOTOR_PINS[2], OUTPUT);
  pinMode(MOTOR_PINS[3], OUTPUT);
}

void updatePID() 
{
  sensors_event_t accelEvent, gyroEvent;
 
  // Read accelerometer and gyro data
  mpu.getAccelerometerSensor()->getEvent(&accelEvent);
  mpu.getGyroSensor()->getEvent(&gyroEvent);
 

  currentAngleRoll = atan2(accelEvent.acceleration.y, accelEvent.acceleration.z) * 180.0 / PI;
  currentAnglePitch = atan2(-accelEvent.acceleration.x, accelEvent.acceleration.z) * 180.0 / PI;
  // Calculate yaw using a complementary filter
  currentAngleYaw = beta * (currentAngleYaw + gyroEvent.gyro.z * 0.01) + (1 - beta) * (atan2(accelEvent.acceleration.x, accelEvent.acceleration.y) * 180.0 / PI);

  // Print the yaw angle
  //Serial.print("Yaw: ");
  //Serial.println(currentAngleYaw);


  // Adjust target angles based on receiver input (rcValue)
  //targetAngleRoll = map(rcValue[0], 1000, 2000, -maxAngle, maxAngle);
  //targetAnglePitch = map(rcValue[1], 1000, 2000, -maxAngle, maxAngle);
  //targetAngleYaw = map(rcValue[2], 1000, 2000, -maxAngle, maxAngle);
  pidRoll.Compute();
  pidPitch.Compute();
  pidYaw.Compute();

    // Map the PID controller output (in degrees) to the PWM range
  pwmRollValue = map(rollOutputAngle, -maxAngle, maxAngle, MOTOR_MIN, MOTOR_MAX);
  pwmPitchValue = map(pitchOutputAngle, -maxAngle, maxAngle, MOTOR_MIN, MOTOR_MAX);
  pwmYawValue = map(yawOutputAngle, -maxAngle, maxAngle, MOTOR_MIN, MOTOR_MAX);
}

void handleMotorControl(AsyncWebServerRequest *request) 
{
   if (request->method() == HTTP_POST)
    {
        if (request->hasParam("State", true)) 
        {
          AsyncWebParameter* p = request->getParam("State", true);
          String command = p->value();

          // Check if the battery is not low and the command is "flight"
          if (!isLowBattery() && command == "flight") 
          {
            // Map the command to corresponding actions
            if (command == "F") goForward();
            else if (command == "f") goforward();
            else if (command == "B") goBack();
            else if (command == "b") goback();
            else if (command == "L") goLeft();
            else if (command == "l") goleft();
            else if (command == "R") goRight();
            else if (command == "r") goright();
            else if (command == "U") goUp();
            else if (command == "D") goDown();
            else if (command == "rl") rotateLeft();
            else if (command == "rR") rotateRight();
            else 
            {
              Serial.println("Unknown command: " + command);
            }
            } 
          else 
          {
            // Handle other cases (e.g., low battery, emergency, land)
            if (isLowBattery()) automaticLanding();
            else if (command == "emergency") automaticLanding();
            else if (command == "land") automaticLanding();
            else if (command == "stop") stop();
            else 
            {
              Serial.println("Unknown command: " + command);
            }
          }
        }
    }
    request->send(200, "text/plain", "OK");
}

void HTTP_handleRoot(AsyncWebServerRequest *request) 
{
   if (request->hasParam("State", true)) {
        AsyncWebParameter* p = request->getParam("State", true);
        String command = p->value();
        // Process the command received from the client
    }
    request->send(200, "text/plain", "OK");
}

void goForward() 
{
  targetAnglePitch = maxAngle;

  rcPitchValue[0] = pwmPitchValue;  // Set pitch motor values
  rcPitchValue[1] = pwmPitchValue;
  rcPitchValue[2] = pwmPitchValue;
  rcPitchValue[3] = pwmPitchValue;
  
}

void goforward() 
{
    targetAnglePitch = 0;

  rcPitchValue[0] = 0; // Set pitch motor values
  rcPitchValue[1] = 0;
  rcPitchValue[2] = 0; 
  rcPitchValue[3] = 0;
  
}

void goBack() 
{
  targetAnglePitch = -maxAngle;

  rcPitchValue[0] = pwmPitchValue; // Set pitch motor values
  rcPitchValue[1] = pwmPitchValue;
  rcPitchValue[2] = pwmPitchValue;
  rcPitchValue[3] = pwmPitchValue;
  
}

void goback() 
{
    targetAnglePitch = -0;

  rcPitchValue[0] = 0; // Set pitch motor values
  rcPitchValue[1] = 0;
  rcPitchValue[2] = 0; 
  rcPitchValue[3] = 0;
}

void goLeft() 
{
  targetAngleRoll = -maxAngle; // Set roll motor values

  rcRollValue[1] = pwmRollValue; 
  rcRollValue[3] = pwmRollValue;
  rcRollValue[0] = pwmRollValue; 
  rcRollValue[2] = pwmRollValue;
}

void goleft() 
{
    targetAngleRoll = -0; // Set roll motor values

  rcRollValue[1] = 0; 
  rcRollValue[3] = 0;
  rcRollValue[0] = 0; 
  rcRollValue[2] = 0;
}

void goRight() 
{
    targetAngleRoll = maxAngle; // Set roll motor values

  rcRollValue[0] = pwmRollValue; 
  rcRollValue[2] = pwmRollValue;
  rcRollValue[1] = pwmRollValue; 
  rcRollValue[3] = pwmRollValue;
}

void goright() 
{
      targetAngleRoll = 0; // Set roll motor values

  rcRollValue[0] = 0; 
  rcRollValue[2] = 0;
  rcRollValue[1] = 0; 
  rcRollValue[3] = 0;
}

void goUp() 
{
  if(getBatteryLevel() > LOW_BATTERY_THRESHOLD)
  {
  // Increment the counter when the "goUp()" command is received
  upCommandsCounter++;

  // Calculate the exponential increment based on the counter
  float thrIncrement = pow(THR_INCREMENT_FACTOR, upCommandsCounter);
 
  // Map the exponential increment to the desired range (e.g., 100 to 2000)
  throttleValue = map(thrIncrement, 1, pow(THR_INCREMENT_FACTOR, MAX_UP_COMMANDS), 1000, 2000);

  // Ensure THR doesn't exceed the maximum value
  throttleValue = min(throttleValue, 2000);  // Assuming maximum THR value is 2000
  }
}

void goDown() 
{
  

  // Increment the counter when "goDown()" is called
  downCommandsCounter++;
  
  // Calculate the exponential decrement factor
  float thrDecrement = pow(THR_DECREMENT_FACTOR, downCommandsCounter);

  // Map the decrement factor to the throttle range  
  throttleValue = map(thrDecrement, pow(THR_DECREMENT_FACTOR, MAX_DOWN_COMMANDS), 1, 2000, 1000);

  // Constrain value to the minimum
  throttleValue = max(throttleValue, 1000); // Assuming minimum THR is 1000

}

void rotateLeft() 
{
   // Increment counter
  yawRotateLeftCounter++;
  
  // Calculate increment factor
  float yawIncrement = pow(YAW_ROTATE_FACTOR, yawRotateLeftCounter);

  // Decrement target yaw angle 
  targetAngleYaw -= yawIncrement;

 rcYawValue[1] = pwmYawValue;
 rcYawValue[2] = pwmYawValue;
 rcYawValue[0] = pwmYawValue;
 rcYawValue[3] = pwmYawValue;
}

void rotateRight() 
{
 
  // Increment counter
  yawRotateRightCounter++;

  // Calculate increment factor
  float yawIncrement = pow(YAW_ROTATE_FACTOR, yawRotateRightCounter);

  // Increment target yaw angle
  targetAngleYaw += yawIncrement; 

 rcYawValue[0] = pwmYawValue;
 rcYawValue[3] = pwmYawValue;
 rcYawValue[1] = pwmYawValue;
 rcYawValue[2] = pwmYawValue;
}

void stop()
{
  motor[0] = 0;
  motor[1] = 0;
  motor[2] = 0;
  motor[3] = 0;
}

void automaticLanding() 
{
    if (throttleReductionStep < THROTTLE_REDUCTION_STEPS) 
    {
        // Calculate the reduction step for throttle value
        int throttleReduction = throttleValue / THROTTLE_REDUCTION_STEPS;

        // Reduce throttle value gradually
        throttleValue -= throttleReduction;

        // Increment the step
        throttleReductionStep++;
    }
}

void updateMotorValues() 
{
  motor[0] = constrain(throttleValue + rcRollValue[0] - rcPitchValue[0] + rcYawValue[0], MOTOR_MIN, MOTOR_MAX);  // FRONT_L
  motor[1] = constrain(throttleValue - rcRollValue[1] - rcPitchValue[1] - rcYawValue[1], MOTOR_MIN, MOTOR_MAX);  // FRONT_R
  motor[2] = constrain(throttleValue + rcRollValue[2] + rcPitchValue[2] - rcYawValue[2], MOTOR_MIN, MOTOR_MAX);  // REAR_L
  motor[3] = constrain(throttleValue - rcRollValue[3] + rcPitchValue[3] + rcYawValue[3], MOTOR_MIN, MOTOR_MAX);  // REAR_R

}

void writeMotor() 
{

  analogWrite(MOTOR_PINS[0], motor[0]);
  analogWrite(MOTOR_PINS[1], motor[1]);
  analogWrite(MOTOR_PINS[2], motor[2]);
  analogWrite(MOTOR_PINS[3], motor[3]);
}

void setup() 
{
  Serial.begin(115200);
   delay(1000);
   initializeWiFi();
   read_MPU6050(); //this only sets up the MPU6050 read mpu6050 in updatePID()
   delay(1000);
   motorState(); //state of motor pins
}

void loop() 
{
 AsyncWebServerRequest *request; // Declare request here
  if (WiFi.status() == WL_CONNECTED) 
  { 
  updatePID(); // Update PID controllers by reading from mpu6050
  handleMotorControl(request); // Handle motor control based on the received command
  updateMotorValues(); // Update motor values based on PID,
  writeMotor(); // Write motor values to pins
  }
   else
   {
    // If server.onNotFound() is true, it means the route wasn't found.
    automaticLanding();
    updateMotorValues(); // Update motor values for landing
    writeMotor(); // Write motor values to pins
        
   }
  request = nullptr;
}

I'm new at this so i would appreciate it if i could get some help on this.

Thus type of complex setup is hard to comment on .
In building such as system , I would , on a bread board write bits of code to test each part. - get blue tooth working , turn the motors off and on, and so on . Then look at combining the individual
Parts .
That way problem areas become obvious .
When you have a complete system , switch it on and iit doesn’t work it’s much harder.

In setup you have a long delay before dealing with the motors , very long if blue tooth takes a while to connect it fails .I would of thought best to control the motors and switch them off early on .

Thanks for the reply it was very helpful i found the problem to be in the connection pins.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.