3.16. Điều khiển servo¶
Servo hobby (RC) là một động cơ nhỏ có hộp số trong vỏ kín với điều khiển vị trí vòng kín tích hợp bên trong. Bên trong vỏ là một động cơ DC, hộp số giảm tốc, một biến trở nối với trục ra, và một board driver nhỏ so sánh giá trị đọc từ biến trở với điểm đặt nhận từ bên ngoài. Driver chạy động cơ theo hướng nào giảm sai số, và dừng khi vị trí khớp. Từ phía camera, không cần biết tất cả điều đó -- bạn chỉ cần ra lệnh servo di chuyển đến đâu.
3.16.1. Tín hiệu PWM¶
Servo nhận điểm đặt của mình như một tín hiệu PWM ở tốc độ khung hình cố định 50 Hz, trong đó độ rộng xung chọn vị trí:
Xung 1,0 ms điều khiển trục đến một đầu hành trình.
Xung 1,5 ms đặt trục ở giữa.
Xung 2,0 ms điều khiển trục đến đầu kia.
Bất kỳ giá trị nào ở giữa tương ứng với vị trí trung gian.
Khung PWM của servo dài 20 ms; độ rộng xung (1,0 -- 2,0 ms) chọn vị trí.¶
Không giống như LED và động cơ, servo không lấy trung bình PWM. Bản thân độ rộng xung chính là lệnh: logic bên trong servo đo từng xung, đặt mục tiêu tương ứng, và chạy động cơ cho đến khi ngõ ra khớp. Duty cycle theo tỷ lệ phần trăm (từ 5% đến 10% trên toàn bộ phạm vi) chỉ là ngẫu nhiên -- điều quan trọng là độ rộng xung tuyệt đối, và đó là thứ phần mềm cần điều khiển.
3.16.2. Đấu dây¶
Servo hobby dùng đầu nối ba dây:
Nguồn (thường màu đỏ): nguồn cung cấp riêng của servo, thường 4,8 V đến 6 V. Không cấp nguồn cho servo từ đường ray 3,3 V của camera -- nó không thể cung cấp đủ dòng khi servo bị kẹt, và đường ray sẽ bị sụt áp.
GND (thường màu đen hoặc nâu): đường hồi cho nguồn của servo, nối với mass của camera để tín hiệu cũng có chung điểm tham chiếu.
Tín hiệu (thường màu trắng, vàng, hoặc cam): đường PWM từ GPIO của camera.
3.16.3. Code¶
duty_u16() có thể dùng được, nhưng nó đặt duty cycle theo tỷ lệ phần trăm của chu kỳ -- bất tiện với tín hiệu mà độ rộng xung tuyệt đối mới là điều quan trọng và chu kỳ là cố định. duty_ns() đặt độ rộng xung trực tiếp bằng nanosecond:
from machine import PWM, Pin
servo = PWM(Pin("P7"), freq=50, duty_ns=1_500_000) # centre
Sóng mang là 50 Hz (chu kỳ 20 ms); thời gian cao trong mỗi chu kỳ là chính xác 1500 µs. Một hàm trợ giúp nhỏ làm rõ việc ánh xạ từ vị trí sang xung:
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
Quét chậm qua toàn bộ phạm vi:
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)
Phạm vi 1,0 -- 2,0 ms là tiêu chuẩn, nhưng nhiều servo chấp nhận phạm vi rộng hơn (thường là 500 µs đến 2500 µs) để đạt hành trình đầy đủ. Datasheet của servo liệt kê giới hạn độ rộng xung chính xác; các giá trị ngoài phạm vi đó có thể đập mạnh động cơ vào điểm dừng cơ học.
Với servo có phạm vi không tiêu chuẩn, đưa các giới hạn vào hằng số và tham số hóa việc ánh xạ:
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)