무선 조종(RC) 서보는 취미용 항공기, 자동차, 보트의 핵심입니다. 원격 무선 명령을 정밀한 각도 위치로 변환합니다. RC 시스템이 수십 년 된 만큼 업계 표준 인터페이스는 순수 디지털 프로토콜이 아닌 펄스 폭 변조(PWM)입니다. FPGA가 제공하는 결정론적 타이밍으로 고정밀 PWM 구현은 간단합니다. 이 글은 PWM을 사용하는 모든 RC 서보와 호환되는 제네릭 VHDL 서보 컨트롤러를 시뮬레이션 테스트벤치와 Lattice iCEstick FPGA 보드 실구현 예제와 함께 안내합니다.
RC 서보용 PWM 제어 원리
PWM 기초는 다른 곳에서 다루지만, RC 서보는 약간 다른 접근이 필요합니다. 서보는 전체 듀티 사이클을 무시하고 각 펄스의 하이 기간 지속시간만 샘플링합니다. 펄스 간 표준 간격은 20ms로 50Hz 주파수에 해당. 20ms 윈도우 내에서 서보가 읽는 펄스 폭은 일반적으로 1ms(최소 위치)~2ms(최대 위치)이나 제조사마다 정확한 값은 다릅니다.
위 그림은 타이밍 관계: 20ms 주기 반복, 각 펄스의 하이 타임이 서보 각도 위치에 직접 매핑.
VHDL 서보 컨트롤러
클럭 주파수, PWM 펄스 주파수, 최소/최대 펄스 폭(마이크로초), 극단 사이 이산 위치 수를 제네릭 파라미터로 받는 제네릭 VHDL 모듈 제작. FPGA 클럭이 메가헤르츠 대역이라 정수 카운터 연산으로 충분한 해상도 확보. 반올림 모호성 방지 위해 ieee.math_real 패키지의 round 함수 사용(영에서 멀어지는 방향 반올림).
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.round;
서보 모듈 엔티티 선언:
entity servo is generic ( clk_hz : real; pulse_hz : real; -- PWM pulse frequency min_pulse_us : real; -- microseconds at minimum position max_pulse_us : real; -- microseconds at maximum position step_count : positive -- Number of discrete positions ); port ( clk : in std_logic; rst : in std_logic; position : in integer range 0 to step_count - 1; pwm : out std_logic ); end servo;
position 입력이 서보를 최소(0)에서 최대(step_count-1) 설정으로 구동. pwm 출력은 서보 신호선(보통 노란색/흰색)에 연결. 대부분 FPGA가 3.3V 로직 출력이라 서보의 5V 입력에 맞추려면 레벨 시프터 필요.
선언부
마이크로초 단위 시간을 가장 가까운 정수 클럭 사이클 수로 변환하는 헬퍼 함수 정의:
function cycles_per_us (us_count : real) return integer is begin return integer(round(clk_hz / 1.0e6 * us_count)); end function;
constant counter_max : integer := integer(round(clk_hz / pulse_hz)) - 1; signal counter : integer range 0 to counter_max; signal duty_cycle : integer range 0 to max_count;
클럭 사이클 카운팅
다음 프로세스가 프리러닝 카운터 구현:
COUNTER_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then counter <= 0; else if counter < counter_max then counter <= counter + 1; else counter <= 0; end if; end if; end if; end process;
PWM 출력 프로세스
PWM 출력은 현재 duty_cycle 값이 지시하는 카운터 사이클 수만큼 하이 유지:
PWM_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then pwm <= '0'; else pwm <= '0'; if counter < duty_cycle then pwm <= '1'; end if; end if; end if; end process;
듀티 사이클 계산
리셋 시 duty_cycle은 최소 펄스 폭 기본값. 그 외엔 position 입력으로부터 계산:
DUTY_CYCLE_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then duty_cycle <= min_count; else duty_cycle <= position * cycles_per_step + min_count; end if; end if; end process;
cycles_per_step이 정수로 반올림되지만, FPGA 클럭이 50Hz 펄스 레이트보다 수십 배 빠르므로 결과 오차 무시 가능.
서보 테스트벤치
설계 검증 위해 모든 위치 값을 수동으로 순회하며 파형 캡처하는 간단 테스트벤치 구축. 1MHz 테스트 클럭으로 시뮬레이션 가속하면서 현실적 타이밍 반영.
시뮬레이션 상수
constant clk_hz : real := 1.0e6; constant clk_period : time := 1 sec / clk_hz; constant pulse_hz : real := 50.0; constant pulse_period : time := 1 sec / pulse_hz; constant min_pulse_us : real := 1000.0; constant max_pulse_us : real := 2000.0; constant step_count : positive := 5;
DUT 신호
signal clk : std_logic := '1'; signal rst : std_logic := '1'; signal position : integer range 0 to step_count - 1; signal pwm : std_logic;
시퀀서가 DUT 리셋 후 모든 위치 값 순회, 변경 간격 한 펄스 주기 대기. 시퀀스 완료 후 시뮬레이션 종료.
SEQUENCER : process begin wait for 10 * clk_period; rst <= '0'; wait for pulse_period; for i in 0 to step_count - 1 loop position <= i; wait for pulse_period; end loop; report "Simulation done. Check waveform."; finish; end process;
서보 시뮬레이션 파형
다음 스냅샷은 테스트벤치 파형. PWM 출력은 각 위치 값에 맞는 예상 펄스 폭으로 초기 카운터 사이클 동안만 하이.
전체 프로젝트 파일 다운로드로 시뮬레이션 재현 가능.
FPGA 구현 예제
Lattice iCEstick 보드에서 실제 TowerPro SG90 서보 구동. 서보가 5V 로직 레벨 필요하므로 FPGA 핀과 서보 신호선 사이에 레벨 시프터 사용.
최상위 모듈 엔티티
entity top is port ( clk : in std_logic; rst_n : in std_logic; -- Pull-up pwm : out std_logic ); end top;
신호와 상수
서보 펄스 폭 실험적 보정: 0.5ms~2.5ms로 180° 풀 스윕. 다음 상수는 iCEstick 클럭과 서보 파라미터 매칭.
constant clk_hz : real := 12.0e6; -- iCEstick clock constant pulse_hz : real := 50.0; constant min_pulse_us : real := 500.0; -- 0.5 ms constant max_pulse_us : real := 2500.0; -- 2.5 ms constant step_bits : positive := 8; -- 0 to 255 constant step_count : positive := 2**step_bits;
signal rst : std_logic; signal position : integer range 0 to step_count - 1; signal rom_addr : unsigned(step_bits - 1 downto 0); signal rom_data : unsigned(step_bits - 1 downto 0);
전체 회로 브레드보드 구성: FPGA 3.3V 출력을 레벨 시프터로 5V 변환해 서보에 연결. PWM 신호는 iCEstick 핀 119에 연결. 전원 인가 시 서보가 0°~180° 사이 부드럽게 진동하며 극단에서 잠시 정지. 오실로스코프 PWM 파형 영상으로 올바른 타이밍 확인.
마무리
VHDL로 PWM 서보 컨트롤러 구현하는 방법 여럿 있지만 정수 카운터 사용하면 합성 로직이 단순(카운터, 레지스터, 멀티플렉서만). 가장 흔한 함정은 32비트 산술에서 무음 오버플로이므로, 선택한 파라미터로 중간 계산이 범위 내에 있는지 항상 검증해야 합니다.
이 PWM 스타일은 RC 서보 전용. 듀티 사이클이 주파수보다 중요한 애플리케이션(아날로그 전력 제어 등)엔 다른 PWM 전략이 바람직.