Você está na página 1de 11

Controle de motor BLDC sem sensor com

Arduino – DIY ESC


Este tópico mostra como construir um controlador de motor brushless DC (BLDC) sensorless ou
simplesmente um ESC (Electronic Speed Controller) com uma placa Arduino UNO.
Existem dois tipos de motores CC sem escova: com sensor e sem sensor. O motor BLDC com
sensor possui 3 sensores de efeito hall embutidos, esses sensores detectam a posição do rotor do
motor BLDC. Controlar um motor BLDC sensorizado é fácil, pois sabemos a posição do rotor
como foi feito no projeto abaixo:
A comutação do motor BLDC sensorizado é feita de acordo com o estado dos sensores de efeito
Hall.
O motor BLDC sensorless não possui nenhum sensor para detectar a posição do rotor, sua
comutação é baseada na BEMF (Back Electromotive Force) produzida nos enrolamentos do estator.
A principal vantagem do controle do motor BLDC sem sensor é o menor custo do sistema e a
principal desvantagem é que o motor deve estar se movendo a uma taxa mínima para produzir
BEMF suficiente para ser detectado.

Como funciona:
Quando o motor BLDC gira, cada enrolamento (3 enrolamentos) gera BEMF oposto à tensão
principal. Os 3 sinais BEMF gerados estão 120° fora de fase, o que é o mesmo que os sinais do
sensor de efeito hall. A figura abaixo mostra a relação entre os sinais de efeito hall e os sinais
BEMF:

Conforme mostrado na figura acima, os sinais BEMF não são sincronizados com os sinais do sensor
de efeito hall (deslocamento de fase de 30°). Em cada sequência de energização, dois enrolamentos
são energizados (um ligado ao positivo e outro ao negativo) e o terceiro enrolamento é deixado
aberto (flutuante). O enrolamento flutuante é usado para detectar o cruzamento de zero, portanto, a
combinação de todos os 3 pontos de cruzamento de zero é usada para gerar a sequência de
energização. No total temos 6 eventos:
Passagem por zero Fase A: de alto para baixo e de baixo para alta
Passagem por zero Fase B: de alta para baixa e de baixa para alta
Passagem por zero Fase C: de alta para baixa e de baixa para alta

Como detectar o evento de passagem por zero:


A maneira mais fácil de detectar os eventos de passagem por zero é usando comparadores. O
comparador possui 3 terminais principais: 2 entradas (positiva e negativa) e uma saída. A saída do
comparador é lógica alta se a tensão positiva for maior que a tensão negativa e lógica baixa se a
tensão positiva for menor que a tensão negativa.
Basicamente são necessários 3 comparadores para este projeto, as conexões são feitas conforme a
figura abaixo (exemplo para a fase B). Cada fase requer um circuito similar.

O ponto natural virtual é o mesmo para todos os 3 comparadores, é gerado usando 3


resistores. Quando o BEMF gerado no enrolamento flutuante (aberto) cruza o ponto zero em
direção ao lado positivo, a saída do comparador faz uma transição de baixo para alto. Quando o
BEMF gerado no enrolamento flutuante cruza o ponto zero em direção ao lado negativo, a saída do
comparador faz uma transição de alto para baixo. Por ter três desses circuitos comparadores, um em
cada uma das fases fornece três sinais digitais correspondentes ao sinal BEMF nos enrolamentos. A
combinação desses três sinais é usada para derivar a sequência de comutação.

Hardware Necessário:
placa Arduino UNO
Motor CC sem escova (BLDC)
6 x mosfet tipo N 06N03LA (ou equivalente) – folha de dados
3 x IC de driver de porta IR2104S (IR2104) – folha de dados
6 resistores de 33k ohms
3 resistores de 10k ohms
6 x resistor de 100 ohms
3 x diodo IN4148
3 capacitores de 10uF
3 capacitores de 2,2uF
2 x botão
fonte 12V
Protoboard
Fios de jumper

Controle de motor BLDC sem sensor com circuito Arduino:


O esquema do circuito do projeto é mostrado na próxima pagina:
Observe que todos os terminais aterrados estão conectados juntos.
No circuito existem 2 botões de pressão, um é usado para aumentar a velocidade do motor BLDC e
o 2º é usado para diminuí-la.
Os três primeiros resistores de 33k (conectados às fases do motor) e os três resistores de 10k são
usados como divisores de tensão, pois não podemos alimentar o microcontrolador com 12V, os
outros três resistores de 33k geram o ponto natural virtual. O ponto natural virtual é conectado ao
pino 6 do Arduino.
A placa Arduino UNO é baseada no microcontrolador ATmega328P que possui um comparador
analógico. A entrada positiva deste comparador está no Arduino uno pino 6 (AIN0) e a entrada
negativa pode ser o pino 7 (AIN1), A0 (ADC0), A1 (ADC1), A2 (ADC2), A3 (ADC3), A4 (ADC4 )
ou A5 (ADC5). Então conectei o ponto natural virtual ao pino positivo do comparador analógico
(pino 6), fase A BEMF ao pino 7 (AIN1), fase B BEMF ao pino A2 e fase C BEMF ao pino A3. A
cada vez o comparador compara o ponto virtual com o BEMF de uma fase (isso é feito no
software). Isso minimiza o hardware necessário e simplifica o circuito.
Os chips IR2104S são usados para controlar os mosfets do lado alto e do lado baixo de cada fase. A
comutação entre o lado alto e o lado baixo é feita de acordo com as linhas de controle IN e SD. A
figura abaixo mostra o diagrama de temporização de entrada e saída:

As linhas SD dos três IR2104S são conectadas aos pinos 11, 10 e 9 respectivamente para fase A,
fase B e fase C. O Arduino UNO pode gerar sinais PWM naqueles pinos onde apenas os mosfets do
lado alto são PWMed.

Como mencionado acima, os pinos 9, 10 e 11 do Arduino podem gerar sinais PWM onde os pinos 9
e 10 estão relacionados com o módulo Timer1 (OC1A e OC1B) e o pino 11 está relacionado com o
módulo Timer2 (OC2A). Ambos os módulos Timer são configurados para gerar um sinal PWM
com uma frequência de cerca de 31KHz e uma resolução de 8 bits. Os ciclos de trabalho dos sinais
PWM são atualizados quando um botão é pressionado (acelerar ou desacelerar) escrevendo em seus
registradores (OCR1A, OCR1B e OCR2A).
O comparador analógico compara a entrada positiva AIN0 (pino 6 do Arduino) com a entrada
negativa que pode ser AIN1 (pino 7), ADC2 (pino A2) ou ADC3 (pino A3). Quando a tensão do
pino positivo é maior que a tensão do pino negativo, a saída do comparador analógico ACO é
definida, e quando a tensão do pino positivo é menor que a tensão do pino negativo, o ACO é limpo.
Neste projeto eu usei a interrupção do comparador analógico e usei sua interrupção na subida
(transição de baixo para alto) e interrupção na queda (transição de alto para baixo), isso faz com que
os eventos de cruzamento de zero interrompam o microcontrolador.
Para entender completamente o código, leia o datasheet do ATmega328!

Codigo abaixo:
/* Sensorless brushless DC (BLDC) motor control with Arduino UNO (Arduino DIY ESC).
* This is a free software with NO WARRANTY.
* https://simple-circuit.com/
*/

#define SPEED_UP A0
#define SPEED_DOWN A1
#define PWM_MAX_DUTY 255
#define PWM_MIN_DUTY 50
#define PWM_START_DUTY 100

byte bldc_step = 0, motor_speed;


unsigned int i;
void setup() {
DDRD |= 0x38; // Configure pins 3, 4 and 5 as outputs
PORTD = 0x00;
DDRB |= 0x0E; // Configure pins 9, 10 and 11 as outputs
PORTB = 0x31;
// Timer1 module setting: set clock source to clkI/O / 1 (no prescaling)
TCCR1A = 0;
TCCR1B = 0x01;
// Timer2 module setting: set clock source to clkI/O / 1 (no prescaling)
TCCR2A = 0;
TCCR2B = 0x01;
// Analog comparator setting
ACSR = 0x10; // Disable and clear (flag bit) analog comparator interrupt
pinMode(SPEED_UP, INPUT_PULLUP);
pinMode(SPEED_DOWN, INPUT_PULLUP);
}
// Analog comparator ISR
ISR (ANALOG_COMP_vect) {
// BEMF debounce
for(i = 0; i < 10; i++) {
if(bldc_step & 1){
if(!(ACSR & 0x20)) i -= 1;
}
else {
if((ACSR & 0x20)) i -= 1;
}
}
bldc_move();
bldc_step++;
bldc_step %= 6;
}
void bldc_move(){ // BLDC motor commutation function
switch(bldc_step){
case 0:
AH_BL();
BEMF_C_RISING();
break;
case 1:
AH_CL();
BEMF_B_FALLING();
break;
case 2:
BH_CL();
BEMF_A_RISING();
break;
case 3:
BH_AL();
BEMF_C_FALLING();
break;
case 4:
CH_AL();
BEMF_B_RISING();
break;
case 5:
CH_BL();
BEMF_A_FALLING();
break;
}
}

void loop() {
SET_PWM_DUTY(PWM_START_DUTY); // Setup starting PWM with duty cycle =
PWM_START_DUTY
i = 5000;
// Motor start
while(i > 100) {
delayMicroseconds(i);
bldc_move();
bldc_step++;
bldc_step %= 6;
i = i - 20;
}
motor_speed = PWM_START_DUTY;
ACSR |= 0x08; // Enable analog comparator interrupt
while(1) {
while(!(digitalRead(SPEED_UP)) && motor_speed < PWM_MAX_DUTY){
motor_speed++;
SET_PWM_DUTY(motor_speed);
delay(100);
}
while(!(digitalRead(SPEED_DOWN)) && motor_speed > PWM_MIN_DUTY){
motor_speed--;
SET_PWM_DUTY(motor_speed);
delay(100);
}
}
}

void BEMF_A_RISING(){
ADCSRB = (0 << ACME); // Select AIN1 as comparator negative input
ACSR |= 0x03; // Set interrupt on rising edge
}
void BEMF_A_FALLING(){
ADCSRB = (0 << ACME); // Select AIN1 as comparator negative input
ACSR &= ~0x01; // Set interrupt on falling edge
}
void BEMF_B_RISING(){
ADCSRA = (0 << ADEN); // Disable the ADC module
ADCSRB = (1 << ACME);
ADMUX = 2; // Select analog channel 2 as comparator negative input
ACSR |= 0x03;
}
void BEMF_B_FALLING(){
ADCSRA = (0 << ADEN); // Disable the ADC module
ADCSRB = (1 << ACME);
ADMUX = 2; // Select analog channel 2 as comparator negative input
ACSR &= ~0x01;
}
void BEMF_C_RISING(){
ADCSRA = (0 << ADEN); // Disable the ADC module
ADCSRB = (1 << ACME);
ADMUX = 3; // Select analog channel 3 as comparator negative input
ACSR |= 0x03;
}
void BEMF_C_FALLING(){
ADCSRA = (0 << ADEN); // Disable the ADC module
ADCSRB = (1 << ACME);
ADMUX = 3; // Select analog channel 3 as comparator negative input
ACSR &= ~0x01;
}

void AH_BL(){
PORTB = 0x04;
PORTD &= ~0x18;
PORTD |= 0x20;
TCCR1A = 0; // Turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void AH_CL(){
PORTB = 0x02;
PORTD &= ~0x18;
PORTD |= 0x20;
TCCR1A = 0; // Turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
TCCR2A = 0x81; //
}
void BH_CL(){
PORTB = 0x02;
PORTD &= ~0x28;
PORTD |= 0x10;
TCCR2A = 0; // Turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void BH_AL(){
PORTB = 0x08;
PORTD &= ~0x28;
PORTD |= 0x10;
TCCR2A = 0; // Turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
TCCR1A = 0x21; //
}
void CH_AL(){
PORTB = 0x08;
PORTD &= ~0x30;
PORTD |= 0x08;
TCCR2A = 0; // Turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}
void CH_BL(){
PORTB = 0x04;
PORTD &= ~0x30;
PORTD |= 0x08;
TCCR2A = 0; // Turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
TCCR1A = 0x81; //
}

void SET_PWM_DUTY(byte duty){


if(duty < PWM_MIN_DUTY)
duty = PWM_MIN_DUTY;
if(duty > PWM_MAX_DUTY)
duty = PWM_MAX_DUTY;
OCR1A = duty; // Set pin 9 PWM duty cycle
OCR1B = duty; // Set pin 10 PWM duty cycle
OCR2A = duty; // Set pin 11 PWM duty cycle
}

Link do video no youtube: https://youtu.be/2q0zsLUPKCY

Você também pode gostar