3.15. การควบคุมมอเตอร์ DC

มอเตอร์ DC แบบใช้แปรงถ่านคือขดลวดพันรอบเพลาภายในสนามแม่เหล็ก เมื่อผ่านกระแสไฟเข้าขดลวด สนามแม่เหล็กจะออกแรงกระทำต่อขดลวด ซึ่งแรงนี้กลายเป็นแรงบิดบนเพลา แปรงถ่านภายในมอเตอร์จะสลับทิศทางกระแสในขดลวดขณะที่เพลาหมุน ทำให้แรงบิดผลักเพลาในทิศทางเดิมเสมอ การจ่ายแรงดัน DC ระหว่างขั้วมอเตอร์ทั้งสองทำให้เพลาหมุน และหากสลับขั้วไฟ เพลาจะหมุนในทิศทางตรงข้าม

โดยทั่วไปมอเตอร์ต้องการกระแสไฟหลายร้อยมิลลิแอมป์ถึงหลายแอมป์ที่แรงดันจ่ายสูงกว่าระดับลอจิก 3.3 V ของกล้อง พิน GPIO จ่ายกระแสได้ประมาณ 25 mA และไม่สามารถกลับขั้วได้ -- มันขับได้เพียงสองระดับแรงดันเท่านั้น วงจรขับระหว่างกล้องกับมอเตอร์จึงต้องรับกระแสของมอเตอร์ จัดหาแหล่งจ่ายแรงดันสูงแยกต่างหาก และให้กล้องสั่งกลับขั้วได้ H-bridge แบบสี่ทรานซิสเตอร์คือคำตอบมาตรฐาน

3.15.1. H-bridge

H-bridge คือสวิตช์สี่ตัวจัดเรียงในรูปตัว H รอบมอเตอร์:

An H-bridge schematic. Vmotor at top connects through switch S1 down to a node A on the left, and through switch S2 down to a node B on the right. The motor M sits horizontally between A and B. From A another switch S3 goes down to ground; from B another switch S4 goes down to ground.

H-bridge: สวิตช์สี่ตัว (S1 -- S4) ต่อมอเตอร์ M ระหว่าง Vmotor กับกราวด์

การปิดสวิตช์คู่ต่างๆ กำหนดแรงดันที่มอเตอร์ได้รับ:

  • S1 + S4 ปิด, S2 + S3 เปิด: กระแสไหลจาก Vmotor ผ่าน S1 เข้า A ข้ามมอเตอร์ไป B และผ่าน S4 ลงดิน มอเตอร์หมุนทิศทางหนึ่ง

  • S2 + S3 ปิด, S1 + S4 เปิด: กระแสไหลผ่านมอเตอร์ในทิศทางตรงข้าม มอเตอร์หมุนกลับทิศ

  • เปิดหมดทั้งสี่ตัว: ขั้วมอเตอร์ทั้งสองลอยอิสระ มอเตอร์ค่อยๆ หยุดเอง

  • S3 + S4 ปิด (หรือ S1 + S2 ปิด): ขั้วมอเตอร์ทั้งสองต่อกับราวเดียวกัน พลังงานจลน์ของมอเตอร์ขับกระแสที่คู่สวิตช์ที่ปิดลัดวงจรเป็นความร้อน มอเตอร์เบรก

การผสมที่ต้องห้ามคือการปิดสวิตช์ทั้งสองในคอลัมน์เดียวกัน -- S1 + S3 หรือ S2 + S4 -- ซึ่งสร้างวงจรลัดจาก Vmotor ไปยังกราวด์โดยตรง นี่คือ shoot-through และโค้ดของกล้องต้องไม่ให้เกิดขึ้น

ในทางปฏิบัติ สวิตช์ทั้งสี่ตัวคือ MOSFET (แนะนำในหน้า การแปลงระดับสัญญาณ) ภายใน IC ขับแบบรวม ชิปเปิดเผยพินอินพุตระดับลอจิกสองหรือสามพินที่แมปภายในกับสวิตช์ทั้งสี่ตัว และมีวงจรอินเตอร์ล็อคที่ป้องกัน shoot-through ทำให้โค้ดของกล้องไม่ต้องจัดการโดยตรง

3.15.2. PWM และความเหนี่ยวนำของมอเตอร์

การปรับ ความเร็ว มอเตอร์ต้องการมากกว่าแค่เปิดเต็มหรือปิดสนิท เทคนิคเดียวกับที่ใช้กับ LED ใน การหรี่ LED ด้วย PWM: พัลส์การขับที่ความถี่สูงและให้โหลดเฉลี่ยผล สำหรับ LED ตัวเฉลี่ยคือดวงตา สำหรับมอเตอร์คือขดลวดนั่นเอง

ขดลวดมอเตอร์มีความเหนี่ยวนำสูง กระแสผ่านตัวเหนี่ยวนำไม่สามารถเปลี่ยนแปลงทันทีทันใด มันเปลี่ยนด้วยอัตราตามแรงดันคร่อม การพัลส์ bridge เปิดปิดที่ 20 kHz ทำให้กระแสในขดลวดเพิ่มขึ้นในช่วงเปิดแต่ละครั้ง และในช่วงปิด กระแสยังต้องไหลต่อ -- ขดลวดกลับแรงดันคร่อมตัวเองเพื่อรักษากระแส

หากไม่มีทางออก กระแสนั้นจะสไปค์แรงดันข้ามสวิตช์ที่เพิ่งเปิดขึ้นและอาจทำลายทรานซิสเตอร์ Freewheeling diode ข้ามแต่ละสวิตช์ -- มักเป็นแค่ body diode ของ MOSFET เองภายในชิปขับ -- ให้กระแสมีเส้นทาง มันไหลผ่าน diode และวนกลับผ่านสวิตช์ที่ปิดอยู่ตัวใดตัวหนึ่ง สร้าง freewheel loop ที่กระแสค่อยๆ ลดลงผ่านความต้านทานเล็กน้อยของ bridge และมอเตอร์เอง diode ยังหนีบแรงดันข้ามสวิตช์ที่เปิดไว้ภายในระดับ diode drop ของราวที่ loop กลับ ซึ่งอยู่ในพื้นที่ปฏิบัติงานที่ปลอดภัยของ MOSFET

ค่าเฉลี่ย ของกระแสในแต่ละรอบ PWM คือสิ่งที่ผลิตแรงบิด และค่าเฉลี่ยนั้นติดตาม duty cycle เป็นเส้นตรง -- การเพิ่ม duty เป็นสองเท่าทำให้แรงบิดเพิ่มประมาณสองเท่า และที่โหลดคงที่ความเร็วก็เพิ่มประมาณสองเท่า ต่างจาก LED dimming ที่การตอบสนองแบบไม่เชิงเส้นของดวงตาต้องการเส้นโค้ง การกวาด duty_u16 เป็นเส้นตรงสอดคล้องกับการกวาดแรงดันมอเตอร์เป็นเส้นตรงอยู่แล้ว

ความถี่ PWM ต้องผ่านค่าขีดแบ่งสองอย่างเท่านั้น:

  • เหนือ ~20 kHz คลื่นพาหะอยู่นอกช่วงการได้ยินของมนุษย์ ต่ำกว่านั้น แรงแม่เหล็กบนขดลวดจะเพิ่มขึ้นและลดลงตามพัลส์ PWM แต่ละครั้ง และขดลวดกับแผ่นเหล็กลามิเนตสั่นสะเทือนทางกายภาพที่ความถี่พาหะ -- มอเตอร์กลายเป็นลำโพงเล็กๆ ที่ส่งเสียงที่ความถี่ PWM

  • สูงกว่า ~50 kHz มาก MOSFET และไดรเวอร์เกตเริ่มสูญเสียประสิทธิภาพจาก switching loss ในแต่ละการเปลี่ยนสถานะ MOSFET รับทั้งแรงดันและกระแสสูงชั่วคราว ทำให้พลังงานกระจายเป็นความร้อน ความจุเกตของ MOSFET ต้องถูกชาร์จและดิสชาร์จทุกรอบ ซึ่งชิปขับต้องรับผิดชอบ ทั้งสองต้นทุนขยายตามความถี่ PWM ดังนั้นที่อัตราสูง ความร้อนจาก switching อาจเทียบเท่ากับความร้อนจากการนำกระแสมอเตอร์

20 kHz คือค่าเริ่มต้นที่เหมาะสมสำหรับมอเตอร์งานอดิเรก

3.15.3. การขับ H-bridge

ชิปขับ H-bridge แบบสองอินพุตแมป IN1 และ IN2 กับสวิตช์สี่ตัวโดยประมาณดังนี้:

  • IN1 = 0, IN2 = 0 -- coast (สวิตช์ทั้งสี่เปิด)

  • IN1 = 1, IN2 = 0 -- ขับในทิศทางหนึ่ง

  • IN1 = 0, IN2 = 1 -- ขับในทิศทางอื่น

  • IN1 = 1, IN2 = 1 -- เบรก

การขับอินพุตทั้งสองเป็นเอาต์พุต PWM ให้กล้องกำหนดทิศทางโดยเลือก พิน ใดพินหนึ่งจากสองพินรับ duty และความเร็วโดยค่า duty เอง:

import time
from machine import PWM, Pin

in1 = PWM(Pin("P7"), freq=20_000, duty_u16=0)
in2 = PWM(Pin("P8"), freq=20_000, duty_u16=0)

def drive_a(speed):       # speed: 0..65535
    in1.duty_u16(speed)
    in2.duty_u16(0)

def drive_b(speed):
    in1.duty_u16(0)
    in2.duty_u16(speed)

def coast():
    in1.duty_u16(0)
    in2.duty_u16(0)

def brake():
    in1.duty_u16(65535)
    in2.duty_u16(65535)

drive_a(32768)    # half speed in direction A
time.sleep(2)
drive_b(16384)    # quarter speed in direction B
time.sleep(2)
coast()

การกวาดจากปิดไปเต็มและกลับทำให้เริ่มและหยุดได้อย่างนุ่มนวล:

for d in range(0, 65535, 256):
    in1.duty_u16(d)
    time.sleep_ms(10)
for d in range(65535, 0, -256):
    in1.duty_u16(d)
    time.sleep_ms(10)

3.15.4. ไดรเวอร์แบบทิศทางและความเร็ว

ชิป H-bridge ตระกูลที่สองเปิดเผยอินเทอร์เฟซที่สะดวกกว่า: อินพุตดิจิทัล ทิศทาง หนึ่งตัว (มักติดป้าย DIR หรือ PH สำหรับ "phase") บวกกับอินพุต ความเร็ว หนึ่งตัว (มักเป็น PWM หรือ EN สำหรับ "enable") พินทิศทางเลือกว่า bridge จะขับทางไหน duty cycle บนพินความเร็วกำหนดกระแสเฉลี่ย

วิธีนี้ขับจากซอฟต์แวร์ได้ง่ายกว่าแบบสองอินพุต PWM สัญญาณทั้งสองตรงกับวิธีที่มักตั้งปัญหา -- "หมุนทางนี้ ที่ความเร็วนี้" -- โค้ดจึงเขียน set_direction(forward); set_speed(50) แทนการแยกกิ่ง in1 กับ in2 ต้องการช่อง PWM เพียงช่องเดียว ทำให้อีกช่องในตัวจับเวลาเดียวกันว่างสำหรับงานอื่น และพินทิศทางสามารถคงค่าระหว่างการเปลี่ยนแปลงโดยไม่ trigger bridge ซ้ำ ดังนั้นการเปลี่ยนความเร็วที่ทิศทางคงที่แตะเพียงรีจิสเตอร์เดียว

import time
from machine import PWM, Pin

dir_pin = Pin("P8", Pin.OUT)
speed = PWM(Pin("P7"), freq=20_000, duty_u16=0)

def drive(direction, speed_u16):
    dir_pin.value(direction)         # 0 or 1
    speed.duty_u16(speed_u16)        # 0..65535

drive(0, 32768)     # direction A at half speed
time.sleep(2)
drive(1, 16384)     # direction B at quarter speed
time.sleep(2)
speed.duty_u16(0)   # stop

สิ่งที่ "หยุด" ทำจริงในไดรเวอร์ประเภทนี้ -- coast หรือเบรก -- ขึ้นอยู่กับชิป ด้วยไดรเวอร์สองอินพุต โค้ดของกล้องเลือกได้ (อินพุตทั้งสองต่ำสำหรับ coast ทั้งสองสูงสำหรับเบรก) ด้วยไดรเวอร์แบบทิศทางและความเร็ว ชิปเป็นผู้ตัดสินใจ ดังนั้นควรอ่าน data sheet ก่อนพึ่งพาพฤติกรรมใดก็ตาม