3.15. DC 모터 제어¶
DC 브러시 모터는 자기장 안의 축에 감긴 코일입니다. 코일에 전류를 흘리면 자기장이 코일에 힘을 가하고, 그 힘은 축에 토크로 작용합니다. 모터 내부의 브러시는 축이 회전할 때 코일에 흐르는 전류의 방향을 바꿔주어, 토크가 항상 같은 방향으로 축을 밀도록 합니다. 모터의 두 단자에 DC 전압을 가하면 축이 회전하고, 극성을 바꾸면 반대 방향으로 회전합니다.
모터는 일반적으로 카메라의 3.3 V 로직 레일보다 높은 공급 전압에서 수백 밀리암페어에서 수 암페어의 전류를 필요로 합니다. GPIO 핀은 약 25 mA 정도를 공급할 수 있으며 극성을 반전시킬 수 없습니다 – 두 레일만 구동할 수 있을 뿐입니다. 카메라와 모터 사이의 구동단은 모터 전류를 흘려보내고, 별도의 더 높은 전압의 모터 전원을 연결하며, 카메라가 명령에 따라 극성을 반전시킬 수 있게 해야 합니다. 네 개의 트랜지스터로 구성된 H-브리지가 표준적인 해답입니다.
3.15.1. H-브리지¶
H-브리지는 모터를 둘러싼 H자 형태로 배치된 네 개의 스위치입니다:
H-브리지: 네 개의 스위치(S1 – S4)가 Vmotor와 접지 사이에 모터 M을 연결합니다.¶
서로 다른 스위치 쌍을 닫으면 모터가 단자에서 보는 상태가 선택됩니다:
S1 + S4 닫힘, S2 + S3 열림. 전류는 Vmotor에서
S1을 통해A로, 모터를 가로질러B로, 그리고S4를 통해 접지로 흐릅니다. 모터가 한 방향으로 회전합니다.S2 + S3 닫힘, S1 + S4 열림. 전류가 모터를 통해 반대 방향으로 흐릅니다. 모터가 반대 방향으로 회전합니다.
네 개 모두 열림. 두 모터 단자가 모두 떠 있어, 모터가 관성으로 돕니다.
S3 + S4 닫힘(또는 S1 + S2 닫힘). 두 모터 단자가 같은 레일에 묶여, 모터 자신의 운동 에너지가 만들어내는 전류를 닫힌 쌍이 단락시켜 열로 소모합니다. 모터가 제동됩니다.
금지된 조합은 같은 열의 두 스위치를 동시에 닫는 것입니다 – S1 + S3 또는 S2 + S4 – 이는 Vmotor에서 접지로 곧장 이어지는 단락 회로를 형성합니다. 이것이 슛스루(shoot-through)이며, 카메라의 코드는 이를 허용해서는 안 됩니다.
실제로 네 개의 스위치는 통합 드라이버 IC 안에 있는 MOSFET(레벨 시프팅 페이지에서 소개됨)입니다. 이 칩은 내부적으로 네 스위치에 매핑되는 두세 개의 로직 레벨 입력 핀을 노출하며 슛스루를 방지하는 인터록 로직을 포함하므로, 카메라의 코드가 이를 직접 관리할 필요가 없습니다.
3.15.2. PWM과 모터의 인덕턴스¶
모터의 속도를 설정하려면 완전 켜짐과 완전 꺼짐만으로는 부족합니다. 그 비결은 PWM을 이용한 LED 디밍에서 LED에 사용한 것과 같습니다: 구동 신호를 높은 주파수로 펄스화하고 부하가 그 결과를 평균하도록 두는 것입니다. LED의 경우 평균을 내는 것은 눈이었고, 모터의 경우에는 코일 자체입니다.
모터 코일은 상당한 인덕턴스를 가지고 있습니다. 인덕터를 통과하는 전류는 순간적으로 변할 수 없으며, 양단에 걸린 전압에 비례하는 속도로 변합니다. 브리지를 20 kHz로 켜고 끄면 각 온(on) 구간 동안 코일 전류가 상승하고, 오프(off) 구간 동안에는 전류가 계속 흘러야 합니다 – 코일이 이를 유지하기 위해 양단 전압을 반전시킵니다.
흘러갈 곳이 없으면 그 전류는 방금 열린 스위치 양단의 전압을 위로 치솟게 하여 트랜지스터를 손상시킬 수 있습니다. 각 스위치에 걸쳐 있는 프리휠링 다이오드 – 흔히 드라이버 칩 내부 MOSFET 자체의 바디 다이오드 – 가 전류에 필요한 경로를 제공합니다. 전류는 다이오드를 통해 흐른 뒤 아직 닫혀 있는 스위치 중 하나를 통해 되돌아 흐르며, 브리지와 모터 자체의 작은 저항을 통해 전류가 서서히 감쇠하는 프리휠 루프를 완성합니다. 또한 다이오드는 열린 스위치 양단의 전압을 루프가 되돌아가는 레일에서 다이오드 전압 강하 이내로 고정시켜, MOSFET의 안전 동작 영역 안에 충분히 머물게 합니다.
각 PWM 주기에 걸친 전류의 평균이 토크를 만들어내며, 그 평균은 듀티 사이클을 선형적으로 따라갑니다 – 듀티를 두 배로 하면 토크가 대략 두 배가 되고, 부하가 일정할 때 속도도 대략 두 배가 됩니다. 눈의 비선형 반응 때문에 곡선이 필요한 LED 디밍과 달리, duty_u16의 선형적인 스윕이 이미 모터 출력의 선형적인 스윕에 대응합니다.
PWM 주파수는 두 가지 임계값만 넘으면 됩니다:
약 20 kHz 이상이면 반송파가 사람의 가청 대역을 벗어납니다. 그 아래에서는 코일에 작용하는 자기력이 각 PWM 펄스마다 상승하고 하강하며, 권선과 적층 철심이 반송파 주파수로 물리적으로 진동합니다 – 모터가 사실상 PWM 음높이로 소리를 내는 작은 스피커가 됩니다.
약 50 kHz를 훨씬 넘어서면 MOSFET과 그 게이트 드라이버가 스위칭 손실로 인해 효율을 잃기 시작합니다. 각 온-오프 전환 동안 MOSFET은 잠시 상당한 전압과 상당한 전류를 동시에 부담하여 작은 전력을 열로 소모합니다. 또한 MOSFET의 게이트 정전 용량을 매 사이클마다 충전하고 방전해야 하는데, 이는 드라이버 칩이 부담합니다. 두 비용 모두 PWM 주파수에 비례하므로, 높은 주파수에서는 스위칭으로 인한 열이 모터 전류를 흘리는 데서 나오는 열에 맞먹을 수 있습니다.
20 kHz는 취미용 크기의 모터에 적합한 기본값입니다.
3.15.3. H-브리지 구동하기¶
두 입력 H-브리지 드라이버 칩은 IN1과 IN2를 대략 다음과 같이 네 스위치에 매핑합니다:
IN1 = 0, IN2 = 0– 관성 주행(네 스위치 모두 열림).IN1 = 1, IN2 = 0– 한 방향으로 구동.IN1 = 0, IN2 = 1– 다른 방향으로 구동.IN1 = 1, IN2 = 1– 제동.
두 입력을 PWM 출력으로 구동하면, 카메라는 두 핀 중 어느 핀에 듀티를 실을지 선택하여 방향을 정하고, 듀티 값 자체로 속도를 정할 수 있습니다:
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-브리지 칩은 더 편리한 인터페이스를 제공합니다: 하나의 디지털 방향 입력(흔히 DIR 또는 “위상”을 뜻하는 PH로 표기됨)과 하나의 속도 입력(흔히 PWM 또는 “enable”을 뜻하는 EN)입니다. 방향 핀은 브리지가 구동할 방향을 선택하고, 속도 핀의 듀티 사이클은 평균 전류를 설정합니다.
이 방식은 두 PWM 입력 방식보다 소프트웨어에서 구동하기 더 쉽습니다. 두 신호는 문제가 보통 표현되는 방식 – “이 방향으로, 이 속도로 돌려라” – 과 일치하므로, 코드는 in1과 in2 사이에서 분기하는 대신 set_direction(forward); set_speed(50)이라고 쓸 수 있습니다. PWM 채널이 하나만 필요하므로, 같은 타이머의 다른 채널을 별개의 작업에 쓸 수 있습니다. 그리고 방향 핀은 변경 사이에 브리지를 다시 트리거하지 않고 그대로 둘 수 있으므로, 방향을 고정한 채 속도를 바꾸는 것은 단 하나의 레지스터만 건드립니다.
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
이런 종류의 드라이버에서 “정지”가 실제로 무엇을 하는지 – 관성 주행인지 제동인지 – 는 칩에 따라 다릅니다. 두 입력 드라이버에서는 카메라의 코드가 선택하지만(관성 주행은 두 입력 모두 로우, 제동은 두 입력 모두 하이), 방향-속도 드라이버에서는 칩이 결정하므로, 어느 한쪽 동작에 의존하기 전에 데이터시트를 한번 살펴볼 가치가 있습니다.