สเต็ปเปอร์มอเตอร์หรือที่บางคนเรียกว่าสเต็ปปิ้งมอเตอร์ เป็นมอเตอร์ที่ทำงานโดยอาศัยพลังงานจากไฟฟ้ากระแสตรงเช่นเดียวกับมอเตอร์กระแสตรง แต่มีความความแตกต่างจากมอเตอร์กระแสตรงที่เมื่อป้อนไฟให้กับสเต็ปเปอร์มอเตอร์จะขยับเพียงเล็กน้อยเพื่อเข้าสเต็ป ในขณะที่มอเตอร์ไฟฟ้ากระแสตรงทั่วไปจะหมุนตราบที่ยังมีพลังงานจ่ายให้แก่ตัวมัน ทั้งนี้เป็นเพราะโครงสร้างของสเต็ปเปอร์มอเตอร์นั่นเอง โดย สเต็ปเปอร์มอเตอร์มีด้วยกัน 2 แบบคือ
1. Bipolar เป็นสเต็ปเปอร์มอเตอร์ที่มีขดลวด 2 ขดมีสายไฟให้ต่อใช้งาน 4 เส้น
2. Unipolar เป็นสเต็ปเปอร์มอเตอร์ที่มีขดลวด 4 ขด (2 ขดแบบมีแท็ปกลาง)
สำหรับการเรียรรู้ในครั้งนี้เป็นการเรียนรู้ที่ใช้สเต็ปเปอร์มอเตอร์แบบ Unipolar แบบที่มี 5 สาย (จุดแท็ปกลางของทั้ง 2 ขดเชื่อมต่อกันแล้ว) เป็นมอเตอร์เบอร์ เบอร์ 28BYJ-48-5V มีคุณสมบัติในการขับสเต็ปครบ 1 รอบคือ 360° ใช้ 512 สเต็ป เมื่อขับแบบฟูลสเต็ป 1 เฟส คุณสมบัติโดยทั่วไปของมอเตอร์มีดังนี้
4 Phase 5 Wire Connection
-100% Brand New
-Phase : 4
-Current : 160 mA per winding (320 mA in 4-step mode) Measured: 250mA stopped, 200 mA running fast
-Resistance : 31 Ω per coil winding (from Red wire to any coil) (Some 24-28 ohms)
-Voltage : 5V DC
-Step Angle (8-Step sequence: Internal Motor alone): 5.625° (64 steps per revolution)
-Step Angle (4-Step sequence: Internal Motor alone): 11.25° (32 steps per revolution)
-Gear Reduction ratio: 1 / 64 (Not really exact: probably 63.68395.:1 )
-SO: it takes (64*64 = 4096 steps per output shaft revolution.. In 8-step sequence.
-SO: it takes (32*64 = 2048 steps per output shaft revolution.. In 4-step sequence.
-NOTE: Arduino "Stepper Library" runs in 4-step mode
-No-Load Pull-Out Frequency : 800pps
-No-Load Pull-In Frequency : 500pps
-Pull-In Torque : ≥ 78.4mN.m
-Wiring Instruction : A (Blue), B (Pink), C (Yellow), D (Orange), E (Red, Mid-Point)
-Weight : 30g
คอนเซปของการสร้าง
-บอร์ด Arduino รอรับคำสั่งที่ส่งมาจากคอมพิวเตอร์ผ่านทางพอร์ตอนุกรมแล้วมาถอดรหัสคำสั่งว่าต้องการสั่งให้สเต็ปมอเตอร์หมุนไปทางทิศทางใด (ตามเข็ม:CW หรือทวนเข็มนาฬิกา:CCW) และต้องการให้หมุนไปจำนวนกี่องศาโดยข้อมูลที่รับมาตัวบอร์ดจะทำการประมวลผลและคำนวณโดยค่ามุมที่รับมาเป็นองศาทำการแปลงเป็นสเต็ปในการควบคุมในอัตราส่วน 360° /512 step แล้วจึงทำการสั่งให้มอเตอร์ทำงานตามสเต็ปที่คำนวณได้ ในขณะที่ขับมอเตอร์แต่ละสเต็ปให้บอร์ดส่งค่ามุมย้อนกลับไปแสดงผลที่จอคอมพิวเตอร์ผ่านทางพอร์ตอนุกรม
-โปรแกรมอินเตอร์เฟสที่สร้างขึ้นด้วย Visual C# ทำการรับค่ามุมและทิศทางหมุนจากผู้ใช้งานแล้วส่งออกไปทางพอร์ตอนุกรมโดยข้อมูลที่ส่งไปเป็นคำสั่งควบคุมที่ประกอบด้วย ข้อมูลสั่งสเต็ปมอเตอร์ ทิศทางหมุนและองศาที่ต้องการหมุน สร้างส่วนรับข้อมูลองศาที่ส่งเข้ามาทางพอร์ตอนุกรม(ถูกส่งมาจากบอร์ดควบคุมมอเตอร์)เพื่อแสดงผลมุมที่กำลังดำเนินการ
มีขั้นตอนดังนี้
1. วงจรบอร์ดควบคุมสเต็ปเปอร์มอเตอร์โดยใช้ Arduino เป็นดังรูป
2. รูปการเชื่อมต่อ
3. โปรโตคอลของคำสั่งที่สร้างขึ้นประกอบด้วย
-คำสั่งสั่งทำงานสเต็ปมอเตอร์ 4 ไบต์แรก
-คำสั่งกำหนดทิศทางการหมุนเป็นไบต์ที่ 5 โดยค่าที่ใส่จะเป็นตัวอักษร "F" หรือ "R"
-ข้อมูลองศาที่ต้องการหมุนในไบต์ที่ 6 เป็นต้นไป (การเรียนรู้ครั้งนี้เขียบบังคับให้ใส่ไม่เกิน 10000°)
4.สร้างโปรเจคไฟล์แล้ววางตัวคอนโทรลและแก้ไขชื่อดังรูป ตัวคอนโทรลที่ใช้งานได้แก่
-Button
-ComboBox
-GroupBox
-Label
-SerialPort
-TextBox
5. คลิกเพิ่มรายการในคอมโบบ็อกที่ใช้เลือกความเร็วในการสื่อสาร
ความเร็วที่ให้เลือกใช้มีดังนี้
9600
19200
38400
57600
74880
115200
6.กดปุ่ม Shift ค้างไว้แล้วคลิกที่คอมโบบ็อกทั้ง 2 ตัวตั้งค่าคุณสมบัติเริ่มต้นให้ DropDownStyle ให้เป็น DropDownList เพื่อไม่ให้ผู้ใช้งานพิมพ์ทับลงในช่องขณะรันโปรแกรม (ให้เลือกอย่างเดียว)
7. ดับเบิลคลิกที่ฟอร์มแล้วเขียนโค้ด
8. เขียนโค้ดให้โปรแกรมสแกนหาพอร์ตอนุกรมที่คอมพิวเตอร์มองเห็น
-ใช้งานพอร์ต
-ประกาศตัวแปรเก็บทิศทางการหมุน
-สแกนหาพอร์ตอนุกรมที่คอมพิวเตอร์มองเห็น ณ ปัจจุบัน และให้เลือกบอดเรทเป็น 19200 เป็นค่าเริ่มต้น
หมายเหตุ เนื่องจากมีการส่งย้อนกลับไปยังคอมพิวเตอร์ผ่านพอร์ตอนุกรมที่เป็นค่ามุมที่ขยับมอเตอร์ถี่ ๆ ต่ำกว่า 20mS ในแต่ละค่าจึงใช้บอดเรทต่ำ (9600) ไม่ได้จะทำให้ข้อมูลรับได้ผิดพลาด
โค้ด
baudrate_cbb.SelectedIndex = 1;
string[] ports = SerialPort.GetPortNames();
port_cbb.Items.AddRange(ports);
port_cbb.SelectedIndex = 0;
9. คลิกที่คอมโบบ็อกที่ใช้เลือกพอร์ต แล้วคลิกเลือกเหตุการณ์กระตุ้นเป็น MouseClick (แล้วดับเบิลคลิก) เพื่อเขียนโค้ดให้ทำงานเมื่อมีเมาส์มาคลิกที่คอมโบบ็อกตัวนี้
10. เขียนโค้ดให้โปรแกรมสแกนหาพอร์ตอนุกรมใหม่ที่คอมพิวเตอร์มองเห็นในจังหวะที่มีการคลิกเมาส์ที่คอมโบบ็อกนี้
โค้ด
port_cbb.Items.Clear();
string[] ports = SerialPort.GetPortNames();
port_cbb.Items.AddRange(ports);
port_cbb.SelectedIndex = 0;
11. ดับเบิลคลิกที่ปุ่ม Connect เพื่อเขียนโค้ดให้โปรแกรมเปิดพอร์ตเชื่อมต่อ
12. เขียนโค้ดควบคุม
โค้ด
con_btn.Enabled = false;
dis_btn.Enabled = true;
send_btn.Enabled = true;
if (serialPort1.IsOpen)
serialPort1.Close();
serialPort1.PortName = port_cbb.Text;
serialPort1.BaudRate = Convert.ToInt32(baudrate_cbb.Text);
try
{
serialPort1.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
13. ดับเบิลคลิกที่ปุ่ม Disconnect เพื่อเขียนโค้ดปิดการใช้งานพอร์ต
14. เขียนโค้ดควบคุม
โค้ด
con_btn.Enabled = true;
dis_btn.Enabled = false;
send_btn.Enabled = false;
if (serialPort1.IsOpen)
{
serialPort1.Close();
}
15. คลิกที่ TextBox เลือกเหตุการณ์กระตุ้นเป็น KeyPress เพื่อเขียนโค้ดให้รับเฉพาะตัวเลขเท่านั้น
16. เขียนโค้ดให้พิมพ์ได้เฉพาะตัวเลขลงช่องเท่านั้น
โค้ด
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
17. คลิกที่ TextBox เลือกเหตุการณ์กระตุ้นเป็น TextChange เพื่อเขียนโค้ดให้รับได้ไม่เกิน 10000
18. เขียนโค้ดให้รับตัวเลขได้ไม่เกิน 10000
โค้ด
if (angle_tb.Text != "" && Int16.Parse(angle_tb.Text) > 10000)
{
MessageBox.Show("Number of angle is over size.", "invalid value angle");
angle_tb.Text = angle_tb.Text.Substring(0, (angle_tb.TextLength - 1));
}
19. ดับเบิลคลิกที่ปุ่มส่งคำสั่งไปยังบอร์ดเพื่อเขียนโค้ด
20. เขียนโค้ดส่งคำสั่งไปยังบอร์ด
โค้ด
if (angle_tb.Text != "")
{
if (cw_rdb.Checked == true)
direction = "F";
else
direction = "R";
serialPort1.WriteLine("STM1" + direction + angle_tb.Text);
}
else
MessageBox.Show("No angle value", "False Command");
21. คลิกไอคอน Serial Port เลือกการกระตุ้นเป็น DataReceived แล้วดับเบิลคลิก
22. เขียนโค้ดรับข้อมูลเข้ามาแล้วแสดงผลมุม(องศา) ที่บอร์ดกำลังหมุนไป
โค้ด
private string DispString; //used to store the values read
DispString = serialPort1.ReadExisting();
this.Invoke(new EventHandler(DisplayText));
private void DisplayText(object sender, EventArgs e)
{
string[] value = DispString.Split(new string[] { "," }, StringSplitOptions.None);
status_lable.Text =value[0];
}
23. คลิกที่ฟอร์มเลือกเหตุการณ์กระตุ้นเป็น FormClosing
24. เขียนโค้ดให้ปิดการใช้งานพอร์ตอนุกรมก่อนปิดโปรแกรม
โค้ด
if (serialPort1.IsOpen)
serialPort1.Close();
Application.Exit();
โค้ดสำหรับบอร์ด Arduino
25. โค้ดส่วนแยกรหัสคำสั่งที่รับเข้ามาจากพอร์ตอนุกรมแล้วสั่งให้สเต็ปมอเตอร์หมุนตามค่ามุมที่รับมาได้
26. ฟังก์ชั่นสั่งให้สเต็ปมอเตอร์หมุนไปยังมุมที่กำหนด
โค้ดเต็ม(บอร์ด Arduino)
#define phaseA 4
#define phaseB 5
#define phaseC 6
#define phaseD 7
char PinCon[] = {phaseA, phaseB, phaseC, phaseD};
int i, j; // Step counter
String inputString = ""; // a String to hold incoming data
String command = ""; // a String to hold command
String direction = ""; // a String to hold direction of motor rotaged
int angle = 0; // a String to hold angle to rotation
bool stringComplete = false; // whether the string is complete
byte pattern[] = {
0B1000,
0B0100,
0B0010,
0B0001
};
void send2port(byte data);
void setup()
{
Serial.begin(19200); // if 9600 when send data to serial port delay over 30ms.
inputString.reserve(200); // reserve 200 bytes for the inputString:
for (i = 0; i < 4; i++)
{
pinMode(PinCon[i], OUTPUT);
}
i = 0;
}
void loop()
{
int x = inputString.length() - 1; //calculate length of incoming string
if (stringComplete) {
inputString = inputString.substring(0, x); //delete '\n'
command = inputString.substring(0, 4); //detect command
direction = inputString.substring(4, 5); //detect direction
angle = inputString.substring(5, x).toInt(); //detect angle
if (command == "STM1")
{
stepcontrol();
}
inputString = ""; // clear the string:
stringComplete = false;
}
send2port(0B0000);
}
void stepcontrol(void)
{
int stepm = map(angle, 0, 360, 0, 512); //convert true angle to step control
for ( j = 0; j < stepm; j++)
{
send2port(pattern[i]);
Serial.print(map(j, 0, 512, 0, 360)); //Send angle return to computer
Serial.println(",");
delay(5);
if (direction == "F")
(i < 3) ? i++ : i = 0;
else
(i > 0) ? i-- : i = 3;
}
Serial.print(angle); //Send final angle return to computer
}
void send2port(byte data)
{
digitalWrite(PinCon[0], (data & 1 ) ? HIGH : LOW);
digitalWrite(PinCon[1], (data & 2 ) ? HIGH : LOW);
digitalWrite(PinCon[2], (data & 4 ) ? HIGH : LOW);
digitalWrite(PinCon[3], (data & 8 ) ? HIGH : LOW);
}
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '\n') {
stringComplete = true;
}
}
}
27. ผลการรัน
https://www.youtube.com/v/7IHtRPFcg2Q