در این مقاله راه اندازی ماژول جوی استیک دو محوره با آردوینو را به شما آموزش خواهیم داد.
وقتی كلمه جوی استيک را میشنويد، معمولا یاد چه چیزی میافتید؟ به احتمال زیاد دسته بازی. جوی استيک معمولا برای بازيیهای كامپيوتری بهكار میرود هر چند كاربردهای سرگرم كننده ديگری نيز دارد. از آن جمله میتوان به كنترل يک ربات يا كنترل جابجايی يک دوربین اشاره نمود.
در ادامه ماژول جوی استیک را با هم بررسی خواهیم کرد و سپس به راه اندازی آن میپردازیم.
مرور سخت افزار
در شكل زير جوي استيكی همانند جوي استيک آنالوگ پلي استيشن PS2 نشان داده شده است. طراحي اين جوي استيک بگونهاي است كه چنانچه دسته را رها كنيم، خودبخود به وضعيت مركزي برميگردد. به علاوه این جوی استیک دارای یک سرپوش فنجانی شکل است که تجربه ای همانند جوی استیک های انگشتی را برای کاربران فراهم می کند.
هدف جوي استيک انتقال حركت دو بعدي (در امتداد دو محور) به آردوينو است. براي دستيابي به اين هدف از دو پتانسيومتر 10 كيلو اهم مستقل استفاده شده است (براي هر محور يك پتانسيومتر). اين پتانسيومترها به عنوان تقسيمكنندههاي ولتاژ قابل تنظيم بكار گرفته شده اند كه ورودي آنالوگ دوبعدي را فراهم ميكنند.
پتانسيومترها همان دو قطعه آبي رنگ در طرفين جوي استيک هستند. اگر در هنگام مشاهده شافت مركزي پتانسيومترها دسته جوي استيک حركت داده شود، خواهيد ديد كه حركت هر پتانسيومتر فقط در يك جهت است. در بخش بعدی در خصوص جزئيات نحوه كار جوي استيک صحبت خواهيم كرد.
همچنين اين جوي استيک داراي يك سوئيچ است كه در موقع اعمال فشار بر روي دسته فعال خواهد شد. اين سوئيچ بصورت يك قطعه مشكي در كنار جوي استيک قابل مشاهده است. اگر بر روي سر دسته فشار دهيم، يك اهرم بر روي اين سوئيچ فشار وارد خواهد كرد. این اهرم بدون در نظر گرفتن وضعیت جوی استیک، کار می کند.
نحوه كار ماژول جوی استیک دو محوره
ايده اصلي ماژول جوی استیک دو محوره بر اين اساس است كه موقعيت دسته بر روي دو محور x (براي حركت چپ و راست) و محور y (براي حركت بالا و پايين) به صورت اطلاعات الكترونيكي مورد قبول آردوينو بيان شود.
در نگاه اول ممكن است اين موضوع كمي دشوار به نظر برسد، اما راه حل مسئله استفاده از جوی استیکی است كه در آن از دو پتانسيومتر و يك مكانيسم Gimbal استفاده ميشود.
مكانيسم Gimbal
وقتي شما دسته جوي استيک را ميچرخانيد، يك ميله باريك كه بر روي دو شافت شياردار قابل چرخش (Gimbal) سوار شده است، توسط دسته به حركت در خواهد آمد. يكي از اين شافتها اجازه حركت در راستاي محور x (چپ و راست) و شافت ديگر اجازه حركت در راستاي محور y (بالا و پايين) را ميدهد. حركت جلو و عقب دسته سبب چرخش شافت محور y ميشود. در حالی که حركت چپ و راست دسته سبب چرخش شافت مربوط به محور x ميشود. چنانچه دسته به صورت دایره وار حركت داده شود، هر دو شافت محور x و محور y چرخش خواهند داشت.
به هر شافت يك پتانسيومتر متصل شده است كه موقعيت مكاني دسته جوي استيك را به شكل سيگنال هاي آنالوگ تفسير می کند. حركت شافت سبب چرخش بازوي پتانسيومتر می شود. به عبارت ديگر، اگر دسته جوي استيك را تا آخرين حد ممكن به سمت جلو حركت دهيد، بازوي پتانسيومتر تا حد نهايي خود به يك سمت ميچرخد. اما اگر دسته را تا آخرين حد ممكن به سمت عقب (سمت خود) حرکت دهید، پتانسيومتر مربوطه نيز در جهت معكوس تا آخر ميچرخد.
خواندن سيگنال آنالوگ ماژول جوی استیک دو محوره
براي خواندن موقعيت فيزيكي جوي استيک لازم است تغييرات مقاومتي پتانسيومتر را اندازه گيري كنيم. اين تغييرات مقاومتي با استفاده از پين آنالوگ آردوينو به كمك مبدل آنالوگ به ديجيتال ADC قابل خواندن است.
با توجه به اينكه بورد آردوينو داراي يك مبدل ADC با رزولوشن ده بيت است، مقادير هر كانال آنالوگ (هر محور) ميتوانند بين 0 تا 1023 تغيير داشته باشد. بنابراين چنانچه دسته جوي استيک در راستاي محور x از ابتدا تا انتها حركت داده شود، مقدار متغير x بين 0 تا 1023 تغيير خواهد كرد. بطور مشابه، در صورت حركت كامل دسته جوي استيک در راستاي محور y از يك سمت به سمت ديگر، مقدار y نیز بين 0 تا 1023 تغيير خواهد داشت. زمانی که دسته جوي استيک در موقعيت مركزي قرار داشته باشد، مقادير x و y تقريبا 512 خواهد بود.
شکل زیر جهت های x و y و چگونگی پاسخ این دو خروجی به حرکت جوی استیک را در وضعیت های مختلف نشان می دهد:
نکته: براي استفاده از اين جوي استيك در ابتدا لازم است بدانيم كدام جهت x و كدام جهت y است. به علاوه آگاهی از حرکات جوی استیک به صورت مختصات x و y نیز ضروری است.
پينهاي ماژول جوی استیک دو محوره
در شكل زير پين هاي ماژول جوی استیک دو محوره PS2 نشان داده شده است.
GND پين زمين ماژول است كه به زمين آردوينو متصل ميشود.
VCC تغذيه مورد نياز ماژول را تامين ميكند كه ميتوان آن را به خروجي 5 ولت آردوينو متصل نمود.
VRx پین خروجي جوي استيك در راستاي محور افقي x است. به عبارت ديگر این پین مشخص مي كند كه دسته جوي استيك چقدر به سمت چپ و راست حركت كرده است.
VRy پین خروجي جوي استيك در راستاي محور عمودي y است و میزان بالا و پايين رفتن دسته جوي استيك را نشان ميدهد.
SW خروجي سوئيچ فشاري بر روي دسته جوي استيك می باشد. اين سوئيچ به زمين GND متصل است و در حالت پيش فرض به شكل باز است (بصورت NO) به این معنا که مقدار آن در حالت عادي بصورت high ميباشد. در مواقعي كه سوئيچ روي دسته فشار داده شود، سوئيچ بسته و به زمين متصل ميشود و لذا مقدار اين پين Low خواهد شد.
راه اندازی ماژول جوی استیک دو محوره با آردوینو
اكنون كه اطلاعات کافی کسب کرده ایم، می توانیم راه اندازی ماژول جوی استیک دو محوره با آردوینو را آغاز کنیم.
برای راه اندازی این ماژول با آردوینو می توانید وسایل مورد نیاز خود را از طریق لینک های زیر تهیه کنید:
- ماژول جوی استیک دو محوره
- مینی برد بورد با 400 سوراخ
- سیم برد بورد در چهار سایز
- ماژول آردوینو UNO
- کابل پرینتری
براي تعيين مختصات دسته جوي استيک در راستاي محور x و y، لازم است هر دو خروجي آنالوگ ماژول به پينهاي مربوطه آردوينو متصل شود. در اينجا پين خروجي VRx را به پين A0 آردوينو و پين VRy ماژول جوي استيك را به پين A1 آردوينو متصل ميكنيم.
برای تشخیص اینکه دسته جوی استیک فشرده شده است یا نه، پين SW جوي استيك را به پين ديجيتال D8 آردوينو متصل ميكنيم. علاوه بر این، براي تغذيه ماژول جوي استيك، پين VCC و GND آن را به ترتيب به ترمينال 5 ولت و زمين آردوينو متصل مي نماييم.
اكنون زمان استفاده از جوي استيک فرا رسيده است.
كد آردوينو برای راه اندازی ماژول جوی استیک دو محوره
اين برنامه بسيار ساده است. فقط كافيست اطلاعات دو ورودي آنالوگ و يك خروجي ديجيتال را بخوانيم. پس از آن مي توانيم نتيجه را بر روي سریال مانیتور مشاهده کنیم.
// Arduino pin numbers
const int SW_pin = 8; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
void setup() {
pinMode(SW_pin, INPUT);
digitalWrite(SW_pin, HIGH);
Serial.begin(9600);
}
void loop() {
Serial.print("Switch: ");
Serial.print(digitalRead(SW_pin));
Serial.print(" | ");
Serial.print("X-axis: ");
Serial.print(analogRead(X_pin));
Serial.print(" | ");
Serial.print("Y-axis: ");
Serial.print(analogRead(Y_pin));
Serial.println(" | ");
delay(200);
}
اگر همه چيز بدرستي انجام شده باشد، می توانید خروجي زير را بر روي سریال مانیتور مشاهده كنيد:
توضيح كد
كد آردوينو با تعريف و راه اندازي اتصالات ماژول جوي استیک دو محوره در برنامه آردوينو شروع ميشود. پين SW این ماژول به پين شماره 8 آردوينو و پينهاي VRx و VRy به پينهاي 0 و 1 آردوينو وصل شدهاند.
// Arduino pin numbers
const int SW_pin = 8; // digital pin connected to switch output
const int X_pin = 0; // analog pin connected to X output
const int Y_pin = 1; // analog pin connected to Y output
در تابع ()setup پين SW به عنوان يك ورودي تعریف می شود و مقدار آن بصورت High خواهد بود، چرا كه تا زماني كه مقدار SW بصورت High باشد به این معنا است كه سوئيچ فشاري جوي استيك هنوز فشار داده نشده است. علاوه بر این، ارتباط سريال را نیز آغاز می کنیم.
pinMode(SW_pin, INPUT);
digitalWrite(SW_pin, HIGH);
Serial.begin(9600);
در تابع ()loop، تنها مقدار پين SW را با استفاده از تابع ()digitalRead و مقادير VRx و VRy را توسط تابع ()analogRead می خوانیم. نتيجه آن بر روي سریال مانیتور نمايش داده ميشود:
Serial.print("Switch: ");
Serial.print(digitalRead(SW_pin));
Serial.print(" | ");
Serial.print("X-axis: ");
Serial.print(analogRead(X_pin));
Serial.print(" | ");
Serial.print("Y-axis: ");
Serial.print(analogRead(Y_pin));
Serial.println(" | ");
delay(200);
پروژه آردوینو: انيميشن حركت جوي استيک در IDE
در اینجا ميخواهيم يك پروژه آردوينو بسازیم و با استفاده از آن نحوه كار ماژول جوی استیک دو محوره براي كنترل يك انيميشن در IDE را نشان دهيم.
در ابتدا آردوينو را پروگرام مي كنيم تا به كمك آن اطلاعات مربوط به موقعيت جوي استيک در راستاي محور x و y و وضعيت سوئيچ فشاري روي دسته جوي استيک را بر روی پورت سريال داشته باشيم. در IDE اين مقادير را از پورت سريال ميخوانيم و با استفاده از آنها موقعيت لحظهاي جوي استيک را بصورت انيميشن بر روي IDE نمايش ميدهيم.
نتيجه كار چيزي شبيه به شكل زير خواهد بود:
البته اين پروژه را مي توان براي نمايش كاراكتر های انیمیشنی، پروژه های جاسوسی و يا كنترل خودروهاي بدون سرنشين به کار گرفت.
كد آردوينو
در ابتدا لازم است آردوینو را پروگرام كنيم تا اطلاعات مقادير محور x و y و وضعيت سوئيچ فشاري روي دسته جوي استيک را بر روي پورت سريال داشته باشيم. اين كد دقيقا مشابه كدي است كه در قسمت قبل توضيح داده شد، اما با اين تفاوت كه در اينجا بجاي پرينت اطلاعات بر روي سریال مانیتور، آنها را با كاراكتر كاما از يكديگر تفكيك می کنیم. اما چرا از کاما استفاده می کنیم؟ پاسخ اين است كه اين يك روش متداول جهت ارسال اطلاعات بين ابزارهاي مختلف می باشد. در IDE ميتوان مقادير دريافتي بر روي پورت سريال را بر اساس كاراكتر كاما از يكديگر تفكيک نمود و بدين ترتيب اطلاعات مورد نياز را بدست آورد.
كد زير را روی آردوينو آپلود كنيد:
int xValue = 0 ; // read value of the X axis
int yValue = 0 ; // read value of the Y axis
int bValue = 0 ; // value of the button reading
void setup()
{
Serial.begin(9600) ; // Open the serial port
pinMode(8,INPUT) ; // Configure Pin 2 as input
digitalWrite(8,HIGH);
}
void loop()
{
// Read analog port values A0 and A1
xValue = analogRead(A0);
yValue = analogRead(A1);
// Read the logic value on pin 2
bValue = digitalRead(8);
// We display our data separated by a comma
Serial.print(xValue,DEC);
Serial.print(",");
Serial.print(yValue,DEC);
Serial.print(",");
Serial.print(!bValue);
// We end with a newline character to facilitate subsequent analysis
Serial.print("\n");
// Small delay before the next measurement
delay(10);
}
كد IDE
پس از آپلود كد قسمت قبل بر روی آردوينو، ميتوانيد انيميشني از موقعيت و حركات جوي استيک در IDE داشته باشيد. كافيست كد زير را در IDE اجرا كنيد:
import processing.serial.*; //import the Serial library
Serial myPort;
int x; // variable holding the value from A0
int y; // variable holding the value from A1
int b; // variable holding the value from digital pin 2
PFont f; // define the font variable
String portName;
String val;
void setup()
{
size ( 512 , 512 ) ; // window size
// we are opening the port
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil('\n');
// choose the font and size
f = createFont("Arial", 16, true); // Arial, 16px, anti-aliasing
textFont ( f, 16 ) ; // size 16px
}
// drawing loop
void draw()
{
fill(0) ; // set the fill color to black
clear() ; // clean the screen
fill(255) ; // set the fill color to white
if (b == 1) // check if the button is pressed
{
// draw a larger circle with specified coordinates
ellipse(x/2,y/2, 50, 50);
}
else
{
// we draw a circle with a certain coordinates
ellipse(x/2,y/2, 25, 25);
}
// we display data
text("AnalogX="+(1023-x)+" AnalogY="+(1023-y),10,20);
}
// data support from the serial port
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
x = vals[0];
y = vals[1] ;
b = vals[2];
}
}
توضيح كد IDE
در اینجا نگاه سريعي به برنامه خواهيم داشت. در ابتدا كتابخانه سريال را فراخوانی می کنیم تا به كمك آن مقادير دريافتي از پورت سريال را بخوانيم.
import processing.serial.*; //import the Serial library
Serial myPort;
پس از آن متغيرهايي براي نگهداري مقادير محور x و محور y و وضعيت سوئيچ فشاري تعريف ميكنيم.
int x; // variable holding the value from A0
int y; // variable holding the value from A1
int b; // variable holding the value from digital pin 2
PFont f; // define the font variable
String portName;
String val;
در تابع setup، يك پنجره به ابعاد 512*512 براي نمايش انيميشن ايجاد ميكنيم. در قدم بعد، توسط serial.list()[0] يك پورت سريال در دسترس را انتخاب ميكنيم. اگر اين دستور براي شما كار نكرد كافيست پورت سريالي كه آردوينو به آن متصل است را انتخاب كنيد. به علاوه باید فونت نمايش اطلاعات بر روي انيميشن نيز انتخاب شود.
size ( 512 , 512 ) ; // window size
// we are opening the port
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil('\n');
// choose the font and size
f = createFont("Arial", 16, true); // Arial, 16px, anti-aliasing
textFont ( f, 16 ) ; // size 16px
در تابع draw، ابتدا پس زمينه نمايش انيميشن با رنگ سياه پر ميشود. سپس براي نمايش موقعيت جوي استيك بر روي اين صفحه سياه يك دايره با رنگ سفيد می کشیم. براي نمايش وضعيت آزاد بودن و يا فشرده بودن سوئيچ فشاري با استفاده از عبارت شرطي if در هر يك از اين دو وضعيت يك دايره بزرگ يا كوچك می کشیم.
fill(0) ; // set the fill color to black
clear() ; // clean the screen
fill(255) ; // set the fill color to white
if (b == 1) // check if the button is pressed
{
// draw a larger circle with specified coordinates
ellipse(x/2,y/2, 50, 50);
}
else
{
// we draw a circle with a certain coordinates
ellipse(x/2,y/2, 25, 25);
}
در خط بعدي كد، مختصات y و x در گوشه چپ در بالاي پنجره نمايش داده ميشود.
// we display data
text("AnalogX="+(1023-x)+" AnalogY="+(1023-y),10,20);
serialEvent (Serial-myPort) یک تابع دست نویس است که رشته کاراکتر های موجود بر روی پورت سریال را تا زمان ظاهر شدن خط جدید کاراکتر ها می خواند. اين رشته كاراكترها بر اساس كاراكتر كاما تفكيك شده و به متغيرهاي مربوطه انتساب داده ميشوند.
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
x = vals[0];
y = vals[1] ;
b = vals[2];
}
}
مشكلات جوي استيک هاي آنالوگ
سيستم جوي استيک آنالوگ تعدادی مشکل كوچک اما مهم دارد:
- اولین مشکل سیستم جوی استیک این است که پروسه تبديل آنالوگ به ديجيتال در آن دقيق نيست. زیرا اين سيستم فاقد يك مبدل آنالوگ به ديجيتال واقعي است. چنين مشكلي متناقض با نياز به حساسیت جوي استيك خواهد بود.
- دومین مشکل این سیستم مصرف زیاد توان محاسباتی میکروکنترلر به منظور خواندن موقعیت دسته از سیستم جوی استیک است. اين عامل باعث می شود توان این سیستم در سایر عملیات محاسباتی کاهش پیدا کند.
با این مقاله آموزشی، راه اندازی ماژول جوی استیک دو محوره با آردوینو به راحتی انجام می پذیرد. اگر در این زمینه با مشکلی برخورد کردید، می توانید آن را با ما در میان بگذارید.
۲ دیدگاه. Leave new
سلام وقت بخیر
میشه راهنمایی کنید چطور جوی استیک رو با فرستنده و گیرنده مادون قرمز تلفيق کرد؟
سلام و درود خدمت شما دوست عزیز
جهت ارائه پاسخ کامل و مناسب، لطفاً توضیح بیشتری بدید که چه عملکردی مدنظرتون هست و اینکه آیا داخل کدنویسی ابهام دارید یا اتصالات یا… .
تشکر از همراهی شما 🙂