BLDC Motor speed control from washing machine by Arduino UNO

โครงงานนี้จะเป็นการทดลองการควบคุมความเร็วมอเตอร์แบบไม่ใช้แปรงถ่าน (ฺBLDC Motor) ซึ่งใช้ในเครื่องซักผ้า และเป็นมอเตอร์แบบไม่ใช้เซนเซอร์ตำแหน่งการหมุนภายใน (Sensorless BLDC motor) โดยในโครงงานนี้จะใช้ตัวประมวลผล Arduino UNO เพื่อทำการตรวจจับตำแหน่งการหมุน และใช้วงจรไอซี LM339 ปรับสัญญาณด้วยการรับค่าแรงดันย้อนกลับ (Back EMF) ที่เกิดขึ้นจากการนำกระแสภายในขดลวดของมอเตอร์ ซึ่งในการทดลองจะใช้แหล่งจ่ายไฟสำหรับทดสอบประมาณ 50V โดยสามารถจ่ายกระแสได้ที่ 5A ในการทดลองเบื้องต้น

BLDC Motor speed control from washing machine by Arduino UNO
รูปที่ 1 บอร์ดขับ BLDC Motor ต้นแบบ V.1

รูปที่ 1 แสดงบอร์ดต้นแบบสำหรับขับมอเตอร์ที่ออกแบบและพัฒนาขึ้นเป็นเวอร์ชั่น 1 ซึ่งในตัวบอร์ดจะสามารถรับสัญญาณขับจากบอร์ดควบคุมต่างๆ ได้โดยตรงในระดับ TTL, มีวงจรตรวจจับกระแสและส่งค่าการทำงานของตัวมอเตอร์ไปยังบอร์ดควบคุมได้, ตัวบอร์ดรับแรงดันไฟเลี้ยงกระแสตรงได้ที่ 36V และสามารถส่งค่าสัญญาณค่าแรงดันย้อนกลับ (Back EMF) ไปยังบอร์ดควบคุมได้สำหรับควบคุมการปรับความเร็วมอเตอร์ เป็นต้น

BLDC Motor speed control from washing machine by Arduino UNO
รูปที่ 2 การประบความเร็วรอบให้กับ BLDC Motor

รูปที่ 2 แสดงการปรับความเร็วของตัวมอเตอร์ โดยในการทดลองนี้จะปรับตัวต้านทานปรับค่าบนบอร์ด สำหรับปรับลักษณะของสัญญาณที่เกิดขึ้นจากค่าแรงดันย้อนกลับที่เกิดจากตัวมอเตอร์ ทั้งนี้ค่าแรงดันย้อนกลับมานั้นจะต้องถูกปรับรูปแบบสัญญาณให้เป็นแบบพัลซ์สี่เหลี่ยมที่สมบูรณ์อีกครั้ง โดยใช้ไอซี LM339 สัญญาณที่ปรับแล้วจะถูกส่งไปยังบอร์ดควบคุม Arduino UNO ในการประมวลผล เพื่อหาตำแหน่งการเคลื่อนที่ในช่วงเวลาถัดไป

Program by : https://simple-circuit.com/arduino-sensorless-brushless-motor-bldc/

/* 
Sensorless brushless DC motor control with Arduino UNO and IR2101 (Arduino DIY ESC).
 BLDC motor speed is controlled with a potentiometer connected to A0.
 This is a free software with NO WARRANTY.
 https://simple-circuit.com/
 */ 

 #define PWM_MAX_DUTY      255
 #define PWM_MIN_DUTY      30  //50
 #define PWM_START_DUTY   80  // 100
 byte bldc_step = 0, motor_speed, pin_state;
 
void setup()
 {
   DDRD  |= 0xE0;  // configure pins 5, 6 and 7 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;
   // ADC module configuration
   ADMUX  = 0x60;   // configure ADC module and select channel 0
   ADCSRA = 0x84;   // enable ADC module with 16 division factor (ADC clock = 1MHz)
 PCICR  = EIMSK = 0;  // disable all external interrupts
 pinMode(2, INPUT_PULLUP);
   pinMode(3, INPUT_PULLUP);
   pinMode(4, INPUT_PULLUP);
 }
 // pin change interrupt 2 (PCINT2) ISR
 ISR (PCINT2_vect)
 {
   if( (PIND & PCMSK2) != pin_state )
     return;
   // BEMF debounce
   for(byte i = 0; i < 20; i++)
   {
     if(bldc_step & 1){
       if(PIND & PCMSK2)     i -= 1;
     }
     else {
       if(!(PIND & PCMSK2))  i -= 1;
     }
   }
 bldc_move();
   bldc_step++;
   bldc_step %= 6;
 }
 // BLDC motor commutation function
 void bldc_move()
 {
   switch(bldc_step)
   {
     case 0:
       AH_BL();
       BEMF_C_FALLING();
       break;
     case 1:
       AH_CL();
       BEMF_B_RISING();
       break;
     case 2:
       BH_CL();
       BEMF_A_FALLING();
       break;
     case 3:
       BH_AL();
       BEMF_C_RISING();
       break;
     case 4:
       CH_AL();
       BEMF_B_FALLING();
       break;
     case 5:
       CH_BL();
       BEMF_A_RISING();
   }
 }
 
void loop()
 {
   SET_PWM_DUTY(PWM_START_DUTY);  // setup starting PWM with duty cycle = PWM_START_DUTY
   int i = 5000;
 // motor start
   while(i > 100)
   {
     delayMicroseconds(i);
     bldc_move();
     bldc_step++;
     bldc_step %= 6;
     i = i - 20;
   }
 motor_speed = PWM_START_DUTY;
 PCICR  = 4;  // enable pin change interrupt for pins PCINT23..16 (Arduino 0 to 7)
 while(1)
   {
     ADCSRA |= 1 << ADSC;    // start conversion
     while(ADCSRA & 0x40);   // wait for conversion complete
     motor_speed = ADCH;     // read ADC data (8 bits only)
     if(motor_speed < PWM_MIN_DUTY)
       motor_speed = PWM_MIN_DUTY;
     SET_PWM_DUTY(motor_speed);
   }
 }
 void BEMF_A_RISING()
 {
   PCMSK2 = 0x04;    // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
   pin_state = 0x04;
 }
 void BEMF_A_FALLING()
 {
   PCMSK2 = 0x04;    // enable Arduino pin 2 (PCINT18) interrupt, others are disabled
   pin_state = 0;
 }
 void BEMF_B_RISING()
 {
   PCMSK2 = 0x08;    // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
   pin_state = 0x08;
 }
 void BEMF_B_FALLING()
 {
   PCMSK2 = 0x08;    // enable Arduino pin 3 (PCINT19) interrupt, others are disabled
   pin_state = 0;
 }
 void BEMF_C_RISING()
 {
   PCMSK2 = 0x10;    // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
   pin_state = 0x10;
 }
 void BEMF_C_FALLING()
 {
   PCMSK2 = 0x10;    // enable Arduino pin 4 (PCINT20) interrupt, others are disabled
   pin_state = 0;
 }
 void AH_BL()
 {
   PORTD &= ~0xA0;
   PORTD |=  0x40;
   TCCR1A =  0;      // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
   TCCR2A =  0x81;   //
 }
 void AH_CL()
 {
   PORTD &= ~0xC0;
   PORTD |=  0x20;
   TCCR1A =  0;      // turn pin 11 (OC2A) PWM ON (pin 9 & pin 10 OFF)
   TCCR2A =  0x81;   //
 }
 void BH_CL()
 {
   PORTD &= ~0xC0;
   PORTD |=  0x20;
   TCCR2A =  0;       // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
   TCCR1A =  0x21;    //
 }
 void BH_AL()
 {
   PORTD &= ~0x60;
   PORTD |=  0x80;
   TCCR2A =  0;      // turn pin 10 (OC1B) PWM ON (pin 9 & pin 11 OFF)
   TCCR1A =  0x21;   //
 }
 void CH_AL()
 {
   PORTD &= ~0x60;
   PORTD |=  0x80;
   TCCR2A =  0;       // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
   TCCR1A =  0x81;    //
 }
 void CH_BL()
 {
   PORTD &= ~0xA0;
   PORTD |=  0x40;
   TCCR2A =  0;       // turn pin 9 (OC1A) PWM ON (pin 10 & pin 11 OFF)
   TCCR1A =  0x81;    //
 }
 void SET_PWM_DUTY(byte 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
 }

สำหรับโปรแกรมข้างบนนี้เป็นโปรแกรมต้นแบบที่นำมาปรับใช้ในการทดลองต่างๆ ซึ่งเราจะต้องปรับแต่งโปรแกรมการทำงานบางส่วนเพื่อให้เหมาะสมกับขนาดของตัวมอเตอร์และมีความเฉพาะแตกต่างๆ กัน หรือเรียกว่า การปรับโปรแกรมให้เหมาะสมกับค่าพารามิเตอร์ในตัวมอเตอร์ ซึ่งจากการทดลองลูปคำสั่ง // motor start ต้องปรับค่าเริ่มต้น

BLDC Motor speed control from washing machine by Arduino UNO
รูปที่ 3 การต่อวงจรและบอร์ดต้นแบบต่างๆ ในการทดลอง

รูปที่ 3 การต่อบอร์ดทดลองต่างๆ เข้าด้วยกัน ซึ่งในการทดลองนี้จะมี 3 ส่วนคือ บอร์ดสำหรับควบคุมการทำงานทั้งหมดและสร้างสัญญาณขับมอเตอร์ Arduino UNO (บอร์ดสีน้ำเงิน) บอร์ดที่สอง เป็นบอร์ดสำหรับปรับลักษณะของสัญญาณที่เกิดขึ้นจากค่าแรงดันย้อนกลับ (Back EMF) ที่เกิดขึ้นในช่วงที่มอเตอร์หมุนเพื่อให้มีความถูกต้องสมบูรณ์และส่งให้บอร์ดควบคุม สุดท้ายเป็นบอร์ดขับมอเตอร์ (บอร์ดข้างบน) ทำหน้าที่ขับกำลังให้กับมอเตอร์หมุน รวมทั้งรับสัญญาณขับกำลังและส่งสัญญาณค่าแรงดันย้อนกลับ

BLDC Motor speed control from washing machine by Arduino UNO
รูปที่ 4 ลักษณะการทดลองปรับความเร็วของ BLDC Motor ของเครื่องซักผ้าแบบง่าย

สำหรับการทดลองนี้ยังคงเป็นการทดลองแบบง่าย เพื่อให้เราสามารถเข้าใจการขับมอเตอร์กระแสตรงชนิดไม่ใช้แปรงถ่าน (BLDC Motor) สำหรับเครื่องซักผ้าด้วยบอร์ดควบคุม Arduino UNO ซึ่งยังคงสามารถหาซื้อตัวมอเตอร์มาทดลองได้ ทั้งนี้การขับมอเตอร์ชนิดนี้เป็นอีกรูปแบบหนึ่งที่น่าสนใจ และมีความแตกต่างจากมอเตอร์กระแสตรงแบบใช้แปรงถ่าน (DC Motor) ปกติครับ.

Reference

  1. https://simple-circuit.com/arduino-sensorless-brushless-motor-bldc/
  2. http://ww1.microchip.com/downloads/en/appnotes/00885a.pdf
  3. https://www.nxp.com/docs/en/application-note/AN1914.pdf
  4. https://www.st.com/resource/en/application_note/cd00020086-sensorless-bldc-motor-control-and-bemf-sampling-methods-with-st7mc-stmicroelectronics.pdf
  5. http://ww1.microchip.com/downloads/en/AppNotes/doc8012.pdf
  6. https://www.mdpi.com/1996-1073/10/9/1384