[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
  myMotor.attach(9);

  // Required for I/O from Serial monitor
  Serial.begin(9600);
  // Print a startup message
  Serial.println(“initializing”);
}

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);
      Serial.print(’\n’);
    
      // Add the character to
      // the incomingString
      incomingString += ch;
    }
    // received a newline (linefeed) character
    // this means we are done making a string
    else
    {
      // print the incoming string
      Serial.println(“I am printing the entire string”);
      Serial.println(incomingString);
    
      // Convert the string to an integer
      int val = incomingString.toInt();
    
      // print the integer
      Serial.println("Printing the value: ");
      Serial.println(val);
    
      /
        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
       myMotor.write(val);
     }
     // The value is not between 0 and 180.
     // We do not want write this value to
     // the motor.
     else
     {
       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()

  delay(1000);
  esc.attach(9); // attaches the servo on pin 9 to the servo object
  
  //delay(1000);
  Serial.begin(9600);
  
  esc.write(10);
  delay(1000);
  //esc.write(90);
  

void loop()

  esc.write(100);
  //delay(3500);
  //esc.write(0);
  //delay(10000);
}

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? :confused:

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 

sigh, double post, carry on…


Mostly just a guess, but

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
esc.write(i);
}

for(i=180; i>90; i–){ // Ramp throttle down
esc.write(i);
}

}

Additional info

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):
http://techvalleyprojects.blogspot.com/2012/10/arduino-control-escmotor-arduino-code.html

More additional info

Example:

Used two motor/esc’s, radioshack enclosure, two arms from the “diy drones” kit, arduino duemilanove.

Used bluetooth and later used longer range xbee’s.

When using the longer range xbee’s were, there were two problems that had to be solved.

A latency problem when sending data from usb to arduino via xbee that had to be solved: http://ilektron-x.blogspot.com/2010/02/xbee-and-ftdi-latency-and-dropped.html

Many times, the data sent over the air would be changed after receiving it.  This was the reason for all the logic involed in the techvalleyprojects link.  It is checking the data received character by character.  If I wasn’t concerned about the garbage problem, probably just would have used a delimitted message.  Good luck.

 

 

 

 

 

Well, I think I’ve tried

Well, I think I’ve tried similar strategies before, even so as soon as I can I’ll give this a try.

My usage of

Serial.begin(9600);

was intended as a blackbox (under my knowledgebase) possible trick of some sorts. I’ll just try it again as an alternative to total failure attempts.

Regarding ramping the throttle I believe I did not got any movement when sending values in the interval [90, 100[, so I might hazard to guess the the step equals 10. But then this are only “shots under very dim lights” :expressionless: I’ll report back on how it goes.

----- UPDATE:

Well JZ I’ve tried your code JZ (Just commented the Serial line and typecasted/declared the for loop ints for it to compile) but no dice… not even a single beep did I got from it :confused: Well but it was worth a try :slight_smile: Anyhow, I’ve done a bit more tests I’ll describe as reply to other comments

 

**Useful no “zero” tip **

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

code snippet

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

esc.write(I);

}

yeah

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

Arming ESC’s

late reply

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

True and yes.  You only need to run the arming procedure once. So running the arming procedure in setup would be a perfect place to arm the esc’s.

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

In using regular RC equipment, I’m fairly sure that you can arm the ESC anytime after the ESC’s have power.  I had the esc’s/motors power up first and then powered up the arduino.  As for the “for” loop, below is an example of an arming sequence.  It is only run once in setup(). 

 

/
    use however / for whatever
*/

#include “Servo.h”

// This is a motor on pin 9
#define MOTOR_PIN         9   

// This is the speed that will start the motor
#define MOTOR_START_SPEED     60   

// This is the motor object
Servo motor;

setup()
{
    // 9600 default for most people
    Serial.begin(9600);

    // setup the motor
    // The motor object is set to pin 9
    motor.attach(MOTOR_PIN);   

    // This is the arming sequece (for loop)
    motorStartAt(MOTOR_START_SPEED); // Arming procedure
   
   
}


loop()
{
    // Now that the motor has armed, write the values to the motor
    
}



// Wrapper function for Servo’s “.write(speed)” function
void motorSetSpeed(int speed)
{
    motor.write(speed);
       
    motor_current_speed = speed;

    //Serial.print("current motor speed = ");
    //Serial.println(motor_current_speed);
    
}

// This is the arming sequence
// If the “start_speed” is 60 then the loop will write
// from 0 to 60 in increments of 5 (e.g. 0,5,10,15,20)

// In the setup() we are using this function and pass in the variable
// “MOTOR_START_SPEED” which is set to 60 at the start of the program
void motorStartAt(int start_speed)
{
    int i;
    for (i=0; i < start_speed; i+=5) {
    motorSetSpeed(i);
    //Serial.println(i);
    delay(100);
}

 

 

 

 

late counter-reply

EDIT/UPDATE: After a few more iterations both through interactive serial and the actual craft build, and some re-googling and re-reading of some tips I’ve finally managed to arm the ESC within the whole system.

Conceptually is quite simple, in practice it just isn’t a clear cut failproof (or at least my implemention isn’t) solution. Nevertheless, the instructions for an RC setup say:

Full throttle (stick up); power up ESC & beeps ; Throttle 0% (stick down) beeps & it’s ready to go, so it makes sense for a calibration even… given my last experiments… I’ve repeated the interactive process and got successfull power up with a

90-10-20-<40 would start the motor at the minimum> …

So I decided to implement this interation via remote buttons instead of a loop…

Button for <10>, Button for <90> and buttons for increment/decrement by 10 within that range. At setup() I set lift fan velocity to 90 (max) and then I just went through pushing 10… and incrementing by 10… it took a few tries but after a bit I finally set the calibration/arming beep at 30. So, I guess is that…

EXTRA … well it wasn’t that after all… at least my implemention isn’t clear cut, sometimes I need quite a few minutes cycling through the values until I activate the ESC… [more at the original post]

then I pressed full thrust… and my EDF shoot of it’s mount :stuck_out_tongue: but that’s a different story :stuck_out_tongue:

----- Original post ----

Do not worry, I’m on and off this project anyway. In the meantime I was waiting for another ESC and EDF to use with propulsion so I left it be. Picked up the project again after they arrived… 

The good news is that the second ESC (Mystery brand) is not fussy at all, as it seems I managed to control it even without any fancy arming procedure (but will probably have to fuss around a little later on if I want it to be reversible).

The bad news, is that the HobbyKing ESC still iludes me, I’ve tried a few things based on the advice received, but so far no luck

 

void armLiftESC()
{

//lift.write(10);
//delay(200);
for (int ang = 0; ang <= 90; ang +=10){
lift.write(ang);
telemetrics.Z = ang;
delay(100);
}

//delay(2000);
//lift.write(90);
delay(1000);

}

Tried a few variations of the code above that can be glimpsed by the commented out code I have there, but no luck whatsoever. That code was run whenever I pressed a button on a remote, and I had feedback to know if it had actually run, and it did, however to no effect… :confused:

Returned to the interactive serial code and there I can arm the ESC by sending 10, then 90 (and the ESC beeps) then 100 or above and it spins…

tried that in simple sketch 10 and 90 in setup() separated by a delay… and then 100 in loop() … and no dice (it has work sometimes before as I think I’ve mentioned).

Then went back to the serial interactive code and decided to start with…

90 (no reaction)

10 (no reaction)

0 (still no reaction)

10 (again no reaction)

20 (maybe a beep here)

30 (or the beep here)

90 (vrrrrrooooooooooooom)

40 (vroooom)

30 (vroom)

20 (stop)

So, the only things I can read from here is:

90 is not an hard-neutral point (seems like 20 managed to be one as well)

Seems that I can/need to calibrate the range of the “stick” … somehow, oscillating between minimum and maximum… but from my previous testing seems like that which comes first is somewhat irrelevant?