Merancang Pengontrol Servo RC Berbasis FPGA dengan PWM Presisi
Servo radio-kontrol (RC) adalah jantung pesawat, mobil, dan kapal hobi. Mereka menerjemahkan perintah radio jarak jauh menjadi posisi sudut yang tepat. Karena sistem RC sudah ada selama beberapa dekades, antarmuka standar industri adalah modulasi lebar pulsa (PWM) daripada protokol digital murni. Dengan waktu yang deterministik yang ditawarkan oleh lapangan gate array yang dapat diprogram (FPGA), implementasi PWM presisi tinggi adalah mudah. Artikel ini memandu Anda melalui pengontrol servo VHDL generik yang bekerja dengan setiap servo RC menggunakan PWM, termasuk testbench simulasi dan implementasi dunia nyata pada papan FPGA Lattice iCEstick.
Bagaimana PWM Kontrol untuk Servo RC Bekerja
Sementara dasar-dasar PWM dibahas di tempat lain, servo RC memerlukan pendekatan yang sedikit berbeda. Servo mengabaikan siklus kerja penuh; ia hanya mengecek durasi periode tinggi dari setiap pulsa. Interval standar di antara pulsa adalah 20 ms, yang sesuai dengan frekuensi 50 Hz. Dalam jendela 20 ms tersebut, servo membaca pulsa yang lebarnya biasanya berkisar dari 1 ms (posisi minimum) hingga 2 ms (posisi maksimum), meskipun nilai yang tepat bervariasi menurut produsen.
Gambar ini menunjukkan hubungan waktu: periode 20 ms berulang, dan waktu tinggi dari setiap pulsa langsung memetakan ke posisi sudut servo.
Pengontrol Servo VHDL
Kami akan membangun modul VHDL generik yang menerima parameter generik untuk frekuensi clock, frekuensi pulsa PWM, lebar pulsa minimum dan maksimum (dalam mikrodetik), dan jumlah posisi diskrit antara ekstrem. Karena clock FPGA berjalan dalam rentang megahertz, aritmetika counter integer memberikan resolusi yang cukup. Untuk menghindari ambigu pembulatan, kami akan menggunakan fungsi round dari paket ieee.math_real, yang selalu membulatan jauh dari nol.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.math_real.round;
Berikut adalah deklarasi entitas untuk modul servo:
entity servo is generic ( clk_hz : real; pulse_hz : real; -- frekuensi pulsa PWM min_pulse_us : real; -- mikrodetik pada posisi minimum max_pulse_us : real; -- mikrodetik pada posisi maksimum step_count : positive -- Jumlah posisi diskrit ); port ( clk : in std_logic; rst : in std_logic; position : in integer range 0 to step_count - 1; pwm : out std_logic ); end servo;
Input position menggerakkan servo dari minimum (0) hingga pengaturan maksimum (step_count‑1). Output pwm terhubung ke kabel sinyal servo (biasanya kuning atau putih). Sebagian besar FPGA mengeluarkan logika 3.3 V, jadi penggeser level diperlukan untuk mencocokkan input 5 V servo.
Wilayah Deklaratif
Kami memulai dengan mendefinisikan fungsi pembantu yang mengubah waktu dalam mikrodetik ke bilangan integer siklus clock terdekat:
function cycles_per_us (us_count : real) return integer is begin return integer(round(clk_hz / 1.0e6 * us_count)); end function;
Menggunakan fungsi itu, kami menghitung konstanta timing inti:
Selanjutnya, kami menyiapkan counter PWM yang berjalan pada frekuensi pulsa yang diinginkan:
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;
Menghitung Siklus Clock
Proses berikut mengimplementasikan counter bebas berjalan:
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;
Proses Output PWM
Output PWM dijalankan tinggi untuk sebanyak siklus counter yang ditentukan oleh nilai duty_cycle saat ini:
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;
Menghitung Siklus Kerja
Pada reset, duty_cycle default ke lebar pulsa minimum. Lainnya, itu dihitung dari input 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;
Meskipun cycles_per_step dibulatkan ke integer terdekat, kesalahan yang dihasilkan tidak signifikan karena clock FPGA sangat lebih cepat daripada laju pulsa 50 Hz.
Testbench Servo
Untuk memverifikasi desain, kami membangun testbench sederhana yang secara manual melangkah melalui semua nilai posisi dan menangkap gelombang. Clock tes 1 MHz mempercepat simulasi sambil masih mencerminkan waktu yang realistis.
Konstanta Simulasi
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;
Sinyal DUT
signal clk : std_logic := '1'; signal rst : std_logic := '1'; signal position : integer range 0 to step_count - 1; signal pwm : std_logic;
Sequencer mereset DUT, kemudian melalui semua nilai posisi, menunggu satu periode pulsa di antara perubahan. Setelah menyelesaikan urutan, simulasi berakhir.
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;
Gelombang Simulasi Servo
Cuplikan berikut menunjukkan gelombang testbench. Output PWM hanya tinggi untuk siklus counter terawal, cocok dengan lebar pulsa yang diharapkan untuk setiap nilai posisi.
Unduh file proyek lengkap untuk mereproduksi simulasi.
Contoh Implementasi FPGA
Selanjutnya, kami menggerakkan servo TowerPro SG90 nyata dari papan Lattice iCEstick. Servo membutuhkan level logika 5 V, jadi kami menggunakan penggeser level di antara pin FPGA dan kabel sinyal servo.
Entitas Modul Top
entity top is port ( clk : in std_logic; rst_n : in std_logic; -- Pull‑up pwm : out std_logic ); end top;
Sinyal dan Konstanta
Kami mengkalibrasi lebar pulsa servo secara eksperimental: 0,5 ms hingga 2,5 ms menghasilkan ayunan 180° penuh. Konstanta berikut cocok dengan parameter clock dan servo iCEstick.
constant clk_hz : real := 12.0e6; -- clock iCEstick 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 hingga 255 constant step_count : positive := 2**step_bits;
Counter bebas berjalan 25 bit lebar, memberikan waktu wrap sekitar 2,8 detik pada clock 12 MHz.
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);
Seluruh rangkaian di breadboard: output 3,3 V FPGA di-level-shift ke 5 V untuk servo. Sinyal PWM terhubung ke pin 119 pada iCEstick. Khi dinyalakan, servo berosilasi halus antara 0° dan 180°, berhenti sejenak di ekstrem. Video gelombang PWM pada osiloskop menunjukkan waktu yang benar.
Pikiran Akhir
Ada banyak cara untuk mengimplementasikan pengontrol servo PWM dalam VHDL, tetapi menggunakan counter integer menjaga logika yang dihasilkan tetap sederhana—hanya counter, register, dan multiplexer. Penggolongan yang paling sering terjadi adalah overflow diam dalam aritmetika 32-bit, jadi selalu verifikasi bahwa perhitungan perantara tetap dalam batas untuk parameter yang Anda pilih.
Perhatikan bahwa gaya PWM ini disesuaikan untuk servo RC. Untuk aplikasi di mana siklus kerja lebih penting daripada frekuensi (misalnya, kontrol daya analog), strategi PWM yang berbeda lebih disarankan.
Siap mencoba sendiri? Unduh arsip ZIP yang berisi kode VHDL lengkap, testbench ModelSim, proyek iCEcube2, dan konfigurasi programmer dengan memasukkan alamat email Anda di bawah ini.