ในกระทู้นี้เรียกว่ามาแลกเปลี่ยนแนวความคิดเรื่องการขับ Stepper Motor แบบ Microstep ด้วยโปรแกรมกันดีกว่าครับ เผื่อใครจะมีความคิดอะไรใหม่ๆ มาแลกเปลี่ยนกัน สำหรับคนที่พื้นฐานการเขียนโปรแกรมและเข้าใจ Stepper Motor อยู่บ้างแล้วครับ
โดยปกติอย่าที่ทราบเวลาเราขับ Stepper Motor แบบ 2 phase 4 เส้น โดยมี สาย +A ,-A, +B, -B ตามลำดับ เวลาขับมอเตอร์ก็ต้อง ไล่เป็น +A, +B, -A, -B แบบนี้ ใครไม่เข้าใจก็ไปอ่านวิธีขับมอเตอร์นะครับหรือหลังไมค์ ผมก็พอมีบ้างหากอธิบายได้ก็จะบอก แต่จะไม่อธิบายในกระทู้นี้ครับ
ทีนี้ปัญหาที่ทุกคนจะเจอคือเมื่อหมุนช้าๆเวลามันเคลื่อนที่มันจะไม่เรียบมันจะกระโดด สะเทือนตาม Step เลยครับ ยิ่งช้าก็ยิ่งสั่นมากผมเจอตอนจะทำอุปกรณ์ Slide เอาไว้ถ่ายรูป วิธีแก้คือแบ่ง Step การเคลื่อนที่ ย่อยๆลงไปเรียก Microstep ในบาง Stepper Driver เช่น DRV8825 จะสามารถทำแบบนี้ได้ แต่กระทู้นี้เราจะสร้างมันเองด้วโปรแกรมตรงๆไปแต่ละ Phase เพื่อทดลองแนวคิดเผื่อใครจะเอาไปประยุกต์ใช้แบบอื่น
ผมเลยมาคิดว่าแทนที่จะขับทีละ phase แต่เปลี่ยนมาขับทีละ 2 phase แต่จ่ายไฟไม่เท่ากันเปลี่ยนไปเรื่อยๆ สนามแม่เหล็กในมอเตอร์ก็จะถูกเหนี่ยวนำไปหา phase ต่อไปเหมือนมีคนสองคนดึงเชือกที่มีบอลตรงกลางฝ่ายหนึ่งค่อยๆปล่อยอีกฝ่ายตค่อยๆดึงบองมันก็จะไปหาคนดึงอย่างช้าๆ การจ่ายไฟ Phase +A และ +B เป็นดังรูป จากเริ่มต้นเฟส +A มีกำลังไฟ 100% และลดลงตามลำดับ ส่วนเฟส +B ก็เพิ่มขึ้นจาก 0 เป็น 100% เมื่อมอเตอร์เริ่มเคลื่อนไปจากจุด 1 ไป 11
ดังนั้นเราจะต้องโปรแกรมแบ่งการสั่งจ่ายไฟให้ได้ตามนั้น โดยจะจ่ายไปตาม Pin ที่เป็นแบบ PWM ของ Micro Controller และ ตัว Driver ก็ต้องรับด้วยครับเช่น
ผมต่อ Driver +A,-A,+B,-B กับ Arduino Uno Pin 3,5,6,9 ตามลำดับ(เช็คด้วยนะครับว่า Controller มี Digital I/O pin ไหนรอรับบ้าง) และต่อ Switch ระหว่าง Pin 2 กับ GND อีกตัว เอาไว้สลับ Mode ระหว่างขับปกติ กับ Microstep
มาดูโปรแกรมครับ
//**************************************************************
// Programmed by Ruth.Pra
// For public knowledge
long xdelay = 30; //เวลาหน่วงมอเตอร์ ระหว่าง step ค่ายิ่งน้อยยิ่งเร็ว in millisec
byte StepDiv=25;// การแบ่งจำนวน MicroStep should be 10- 25
byte MotorPin1 = 3; // Step Motor Driver pin 1
byte MotorPin2 = 5; // Step Motor Driver pin 2
byte MotorPin3 = 6; // Step Motor Driver pin 3
byte MotorPin4 = 9; // Step Motor Driver pin 4
byte SW = 2; // Switch สลับ ระหว่าขับธรรมดา กับ Micro Step
byte cphase = 1;//เฟสชองมอเตอร์
void RotateMotorMicro(byte xphase)///ขับทีละ Step แบบแยก Micro Step
{
switch (xphase)
{
case 1:
MicroDive(MotorPin4, MotorPin1,xdelay,StepDiv);
break;
case 2:
MicroDive(MotorPin1, MotorPin3,xdelay,StepDiv);
break;
case 3:
MicroDive(MotorPin3, MotorPin2,xdelay,StepDiv);
break;
case 4:
MicroDive(MotorPin2, MotorPin4,xdelay,StepDiv);
break;
}
}
void MicroDive(byte PinA, byte PinB, long Sdelay, byte MicroStepDiv)
{
int P = 0;
int PowerA;
int PowerB;
long MicroDelay;
for (int i = 0; i <= MicroStepDiv; i++)
{
PowerA = 250 - P;
PowerB = 0 + P;
analogWrite(PinA, PowerA);
analogWrite(PinB, PowerB);
MicroDelay = Sdelay*1000L/(MicroStepDiv+1);
delay(MicroDelay/1000);
delayMicroseconds(MicroDelay00);
P = P + 10;
}
analogWrite(PinA, 0);
analogWrite(PinB, 255);
}
void RotateMotorNor(byte xphase)//ขับทีละ Step ปกติ
{
analogWrite(MotorPin1, 0);
analogWrite(MotorPin2,0);
analogWrite(MotorPin3, 0);
analogWrite(MotorPin4, 0);
switch (xphase)
{
case 1:
analogWrite(MotorPin1, 255);
delay(xdelay);
break;
case 2:
analogWrite(MotorPin3, 255);
delay(xdelay);
break;
case 3:
analogWrite(MotorPin2, 255);
delay(xdelay);
break;
case 4:
analogWrite(MotorPin4, 255);
delay(xdelay);
break;
}
}
void setup()
{
pinMode(SW,INPUT_PULLUP);
analogWrite(MotorPin1, 0);
analogWrite(MotorPin2, 0);
analogWrite(MotorPin3, 0);
analogWrite(MotorPin4, 0);
}
void loop()
{
cphase++;
if (cphase > 4) cphase = 1;
if (digitalRead(SW))
{
RotateMotorMicro(cphase);
}
else
{
RotateMotorNor(cphase);
}
}
//**************************************************************
หมายเหตุ ใน คำสั่ง analogWrite นั้นค่าที่ส่งจะไม่ใช่ 0-100% ตรงๆ เพราะ Arduino จะแบ่งเป็น 0-255 คือ 255 เท่ากับ 100% ส่วนใครใช้ ESP นี่จะยากครับเพราะคำสั่ง AnalogWrite จะไม่ทำงาน แต่ก็มีวิธีเขียนที่ยุ่งยากมากกว่าใครใช้ก็หลังไมค์ละกัน
ในโปรแกรมจะมีตัวแปร 2 ตัวคือ xdelay กับ StepDiv ครับ ตัว xdelay คือตัวบอกว่าจะให้มอเตอร์เคลื่อนแต่ละ Step ใช้เวลานานเท่าไรยิ่งเยอะยิ่งช้า ส่วน StepDiv เอาไว้บอกว่าจะแบ่งMicroStep ของแต่ละ Step เป็นย่อยๆเท่าไร เช่น 25 ก็แบ่งเป็น 25ช่วงย่อย (จริงเป็น 26 เพราะ 0-25)
ตัวโปแกรมจะขับแบบ MicroStep แต่หากกดสวิทช์จะขับแบบธรรมดาครับทดลองแล้วดูความแตกต่างครับ
สรุป
1 หากเวลาน้อยๆต้องการ Motor หมุนเร็วๆ เช่น xdelay น้อยกว่า 5 การขับแบบปกติจะดูราบเรียบกว่า คงเพราะมันพอดีต่อการเคลื่นของแต่ละเฟส ส่วนการขับแบบ Microstep จะถูกแบบเยอะมากในเวลาจำกัดจึงแย่ลง แต่หากเวลา xdelay เพิ่มเยอะมากขึ้นเรื่อยๆจะเห็นความแตกต่างอย่างชัดเจน
2 การแบ่ง StepDiv หากแบ่งน้อยก็เรียบน้อย แต่หากมากเกิน ก็เหมือนว่ามันทำงานไม่ทัน ค่าที่ดูเหมือนจะพอดีคือ 25
3 ค่า xdelay กับ StepDiv นี่ดูเหมือนมันจะต้องพอดีกัน แต่อย่างไรนี่ยังไม่รู้
4 ในการขับแบบ MicroStep การกินไฟลดลงไปครึ่ง แต่แรงบิดก็หายไปด้วย แต่ไม่มากนัก
สุดท้ายคือ อันนี้เป็นการทดลองเล่นๆของผมแชร์เอาไว้เผื่อใครเอาไปร่วมด้วยช่วยพัฒนาต่อ บางจุดบางสาเหตุว่าทำไมมันเป็นเช่นนั้นผมก็ไม่รู้เหมือนกัน แต่การใช้งานคงต้องเขียนโปรแกรมไว้อีกว่าเมื่อความเร็วเท่าไรจะขับแบบไหนครับ หวังว่ากระทู้นี้คงได้ประโยชน์บ้างนะครับ ใครดูแล้วไร้สาระก็ขออภัยด้วยครับ
การขับ Stepper Motor 2 phases ให้เรียบ ไม่สะเทือนด้วยโปรแกรม
โดยปกติอย่าที่ทราบเวลาเราขับ Stepper Motor แบบ 2 phase 4 เส้น โดยมี สาย +A ,-A, +B, -B ตามลำดับ เวลาขับมอเตอร์ก็ต้อง ไล่เป็น +A, +B, -A, -B แบบนี้ ใครไม่เข้าใจก็ไปอ่านวิธีขับมอเตอร์นะครับหรือหลังไมค์ ผมก็พอมีบ้างหากอธิบายได้ก็จะบอก แต่จะไม่อธิบายในกระทู้นี้ครับ
ทีนี้ปัญหาที่ทุกคนจะเจอคือเมื่อหมุนช้าๆเวลามันเคลื่อนที่มันจะไม่เรียบมันจะกระโดด สะเทือนตาม Step เลยครับ ยิ่งช้าก็ยิ่งสั่นมากผมเจอตอนจะทำอุปกรณ์ Slide เอาไว้ถ่ายรูป วิธีแก้คือแบ่ง Step การเคลื่อนที่ ย่อยๆลงไปเรียก Microstep ในบาง Stepper Driver เช่น DRV8825 จะสามารถทำแบบนี้ได้ แต่กระทู้นี้เราจะสร้างมันเองด้วโปรแกรมตรงๆไปแต่ละ Phase เพื่อทดลองแนวคิดเผื่อใครจะเอาไปประยุกต์ใช้แบบอื่น
ผมเลยมาคิดว่าแทนที่จะขับทีละ phase แต่เปลี่ยนมาขับทีละ 2 phase แต่จ่ายไฟไม่เท่ากันเปลี่ยนไปเรื่อยๆ สนามแม่เหล็กในมอเตอร์ก็จะถูกเหนี่ยวนำไปหา phase ต่อไปเหมือนมีคนสองคนดึงเชือกที่มีบอลตรงกลางฝ่ายหนึ่งค่อยๆปล่อยอีกฝ่ายตค่อยๆดึงบองมันก็จะไปหาคนดึงอย่างช้าๆ การจ่ายไฟ Phase +A และ +B เป็นดังรูป จากเริ่มต้นเฟส +A มีกำลังไฟ 100% และลดลงตามลำดับ ส่วนเฟส +B ก็เพิ่มขึ้นจาก 0 เป็น 100% เมื่อมอเตอร์เริ่มเคลื่อนไปจากจุด 1 ไป 11
ดังนั้นเราจะต้องโปรแกรมแบ่งการสั่งจ่ายไฟให้ได้ตามนั้น โดยจะจ่ายไปตาม Pin ที่เป็นแบบ PWM ของ Micro Controller และ ตัว Driver ก็ต้องรับด้วยครับเช่น
ผมต่อ Driver +A,-A,+B,-B กับ Arduino Uno Pin 3,5,6,9 ตามลำดับ(เช็คด้วยนะครับว่า Controller มี Digital I/O pin ไหนรอรับบ้าง) และต่อ Switch ระหว่าง Pin 2 กับ GND อีกตัว เอาไว้สลับ Mode ระหว่างขับปกติ กับ Microstep
มาดูโปรแกรมครับ
//**************************************************************
// Programmed by Ruth.Pra
// For public knowledge
long xdelay = 30; //เวลาหน่วงมอเตอร์ ระหว่าง step ค่ายิ่งน้อยยิ่งเร็ว in millisec
byte StepDiv=25;// การแบ่งจำนวน MicroStep should be 10- 25
byte MotorPin1 = 3; // Step Motor Driver pin 1
byte MotorPin2 = 5; // Step Motor Driver pin 2
byte MotorPin3 = 6; // Step Motor Driver pin 3
byte MotorPin4 = 9; // Step Motor Driver pin 4
byte SW = 2; // Switch สลับ ระหว่าขับธรรมดา กับ Micro Step
byte cphase = 1;//เฟสชองมอเตอร์
void RotateMotorMicro(byte xphase)///ขับทีละ Step แบบแยก Micro Step
{
switch (xphase)
{
case 1:
MicroDive(MotorPin4, MotorPin1,xdelay,StepDiv);
break;
case 2:
MicroDive(MotorPin1, MotorPin3,xdelay,StepDiv);
break;
case 3:
MicroDive(MotorPin3, MotorPin2,xdelay,StepDiv);
break;
case 4:
MicroDive(MotorPin2, MotorPin4,xdelay,StepDiv);
break;
}
}
void MicroDive(byte PinA, byte PinB, long Sdelay, byte MicroStepDiv)
{
int P = 0;
int PowerA;
int PowerB;
long MicroDelay;
for (int i = 0; i <= MicroStepDiv; i++)
{
PowerA = 250 - P;
PowerB = 0 + P;
analogWrite(PinA, PowerA);
analogWrite(PinB, PowerB);
MicroDelay = Sdelay*1000L/(MicroStepDiv+1);
delay(MicroDelay/1000);
delayMicroseconds(MicroDelay00);
P = P + 10;
}
analogWrite(PinA, 0);
analogWrite(PinB, 255);
}
void RotateMotorNor(byte xphase)//ขับทีละ Step ปกติ
{
analogWrite(MotorPin1, 0);
analogWrite(MotorPin2,0);
analogWrite(MotorPin3, 0);
analogWrite(MotorPin4, 0);
switch (xphase)
{
case 1:
analogWrite(MotorPin1, 255);
delay(xdelay);
break;
case 2:
analogWrite(MotorPin3, 255);
delay(xdelay);
break;
case 3:
analogWrite(MotorPin2, 255);
delay(xdelay);
break;
case 4:
analogWrite(MotorPin4, 255);
delay(xdelay);
break;
}
}
void setup()
{
pinMode(SW,INPUT_PULLUP);
analogWrite(MotorPin1, 0);
analogWrite(MotorPin2, 0);
analogWrite(MotorPin3, 0);
analogWrite(MotorPin4, 0);
}
void loop()
{
cphase++;
if (cphase > 4) cphase = 1;
if (digitalRead(SW))
{
RotateMotorMicro(cphase);
}
else
{
RotateMotorNor(cphase);
}
}
//**************************************************************
หมายเหตุ ใน คำสั่ง analogWrite นั้นค่าที่ส่งจะไม่ใช่ 0-100% ตรงๆ เพราะ Arduino จะแบ่งเป็น 0-255 คือ 255 เท่ากับ 100% ส่วนใครใช้ ESP นี่จะยากครับเพราะคำสั่ง AnalogWrite จะไม่ทำงาน แต่ก็มีวิธีเขียนที่ยุ่งยากมากกว่าใครใช้ก็หลังไมค์ละกัน
ในโปรแกรมจะมีตัวแปร 2 ตัวคือ xdelay กับ StepDiv ครับ ตัว xdelay คือตัวบอกว่าจะให้มอเตอร์เคลื่อนแต่ละ Step ใช้เวลานานเท่าไรยิ่งเยอะยิ่งช้า ส่วน StepDiv เอาไว้บอกว่าจะแบ่งMicroStep ของแต่ละ Step เป็นย่อยๆเท่าไร เช่น 25 ก็แบ่งเป็น 25ช่วงย่อย (จริงเป็น 26 เพราะ 0-25)
ตัวโปแกรมจะขับแบบ MicroStep แต่หากกดสวิทช์จะขับแบบธรรมดาครับทดลองแล้วดูความแตกต่างครับ
สรุป
1 หากเวลาน้อยๆต้องการ Motor หมุนเร็วๆ เช่น xdelay น้อยกว่า 5 การขับแบบปกติจะดูราบเรียบกว่า คงเพราะมันพอดีต่อการเคลื่นของแต่ละเฟส ส่วนการขับแบบ Microstep จะถูกแบบเยอะมากในเวลาจำกัดจึงแย่ลง แต่หากเวลา xdelay เพิ่มเยอะมากขึ้นเรื่อยๆจะเห็นความแตกต่างอย่างชัดเจน
2 การแบ่ง StepDiv หากแบ่งน้อยก็เรียบน้อย แต่หากมากเกิน ก็เหมือนว่ามันทำงานไม่ทัน ค่าที่ดูเหมือนจะพอดีคือ 25
3 ค่า xdelay กับ StepDiv นี่ดูเหมือนมันจะต้องพอดีกัน แต่อย่างไรนี่ยังไม่รู้
4 ในการขับแบบ MicroStep การกินไฟลดลงไปครึ่ง แต่แรงบิดก็หายไปด้วย แต่ไม่มากนัก
สุดท้ายคือ อันนี้เป็นการทดลองเล่นๆของผมแชร์เอาไว้เผื่อใครเอาไปร่วมด้วยช่วยพัฒนาต่อ บางจุดบางสาเหตุว่าทำไมมันเป็นเช่นนั้นผมก็ไม่รู้เหมือนกัน แต่การใช้งานคงต้องเขียนโปรแกรมไว้อีกว่าเมื่อความเร็วเท่าไรจะขับแบบไหนครับ หวังว่ากระทู้นี้คงได้ประโยชน์บ้างนะครับ ใครดูแล้วไร้สาระก็ขออภัยด้วยครับ