ماژول جوی‌استیک PS2

(Dual-Axis Joystick Module)

کنترلر آنالوگ دو محوره برای پروژه‌های رباتیک و تعاملی

جوی‌استیک PS2: کنترلر آنالوگ حرفه‌ای با دقت بالا برای پروژه‌های رباتیک و رابط‌های کاربری

ماژول جوی‌استیک PS2 یک کنترلر آنالوگ دو محوره است که موقعیت دسته در دو محور X و Y را با استفاده از پتانسیومترهای دقیق اندازه‌گیری می‌کند. این ماژول با طراحی مشابه جوی‌استیک‌های کنترلرهای بازی، ابزاری ایده‌آل برای کنترل ربات‌ها، پهپادها، سیستم‌های CNC کوچک و پروژه‌های تعاملی می‌باشد.


ویژگی‌های حرفه‌ای و قابلیت‌های کلیدی

  • کنترل دو محوره: اندازه‌گیری همزمان موقعیت در محور X و Y.

  • خروجی آنالوگ دقیق: خروجی ولتاژ آنالوگ ۰-۵V متناسب با زاویه دسته.

  • دکمه فشار (SW): کلید فشاری متمرکز (مرکز دسته) برای عملکرد اضافی.

  • کالیبراسیون داخلی: معمولاً دارای مقاومت‌های کالیبره شده برای دقت.

  • سازگاری گسترده: کار با آردوینو، رزبری پای و اکثر میکروکنترلرها.

  • طراحی ارگونومیک: دسته با بازگشت به مرکز (Self-Centering).


مشخصات فنی دقیق

پارامتر مشخصات فنی
ولتاژ کاری ۳.۳ تا ۵ ولت DC (توصیه: ۵V برای دقت بیشتر)
جریان مصرف ≈ ۵-۱۰ میلی‌آمپر (بدون بار)
پتانسیومترها ۲ عدد (۱۰kΩ خطی – برای محور X و Y)
رزولوشن در عمل ≈ ۸-۱۰ بیت (متناسب با ADC میکروکنترلر)
خروجی آنالوگ X/Y ۰ تا VCC ولت (متناسب با موقعیت)
خروجی دیجیتال SW ACTIVE LOW (هنگام فشرده شدن = LOW)
زاویه حرکتی ±۳۰ درجه در هر جهت (معمولاً)
مقاومت مکانیکی میلیون‌ها چرخه (با کیفیت مناسب)
ابعاد ماژول حدود ۴۰mm × ۳۰mm × ۲۰mm (با دسته)
طول کابل ۱۵-۲۰cm (در ماژول‌های آماده)

پین‌های ماژول و عملکرد

پین ماژول نام عملکرد اتصال به آردوینو
VCC تغذیه ۵V 5V
GND زمین زمین GND
VRx ولتاژ محور X خروجی آنالوگ X پین آنالوگ (مثلاً A0)
VRy ولتاژ محور Y خروجی آنالوگ Y پین آنالوگ (مثلاً A1)
SW کلید فشاری خروجی دیجیتال (Active Low) پین دیجیتال + Pull-up (مثلاً D2)

اتصال پایه‌ای و کد نمونه خواندن مقادیر

// اتصال جوی‌استیک PS2 به آردوینو
// VCC -> 5V
// GND -> GND
// VRx -> A0
// VRy -> A1
// SW -> D2 (با مقاومت Pull-up داخلی)

const int xPin = A0;
const int yPin = A1;
const int swPin = 2;

int xValue = 0;
int yValue = 0;
int swValue = 0;

void setup() {
  pinMode(swPin, INPUT_PULLUP); // فعال‌سازی مقاومت Pull-up داخلی برای کلید
  Serial.begin(9600);
  Serial.println("جوی‌استیک PS2 آماده است...");
  Serial.println("مقادیر: X, Y, SW");
}

void loop() {
  // خواندن مقادیر آنالوگ (0-1023)
  xValue = analogRead(xPin);
  yValue = analogRead(yPin);
  
  // خواندن وضعیت کلید (0=فشرده, 1=آزاد)
  swValue = digitalRead(swPin);
  
  // تبدیل به محدوده -512 تا +512 برای نمایش بهتر
  int xMapped = map(xValue, 0, 1023, -512, 512);
  int yMapped = map(yValue, 0, 1023, -512, 512);
  
  // نمایش در سریال مانیتور
  Serial.print("X: ");
  Serial.print(xMapped);
  Serial.print("\tY: ");
  Serial.print(yMapped);
  Serial.print("\tSW: ");
  Serial.println(swValue == LOW ? "فشرده" : "آزاد");
  
  // تشخیص جهت‌های اصلی
  detectDirection(xMapped, yMapped);
  
  delay(200); // تاخیر برای خوانایی
}

// تابع تشخیص جهت
void detectDirection(int x, int y) {
  // آستانه حساسیت (مقادیر نزدیک به مرکز را نادیده بگیر)
  const int threshold = 100;
  
  if (x > threshold && abs(y) < threshold) {
    Serial.println("  -> RIGHT");
  } else if (x < -threshold && abs(y) < threshold) {
    Serial.println("  -> LEFT");
  } else if (y > threshold && abs(x) < threshold) {
    Serial.println("  -> DOWN");
  } else if (y < -threshold && abs(x) < threshold) {
    Serial.println("  -> UP");
  } else if (abs(x) > threshold && abs(y) > threshold) {
    if (x > 0 && y > 0) Serial.println("  -> DOWN-RIGHT");
    if (x > 0 && y < 0) Serial.println("  -> UP-RIGHT");
    if (x < 0 && y > 0) Serial.println("  -> DOWN-LEFT");
    if (x < 0 && y < 0) Serial.println("  -> UP-LEFT");
  }
}

کد پیشرفته: کنترل سروو موتور با جوی‌استیک

#include <Servo.h>

const int xPin = A0;
const int yPin = A1;
const int swPin = 2;

Servo servoX; // سروو برای محور X
Servo servoY; // سروو برای محور Y

int lastSwState = HIGH;
unsigned long lastDebounceTime = 0;
const int debounceDelay = 50;

void setup() {
  pinMode(swPin, INPUT_PULLUP);
  
  servoX.attach(9);  // سروو X به پین 9
  servoY.attach(10); // سروو Y به پین 10
  
  Serial.begin(9600);
}

void loop() {
  // خواندن مقادیر جوی‌استیک
  int xValue = analogRead(xPin);
  int yValue = analogRead(yPin);
  
  // تبدیل به زاویه سروو (0-180 درجه)
  int servoXAngle = map(xValue, 0, 1023, 0, 180);
  int servoYAngle = map(yValue, 0, 1023, 0, 180);
  
  // حرکت سرووها
  servoX.write(servoXAngle);
  servoY.write(servoYAngle);
  
  // کنترل حالت با کلید (مثلاً حالت قفل/آزاد)
  int swReading = digitalRead(swPin);
  
  if (swReading != lastSwState) {
    lastDebounceTime = millis();
  }
  
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (swReading == LOW) {
      Serial.println("کلید فشرده شد - حالت قفل فعال");
      // کد برای فعال‌سازی حالت خاص
    }
  }
  
  lastSwState = swReading;
  
  delay(20); // تاخیر برای حرکت نرم سروو
}

کاربردهای اصلی و رایج

  1. کنترل ربات: کنترل حرکت ربات‌های چرخ‌دار، بازوهای رباتیک.

  2. پروژه‌های RC: کنترل ماشین‌ها، قایق‌ها، هواپیماهای مدل.

  3. منوهای تعاملی: کنترل منوها در پروژه‌های با نمایشگر.

  4. کنترل دوربین: کنترل پن و تیلت دوربین‌های نظارتی.

  5. شبیه‌سازها: ساخت شبیه‌سازهای پرواز، رانندگی.

  6. هنرهای تعاملی: کنترل انیمیشن‌ها، نورپردازی، صدا.

  7. دستگاه‌های صنعتی: کنترل موقعیت در سیستم‌های کوچک.


نحوه کالیبراسیون و کد کالیبراسیون

// کالیبراسیون جوی‌استیک برای پیدا کردن مقادیر Min/Max و Center
const int xPin = A0;
const int yPin = A1;

int xMin = 1023, xMax = 0, xCenter = 0;
int yMin = 1023, yMax = 0, yCenter = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("کالیبراسیون جوی‌استیک");
  Serial.println("جوی‌استیک را در تمام جهات حرکت دهید...");
  delay(3000);
}

void loop() {
  int xValue = analogRead(xPin);
  int yValue = analogRead(yPin);
  
  // به‌روزرسانی Min/Max
  if (xValue < xMin) xMin = xValue;
  if (xValue > xMax) xMax = xValue;
  if (yValue < yMin) yMin = yValue;
  if (yValue > yMax) yMax = yValue;
  
  // محاسبه مرکز
  xCenter = (xMin + xMax) / 2;
  yCenter = (yMin + yMax) / 2;
  
  Serial.print("X: Min="); Serial.print(xMin);
  Serial.print(" Max="); Serial.print(xMax);
  Serial.print(" Center="); Serial.print(xCenter);
  Serial.print(" | Y: Min="); Serial.print(yMin);
  Serial.print(" Max="); Serial.print(yMax);
  Serial.print(" Center="); Serial.println(yCenter);
  
  // اگر 5 ثانیه گذشت، کالیبراسیون تمام است
  static unsigned long startTime = millis();
  if (millis() - startTime > 5000) {
    Serial.println("کالیبراسیون تکمیل شد!");
    Serial.println("مقادیر نهایی:");
    Serial.print("const int xMin = "); Serial.print(xMin); Serial.println(";");
    Serial.print("const int xMax = "); Serial.print(xMax); Serial.println(";");
    Serial.print("const int xCenter = "); Serial.print(xCenter); Serial.println(";");
    Serial.print("const int yMin = "); Serial.print(yMin); Serial.println(";");
    Serial.print("const int yMax = "); Serial.print(yMax); Serial.println(";");
    Serial.print("const int yCenter = "); Serial.print(yCenter); Serial.println(";");
    while(1); // توقف
  }
  
  delay(100);
}

مقایسه با سایر ماژول‌های کنترل

کنترلر جوی‌استیک PS2 پتانسیومتر ساده سنسور اثر هال کمربند لمسی
محورها ۲ محور + کلید ۱ محور ۱ محور (معمولاً) ۱ بعد
دقت ⭐⭐⭐⭐ (خوب) ⭐⭐⭐ (متوسط) ⭐⭐⭐⭐⭐ (عالی) ⭐⭐ (پایین)
دوام ⭐⭐⭐⭐ (میلیون چرخه) ⭐⭐⭐ (صدها هزار) ⭐⭐⭐⭐⭐ (بدون تماس) ⭐⭐⭐⭐ (خوب)
نویز کمی نویز مکانیکی نویز تماسی بدون نویز تماسی نویز محیطی
قیمت ⭐⭐⭐ (مناسب) ⭐⭐⭐⭐⭐ (بسیار ارزان) ⭐⭐ (گران) ⭐⭐⭐ (مناسب)
کاربرد اصلی کنترل دقیق تنظیمات اندازه‌گیری دقیق رابط لمسی

سوالات متداول (FAQ)

✅ چگونه مقادیر Dead Zone (منطقه مرده) ایجاد کنم؟
در کد، مقادیر نزدیک به مرکز را نادیده بگیرید:

if (abs(xValue - centerX) < deadZone) xValue = centerX;

✅ آیا می‌توانم دو جوی‌استیک را همزمان استفاده کنم؟
بله، آردوینو UNO دارای ۶ پین آنالوگ است، بنابراین تا ۳ جوی‌استیک را می‌توانید مستقیماً وصل کنید.

✅ چرا مقادیر نوسان دارند؟
۱. پتانسیومتر کثیف/فرسوده (با اسپری تمیزکننده تمیز کنید).
۲. نویز برق (خازن ۱۰۰nF بین VCC و GND نزدیک ماژول اضافه کنید).
۳. مقاومت Pull-up ضعیف.

✅ تفاوت این ماژول با جوی‌استیک‌های صنعتی چیست؟
جوی‌استیک‌های صنعتی: دقت بالاتر، دوام بیشتر (میلیون‌ها چرخه)، خروجی‌های اضافی (مثل I2C)، ضد آب/غبار.

✅ چگونه برای کنترل موتور DC استفاده کنم؟
مقادیر X و Y را به سرعت و جهت موتور مپ کنید:

// کنترل موتور DC با درایور L298N
int speed = map(yValue, 0, 1023, -255, 255);
if (speed > 0) {
    // حرکت به جلو
} else if (speed < 0) {
    // حرکت به عقب
}

✅ آیا می‌توانم از آن در ربات مسیریاب استفاده کنم؟
بله، اما جوی‌استیک برای کنترل دستی است. برای مسیریابی خودکار از سنسورهای دیگر (مانند اولتراسونیک، IR) استفاده کنید.

✅ طول عمر آن چقدر است؟
با کیفیت خوب: ۱-۲ میلیون چرخه. با استفاده شدید ممکن است پتانسیومتر نویز پیدا کند یا ساییدگی داشته باشد.


چرا ماژول جوی‌استیک PS2 را از ما بخرید؟

✅ کیفیت ساخت: استفاده از پتانسیومترهای خطی با کیفیت و کم‌نویز.
✅ کالیبراسیون کارخانه: تست خطی بودن و بازگشت به مرکز قبل از ارسال.
✅ طراحی مکانیکی بهینه: دسته با احساس مکانیکی مناسب و کلید با فشار مطمئن.
✅ پشتیبانی فنی: ارائه کدهای کالیبراسیون، کتابخانه و پروژه‌های نمونه.


پکیج پیشنهادی برای رباتیک

  1. ماژول جوی‌استیک PS2 (۲ عدد برای کنترل کامل)

  2. آردوینو UNO/NANO با کابل USB

  3. درایور موتور L298N (برای کنترل موتورها)

  4. موتور DC با گیربکس (۲ عدد برای ربات دوچرخ)

  5. سروو موتور ۹g (۲ عدد برای کنترل بازو)

  6. برد بورد و سیم‌های رابط


نحوه انتخاب و نصب

  • برای کنترل دقیق: از جوی‌استیک با پتانسیومتر خطی استفاده کنید.

  • برای محیط صنعتی: مدل‌های با پوشش محافظ انتخاب کنید.

  • نصب: با پیچ یا چسب روی پنل محکم کنید.

  • سیم‌کشی: از سیم‌های به هم تابیده برای کاهش نویز استفاده کنید.