3.16. การควบคุมเซอร์โว¶
เซอร์โวงานอดิเรก (RC) คือมอเตอร์เกียร์ขนาดเล็กในกล่องปิดสนิทพร้อมการควบคุมตำแหน่งแบบวงปิดในตัว ภายในกล่องมี DC มอเตอร์ กล่องเกียร์ทด โพเทนชิโอมิเตอร์ต่อกับเพลาเอาต์พุต และบอร์ดไดรเวอร์ขนาดเล็กที่เปรียบเทียบค่าของโพเทนชิโอมิเตอร์กับ setpoint ที่ส่งเข้ามาจากภายนอก ไดรเวอร์เดินมอเตอร์ในทิศทางที่ลดค่าความผิดพลาด และหยุดเมื่อตำแหน่งตรงกัน จากฝั่งกล้องไม่มีสิ่งใดเหล่านี้มองเห็นได้ -- เพียงแค่บอกเซอร์โวว่าจะไปที่ไหน
3.16.1. สัญญาณ PWM¶
เซอร์โวรับ setpoint เป็นสัญญาณ PWM ที่อัตราเฟรมคงที่ 50 Hz โดย ความกว้างพัลส์ เลือกตำแหน่ง:
พัลส์ 1.0 ms ขับเพลาไปยังปลายด้านหนึ่งของการเดินทาง
พัลส์ 1.5 ms จอดเพลาที่ตำแหน่งกึ่งกลาง
พัลส์ 2.0 ms ขับเพลาไปยังปลายอีกด้านหนึ่ง
ค่าที่อยู่ระหว่างนั้นแมปกับตำแหน่งกลางๆ
เฟรม PWM ของเซอร์โวยาว 20 ms ความกว้างพัลส์ (1.0 -- 2.0 ms) เลือกตำแหน่ง¶
ต่างจาก LED และมอเตอร์ เซอร์โวไม่ได้ เฉลี่ย PWM ความกว้างพัลส์เองคือคำสั่ง ลอจิกภายในของเซอร์โววัดแต่ละพัลส์ กำหนดเป้าหมายตามนั้น และเดินมอเตอร์จนกว่าเอาต์พุตจะตรงกัน duty cycle เป็นเศษส่วน (ระหว่าง 5 % ถึง 10 % ตลอดช่วงทั้งหมด) เป็นเรื่องบังเอิญ -- ความกว้างพัลส์แบบสัมบูรณ์คือสิ่งที่สำคัญ ซึ่งเป็นสิ่งที่ซอฟต์แวร์ต้องควบคุม
3.16.2. การต่อวงจร¶
เซอร์โวงานอดิเรกใช้ขั้วต่อสามสาย:
Power (มักเป็นสีแดง): แหล่งจ่ายของเซอร์โวเอง โดยทั่วไป 4.8 V ถึง 6 V อย่าจ่ายไฟเซอร์โวจากราว 3.3 V ของกล้อง -- มันไม่สามารถจ่ายกระแส stall ได้ และราวจะตกแรงดัน
Ground (มักเป็นสีดำหรือน้ำตาล): เส้นทางกลับสำหรับไฟของเซอร์โว ต่อกับกราวด์ของกล้องเพื่อให้สัญญาณมีอ้างอิงร่วมกัน
Signal (มักเป็นสีขาว เหลือง หรือส้ม): สาย PWM จาก GPIO ของกล้อง
3.16.3. โค้ด¶
duty_u16() ใช้งานได้ แต่กำหนด duty เป็นเศษส่วนของรอบ -- ไม่สะดวกสำหรับสัญญาณที่ความกว้างพัลส์แบบสัมบูรณ์คือสิ่งสำคัญและรอบคงที่ duty_ns() กำหนดความกว้างพัลส์โดยตรงเป็นนาโนวินาที:
from machine import PWM, Pin
servo = PWM(Pin("P7"), freq=50, duty_ns=1_500_000) # centre
คลื่นพาหะคือ 50 Hz (รอบ 20 ms) เวลาสูงในแต่ละรอบคือ 1500 µs พอดี ตัวช่วยเล็กๆ ทำให้การแมปตำแหน่งเป็นพัลส์ชัดเจน:
def set_position(angle):
# angle: 0..180 degrees mapped to 1.0..2.0 ms
pulse_us = 1000 + (angle * 1000) // 180
servo.duty_ns(pulse_us * 1000)
set_position(0) # full one way
set_position(90) # centre
set_position(180) # full the other way
การกวาดช้าๆ ตลอดช่วง:
import time
for angle in range(0, 181, 5):
set_position(angle)
time.sleep_ms(20)
for angle in range(180, -1, -5):
set_position(angle)
time.sleep_ms(20)
ช่วง 1.0 -- 2.0 ms คือมาตรฐาน แต่เซอร์โวหลายตัวรับช่วงที่กว้างกว่า (มักเป็น 500 µs ถึง 2500 µs) สำหรับการเดินทางเต็มที่ data sheet ของเซอร์โวระบุขีดจำกัดความกว้างพัลส์ที่แน่นอน ค่าที่อยู่นอกช่วงนั้นอาจฟาดมอเตอร์เข้ากับจุดหยุดทางกล
สำหรับเซอร์โวที่มีช่วงไม่ได้มาตรฐาน ให้ยกขีดจำกัดไปไว้ในค่าคงที่และกำหนดพารามิเตอร์การแมป:
PULSE_MIN_US = 500 # full one way (from the data sheet)
PULSE_MAX_US = 2500 # full the other way
def set_position(angle):
span_us = PULSE_MAX_US - PULSE_MIN_US
pulse_us = PULSE_MIN_US + (angle * span_us) // 180
servo.duty_ns(pulse_us * 1000)