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.
-
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.
-
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".
-
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.

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(¤tAngleRoll, &rollOutputAngle, &targetAngleRoll, kpRoll, kiRoll, kdRoll, DIRECT);
PID pidPitch(¤tAnglePitch, &pitchOutputAngle, &targetAnglePitch, kpPitch, kiPitch, kdPitch, DIRECT);
PID pidYaw(¤tAngleYaw, &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.