arduinoesp32

programming ESP32 to control BLHeli S ESC


I'm trying to control a brushless motor from an ESP32-devkit-v1 with an ESC with BLHeli S firmware. I've watched a LOT of videos, manuals, ChatGPT, etc., with no success. The following code got me at least a musical response from the ESC: the three-note startup chime twice, a low tone, a double high tone, and then four quick ascending tones repeat for a while. I've tried using DShot, too, without success. If anyone can point out what I'm missing or point me toward a resource that can help, that would be awesome.

Auxiliary info: The esp32 is connected and powered by my computer. The ESC is powered by a spare 60w desktop PSU; I cut a Molex connector off and connected the 12v wire and ground to the ESC, although the PSU only delivers about 10.5v. It's pretty stable, tho, so I don't think that's an issue.

#include <Arduino.h>

// GPIO pin for ESC signal
const int escPin = 18;

// PWM configuration
const int freq = 50; // 50 Hz for ESC control
const int resolution = 16; // 16-bit resolution
const int channel = 0; // PWM channel

void setThrottle(int dutyCycle);
void calibrateESC();

void setup() {
  // Initialize serial communication
  Serial.begin(115200);
  Serial.println("Initializing ESC...");

  // Configure the PWM channel
  ledcSetup(channel, freq, resolution);
  ledcAttachPin(escPin, channel);

  // Send initial ESC calibration signals
  calibrateESC();
}

void loop() {
  // Example: Gradually increase motor speed
  Serial.println("Increasing throttle...");
  for (int dutyCycle = 1000; dutyCycle <= 2000; dutyCycle += 100) {
    setThrottle(dutyCycle);
    delay(500);
  }

  Serial.println("Stopping motor...");
  setThrottle(1000); // Stop the motor
  delay(2000);
}

void calibrateESC() {
  Serial.println("Calibrating ESC...");
  setThrottle(2000); // Maximum throttle
  delay(2000);       // Wait for ESC to recognize max throttle
  setThrottle(1000); // Minimum throttle
  delay(2000);       // Wait for ESC to arm
  Serial.println("ESC calibration complete.");
}

void setThrottle(int dutyCycle) {
  // Map 1000-2000 µs to 16-bit resolution
  int pwmValue = map(dutyCycle, 1000, 2000, 0, 65535);
  ledcWrite(channel, pwmValue);
}


Solution

  • I don't know if you already solved this issue. I just got mine working. For anyone else that might have the same issue. The following code works. It goes from 0 (1000ms pw) to 5% (1050ms pw).

    One thing that I found is that not every pin on my ESP32 Dev kit v1 can be used. It's also important that the ESC gnd is connected to the ESP32.

    The code:

    #include <Arduino.h>
    #include <ESP32Servo.h>
    
    const int ESC_PIN = 13;  // GPIO pin connected to the ESC
    const int MIN_THROTTLE = 1000;  // Minimum throttle (1ms pulse width)
    const int MAX_THROTTLE_5_PERCENT = 1050;  // Maximum throttle at 5% (1.05ms pulse width)
    const int FREQUENCY = 50;  // 50Hz frequency for ESC
    
    // Initialize the Servo object for ESC control
    Servo escServo;
    
    void setup() {
      // Start Serial communication for debugging
      Serial.begin(115200);
      Serial.println("Starting PWM control using ESP32Servo...");
    
      // Attach the ESC to the specified GPIO pin
      escServo.setPeriodHertz(FREQUENCY);  // Set frequency to 50Hz
      escServo.attach(ESC_PIN, MIN_THROTTLE, MAX_THROTTLE_5_PERCENT); // Attach to the ESC pin
    
      // Initial throttle setting (this will arm the ESC if it's idle)
      Serial.println("Sending minimum throttle for arming sequence...");
      escServo.writeMicroseconds(MIN_THROTTLE);  // Minimum throttle to arm the ESC
      delay(2000);  // Wait for arming sequence
    
      // Send zero throttle value to complete arming sequence
      Serial.println("Sending zero throttle to complete the arming sequence...");
      escServo.writeMicroseconds(MIN_THROTTLE);  // Zero throttle
      delay(1000);  // Allow ESC to register the zero throttle
    
      // Send zero throttle again (or fail-safe throttle if desired)
      Serial.println("Sending zero throttle again.");
      escServo.writeMicroseconds(MIN_THROTTLE);  // Zero throttle again
    }
    
    void loop() {
      // You can implement logic to gradually increase or decrease the throttle here
      // Example: Ramp up throttle from min to 5% max
      
      // Ramp up throttle from minimum to 5% of maximum (1600 µs)
      for (int pulse = MIN_THROTTLE; pulse <= MAX_THROTTLE_5_PERCENT; pulse += 10) {
        escServo.writeMicroseconds(pulse);
        Serial.print("Throttle: ");
        Serial.println(pulse);
        delay(100);  // Ramp up slowly
      }
      
      delay(2000); // Hold throttle for 2 seconds
      
      // Ramp down throttle from 5% of maximum to minimum
      for (int pulse = MAX_THROTTLE_5_PERCENT; pulse >= MIN_THROTTLE; pulse -= 10) {
        escServo.writeMicroseconds(pulse);
        Serial.print("Throttle: ");
        Serial.println(pulse);
        delay(50);  // Ramp down slowly
      }
      
      delay(2000); // Hold minimum throttle for 2 seconds
    }
    

    The serial log:

    Throttle: 1030
    Throttle: 1040
    Throttle: 1050
    Throttle: 1050
    Throttle: 1040
    Throttle: 1030
    Throttle: 1020
    Throttle: 1010
    Throttle: 1000
    

    Edit: Depending on you ESC 1050 for the max throttle might not be high enough. I have a 4 in 1 ESC board. Two of the ESCs were configured so the firmware would ignore anything below 1121. I would recommend checking the firmware with something like BLHeliSuite or esc-configurator.com to she what the min values have to be. Also while you're in there make sure every ESC has the same value. (assuming you haven't done any calibiration).