เซอร์โว SG90 และ MG90S กับ ESP32: สัญญาณ PWM 50 Hz และไฟเลี้ยงแยก
เซอร์โวจิ๋วหมุนตามความกว้างพัลส์ 1–2 ms ทุก 20 ms ต่อกับ ESP32 ยังไง ทำไมต้องใช้ไฟเลี้ยงแยกและกราวด์ร่วม กระแสตอนติดขัดเท่าไร และเขียนด้วย ESP32Servo หรือ LEDC
- เซอร์โวจิ๋วรับพัลส์ทุก 20 ms (50 Hz) ความกว้างราว 1 ms = สุดด้านหนึ่ง 1.5 ms = กลาง 2 ms = สุดอีกด้าน
- ไฟเลี้ยงเซอร์โวแยกจากบอร์ดได้ แต่กราวด์ต้องต่อร่วมกันเสมอ ไม่งั้นสัญญาณไม่มีจุดอ้างอิง
- เผื่อกระแสตัวละอย่างน้อย 0.5 A สำหรับ SG90 และมากกว่านั้นสำหรับ MG90S เพราะตอนติดขัดกินกระแสสูงสุด
- อย่าสั่งไปชนขอบกลไก ใช้ช่วงที่ทดสอบแล้ว เช่น 20–160° เพื่อลดกระแสค้างและเฟืองรูด
เซอร์โวจิ๋วอย่าง SG90 และ MG90S คือมอเตอร์ที่มีวงจรควบคุมและเฟืองทดในตัว สั่งด้วยพัลส์ไฟฟ้าทุก 20 ms (50 Hz) ความกว้างพัลส์ราว 1–2 ms บอกมุมที่ต้องการ แล้วมันหมุนไปค้างที่มุมนั้นเอง จุดที่มือใหม่พลาดเกือบทุกคนไม่ใช่โค้ด แต่เป็นไฟเลี้ยง เซอร์โวกินกระแสกระชากจนบอร์ดรีเซ็ต บทนี้จึงพูดเรื่องสัญญาณกับไฟเลี้ยงไปพร้อมกัน
ตัวเลขในบทอ้างอิง ESP32 รุ่นแรกบน Arduino-ESP32 core 3.x และเซอร์โวแบบ 180° (ไม่ใช่แบบหมุนต่อเนื่อง 360°)
เซอร์โวรู้มุมได้ยังไง
ข้างในมีมอเตอร์ DC เฟืองทด และตัวต้านทานปรับค่า (potentiometer) ติดกับแกนขาออก วงจรในตัวเทียบความกว้างพัลส์ที่เราส่งกับตำแหน่งแกนจริง แล้วหมุนมอเตอร์จนสองค่าตรงกัน ถ้ามีแรงดันแกนออกจากตำแหน่ง มันจะดันกลับ นี่คือเหตุผลที่เซอร์โวกินกระแสแม้ไม่ได้ขยับให้เห็น
สายมี 3 เส้น สีที่พบบ่อยคือ น้ำตาล = GND, แดง = ไฟเลี้ยง, ส้ม = สัญญาณ ดูเอกสารของตัวที่ซื้อมาก่อนต่อทุกครั้ง
สัญญาณ: 50 Hz และความกว้างพัลส์
| ความกว้างพัลส์ | ตำแหน่ง (ตามสเปกผู้ขาย SG90) |
|---|---|
| 1.0 ms | 0° |
| 1.5 ms | 90° (กลาง) |
| 2.0 ms | 180° |
ส่งพัลส์ซ้ำทุก 20 ms ค่ากลางเป็นทางสายกลางที่ใช้ได้ทุกตัว แต่ปลายสองด้านแต่ละตัวไม่เท่ากัน ไลบรารี ESP32Servo ตั้งค่าเริ่มต้นไว้ 544–2400 µs และยอมให้กว้างสุด 500–2500 µs ตัวที่ซื้อมาอาจหมุนได้ไม่ถึง 180° เพราะติดตัวหยุดกลไก ถ้าสั่งเลยไป มอเตอร์จะพยายามดันค้างไว้ กินกระแสเต็มที่และร้อน
ทดสอบหาปลายจริงของเซอร์โวตัวนั้นก่อน แล้วใช้ช่วงที่ปลอดภัย เช่น 20–160° อย่าสั่งไปชนขอบ
ตัวอย่างคำนวณ: แปลง µs เป็นค่า duty ของ LEDC
ESP32 สร้าง PWM ด้วยวงจร LEDC ตั้งความถี่ 50 Hz และความละเอียด 14 บิต (ช่วงที่ใช้ได้ทุกชิปตามเอกสาร Arduino-ESP32 ชิปรุ่นแรกได้ถึง 20 บิต)
- หนึ่งรอบ = 1 ÷ 50 = 20 ms = 20,000 µs
- 14 บิต = 2¹⁴ = 16,384 ขั้น ต่อรอบ → ขั้นละ 20,000 ÷ 16,384 ≈ 1.22 µs
- 1,500 µs → 1,500 × 16,384 ÷ 20,000 = 1,228.8 → ใช้ 1,229 (โค้ดหารจำนวนเต็มได้ 1,228 ต่างกันไม่ถึง 1.3 µs)
- 1,000 µs → 819 และ 2,000 µs → 1,638
- ช่วง 1,000 µs ครอบ 180° → 1° ≈ 5.6 µs ≈ 4.5 ขั้น ละเอียดพอสำหรับของเล่น
// ESP32 + Arduino-ESP32 core 3.x, เซอร์โวต่อ GPIO13
const int SERVO_PIN = 13;
uint32_t usToDuty(uint32_t us) {
return us * 16384UL / 20000UL; // 14 บิต ที่ 50 Hz
}
void setup() {
ledcAttach(SERVO_PIN, 50, 14);
ledcWrite(SERVO_PIN, usToDuty(1500)); // ไปตำแหน่งกลาง
}
void loop() {}
ถ้าไม่อยากคิดเอง ไลบรารี ESP32Servo (ติดตั้งจาก Library Manager) ทำเหมือนกันแต่สั่งเป็นองศา
#include <ESP32Servo.h>
Servo arm;
void setup() {
arm.setPeriodHertz(50);
arm.attach(13, 1000, 2000); // ขา, พัลส์ต่ำสุด, สูงสุด (µs)
}
void loop() {
arm.write(20); delay(1000);
arm.write(160); delay(1000);
}
ESP32 รุ่นแรกคุมเซอร์โวได้ 16 ตัวด้วย LEDC ตาม README ของไลบรารี (S2 ได้ 8, C3 ได้ 6) ขาที่ README แนะนำคือ 2, 4, 12–19, 21–23, 25–27, 32–33
ไฟเลี้ยง: แยกได้ แต่กราวด์ต้องร่วม
สเปกผู้ขายระบุไฟเลี้ยง 4.8–6 V (5 V ใช้ทั่วไป) กระแสแต่ละช่วงต่างกันมาก
| สถานะ | SG90 | MG90S |
|---|---|---|
| อยู่นิ่ง | ~10 mA | ~10 mA |
| กำลังหมุน | 100–250 mA | 120–250 mA |
| ติดขัด (stall) | ~360 mA (วัดโดยผู้ขายหนึ่งราย) แหล่งอื่นบอก ~550 mA | ~700 mA (วัด) |
| แรงบิด | ~1.7 kg·cm (วัด) | 2.2 kg·cm (สเปก) |
ตัวเลข stall ของ SG90 ต่างกันตามแหล่งและตามล็อตของตัวเลียนแบบที่มีเยอะในตลาด ใช้เป็นช่วงสำหรับวางแผน ไม่ใช่ค่าตายตัว
วิธีต่อที่ปลอดภัย:
- ไฟ 5 V ของเซอร์โว มาจากแหล่งจ่ายแยก (อะแดปเตอร์ 5 V หรือโมดูลลดแรงดัน) ไม่ดึงจากขา 3.3 V ของบอร์ดเด็ดขาด
- GND ของแหล่งจ่าย ต่อเข้ากับ GND ของ ESP32 สัญญาณ PWM วัดเทียบกับกราวด์ ถ้าไม่ต่อร่วม เซอร์โวจะสั่น กระตุก หรือไม่ขยับเลย
- ตัวเก็บประจุ 470 µF ขึ้นไป คร่อมไฟเลี้ยงใกล้เซอร์โว (ขายาว = +) ทำหน้าที่เป็นถังสำรองตอนมอเตอร์ออกตัว Adafruit แนะนำค่านี้เพื่อแก้อาการบอร์ดรีเซ็ต
ตัวอย่างคำนวณ: เลือกแหล่งจ่ายให้หุ่นแขน 3 ข้อ
แขนกลของเล่นใช้ MG90S 3 ตัว
- กรณีแย่สุด ทุกตัวติดขัดพร้อมกัน: 3 × 0.7 A = 2.1 A
- เผื่ออีกราว 20–30% สำหรับตัวที่กินมากกว่าค่าวัด: 2.1 × 1.25 ≈ 2.6 A
- เลือกแหล่งจ่าย 5 V 3 A แยกจากบอร์ด ESP32 ใช้ไฟ USB ของมันเอง
- ถ้าเป็น SG90 3 ตัว เผื่อตัวละ 0.5 A → 1.5 A → แหล่งจ่าย 5 V 2 A ก็พอ
ถ้าใช้แบตเตอรี่ลิเธียม ให้ผ่านวงจรป้องกันและโมดูลลดแรงดันที่รับกระแสได้ตามนี้ ห้ามต่อแบตตรงเข้าเซอร์โวโดยไม่รู้แรงดันจริง แพ็กลิเธียม 2 เซลล์เต็มที่ราว 8.4 V เกินสเปกเซอร์โวไปมาก
ข้อผิดพลาดที่เจอบ่อย
- ESP32 รีเซ็ตทุกครั้งที่เซอร์โวขยับ ไฟตกจากกระแสกระชาก แยกไฟเลี้ยงและใส่ตัวเก็บประจุ
- ลืมต่อกราวด์ร่วม อาการคือสั่นมั่ว หรือหมุนไปมุมแปลก ๆ
- สั่งไปสุดขอบ 0° หรือ 180° เซอร์โวครางค้าง ร้อน เฟืองพลาสติกของ SG90 รูดได้
- ใช้เซอร์โวแบบ 360° ด้วยความเข้าใจว่าสั่งมุมได้ แบบนั้นพัลส์คุมความเร็วและทิศ ไม่ใช่มุม
- ใช้แขนยาวเกินแรงบิด 1.7 kg·cm แปลว่าที่ระยะ 1 cm ยกได้ราว 1.7 kg ที่ระยะ 5 cm เหลือราว 340 g ก่อนติดขัด
- ชิ้นงานพิมพ์ยึดเซอร์โวหลวม เซอร์โวหมุนตัวเองแทนหมุนแขน ออกแบบช่องให้พอดี (ดูวิธีพิมพ์ชิ้นงานให้สวมพอดี)
ความปลอดภัย
งานนี้อยู่ที่ 5 V ทั้งหมด ถ้าใช้อะแดปเตอร์เสียบปลั๊ก ใช้ตัวที่มีกล่องปิดมิดชิด ห้ามแกะหรือต่อสายฝั่งไฟบ้าน มอเตอร์ที่ติดขัดนาน ๆ ร้อนจนเฟืองละลายได้ ตัดไฟเมื่อได้ยินเสียงครางค้าง และระวังนิ้วกับแขนกลตอนเปิดไฟครั้งแรก เพราะเซอร์โวจะกระโดดไปตำแหน่งเริ่มต้นทันที
บทถัดไป: เซนเซอร์สำหรับของเล่น เลือกแบบไหน ต่อยังไง
แหล่งข้อมูล
คำถามที่พบบ่อย
ต่อเซอร์โวตัวเดียวเข้าขา 5V ของบอร์ดได้ไหม
ทดลองตัวเดียวแบบไม่มีโหลดมักพอไหว แต่ตอนเริ่มหมุนกระแสกระชากจนบอร์ดรีเซ็ตได้ ใส่ตัวเก็บประจุ 470 µF ขึ้นไปคร่อมไฟเลี้ยงเซอร์โว และถ้ามีตั้งแต่สองตัวหรือมีแรงต้าน ให้ใช้แหล่งจ่าย 5 V แยก
ขา GPIO 3.3 V ของ ESP32 สั่งเซอร์โวที่เลี้ยง 5 V ได้ไหม
เซอร์โวจิ๋วส่วนใหญ่รับสัญญาณ 3.3 V ได้ในทางปฏิบัติ ตัวอย่างยอดนิยมก็ต่อตรง ถ้าตัวไหนสั่นหรือไม่ตอบสนอง ลองใช้ตัวแปลงระดับสัญญาณ และตรวจกราวด์ร่วมก่อน
SG90 กับ MG90S ต่างกันตรงไหน
ขนาดและสายเหมือนกัน MG90S ใช้เฟืองโลหะ แรงบิดมากกว่า แต่กินกระแสตอนติดขัดสูงกว่า (ผู้ขายรายหนึ่งวัดได้ราว 700 mA เทียบกับ SG90 ราว 360 mA)
วงจรและโค้ดในบทความทดสอบกับบอร์ดตัวอย่าง บอร์ดต่างรุ่นอาจใช้ขาต่างกัน ตรวจ pinout ของบอร์ดที่ใช้ก่อนต่อไฟเสมอ