در قسمت سی و پنجم از آموزش آردوینو به بررسی اندازهگیری دما و خواندن تگهای RFID (NFC) پرداختیم. در این قسمت قصد داریم درباره ردیابی حرکت چرخشی و ردیابی حرکت چرخشی در اسکچ با استفاده از وقفهها صحبت کنیم.
فرض میکنید میخواهید چرخش چیزی را اندازهگیری و نمایش دهید تا سرعت و جهت آن را ردیابی کنید.
برای حسکردن حرکت چرخشی میتوانید از یک انکودر چرخشی (Rotary Encoder) استفاده کنید که به شیء موردنظر برای ردیابی متصل میشود.
انکودر را همانطور که در شکل 1 نشان داده شده است، وصل کنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | * * Read a rotary encoder * This simple version polls the encoder pins * The position is displayed on the Serial Monitor */ const int encoderPinA = 3; const int encoderPinB = 2; const int encoderStepsPerRevolution=16; int angle = 0; int encoderPos = 0; bool encoderALast = LOW; // remembers the previous pin state void setup() { Serial.begin (9600); pinMode(encoderPinA, INPUT_PULLUP); pinMode(encoderPinB, INPUT_PULLUP); } void loop() { bool encoderA = digitalRead(encoderPinA); if ((encoderALast == HIGH) && (encoderA == LOW)) { if (digitalRead(encoderPinB) == LOW) { encoderPos--; } else { encoderPos++; } angle=(encoderPos % encoderStepsPerRevolution)*360/encoderStepsPerRevolution; Serial.print (encoderPos); Serial.print (" "); Serial.println (angle); } encoderALast = encoderA; } |
شکل 1: انکودر چرخشی
یک انکودر چرخشی هنگام چرخاندن، دو سیگنال تولید میکند. هر دو سیگنال با چرخش شفت بین HIGH و LOW تغییر میکنند، اما این سیگنالها کمی از نظر فاز با هم اختلاف دارند.
اگر نقطهای را که یکی از سیگنالها از HIGH به LOW تغییر میکند شناسایی کنید، وضعیت پین دیگر (اینکه در حالت HIGH است یا LOW) به شما نشان میدهد که shaft در کدام جهت در حال چرخش است.
بنابراین، اولین خط کد تابع loop یکی از پینهای انکودر را میخواند:
1 | int encoderA = digitalRead(encoderPinA); |
سپس این مقدار و مقدار قبلی را بررسی میکند تا ببیند آیا مقدار جدید به LOW تغییر کرده است یا نه.
1 | if ((encoderALast == HIGH) && (encoderA == LOW)) |
اگر اینطور نباشد، کد بلوک بعدی را اجرا نمیکند و به انتهای loop میرود، مقداری را که تازه خوانده در encoderALast ذخیره میکند و دوباره از ابتدا برای گرفتن یک خوانش جدید برمیگردد.
وقتی عبارت زیر true باشد:
1 | if ((encoderALast == HIGH) && (encoderA == LOW)) |
کد، پین دیگر انکودر را میخواند و بسته به مقدار بازگشتی، encoderPos را یکی افزایش یا کاهش میدهد. سپس زاویهی shaft را محاسبه میکند (با درنظرگرفتن 0 بهعنوان نقطهای که shaft هنگام شروع اجرای کد در آن قرار داشته است). در نهایت، مقادیر را از طریق پورت سریال ارسال میکند تا بتوانید آن را در Serial Monitor مشاهده کنید.
انکودرها با دقتهای مختلفی عرضه میشوند که برحسب تعداد پله در هر دور بیان میشود. این مقدار نشان میدهد که در یک دور کاملshaft ، سیگنال چند بار بین HIGH و LOW جابهجا میشود. این مقادیر میتوانند از ۱۶ تا ۱۰۰۰ متغیر باشند. مقادیر بالاتر، حرکات کوچکتر را تشخیص میدهند و این نوع انکودرها بسیار گرانتر هستند. مقدار مربوط به انکودر در کد بهصورت ثابت hard-coded در کد زیر نوشته شده است:
1 | const int encoderStepsPerRevolution=16; |
اگر انکودر شما متفاوت باشد، لازم است آن مقدار را تغییر دهید تا مقادیر زاویه بهدرستی محاسبه شوند.
اگر مقادیری که دریافت میکنید بالا و پایین نروند و صرفاً بدون توجه به جهت چرخش انکودر افزایش پیدا کنند، سعی کنید بررسی را روی لبه صعودی (rising edge) بهجای لبه نزولی (falling edge) انجام دهید. مقدارهای LOW و HIGH را در کدی که مقادیر را بررسی میکند جابهجا کنید تا به این شکل شود:
1 | if ((encoderALast == LOW) && (encoderA == HIGH)) |
انکودرهای چرخشی فقط یک سیگنال افزایش/کاهش تولید میکنند و نمیتوانند مستقیماً زاویه shaft را به شما بدهند. کد این زاویه را محاسبه میکند، اما هر بار نسبت به موقعیت شروع در ابتدای اجرای کد خواهد بود. کد پینها را با polling (بررسی مداوم مقدار آنها) مانیتور میکند. هیچ تضمینی وجود ندارد که پینها از آخرین باری که کد مقدارشان را بررسی کرده تغییر نکرده باشند، بنابراین اگر کد کارهای دیگری هم انجام دهد و انکودر خیلی سریع چرخانده شود، ممکن است بعضی از پلهها از دست بروند. این موضوع برای انکودرهای با دقت بالا بیشتر رخ میدهد، چون این انکودرها هنگام چرخش سیگنالها را با فرکانس بالاتری ارسال میکنند.
برای محاسبه سرعت، باید تعداد قدمهایی را که در یک جهت مشخص در یک زمان معین ثبت میشوند، بشمارید.
با گسترش کد و انجام کارهای دیگر علاوه بر خواندن انکودر، یا اگر بخواهید بیش از یک انکودر را بخوانید، خواهید دید که خوانشهای شما از انکودر شروع به غیر قابل اعتماد شدن میکنند. این مشکل بهویژه زمانی که shaft با سرعت زیاد میچرخد، شدیدتر است.
ما از یک کتابخانه استفاده خواهیم کرد که برای خواندن انکودرهای چرخشی بهینه شده است. این کتابخانه از قابلیتهای وقفهی آردوینو استفاده میکند تا به تغییرات وضعیت پایهها سریع پاسخ دهد. از مدیر کتابخانهها برای نصب کتابخانهی Encoder نوشتهی Paul Stoffregen استفاده کنید و اسکچ زیر را اجرا کنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | * /* Rotary Encoder library sketch * Read the rotary encoder with a library that uses interrupts * to process the encoder's activity */ #include <Encoder.h> Encoder myEnc(2, 3); // On MKR boards, use pins 6, 7 void setup() { Serial.begin(9600); } long lastPosition = -999; void loop() { long currentPosition = myEnc.read(); if (currentPosition != lastPosition) { // If the position changed lastPosition = currentPosition; // Save the last position Serial.println(currentPosition); // print it to the Serial monitor } } |
وقتی کد شما کارهای بیشتری برای انجامدادن دارد، پینهای انکودر کمتر بررسی میشوند. اگر پینها یک تغییر کامل مرحلهای را پشت سر بگذارند قبل از اینکه خوانده شوند، آردوینو آن مرحله را تشخیص نخواهد داد. چرخاندن سریع shaft باعث ایجاد خطاهای بیشتر میشود، زیرا مراحل سریعتر رخ میدهند.
برای اطمینان از اینکه کد هر بار که یک مرحله رخ میدهد پاسخ میدهد، باید از وقفهها استفاده کنید. زمانی که شرط وقفه رخ دهد (مثلاً تغییر وضعیت یک پین)، کد از هر جایی که باشد پرش میکند، وقفه را پردازش میکند و سپس به همان جایی که بود بازمیگردد و ادامه میدهد. کتابخانهی Encoder بهترین عملکرد را با پینهایی دارد که از وقفههای سختافزاری پشتیبانی میکنند، اما حتی با پینهایی که این پشتیبانی را ندارند هم بهترین عملکرد ممکن را ارائه میدهد.
در آردوینو Uno و سایر بردهای مبتنی بر ATmega328، تنها دو پین میتوانند بهعنوان وقفه استفاده شوند: پینهای ۲ و ۳. فهرستی از پینهای پشتیبانیشده در بردهای خاص را مشاهده کنید. یک انکودر چرخشی را با کد زیر اعلام و مقداردهی اولیه میکنید:
1 | Encoder myEnc(2, 3); |
پارامترهای مقداردهی اولیهی Encoder دو پین (یا پایهای) هستند که انکودر به آنها متصل شده است. اگر متوجه شدید که مقدار انکودر در حالی کاهش مییابد که انتظار افزایش دارید، میتوانید آرگومانها را جابهجا کنید یا سیمکشی خود را تغییر دهید. پس از مقداردهی اولیهی انکودر، هر زمان که انکودر را بچرخانید، برنامه برای لحظهای متوقف شده و وقفه ایجاد میشود تا حرکت را دنبال کند. شما میتوانید در هر زمانی مقدار آن را با myEnc.read() بخوانید.
شما میتوانید به اندازهی تعداد پینهایتان انکودر ایجاد کنید، اما هر زمان که امکان دارد، از پینهایی استفاده کنید که از وقفهها پشتیبانی میکنند. اسکچ زیر دو انکودر را مدیریت خواهد کرد و به طور بهینه روی بردی که میتواند وقفهها را روی پینهای انتخابشده پشتیبانی کند، مانند بردهای مبتنی بر SAMD21 مانند Adafruit Metro M0 ،SparkFun RedBoard Turbo و Arduino Zero، کار خواهد کرد. اگر از برد دیگری استفاده میکنید، ممکن است لازم باشد از پینهای متفاوتی استفاده کنید. برد Uno و سایر بردهای مبتنی بر ATmega328 تنها وقفهها را روی پینهای ۲ و ۳ پشتیبانی میکنند، بنابراین کیفیت خواندنها برای انکودر دوم صرفنظر از اینکه کدام پینها را انتخاب کنید، کاهش خواهد یافت.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <Encoder.h> Encoder myEncA(2, 3); // MKR boards use pins 4, 5 Encoder myEncB(6, 7); // Mega boards use pins 18, 19 void setup() { Serial.begin(9600); while(!Serial); } long lastA = -999; long lastB = -999; void loop() { long currentA = myEncA.read(); long currentB = myEncB.read(); if (currentA != lastA || currentB != lastB) { // If either position changed lastA = currentA; // Save both positions lastB = currentB; // Print the positions to the Serial Monitor (or Serial Plotter) Serial.print("A:"); Serial.print(currentA); Serial.print(" "); Serial.print("B:"); Serial.println(currentB); } } |
آردوینو MKR Vidor 4000 شامل یک FPGA است که میتواند انکودر چرخشی را با دقت بسیار بیشتری نسبت به خودِ آردوینو بخواند.
اندازهگیری دما + خواندن تگهای RFID (NFC) |...
من کاپیتان آردوینو، اسمم میلاده و اینجا هستم تا تجربیاتم در رابطه با آردوینو رو با شما به اشتراک بزارم!
نویسنده شو !
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.