Let's Make Robots!

[solved...sort of... works... far from perfect] How to properly control (arm+calibrate+command) an HK-20 ESC with arduino?

--- Solution ---

UPDATE: The below solution is NOT 100% reliable, sometimes I have to repeat the 90-10-20 process quite a few times up until I have a proper the ESC properly armed/calibrated. And when I say a few times I mean up to quite a few minutes with battery unplug/re-plug in-between. But now that the craft is mostly finished (I probably just need to tweak the aft side of the skirt), I'll revise my code yet again and see what I can do about it.

In the end the solution was a mix of the regular RC usage instructions:


"Full throttle (stick up); power up ESC & *beeps* ; Throttle 0% (stick down) *beeps* & it's ready to GO!"

& the interactive serial code... once I seen that inserting:

*beeps* 90 <enter> 10 <enter> 20 *beeps* <40 would start the motor at the minimum and progressively incremented it up to 90> ...

...I decided to implement this interation using remote buttons instead of the previously attempted loops...

1x Button for <10> (throttle 0%)

1x Button for <90> (throttle 100%)

and 2x button for increment/decrement by 10 units within that range.

At setup() I set lift fan velocity to 90 (max) and then I just went directly to 10 by pushing the respective button...

...and pushing the increment button after that... eventually led to me hearing the calibration/arming beep. I had however, to be persistant and try this procedure a few times, because either implementation isn't that good and/or I just had some timing issues in the first iterations.



--- Original post ---

I've been trying to control a brushless motor (EMAX CF2812) via ESC with arduino, but so far I've had limited sucess. I've managed to start the motor, but I can't seem to get reproducible results.

The first success I've got was by following the instructions here. From there I also got the following code:

*  This code is in the public domain.
*  (Do whatever you want with it.)

// Need the Servo library
#include <Servo.h>

// This is our motor.
Servo myMotor;

// This is the final output
// written to the motor.
String incomingString;

// Set everything up
void setup()
  // Put the motor to Arduino pin #9

  // Required for I/O from Serial monitor
  // Print a startup message

void loop()
  // If there is incoming value
  if(Serial.available() > 0)
    // read the value
    char ch = Serial.read();
    *  If ch isn't a newline
    *  (linefeed) character,
    *  we will add the character
    *  to the incomingString
    if (ch != 10){
      // Print out the value received
      // so that we can see what is
      // happening
      Serial.print("I have received: ");
      Serial.print(ch, DEC);
      // Add the character to
      // the incomingString
      incomingString += ch;
    // received a newline (linefeed) character
    // this means we are done making a string
      // print the incoming string
      Serial.println("I am printing the entire string");
      // Convert the string to an integer
      int val = incomingString.toInt();
      // print the integer
      Serial.println("Printing the value: ");
      *  We only want to write an integer between
      *  0 and 180 to the motor. 
      if (val > -1 && val < 181)
       // Print confirmation that the
       // value is between 0 and 180
       Serial.println("Value is between 0 and 180");
       // Write to Servo
     // The value is not between 0 and 180.
     // We do not want write this value to
     // the motor.
       Serial.println("Value is NOT between 0 and 180");
       // IT'S a TRAP!
       Serial.println("Error with the input");
      // Reset the value of the incomingString
      incomingString = "";

It allows to interactively send signals (ints) to control the ESC. After a bit I've got some success by sending  first a value of 10, followed by 55 (I believe I might have heard the arming beep then) and then I got the motor actually spinning with a value of 120. After a few more tests it seemed like that I would need a value equal or above 100 to make it spin. So, after analyzing the above code I've tried to write a stripped down code to programatically control the ESC, the code can be found below:

#include <Servo.h> 

Servo esc; 

void setup() 
  esc.attach(9);  // attaches the servo on pin 9 to the servo object 

void loop() 

At first, with this code or small variations I got success in making the motor run, alas today when I've tried again (with variations) no such luck. When back to the interactive code and managed to make the motor work with a sequence of inputs: 10, 90, 100, 0. However, after stopping the motor (sending zero) I was unable to start it again even with sending values above 100 without resetting the arduino...

So, does anyone can shed some light on what is happening here? How can I "tame" this beguilling ESC? :/

Further info:

Regarding ESC documentation the beep list found here seems to be the best that can be found.

Also rumaged the web for answers, but couldn't find anything that I could either wrap my head around or very enlightening :s 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mogul's picture

After googling a little on your problem here  I have this feeling that power-up sequence is important. Like, make sure your arduino is transmitting a servo signal, say 55, before you attach lipo power to the ESC. and first then, after "some time" start the arm sequence.

Dunno, I have no experience with RC ESC's yet.

K120189's picture

im trying to use the 30A model of this..from what i read the throttle must be under 10 when powered on. so have arduino write between 0 and ten. then power on the esc. wish i had my arduino i could be testing all this right along with you


kariloy's picture

Well... I had _some_ success sending "90" two seconds after attaching the ESC on the setup() ... but could only managed to make it work once... again no reproducibility :/

So, the only thing I can conclude is that "90" is perhaps the arming value (a.k.a. neutral?) the question remains when should I send that value? or what is the best set of circumpstances to do so programatically :|

I guess I'll be having to lock the cat in the bedroom a few more times... :/

K120189's picture

why not use the arduino servo and pot sample code and mess with it that way?

you could get all the timing things down and be good to go

JerZ's picture
Looking at the info on the ESC, I think this code should work to calibrate the ESC and "work" 
the throttle. You should just have to adjust the delay before the second esc.write to get the
timing right in between the single beeps. I'm sure someone will chime in with the magic answer,
but this might be worth a shot.

#include <Servo.h> Servo esc; void setup() {    esc.attach(9); // attaches the ESC on pin 9 to the servo object      delay(1000);   Serial.begin(9600);      esc.write(180); // set "TX" to full speed   delay(1000); // Change this to delay until you hear the ESC beep once
esc.write(90); // set "TX" to idle after Li-Po (first beep) is selected from set-up sequence    }  void loop() { 

for(i=90; i<180; i++){
// Ramp throttle up

for(i=180; i>90; i--){ // Ramp throttle down


Good stuff.

Arming sequence:  When the arduino is in the setup function "setup(){}", I have had a lot of luck with stepping from 0 to 55 in steps of 5.  

After arming use:  Writing anything greater than 65 would get the motors turning.  

Getting the motors to stop:  If the motors were spinning and I wanted to stop them, I wrote 60.  Here's the tricky part, if I wrote the value "0" to the motors, I would get unpredictable behaviour and the motors would fail to respond anymore until I disconnect/reconnect power.  

For reference on the code used to arm (I used two (2) motor/esc's):

kariloy's picture

Well, earlier this morning before I've left to work I had the oportunity to do some 20 minutes worth of testing...

So using the "interactive code" I get the "esc-has-detected-a-lipo" beep intial beep once I connect the battery. Afterwards, I kept sending randomly several values like 10, 50, 55, 60 5, etc. all below 90 and nothing happened. After it I finally send 90 and I got what I assume is the "arming beep". Then sending 100 would make the motor spin, following your tip writing 90 again (or below -- but not zero -- which I haven't tried this time) would make them stop, but I could start the motor again just by sending 100 or above.

So, I wrote a simple sketch:

- setup: attach esc, wait 2 sec, send 90

- loop: send 100

Uploaded it... and it work... HOWEVER... I've pulled the usb cable to stop it, and variants of re-plugging it, reseting the arduino, re-uploading the code and disconnecting/connecting the battery haven't managed to putting it to work again.

So, I'm still stumped regarding programatically arming the ESC... and don't quite understand what you mean with this:

"Arming sequence:  When the arduino is in the setup function "setup(){}", I have had a lot of luck with stepping from 0 to 55 in steps of 5."

And I only can guess it will get uglier when I try to add all the rest of the setup regarding r/c comms and stuff :s

birdmun's picture

for(int I = 0;I <= 55; I++){



mogul's picture

You will need some delay in that loop as well. otherwise it will be done way faster than anything can be sent on the servo line

kariloy's picture

the thing is... I actually don't see the purpose of having that on setup()... wouldn't it be ran just once?

The problem I seem to see here is "how to programatically find the right window of oportunity to arm the ESC". :s