Use ESP32 to Control PWM ESCs for BLDC Motors

by radicalroundcat in Circuits > Arduino

70 Views, 0 Favorites, 0 Comments

Use ESP32 to Control PWM ESCs for BLDC Motors

20260612_165644.jpg

I'm building a drone with a custom flight controller based off of the ESP32-S3 chip. It also uses very common ESCs straight from AliExpress. I needed to be able to send the proper signals to such an ESC, but that proved to be more complicated than I thought it would be.

However, after reading the datasheet of the motor, using the ESC actually became very simple, and I got it to work :) So will you, after this tutorial.

I will cover:

  1. Which PWM values to use
  2. Using the ledc api, which is exclusive to the esp32 family. Don't try this with an ATmega or something..
  3. How to arm the ESC
  4. Wiring connections

Supplies

1x - ESP32-S3-DevKit (Or any esp32 variant of your choice)

1x - Brushless (40A) Electronic Speed Controller

1x - BLDC motor

1x - 2-4S LiPo battery

Some jumper wires


This instructable uses PlatformIO because I like it more than the Arduino IDE. It should be easily portable to the latter, however.


Here is a datasheet of an ESC similar to the one I'm using. Keep in mind that some specs on there may be off due to it being a random document that was pulled from the internet. However, it does provide some valuable information about how to send signals to the ESC.

Wiring

20260614_153249.jpg

You will notice a thin orange, red, and brown wire on the ESC. Those are for Signal, 5v and GND respectively.

⚠️ DO NOT plug the red wire into the esp32. It OUTPUTS 5V and will cause a catastrophic failure, probably.

  1. One exception to this is if you want to power the esp32 through the 5v pin, but your USB port should not be plugged in when doing so.


Plug the signal wire into any GPIO of your choice, just make sure its safe to be used, and plug the brown wire to GND.

Connect your motor to the ESC.

Connect your esp32 to your computer.

Don't plug the LiPo battery in yet.

If you have a propeller, don't connect it, otherwise, you'll die.

Learn How the ESC Works

pwm.jpg

I always thought ESCs were dumb machines that just outputted whatever speed that was fed to them. They're actually very intelligent. They communicate by making your motor beep, and also have safety features.


My ESCs use PWM for signaling. It's in the title of the instructable.

By standards, the frequency for communication is 50Hz, or one cycle every 20milliseconds.

The throttle speeds are dictated by the pulse length of each cycle, where 1 millisecond pulses (or a 5% duty cycle) corresponds to minimum throttle, and 2 milliseconds (or a 10% duty cycle) mean maximum throttle.

This is similar to many hobby servo motors you can easily find, such as the MG90s. Having these can be handy for testing code.


Before feeding the signals to the ESC, you'll need to know about, arming them.

The ESC can be armed by being fed 1 millisecond pulses once the battery is plugged in.

Above is approximately what the signal should look like on an oscilloscope.

Programming

Create a project in the IDE of your choice. To reiterate, I'll be using PlatformIO.

If you also happen to use PlatformIO, here are my build flags:

[env:esp32-s3-devkitc1-n16r8]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip
board = esp32-s3-devkitc1-n16r8
framework = arduino
monitor_speed = 115200
build_unflags = -DBOARD_HAS_PSRAM
board_build.arduino.memory_type = qio_qspi
; above, I disabled psram so I could use pin 37


A big part of the code will use the LEDC api, which is basically a pwm library.


We can start by defining some basic parameters

#include <Arduino.h>

const int testPin = 37; // use whatever pin you want

const int PWMfreq = 50; // 50Hz
const int ledcChannel = 0; // you can have 8 channels (0-7) for esp32-s3 boards
const int resolution = 14; // I believe 14 bits is the maximum resolution for esp32-s3
const int minPW = 1000;
const int maxPW = 2000; // min and max pulse width


Now we have to calculate the frequency values for ledcWrite. The formula is pulse length (in microseconds) times resolution divided by cycle length.

const int minDutyCycle = (1000*16384) / 20000;
// 1000 is ur minimum pulse time of 1000 microseconds
// 16384 is the resolution (2^14)
// 20000 is for 20000 microseconds, which is the cycle length.

const int midDutyCycle = (1200*16384) / 20000; // here's a low duty cycle for testing
const int maxDutyCycle = (2000*16384) / 20000;


Next, we'll arm the ESC in the setup() function

void setup() {
Serial.begin(115200);
Serial.println("test");

ledcAttach(testPin, PWMfreq, resolution);

Serial.println("plug the battery in (sending min throttle)");
ledcWrite(testPin, minDutyCycle);

delay(5000);
}


Now you can make the motor move to your heart's content in the loop function!!

void loop() {
ledcWrite(testPin, midDutyCycle);
delay(2000);
ledcWrite(testPin, maxDutyCycle);
delay(2000);
ledcWrite(testPin, midDutyCycle);
delay(1000);
}

Testing It

Flash the code onto the board. Once you turn the microcontroller on, you have no more than 5 seconds to plug in your battery. It should do a happy sequence of beeps and start spinning.


Always unplug the battery first, before turning off the esp32.

Enjoy your motor!