Joystick analog ialah dua potentiometer pada sudut tepat berserta satu butang tekan, jadi anda membacanya dengan analogRead() pada dua pin analog β tetapi satu baris yang semua orang tulis mula-mula, servo.write(map(analogRead(A0),0,1023,0,180)), menghasilkan pan-tilt yang merayap sendiri lalu melompat balik ke tengah. Betulkannya dengan mengukur di mana stick anda benar-benar berehat, dan dengan membiarkan sesaran menetapkan kelajuan, bukan sudut.
Apa yang anda perlukan untuk membina pan-tilt kawalan joystick?
Modul joystick HW-504 ialah board hitam dengan penutup ibu jari hitam matte, dua potentiometer hijau mint di bawah gimbalnya dan satu header male lima pin yang lurus. Dua servo mikro TowerPro MG90S memberikan pan dan tilt; ia tiba sebagai motor berserta wayarnya sahaja, jadi bracket ialah sebahagian daripada binaan ini.
Senarai komponen β joystick analog dan dua servo MG90S pada pan-tilt Arduino Uno
Pilihan β kuasa berasingan untuk servo dan kabel USB
Pemegang 4xAA inilah penyelesaian bila dua servo membuatkan Uno berkuasa USB brownout: empat sel bersiri memberi 6 V nominal, tepat di dalam rating MG90S 4.8β6 V, dan ia membekalkan servo sahaja. Soket pada Uno pula menerima plug USB-B bersaiz penuh (jenis printer) β tambah satu kalau bentuk segi empat itu belum ada dalam laci anda.
Dua pek jumper itu bukan berulang: penyambungnya menghadap arah bertentangan. Joystick membawa pin male, jadi ia perlukan hujung female jumper male-to-female untuk sampai ke Uno dan ke breadboard. Wayar setiap servo pula berakhir dengan soket female tiga laluan, jadi ia perlukan jumper male-to-male β sama seperti dua sambungan dari Uno ke rel breadboard. Shield keypad joystick atau shield dua joystick melangkau pendawaian itu terus; Uno FT232 pula sesuai untuk PC yang bergelut dengan driver CH340.
Bagaimana sebenarnya modul joystick analog berfungsi?
Dua potentiometer pada HW-504 didawai sebagai pembahagi voltan merentasi +5 V dan GND yang sama yang anda bekalkan kepada modul itu, satu diputar oleh setiap paksi gimbal. Setiap wiper berayun dari hampir 0 V ke hampir 5 V sepanjang perjalanan stick, dan ADC 10-bit ATmega328P menukarkannya menjadi 0β1023 β lebih kurang 4.9 mV setiap kiraan.
Butang tekannya ialah suis tactile biasa antara pin SW dengan GND, tanpa perintang pull-up pada modul itu, jadi kalau dibiarkan pin tersebut terapung lalu membaca noise. pinMode(PIN_SW, INPUT_PULLUP) menghidupkan pull-up 20β50 kΞ© milik ATmega328P sendiri: pin itu kemudian duduk pada HIGH dan satu tekanan menariknya ke LOW.
Spring itu memulangkan stick hampir ke pusat elektriknya, bukan tepat kepadanya: toleransi acuan pada yoke dan pada trek pot meletakkan stick yang berehat di mana-mana antara 490-an tinggi hingga 530-an rendah, berbeza pada setiap paksi dan berbeza pada setiap modul. Stick yang berehat pada 507 memang tiada masalah. Menganggapnya 512 itu yang jadi masalah.

Bagaimana cara mendawai joystick dan dua servo ke Uno?
Uno hanya ada satu soket 5 V sedangkan binaan ini perlukan lebih banyak titik cabang, jadi rel breadboard yang memecahkannya. Bekalkan rel itu dari Uno dahulu. Periksa silkscreen joystick sebelum anda mengira pin: tulisannya GND, +5V, VRx, VRy, SW β ground dahulu, bukan susunan VCC-dahulu yang dipakai kebanyakan modul.
| Dari | Ke | Kenapa |
|---|---|---|
Uno 5V dan GND |
Rel + dan β sisi dekat |
Dua jumper male-to-male. Satu soket menjadi satu rel penuh |
Joystick +5V, GND |
Rel + dan β sisi dekat |
Menghidupkan kedua-dua pembahagi voltan daripada 5 V Uno. Bekalan 6 V di sini akan menolak voltan wiper melebihi rujukan ADC itu sendiri |
Joystick VRx, VRy |
A0, A1 |
Dua voltan wiper yang dibaca oleh ADC |
Joystick SW |
D2 |
Suis ke GND; sketch menghidupkan pull-up dalaman |
| Wayar oren servo pan | D9 |
Isyarat sahaja β satu denyut 1β2 ms setiap 20 ms |
| Wayar oren servo tilt | D10 |
Sama, saluran kedua |
| Wayar coklat kedua-dua servo | Rel β sisi jauh |
Menjauhkan arus balik servo daripada ground joystick |
| Wayar merah kedua-dua servo | Rel + sisi jauh |
Dibekalkan oleh bateri, tidak sekali-kali oleh Uno β lihat bahagian kuasa |
Rel β sisi dekat |
Rel β sisi jauh |
Ground sepunya. Satu jumper, dan itu sahajalah wayar yang menghubungkan dua bekalan itu |
Kekalkan dua bekalan itu pada tepi bertentangan board. Breadboard 400 titik membawa jalur + dan βnya sendiri di sepanjang setiap sisi panjang, jadi Uno membekalkan sepasang dan bateri sepasang lagi, dan jumper yang mengikat dua jalur β itu ialah satu-satunya wayar yang menyeberang antara keduanya. Sambungkan dua jalur + itu pula dan 6 V akan mendarat pada pin 5 V Uno β sambungan yang binaan ini tidak boleh buat sama sekali. Tanpa bateri, jambatan itulah cara servo berjalan daripada Uno, dan itu hanya untuk ujian ringkas tanpa beban.
Pin 9 dan 10 ialah pilihan lalai yang munasabah, bukan satu kemestian. Library Servo menuntut Timer1 pada attach() yang pertama, pin mana pun yang anda guna, dan Timer1 itulah hardware yang menjana PWM pada pin 9 dan 10 β jadi analogWrite() di situ berhenti berfungsi walau apa cara sekalipun. Pin 3, 5, 6 dan 11 kekal dengan PWM masing-masing.
Kenapa sketch map() satu baris yang nampak jelas itu hanyut dan menggeletar?
Sketch map() satu baris itu menyasarkan nombor yang salah. Joystick yang berehat pada 507 dipetakan kepada 89Β°, bukan 90Β°, jadi mount duduk tersasar satu darjah. Lebih teruk lagi, mod kedudukan membuatkan mount mengikut stick secara mutlak: lepaskan stick, spring memulangkannya ke tengah, dan kamera yang baru anda halakan tadi berayun balik ke tengah bilik. Itu hukum kawalan yang salah untuk sebuah mount, bukan bug yang boleh ditala sampai hilang.
Dead zone-nya kosong. Bacaan ADC merayau satu dua kiraan, dan map() menyebarkan 1023 kiraan merentasi 180Β°, jadi 5.7 kiraan sudah menjadi satu darjah. Satu darjah arahan itu lebih kurang 10 Β΅s denyut sedangkan dead band MG90S ialah 5 Β΅s β jadi gear train boleh bergerak berulang-alik sendiri pada stick yang tiada sesiapa sentuh.
Groundnya bergerak. Suspek yang paling jelas sebenarnya tidak bersalah: ADC mengukur terhadap rel 5 V yang sama yang menghidupkan potentiometer itu, jadi bila rel itu jatuh, voltan wiper turun seiringan dan bacaannya tidak berubah. Yang tidak membatal ialah arus balik. Dua servo menarik ratusan miliampere balik melalui jumper ground yang dikongsi dan sentuhan breadboard, dan 0.2 Ξ© pada laluan itu menukar 300 mA menjadi 60 mV sesaran ground β lebih kurang 12 kiraan ADC, muncul dan hilang mengikut gerakan servo.
Bagaimana anda buat stick mengawal kelajuan dan bukan sudut?
Kawalan halaju ialah satu perubahan kecil sahaja pada sketch joystick. Daripada sudut = f(stick) anda menulis sudut = sudut + f(stick): stick menetapkan berapa darjah ditambah setiap frame, melepaskannya menambah sifar, dan mount kekal di tempat yang anda halakan tadi. Ia juga memberi percuma pelicinan yang orang selalu tampal kemudian: sudut arahan hanya boleh bergerak paling banyak MAX_STEP setiap frame, jadi tiada bacaan β bising, tersasar atau apa sekalipun β yang mampu menggerakkan mount lebih laju daripada itu. Penapis purata menyerang noise itu; had kadar pula membuatkan noise tersebut tidak memudaratkan, sebesar mana pun ia.
Nombor-nombornya datang daripada servo itu sendiri. Ia menyegar semula setiap 20 ms, jadi frame yang lebih pendek hanya mengarahkan gerakan yang tidak mampu dilaksanakannya. Pada langkah stick penuh 1.5Β° setiap frame, mount menyapu 75Β°/s dan merentasi span pan 10Β°β170Β° dalam sketch ini dalam masa sedikit lebih dua saat β terkawal dan sesuai dirakam. MG90S dirating pada 0.08 s setiap 60Β°, iaitu 750Β°/s, jadi langkah 1.5Β° mengambil masa lebih kurang dua milisaat sahaja β selesai, dan menganggur sepanjang baki frame itu. Servo tidak pernah terkejar-kejar arahan, dan itulah sebabnya sapuannya nampak licin dan bukan tersentak-sentak. Dead zone 60 kiraan pula lima kali ganda bajet sesaran ground di atas, dan masih meninggalkan 88% perjalanan setiap arah untuk digunakan.
/*
Joystick analog (HW-504) -> dua servo MG90S, pan-tilt dengan kawalan HALAJU.
Library: Servo (disertakan bersama Arduino IDE).
Joystick GND -> rel GND +5V -> rel 5V
Joystick VRx -> A0 VRy -> A1 SW -> D2 (pull-up dalaman)
Wayar oren servo -> D9 (pan) dan D10 (tilt)
Wayar merah servo -> bateri 6V + Wayar coklat servo -> GND, dikongsi dengan Uno
SESARAN stick menetapkan KELAJUAN perubahan sudut, bukan sudut itu sendiri.
Lepaskan dan mount kekal di tempatnya. Tahan butang untuk membawanya balik ke tengah.
*/
#include <Servo.h>
const uint8_t PIN_VRX = A0;
const uint8_t PIN_VRY = A1;
const uint8_t PIN_SW = 2;
const uint8_t PIN_PAN = 9; // pin Timer1 - lihat artikel
const uint8_t PIN_TILT = 10;
const int DEADZONE = 60; // kiraan ADC di kiri-kanan nilai rehat yang diukur
const float MAX_STEP = 1.5; // darjah digerakkan setiap frame 20 ms pada stick penuh
const uint16_t FRAME_MS = 20; // satu tempoh segar semula servo
const int PAN_MIN = 10, PAN_MAX = 170; // jauhkan daripada hentian mekanikal
const int TILT_MIN = 30, TILT_MAX = 150;
Servo pan, tilt;
int restX, restY; // diukur semasa board hidup, bukan diandaikan 512
float panAngle = 90.0, tiltAngle = 90.0;
uint32_t lastFrame = 0, lastReport = 0;
// Buang penukaran pertama selepas mux berpindah, kemudian puratakan lapan.
int readAxis(uint8_t pin) {
analogRead(pin);
long sum = 0;
for (uint8_t i = 0; i < 8; i++) sum += analogRead(pin);
return (int)(sum / 8);
}
// Sesaran stick -> darjah setiap frame. Sifar dalam dead zone, MAX_STEP pada hujung.
float axisRate(int raw, int rest) {
int offset = raw - rest;
if (offset > -DEADZONE && offset < DEADZONE) return 0.0;
int span, past;
if (offset > 0) { past = offset - DEADZONE; span = 1023 - rest - DEADZONE; }
else { past = offset + DEADZONE; span = rest - DEADZONE; }
if (span < 1) span = 1;
float k = (float)past / (float)span;
if (k > 1.0) k = 1.0;
if (k < -1.0) k = -1.0;
return k * MAX_STEP;
}
void setup() {
Serial.begin(115200);
pinMode(PIN_SW, INPUT_PULLUP); // modul ini tiada pull-up sendiri
// KALIBRASI: baca di mana stick ANDA benar-benar berehat. Jangan sentuh semasa setup.
restX = readAxis(PIN_VRX);
restY = readAxis(PIN_VRY);
Serial.print(F("rest X = ")); Serial.print(restX);
Serial.print(F(" rest Y = ")); Serial.print(restY);
Serial.println(F(" (near 512, but neither will be exactly 512)"));
pan.attach(PIN_PAN);
tilt.attach(PIN_TILT);
pan.write((int)panAngle);
tilt.write((int)tiltAngle);
}
void loop() {
if (millis() - lastFrame < FRAME_MS) return;
lastFrame = millis();
int x = readAxis(PIN_VRX);
int y = readAxis(PIN_VRY);
if (digitalRead(PIN_SW) == LOW) {
// Butang ditahan: bawa balik ke tengah pada had kadar yang sama. Jangan melompat.
panAngle += constrain(90.0 - panAngle, -MAX_STEP, MAX_STEP);
tiltAngle += constrain(90.0 - tiltAngle, -MAX_STEP, MAX_STEP);
} else {
panAngle = constrain(panAngle - axisRate(x, restX), PAN_MIN, PAN_MAX);
tiltAngle = constrain(tiltAngle + axisRate(y, restY), TILT_MIN, TILT_MAX);
}
pan.write((int)(panAngle + 0.5));
tilt.write((int)(tiltAngle + 0.5));
// Nombor langsung supaya anda boleh lihat dead zone membuat kerjanya.
if (millis() - lastReport >= 500) {
lastReport = millis();
Serial.print(F("X ")); Serial.print(x);
Serial.print(F(" Y ")); Serial.print(y);
Serial.print(F(" pan ")); Serial.print((int)panAngle);
Serial.print(F(" tilt ")); Serial.println((int)tiltAngle);
}
}
Pada Uno, ini dikompil menjadi 6,030 bait flash β 18% daripada 32 KB β dan 252 bait RAM. Serial Monitor pada 115200 mencetak nilai rehat modul anda pada baris pertama. Luaskan DEADZONE kalau mount masih merayap sedangkan tangan anda langsung tidak menyentuh stick; tukar tanda pada satu panggilan axisRate kalau paksi itu bergerak ke arah bertentangan, atau tukar tempat PIN_VRX dengan PIN_VRY kalau pemasangan suku pusingan menyilangkan paksinya.
Bolehkah pin 5 V Arduino menghidupkan dua servo MG90S?
MG90S dirating 4.8β6 V dan menarik lebih kurang 10 mA ketika diam, 120β250 mA semasa bergerak dan sekitar 700 mA pada stall, iaitu angka bench dan bukan rating rasmi TowerPro. Dua yang bergerak serentak menjadi 240β500 mA, Uno sendiri mahu 40β50 mA lagi, dan laluan USB itu dikawal oleh polyfuse boleh set semula yang memutuskan sambungan melebihi 500 mA. Binaan ini duduk tepat pada garisan itu, bukan selesa di dalamnya, dan itulah sebabnya ia nampak menjadi sehinggalah servo tilt menerima beban lalu board reset.
Beri servo bekalan kuasanya sendiri. Empat sel AA bersiri di dalam pemegang bersuis memberi 6.0 V nominal, di dalam rating MG90S, dan set alkali baharu yang bermula pada lebih kurang 6.4 V akan turun ke paras itu di bawah beban. Wayar merahnya pergi ke rel + sisi jauh dan wayar hitamnya ke rel β sisi jauh β jangan sekali-kali ke pin 5 V Uno. Pin itu ialah output pengatur voltan, bukan input, dan semasa board berjalan atas USB ia duduk pada rel yang sama yang dibekalkan oleh port USB, jadi 6 V yang ditolak masuk di situ akan mengalir ke belakang melalui pengatur voltan dan naik ke kabel menuju port laptop anda. Pulas hujung wayar terdedah pemegang itu ketat-ketat sebelum ia masuk ke lubang breadboard.

Servo itu dipasang pada apa?
MG90S dihantar sebagai motor berserta wayarnya, dan itu menjadikan bracket satu keputusan reka bentuk. Dalam sebuah pan-tilt, servo bawah menanggung servo atas berserta apa sahaja yang duduk di atasnya, jadi bebannya ialah berat pada lengan tuas. Satu servo tilt dengan bracket ringan β 40 g pada lengan 3 cm β bersamaan lebih kurang 0.12 kgΒ·cm berbanding 2.2 kgΒ·cm MG90S pada 6 V. Letak pula telefon 200 g pada lengan 5 cm dan anda sudah meminta 1.0 kgΒ·cm: masih dalam rating di atas kertas. Tetapi yang merosakkan gear nylon jarang sekali beban mantap β ia adalah kejutan daripada terlanggar sesuatu atau daripada dipandu masuk ke hentian, yang tiba pada satu gigi serentak. Itulah hujahnya untuk gear logam pada paksi yang menanggung berat. Panduan perbandingan servo kami menghuraikan selebihnya pilihan itu.
Bracket itu cetak-sendiri atau buat-sendiri. Output MG90S ialah spline logam 21 gigi lebih kurang 4.7 mm garis pusatnya dengan lubang skru kecil di tengah, jadi soket bercetak ditekan masuk atas spline itu dan satu skru self-tapping M2 ke dalam lubang tersebut menghalangnya memanjat keluar di bawah beban β Smith3D membekalkan filamen dan printernya.
Pasang bracket sewaktu servo sudah dipusatkan. Aci servo duduk di mana ia ditinggalkan kali terakhir, jadi jalankan sketch dahulu dan biarkan setup() memandu kedua-dua servo ke 90Β°, kemudian tekan setiap bracket lurus ke bawah atas splinenya β lurus ke bawah, bukan diputar, kerana servo sedang menahan sudut itu. Pasangkannya pada aci yang tidak berpusat dan tengah mekanikal mount itu boleh mendarat di mana-mana: stick kehabisan sapuan pada satu arah dan melanggar hentian pada arah yang satu lagi.
Untuk demo di atas meja, kad tebal dan gam panas pun sudah memadai; tiada apa dalam sketch ini yang ambil kisah β dan sebaik mount itu berdiri diam, ESP32-CAM ialah benda yang paling jelas untuk diletakkan di atasnya. Video pemasangan ini menunjukkan gandingan itu dalam tangan:

Kesilapan biasa yang kami nampak daripada pelanggan sebenar
Menghidupkan kedua-dua servo daripada Uno, kemudian menyalahkan joystick. Bacaan melompat-lompat, mount tersekat-sekat, board restart β ketiga-tiganya ialah bajet arus di atas tadi, bukan stick yang rosak.
Membuat kalibrasi sambil tangan masih pada stick. Sketch ini mengukur nilai rehat sekali sahaja, di dalam setup(), dan setiap bacaan selepas itu ialah sesaran daripada nilai tersebut. Pegang stick semasa board boot β atau reset board di tengah-tengah anda mengemudi β dan mount mewarisi pusat yang palsu, jadi ia merayap walaupun stick sudah dilepaskan: itulah tepat-tepat hanyutan yang kalibrasi ini wujud untuk hapuskan. Lepaskan tangan, reset, dan perhatikan dua nombor rehat itu duduk pada pasangan yang sama.
Melawan servo secara mekanikal. Menulis 0Β° atau 180Β° ke dalam servo yang bracketnya menghentikannya lebih awal membuatkan ia menolak hentian itu lalu duduk di situ menarik arus stall sehingga ada sesuatu yang mengalah β itulah gunanya PAN_MIN dan TILT_MAX. Atas sebab yang sama, jangan sekali-kali memulas output servo yang bertenaga dengan tangan.
FAQ
Kenapa joystick Arduino saya baca 512 dan bukan 0?
Sebab ia memang berfungsi. Kedudukan tengah meletakkan setiap wiper di pertengahan treknya, jadi ia menghantar separuh daripada 5 V β lebih kurang 512 daripada 1023 kiraan ADC.
Kenapa joystick saya tidak baca tepat 512 semasa berehat?
Toleransi mekanikal pada gimbal dan pada trek pot. 490-an tinggi hingga 530-an rendah itu normal, dan dua paksi itu berbeza. Ukur kedua-duanya semasa board mula hidup.
Boleh tak saya jalankan dua servo daripada pin 5 V Arduino?
Untuk ujian ringkas tanpa beban sahaja. Dua MG90S yang bergerak serentak menarik 240β500 mA sedangkan bekalan USB Uno terputus melebihi 500 mA. Empat sel AA, ground diikat bersama, itulah susunan yang boleh diharap.
Kenapa library Servo merosakkan analogWrite pada pin 9 dan 10?
Ia mengambil alih Timer1, iaitu hardware yang menghasilkan PWM pada dua pin itu, pada attach() yang pertama β pin mana pun yang digunakan servo. Pin 3, 5, 6 dan 11 kekal dengan PWM mereka.
Perlukah saya guna shield joystick dan bukan modul biasa?
Tidak β kedua-duanya potentiometer pada pin analog, jadi codenya sama sahaja. Shield menjimatkan pendawaian; modul kosong pula boleh duduk di dalam enclosure pegang tangan.
Kemas kini terakhir Ogos 2026. Tersangkut? Chat dengan kami di WhatsApp.



Joystick Module X Y Z axis 5 Pin Analog Joy Stick Controller for Arduino Robotic
SG90 MG90 Tower Pro Micro Servo Motor 9g 180 360 Servo Motor for Arduino Robotic - MG90- 180Β°
Arduino Uno Compatible SMD UNO R3 with Type B Cable - ATMEGA328P with CH340G-Microcontroller Project
MB102 Breadboard 170 400 830 Holes Breadboard Donut Board Arduino Prototype Multi Color - BREADBOARD (400 HOLES)
40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-M 20CM
40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-F 20CM
AA Battery Holder with Cover On/Off Switch 2/3/4 Slots Battery AA Holder Red/Black Wire - AA BATTERY CASE (4S)
Data Cable Type-A Type-C MicroUSB Type-B 0.5m 1m 30cm 0.3m 100cm Data Transfer Upload Code - TYPE-A TO TYPE-B (1.0M)