Sunday, November 21, 2010

Brushless Motors and Speed Controllers.

I am a beginner in electronics and although my skills are still basic, I am still searching documentation to see if I understand how I can properly put into operation one or more motors using the Arduino platform. In most open source quadcopter projects are almost always used the same speed controllers, however it should be possible to use any speed controller that works with a radio control (R/C).
I have been taking a look to several web sites and I have found that there were two main ways of how to communicate with speed controllers and put the motors running. One is to write a pulse width in microseconds directly to the i/o pins and the other is to use the Arduino "Servo" library or similar libraries like "SoftwareServo". In a previous post I have described how to put four motors running with the speed controllers that I have got for this project using the "Servo" library. Although, I have not investigated in depth the internals of the library I have noticed that the motor control is achieved by sending pulses to the speed controller or alternatively by sending an angle that can varies between 0º and 180º (the angle is converted internally to a pulse width in microseconds). However and for the speed controllers I am using, if I only send pulses to the i/o pins that will not put the motors in operation since the speed controllers need be initialized before using. So, in order to have more information available, I have downloaded of the speed controller specifications that I am using. After reviewing that document I have tried to develop an algorithm with the all steps to put the motors in operation. The procedure according to my adaptation of the document to initialize the speed controller is as follow (this procedure must be done before each use):
  1. Connect the Arduino board to the computer via USB to power up the board and set the pulse width value of the stop position on output pin (the stop position must be within the range 800 us to 1700 us for my speed controller). This procedure is like move the throttle stick to the desired stop position, and switch on the transmitter.
  2. Connect now the flight battery to the speed controler. The motor responds with 2 x beep.
  3. Increase the pulse width value (microseconds) in one unit on output pin until the motor responds with 3 x beep (the full-throttle position must be at least 350 us greater than the stop position). This is like move the throttle stick to the desired full-throttle position.
  4. Set again the pulse width value of the stop position on output pin. This procedure is like move the throttle stick to the desired stop position.
  5. If you now increase the pulse width value on output pin the motor will start running. This is like move the throttle stick from the stop position towards full-throttle.
I tried to implement the two methods described above but the only one that worked was the method that uses the library "Servo". The implementation of the procedure is now shown:
/*

  Motors: 4 x ROXXY 2827-34
  ___ESC: 4 x Roxxy BL-Control 818
  _Board: Seeeduino Mega v1.1
  
  ATENTION: Do not put the propellers in motors because this
            sketch is not well tested and can cause damage.
  
*/
#include <Servo.h>

// Set the pulse width value of the stop position to mid-point (1250 us).
#define STOPPOSITION          800+(1700-800)/2
// The full-throttle position must be at least 350 us greater
// than the stop position (1600 us).
#define FULLTHROTTLEPOSITION  STOPPOSITION+350
// My upper speed limit for safety.
#define MAXTHROTTLEPOSITION   FULLTHROTTLEPOSITION-100
// Create servo object to control four motors
Servo escservos[4];
// Variable to store the temporarily pulse width value.
int usvalue = STOPPOSITION;

void programpositions() {
  Serial.println("Type the character [p] to program the Stop and");
  Serial.println("Full-Throttle positions after connect the flight");
  Serial.println("battery to the ESC's.");
  Serial.println("The motor responds with 2 x beep.");
  Serial.println("");
  Serial.println("Type the character:");
  Serial.println("[+] to increase the pulse width value.");
  Serial.println("[-] to decrease the pulse width value.");
  Serial.println("[0] to set the pulse width value to stop position.");
  
  // Wait until get the input from the user.
  while(Serial.available() <= 0) {
    // Set the pulse width value of the stop position on output pins.
    for(int s=0; s<4; s++)
      escservos[s].writeMicroseconds(STOPPOSITION);
  }
  
  char ch = Serial.read();
  if(ch == 'p') {
    // Increase the pulse width value in one unit on output pins.
    // Exactly after a pulse width of the 350 microseconds from
    // the stopping position the motor responds with 3 x beep.
    for(int us=STOPPOSITION; us<=FULLTHROTTLEPOSITION; us++)
      for(int s=0; s<4; s++)
        escservos[s].writeMicroseconds(us);
    delay(5000);
  }
}

void set_speeds(int servo, int usvalue) {
  escservos[servo].writeMicroseconds(usvalue);
}

void setup() {
  Serial.begin(9600);
  
  // Attaches the ESC's on pins 2, 3, 4 and 5 to the servo object.
  for(int s=0; s<4; s++)
    escservos[s].attach(s+2, STOPPOSITION, FULLTHROTTLEPOSITION);
  
  programpositions();
}

void loop() {
  if(Serial.available()) {
    char ch = Serial.read();
    if(ch == '+') {
      // Increase the pulse width value.
      // The motor only starts running after increased up to 40 us.
      usvalue++;
      if(usvalue > MAXTHROTTLEPOSITION)
        usvalue = MAXTHROTTLEPOSITION;
    } else if(ch == '-') {
      // Decrease the pulse width value.
      usvalue--;
      if(usvalue < STOPPOSITION)
        usvalue = STOPPOSITION;
    } else if(ch == '0') {
      // Set the pulse width value to the stop position.
      usvalue = STOPPOSITION;
    }
    Serial.println(usvalue);
  }
  for(int s=0; s<4; s++)
    set_speeds(s, usvalue);
}
This implementation works very well for my speed controllers, but for other speed controllers the implementation will probably be different. The difference to the previous post is that instead using the value of the angles, I have used the pulse width value in microseconds and the delay after sending the angle has been removed. One immediate problem is that the Arduino board must always be connected before the speed controller which requires that board will check if the speed controller is switched on or off. If the speed controller is already connected and initialized and if for any reason you switched off the board and switched it on again, the motor can speed up to full speed because the speed controller was already set up, but as the board does not recognize it, it will make a new initialization. Therefore it is necessary to send a character to do or not the initialization of the speed controller. To solve this problem it is necessary a current sensor which will check whether the speed controller is switched on or off.

No comments:

Post a Comment