Logan Bishop-Van Horn

Home
Old Projects
Contact

Past Project: BLDC Motor Control


In fall of my junior year (2015) I took Physics 219: Electronics Laboratory, one of two laboratory-based (that is project-based) physics courses at Clark. The class was based around six "study guides" or labs, including simple DC circuit analysis, amplifiers and filters, transistors, digital logic, and microcontollers. The course culminated in a final project of the students' choosing. Coincidentally, a Computer Science professor who was at the time teaching a robotics course, recently salvaged nearly a dozen large brushless DC (BLDC) motors from a Pitney Bowes mailing machine that was being thrown away by the university. I decided that for my final project I would build a controller for these motors.

BLDC motor (bottom right) and three-phase MOSFET H-bridge driver (center).

The motors came in three different sizes; the "medium" is shown above. Each motor came equipped with Hall Effect position sensors and a shaft encoder. Because of time constraints, I decided to use the Hall sensors instead of back-EMF sensing to commutate the motor. I wrote three different Arduino "sketches" to control the speed and direction of a BLDC motor using a three-phase MOSFET H-bridge. The commutation methods were:

Unfortunately I was using a small power supply (2.5 Amps at 6 Volts or 0.5 Amps at 20 Volts), so my tests were somewhat limited.

// LBVH Fall 2015
// Sensored BLDC motor controller using TC4469 logic drivers
// PWM speed control

/**********************************************************************/

const int drivePins[6] = {9,2,10,3,11,4}; // H_A,L_A,H_B,L_B,H_C,L_C
const int HEpins[3] = {5,6,7};
const int PWMc = 1; // speed control pot analog input
const int buttonPin = 13; // reverse direction button pin
const int minPWMduty = 26; // 5% min duty cycle
const int PWMincrement = 1; // duty cycle increment ~0.2%
const int motorDelay = 5; // this should probably be zero

const byte cw[6] { // H_A(pwm),L_A,H_B(pwm),L_B,H_C(pwm),L_C,0,0
  B10010000, // phase 1 (101)
  B00011000, // phase 2 (001)
  B01001000, // phase 3 (011)
  B01100000, // phase 4 (010)
  B00100100, // phase 5 (110)
  B10000100, // phase 6 (100)
};

const byte ccw[6] = { // H_A(pwm),L_A,H_B(pwm),L_B,H_C(pwm),L_C,0,0
  B01100100, // phase /1 (101) slash indicates CCW rotation
  B00100100, // phase /2 (001)
  B10000100, // phase /3 (011)
  B10010000, // phase /4 (010)
  B00011000, // phase /5 (110)
  B01001000, // phase /6 (100)
};

int buttonState; // current reading from reverse button
int lastButtonState = HIGH;
int debounceDelay = 50; // debounce timing delay in ms
int desiredPWMduty; // PWM value read from PWM control pot
int currentPWMduty; // current duty cycle
int currentPhase; // current motor phase
boolean fwd = true; // clockwise rotation
boolean stopped = true; // for startup
boolean Running = false; // true when motor is turning

long lastDebounceTime = 0;  // the last time buttonpin was toggled

/**********************************************************************/

void setup() {
  TCCR2B = TCCR2B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 9 and 10
  TCCR1B = TCCR1B & 0b11111000 | 0x01; // set PWM frequency @ 31250 Hz for Pins 11 and 3 (3 not used)
  ICR1 = 1023 ; // 10 bit timer resolution
  for(int i=0; i<6; i++){ // set driver pins outputs
    pinMode(drivePins[i],OUTPUT);
  }
  for(int i=0; i<3; i++){ // set HE sensor pins inputs
    pinMode(HEpins[i],INPUT); 
  }
  //pinMode(PWMc, INPUT);
  pinMode(buttonPin, INPUT);
}

void loop() {  
  int buttonRead = digitalRead(buttonPin);
  if (buttonRead != lastButtonState) { // if button state changes
    lastDebounceTime = millis(); //reset debouncing time
  }

  if ((millis() - lastDebounceTime) > debounceDelay) { // if real button push
      if(buttonRead != buttonState){
        buttonState = buttonRead; // change current button state
      }
      fwd != fwd; // reverse direcition
      lastButtonState = buttonState; // set up to be reverse again
    }
  
  if(stopped){ // if motor is stopped, run startup routine
    startup();
  }
  
  if(Running){ // if motor is running, try to reach desired speed
    desiredPWMduty = analogRead(PWMc);
    if(currentPWMduty < desiredPWMduty){
      currentPWMduty+=PWMincrement;
    } else{
      currentPWMduty-=PWMincrement;
    }
    commutate(currentPWMduty);
  }
  delay(motorDelay);
}

/****************************************************************/

void startup() { // startup routine
  desiredPWMduty = analogRead(PWMc); // read speed control pot
  currentPWMduty = minPWMduty;
  while(currentPWMduty < desiredPWMduty){ // while speeding up
    currentPWMduty += PWMincrement; // increase PWM duty cycle
    commutate(currentPWMduty); // (drivers active low)
  }
  stopped = false;
  Running = true;
}

void commutate(int PWM) { // general commutation
    currentPhase = getSensePhase(); 
    if(fwd){
      setPhase(currentPhase,cw,PWM);
    } else{
      setPhase(currentPhase,ccw,PWM);
    }
  }

int getSensePhase() { // identifies current phase
  if(digitalRead(HEpins[0])){
    if(!digitalRead(HEpins[1]) && digitalRead(HEpins[2])){
      return 0;
    }
    if(digitalRead(HEpins[1])==digitalRead(HEpins[2])){
      return 5;
    }else{
      return 4;
    }
  }
  else{
   if(digitalRead(HEpins[1]) && !digitalRead(HEpins[2])){
    return 3;
   }
   if(digitalRead(HEpins[1])==digitalRead(HEpins[2])){ 
    return 2; 
   }else {
    return 1;
    }     
  }
}

void setPhase(int i, const byte* table, int PWM) {
  // sets appropriate outputs given current state
  analogWrite(drivePins[0], bitRead(table[i],7)*PWM); // H_A
  digitalWrite(drivePins[1], bitRead(table[i],6)); // L_A
  analogWrite(drivePins[2], bitRead(table[i],5)*PWM); // H_B
  digitalWrite(drivePins[3], bitRead(table[i],4)); // L_B
  analogWrite(drivePins[4], bitRead(table[i],3)*PWM); // H_C
  digitalWrite(drivePins[5], bitRead(table[i],2)); // L_C
}
Operation of the block commutation scheme. Clearly the motor is effectively a stepper at low speeds, but the rotation is smooth at high speeds.
Operation of the PWM commutation scheme. The motor chatters at high speeds, but I believe this can be fixed by decreasing the value of motorDelay. This scheme works very well at low speeds.
[Updated: 8/2016]

Logan Bishop-Van Horn © 2019