آموزش راه اندازی ماژول جوی استیک دو محوره با آردوینو

فهرست مطالب

مقدمه

در بسیاری از پروژه های الکترونیکی و رباتیکی کنترل کردن اجزای پروژه مانند موتورها امری مهم و ضروری است، روش های بسیار متنوعی برای کنترل وجود دارد از جمله استفاده از کامپیوتر، گوشی های تلفن هوشمند، ماژول های کنترلی رادیویی، کلیدهای فشاری، جوی استیک و …. در این آموزش با ماژول جوی استیک آشنا می شوید و نحوه راه اندازی و بهینه سازی این ماژول را با آردوینو یاد می گیرید.

آنچه در این آموزش یاد می گیرید

جوی استیک چیست و چگونه کار می کند؟

جوی استیک احتمالا بیشترین وسیله است که گیمر ها با آن سرو کار دارند، به زبان ساده جوی استیک وسیله ای است که حرکات دست شما را به سیگنال الکتریکی تبدیل می کند. راحتی استفاده از جوی استیک باعث شده هنگام کار با آن واقعا حس کنید درون بازی یا درون رباتی که کنترل می کنید هستید.

ساختار ماژول جوی استیک درست مانند جوی استیک های دسته PS2 می باشد، به صورت عادی قسمت سر ماژول در وسط قرار دارد و وقتی آنرا جا به جا می کنید و سپس رها می کنید مجددا با استفاده از فنر مرکزی (self-centering spring)، به حالت وسط باز می گردد، حرکت جوی استیک بسیار نرم بوده و یک کلید نیز روی ماژول تعبیه شده است.

اساس کار جوی استیک بر تغییر مقاومت دو پتانسیومتر معمولا 10 کیلویی استوار است، دو پتانسیومتر برای محور x و y قرار داده شده که با تغییر مقاومت این پتانسیومتر ها و تبدیل این مقاومت به ولتاژ الکتریکی و خواندن ولتاژ توسط آردوینو (یا هر پردازنده دیگری) می توان موقعیت x و y را تخمین زد. برای این کار، پردازنده باید واحد ADC داشته باشد تا مقدار آنالوگ خوانده شده توسط جوی استیک را به مقدار دیجیتال تبدیل کند و بر اساس این مقدار دیجیتال عملیات مورد نظر را انجام دهد.

برد آردوینو 6 کانال ADC ده بیتی دارد، یعنی 5 ولت مرجع را به 1024 بخش تقسیم می کند، وقتی جوی استیک را مثلا در محور x از ابتدا به انتهای مسیر خود می بریم مقدار ADC آن از 0 تا 1023 تغییر می کند و وقتی در موقعیت رها در مرکز قرار دارد مقدار آن 512 خواهد بود. شکل زیر مقدار تقریبی ADS را باتوجه به موقعیت سر جوی استیک نشان میدهد.

ممکن است بخاطر نویز محیط و تفاوت کیفیت ساخت در انواع این ماژول، مقدار ADC کمی متفاوت باشد.

این ماژول دارای 5 پایه می باشد.

  • پایه زمین برای اتصال به زمین مدار.
  • پایه Vcc برای تغذیه مدار که می توانید به 5 ولت متصل کنید.
  • پایه VRx خروجی آنالوگ محور X، معمولا محور X معرف حرکت چپ و راست است.
  • پایه VRy خروجی آنالوگ محور y، معمولا محور Y ومعرف حرکت بالا و پایین است.
  • پایه SW برای کلید که بصورت pull-up داخلی قرار گرفته است، یعنی با فشردن کلید مقدار 0 روی پایه SW قرار می گیرد.

لوازمی که به آن احتیاج دارید

قطعات مورد نیاز

آردوینو UNO R3 × 1
ماژول جوی استیک دو محوره × 1
سیم جامپر نری به مادگی × 1
سروو موتور T-Pro Mini Servo SG90 9G Servo × 1

**سروو موتور برای انجام مثال کنترل سروو با جوی استیک می باشد.

نرم افزار های مورد نیاز

Arduino IDE

راه اندازی جوی استیک با آردوینو

استفاده از ماژول جوی استیک و آردوینو کار ساده ای است، فقط کافیست مقدار ADC را از پایه های VRx و VRy بخوانید.

سیم بندی

ماژول را طبق سیم بندی زیر به آردوینو متصل کنید.

کد

برای برنامه نویسی ماژول جوی استیک نیازی به کتابخانه ندارید، کافیست کد زیر را روی آردوینو خود آپلود کنید و خروجی را در Serial monitor مشاهده کنید.

/*
  Joystick and Arduino
  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  
Home
*/ const int SW = 2; // SW const int X = 0; // VRx const int Y = 1; // VRy void setup() { pinMode(SW, INPUT_PULLUP); Serial.begin(9600); } void loop() { Serial.print("Switch: "); Serial.print(digitalRead(SW)); Serial.print("\t\t"); Serial.print("VRx: "); Serial.print(analogRead(X)); Serial.print("\t\t"); Serial.print("VRy: "); Serial.println(analogRead(Y)); Serial.println("____________________________________________________________"); delay(500); }

فقط کافیست با دستور analogRead(Pin) مقدار آنالوگ را خوانده و از آن استفاده کنید.

چگونه داده های جوی استیک را بهینه کنیم؟

یکی از بزرگترین مشکلات ماژول های جوی استیک غیر خطی بودن آن است، یعنی مقدار ADC بصورت خطی با حرکت سر جوی اسیتک تغییر نمی کند، این موضوع می تواند در پروژه هایی که به دقت بالا نیاز دارد، مانند کنترل ربات های پرنده ، کمی آزار دهنده باشد.

می توان با روش های میانگین گیری، داده های جوی استیک را نرم تر کرد تا این میزان غیرخطی بودن زیاد آزاردهنده نباشد.

کد زیر را روی آردوینو خود آپلود کنید و با مشاهده خروجی در Serial Monitor، داده ها را با حالت راه اندازی ساده مقایسه کنید.

کد

/*
  Joystick Smoothing
  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  
Home
This code is based on https://www.arduino.cc/en/Tutorial/Smoothing */ const int X = 0; const int Y = 1; const int MaxReadings = 10; int Xreadings[MaxReadings]; int XreadIndex = 0; int Xtotal = 0; int X_Pos = 0; int Yreadings[MaxReadings]; int YreadIndex = 0; int Ytotal = 0; int Y_Pos = 0; void Smoother(int x_pin, int y_pin) { Xtotal = Xtotal - Xreadings[XreadIndex]; Ytotal = Ytotal - Yreadings[YreadIndex]; delay(1); Xreadings[XreadIndex] = analogRead(x_pin); Yreadings[YreadIndex] = analogRead(y_pin); delay(1); Xtotal = Xtotal + Xreadings[XreadIndex]; Ytotal = Ytotal + Yreadings[YreadIndex]; delay(1); XreadIndex = XreadIndex + 1; YreadIndex = YreadIndex + 1; if (XreadIndex >= MaxReadings) XreadIndex = 0; if (YreadIndex >= MaxReadings) YreadIndex = 0; delay(1); X_Pos = Xtotal / MaxReadings; Y_Pos = Ytotal / MaxReadings; } void setup() { Serial.begin(9600); for (int i = 0; i < MaxReadings; i++) { Xreadings[i] = 0; Yreadings[i] = 0; } } void loop() { Smoother(X,Y); Serial.print("VRx: "); Serial.print(X_Pos); Serial.print("\t\t"); Serial.print("VRy: "); Serial.println(Y_Pos); Serial.println("____________________________________________________________"); delay(100); }

متغیر MaxReading تعداد دفعات میانگین گیری را مشخص می کند، هر چه این مقدار بیشتر باشد داده ها بصورت نرم تر و خطی تر تغییر می کنند اما درعوض سرعت پاسخ دهی ماژول افت می کند، بنابراین با توجه به دقت مورد نیاز برای پروژه خود باید بین پارامتر سرعت و دقت مصالحه برقرار (trade off) کنید.

کنترل سروو موتور با جوی استیک

در این پروژه برای درک بهتر عملکرد ماژول جوی استیک، یک سرووموتور را به کمک این ماژول کنترل می کنید.

سیم بندی

کد

/*
  Joystick and servo motor

  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  
Home
This code is based on https://www.arduino.cc/en/Tutorial/Smoothing */ #include <Servo.h> Servo myservo; const int X = 0; const int Y = 1; const int MaxReadings = 10; int Xreadings[MaxReadings]; int XreadIndex = 0; int Xtotal = 0; int X_Pos = 0; int Yreadings[MaxReadings]; int YreadIndex = 0; int Ytotal = 0; int Y_Pos = 0; int Servo_Pos = 0, Pos = 0; void Smoother(int x_pin, int y_pin) { Xtotal = Xtotal - Xreadings[XreadIndex]; Ytotal = Ytotal - Yreadings[YreadIndex]; delay(1); Xreadings[XreadIndex] = analogRead(x_pin); Yreadings[YreadIndex] = analogRead(y_pin); delay(1); Xtotal = Xtotal + Xreadings[XreadIndex]; Ytotal = Ytotal + Yreadings[YreadIndex]; delay(1); XreadIndex = XreadIndex + 1; YreadIndex = YreadIndex + 1; if (XreadIndex >= MaxReadings) XreadIndex = 0; if (YreadIndex >= MaxReadings) YreadIndex = 0; delay(1); X_Pos = Xtotal / MaxReadings; Y_Pos = Ytotal / MaxReadings; } void setup() { Serial.begin(9600); myservo.attach(9); for (int i = 0; i < MaxReadings; i++) { Xreadings[i] = 0; Yreadings[i] = 0; } } void loop() { Smoother(X, Y); Servo_Pos = map(X_Pos, 0, 1023, 0, 180); myservo.write(Servo_Pos); Serial.println(Servo_Pos); delay(20); }
برای دریافت داده های جوی استیک از همان روش میانگیری استفاده می کنیم، از آنجایی که موقعیت سروو موتور از 0 تا 180 درجه تغییر می کند باید داده های جوی استیک که از 0 تا 1023 تغییر میکند را تبدیل کنیم، برای این مظور از دستور map(X_Pos, 0, 1023, 0, 180); استفاده می کنیم.

ارتباط جوی استیک و Processing

Processing مجموعه ای از کتابخانه های جاوا بهمراه یک محیط برنامه نویسی برای آموزش ساخت محیط تعاملی بصری است که در سال 2001 توسعه داده شد و امروزه بخاطر راحتی ارتباط آن با بردهایی نظیر آردوینو و ساخت محیط های گرافیکی و تعاملی، محبوبیت زیادی پیدا کرده است. Processing کاملا رایگان بوده و می توانید آنرا از این لینک دانلود کرده و نصب کنید.

برای آشنایی بیشتر با Processing، نحوه برنامه نویسی، توابع و … به مرجع کامل خود نرم افزار مراجعه کنید.

Processing می تواند از سه طریق ماوس، کیبورد و پورت سریال کامپیوتر داده ورودی بگیرد، در این پروژه داده های جوی استیک از طریق پورت سریال به کامپیوتر وارد شده و Processing این داده ها را دریافت و پردازش می کند.

پس به دو کد برای این بخش نیاز داریم:

استخراج موقعیت جوی استیک و ارسال به Processing

کد زیر را روی آردوینو خود آپلود کنید:

/*
  Joystick and Processing
  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  
Home
*/ const int X = 0; const int Y = 1; int b = 0; int x = 0; int y = 0; const int MaxReadings = 10; int Xreadings[MaxReadings]; int XreadIndex = 0; int Xtotal = 0; int X_Pos = 0; int Yreadings[MaxReadings]; int YreadIndex = 0; int Ytotal = 0; int Y_Pos = 0; void Smoother(int x_pin, int y_pin) { Xtotal = Xtotal - Xreadings[XreadIndex]; Ytotal = Ytotal - Yreadings[YreadIndex]; delay(1); Xreadings[XreadIndex] = analogRead(x_pin); Yreadings[YreadIndex] = analogRead(y_pin); delay(1); Xtotal = Xtotal + Xreadings[XreadIndex]; Ytotal = Ytotal + Yreadings[YreadIndex]; delay(1); XreadIndex = XreadIndex + 1; YreadIndex = YreadIndex + 1; if (XreadIndex >= MaxReadings) XreadIndex = 0; if (YreadIndex >= MaxReadings) YreadIndex = 0; delay(1); X_Pos = Xtotal / MaxReadings; Y_Pos = Ytotal / MaxReadings; } void setup() { Serial.begin(9600) ; pinMode(2, INPUT_PULLUP) ; for (int i = 0; i < MaxReadings; i++) { Xreadings[i] = 0; Yreadings[i] = 0; } } void loop() { Smoother(X,Y); x = map(X_Pos, 0, 1023, 0, 512); y = map(Y_Pos, 0, 1023, 0, 512); b = digitalRead(2); Serial.print(x, DEC); Serial.print(","); Serial.print(y, DEC); Serial.print(","); Serial.print(!b); Serial.print("\n"); delay(10); }

برای تمییز داده ها از هم در Processing باید داده ها را با استفاده از “, ” از هم جدا کنید، در انتها نیز برای بیان اتمام داده ها از “\n ” استفاده کنید.

دریافت و پردازش داده های جوی استیک توسط Processing

کد زیر را در Processing کپی کرده و آنرا اجرا کنید:

/*
  Joystick and Processing

  modified on 21 Jul 2019
  by Saeed Hosseini @ Electropeak
  
Home
Thanks to http://learningprocessing.com/examples/ */ import processing.serial.*; Serial myPort; int VRx; int VRy; int but; String val; int maxImages = 5; int imageIndex = 0; int i = 1; PImage[] img = new PImage[maxImages]; PImage image; void setup() { size(512, 512); myPort = new Serial(this, "COM5", 9600); myPort.bufferUntil('\n'); background(0); } void draw() { game(); } void serialEvent( Serial myPort) { // read the data until the newline n appears val = myPort.readStringUntil('\n'); if (val != null) { val = trim(val); // break up the decimal and new line reading int[] vals = int(splitTokens(val, ",")); // we assign to variables VRx = vals[0]; VRy = vals[1] ; but = vals[2]; } } void game() { img[i] = loadImage( "p" + i + ".jpg" ); image = img[i]; loadPixels(); img[i].loadPixels(); for (int x = 0; x < image.width; x++ ) { for (int y = 0; y <image.height; y++ ) { // Calculate the 1D pixel location int loc = x + y*image.width; // Get the R,G,B values from image float r = red (image.pixels[loc]); float g = green(image.pixels[loc]); float b = blue (image.pixels[loc]); // Calculate an amount to change brightness // based on proximity to the mouse float distance = dist(x, y, VRy, VRx); // The closer the pixel is to the mouse, the lower the value of "distance" // We want closer pixels to be brighter, however, so we invert the value using map() // Pixels with a distance of 50 (or greater) have a brightness of 0.0 (or negative which is equivalent to 0 here) // Pixels with a distance of 0 have a brightness of 1.0. float adjustBrightness = map(distance, 0, 50, 1, 0); r *= adjustBrightness; g *= adjustBrightness; b *= adjustBrightness; // Constrain RGB to between 0-255 r = constrain(r, 0, 255); g = constrain(g, 0, 255); b = constrain(b, 0, 255); // Make a new color and set pixel in the window color c = color(r, g, b); pixels[loc] = c; if (but == 1) i++; if (i>4) i = 1; } } updatePixels(); }

با فشردن کلید وسط عکس بعد نمایان می شود.

در دستور float adjustBrightness = map(distance, 0, 50, 1, 0); با افزایش و یا کاهش مقدار 50 می توانید بازی را آسان تر یا سخت تر کنید.

دقت داشته باشید پس از اعمال هر تغییر در برنامه، برای برقراری ارتباط سریال، ابتدا برد آردوینوی خود را از کامپیوتر جدا کرده و مجددا وصل کنید و سپس کدتان را در Processing اجرا کنید.

یک گام جلوتر

  • سعی کنید با استفاده از دو ماژول جوی استیک یک دسته بازی بسازید.
  • سعی کنید به کمک یک ماژول NRF24L01 دسته بازی که در مرحله قبل ساختید را بصورت بیسیم در بیاورید.

آموزش های مشابه

Comments (9)

  • Alireza Pourmoradiyan Reply

    با تشکر از آموزش خوبتون.
    من قصد دارم با 3 عدد ماژول جوی استیک چندتا خروجی کیبورد بگیرم جهت ساخت دسته بازی
    امکانش هست راهنمایی کنید؟

    آوریل 1, 2023 at 2:39 ب.ظ
    • محمد دمیرچی Reply

      با سلام
      در صورتی که به عنوان جوی استیک (دسته بازی) کامپیوتری میخواهید استفاده کنید باید از سری برد های Arduino Pro Micro یا Arduino Leonardo استفاده کنید.
      مابقی برنامه نویسی شما می باشد و میکرو را در مود HID باید قرار بدهید تا به عنوان دسته بازی در سیستم شناخته شود.

      آوریل 8, 2023 at 4:54 ب.ظ
      • Alireza Pourmoradiyan Reply

        با تشکر
        امکان داره با جوی استیک خروجی کیبورد هم گرفت؟
        و اگر امکان داره چگونه؟

        می 26, 2023 at 9:43 ب.ظ
      • ابوالفضل Reply

        خیلی ممنون از آموزش خوبتون .
        من هم میخوام سروو موتور را با جوی استیک کنترل کنم فقط زمانی که سوویچ جوی استیک زده شد ، سروو موتور در همان جا بایستد و زمانی که دوباره سوییچ زده شد سیستم بفهمد که کاربر می‌خواهد فرمان جدیدی دهد

        سپتامبر 24, 2023 at 12:26 ب.ظ
        • محمد دمیرچی Reply

          با سلام
          کافی است 2 شرط برای دکمه قرار بدهید که یک شرظ وضعیت دکمه را مشخص کند. و شرط دوم اینکه هر بار دکمه زده شد مقدار جوی استیک را در یک متغییر بریزد.
          به این صورت در زمان هایی که شرط اول برقرار باشد مقدار های ذخیره شده را به سروو بدهد.

          سپتامبر 25, 2023 at 8:32 ق.ظ
  • محمد Reply

    سلام وقت بخیر
    من میخوام با استفاده از ماژول جوستیک دسته بازی یک موتور چرخش یک موتور Dcرا کنترل کنم ایا امکانش هست؟

    آوریل 1, 2024 at 4:48 ق.ظ
    • محمد دمیرچی Reply

      با سلام
      چرا که نشود، خروجی ماژول جوی استیک یک سیگنال آنالوگ می باشد که به میکرو کنترلر میرود و با برنامه نویسی این مقدار را به یک PWM تبدیل میکند و آن را به درایور موتوری که میخواهید به موتور وصل کنید وصل میکنید تا بتوانید موتور خود را حرکت بدهید.
      توجه داشته باشید که ماژول را به صورت مستقیم نمی توانید به موتور یا درایور موتور وصل کنید.

      آوریل 2, 2024 at 11:27 ق.ظ
  • مهدی Reply

    سلام
    ممنون از آموزش خوب و کاملتون
    من میخوام یک فرمون بازی برای کامپیوتر بسازم
    چجوری دیتا تحلیل شده رو به بازی برای واکنش خودرو شبیه سازی شده بدم

    آوریل 16, 2024 at 10:02 ب.ظ
    • محمد دمیرچی Reply

      با سلام
      برای اینکه دیتا های سنسور ها و ماژول ها را به سیستم بدهید تا داخل سیستم استفاده کنید باید میکرو شما مود HID را ساپورت کند، برای این موضوع فقط برد هایی که USB داخلی دارند را میتوانید استفاده کنید. مانندArduino Leonardo یا Pro Micro یا ESP32S3 و…
      حتما بررسی کنید که مود HID را داشته باشند و بتوانید به صورت joystick به سیستم بشناسانید.

      آوریل 17, 2024 at 9:43 ق.ظ

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد.