আরডুইনো মাল্টিটাস্কিং কি সম্ভব? | Is it possible Arduino Multitasking

প্রথমেই মাল্টিটাস্কিং শব্দটা ক্লিয়ার হওয়া যাক। একের অধিক প্রোগ্রাম যখন একই সময়ে কাজ করতে পারে তখন তাকে মাল্টিটাস্কিং বলা হয়। উদাহরণ হিসেবে বলা যায়, যখন আপনি আপনার পিসিতে দুই বা ততোধিক সফটওয়্যার (হতে পারে ইন্টারনেট ব্রাউজার, গেমস, ফটোশপ ইত্যাদি) রান করছেন অর্থ্যাৎ আপনি মাল্টিটাস্কিং করছেন। একইভাবে, মোবাইলের ক্ষেত্রেও আমরা মিউজিক প্লেয়ার দিয়ে ব্যাকগ্রাউন্ডে গান শুনতেছি এবং ফ্রন্ট এ ফেসবুক ব্রাউজিং/গেমিং অথবা অন্য কোন এ্যাপস ব্যবহার করতেছি। এক্ষেত্রে যে কাজটি হচ্ছে সেটাই মাল্টিটাস্কিং।

প্রশ্ন হলো সি.পি.ইউ কিভাবে মাল্টিটাস্কিং এর কাজগুলো সম্পন্ন করে? মাল্টিটাস্কিং করার জন্য বর্তমানে সি.পি.ইউ গুলোতে উচ্চ ক্লক ফ্রিকোয়েন্সি, একাধিক কোর, একাধিক থ্রেড এবং বেশি স্টোরেজযুক্ত র‌্যাম ব্যবহার করা হয়। অপরদিকে আরডুইনোতে রয়েছে সিঙ্গেল কোর ভিত্তিক মাইক্রোকন্ট্রোলার। যার মাধ্যমে একই সময়ে শুধুমাত্র একটি নির্দেশ প্রসেস করা সম্ভব। একই সময়ে একটিমাত্র কাজ সম্পাদন করলে কিভাবে আরডুইনো দিয়ে আমরা মাল্টিটাস্কিং করব? আসুন জেনে নেয়া যাক আরডুইনো মাল্টিটাস্কিং সম্পর্কে বিস্তারিত।

আরডুইনো মাল্টিটাস্কিং | Arduino Multitasking

ধরুণ আপনার একটি আরডুইনো প্রোজেক্ট যেটা দিয়ে আপনি কয়েকটি কাজ একসাথে করাতে চাচ্ছেন, যেমন : L.E.D ব্লিংক করা, এনালগ ডেটা রিড করে ডিসপ্লে তো দেখানো, সিরিয়াল মনিটর থেকে ডেটা নেয়া অথবা ডেটা প্রিন্ট করা, একসাথে ২-৩ টা মটর কন্ট্রোল করা ইত্যাদি। এই কাজটা করা গেলে একে বলা হবে আরডুইনো মাল্টিটাস্কিং। যেহেতু আরডুইনো মাইক্রোকন্ট্রোলার একই সময়ে একাধিক ইন্সট্রাকশান সম্পন্ন করতে পারেনা সেহেতু আমরা আরডুইনোতে স্ট্যান্ডার্ড প্যারালাল প্রোগ্রাম রান করাতে পারবনা।

প্রফেশনালি বলতে হয়, আরডুইনোতে মাল্টিটাস্কিং সম্ভব নয়। মাল্টিটাস্কিং এর টাইম ডিস্ট্রিবিউশান কনসেপ্ট ব্যবহার করে আমরা আরডুইনোতে মাল্টিটাস্কিং এর স্বাদ নেওয়ার চেষ্টা করব। ধরা যাক ২ টা টাস্ক একসাথে রান হল, সি.পি.ইউ প্রত্যেক টাস্ক এর জন্য নির্দিষ্ট সময়কে সমানভাগে ভাগ করে ২ টা টাস্কই প্রসেস করল। এটাই হল টাইম ডিস্ট্রিবিউশান কনসেপ্ট। এই কনসেপ্টটিকে একটু ভিন্নভাবে ব্যবহার করে আমরা আরডুইনোতে মাল্টিটাস্কিং করতে পারি। আরেকটু ক্লিয়ার হওয়া যাক, ধরুন একটি এল.ই.ডি আমি ২ সেকেন্ড পরপর অন/অফ করতে চাচ্ছি। এক্ষেত্রে আমরা সাধারণত delay() ফাংশান ব্যবহার করে থাকি। ২ সেকেন্ড ডিলে ব্যবহারের জন্য মাইক্রোকন্ট্রোলার ২ সেকেন্ড করে ঘুমাবে এবং ডিলে শেষ হলে সে ঘুম থেকে উঠে প্রোগ্রাম এর পরবর্তী লাইনের কাজ করতে থাকবে।

সুতরাং ডিলে চলাকালীন সময়ে আরডুইনো অন্য সকল প্রসেসিং থেকে বিরত থাকে। যদি এমন হয় যে, আমার পুরো প্রোগ্রাম রান করবে এবং ২ সেকেন্ড পরপর এল.ই.ডি অন/অফ ও হবে তাহলে একে বলা হবে মাল্টিটাস্কিং। এটা করার জন্য আমরা আরডুইনোর বিল্ট ইন milis() ফাংশান ব্যবহার করব।

delay() ফাংশান ব্যবহার না করে millis() কেন ব্যবহার করব?

আরডুইনোতে দুই ধরনের ডিলে ফাংশান ব্যবহার করা হয়। delay() এবং delayMicroseconds()। উভয় ফাংশান ব্যবহারে নির্দিষ্ট ডিলে (প্যারামিটারে ব্যবহৃত মিলিসেকেন্ড/মাইক্রোসেকেন্ড) এর জন্য আরডুইনো মাইক্রোকন্ট্রোলার বিজি/স্লিপ মোডে চলে যায়।

আরডুইনো মাইক্রোকন্ট্রোলার এর কোর ফ্রিকোয়েন্সি হলো 16Mhz। অর্থ্যাৎ একটি আরডুইনো মাইক্রোকন্ট্রোলার প্রতি সেকেন্ড এ 16,000,000 টি সাইকেল/চক্র সম্পন্ন করতে পারে। এখন প্রশ্ন হলো delay এর সাথে ফ্রিকোয়েন্সি এর কি সম্পর্ক? সমস্যাটা এখানেই, আমরা নিচের কোডের দিকে একটু লক্ষ করি।

int myLed = 8; //LED is connected to arduino digital pin 8.

void setup() {
  pinMode(myLed, OUTPUT); // initialize myLed as an output.
}
void loop() {
  digitalWrite(myLed, HIGH); // Turn the LED on
  delay(1000);
  digitalWrite(myLed, LOW); // Turn the LED off
  delay(1000);   
}

এখানে, এল.ই.ডি অন করার পর ১০০০ মিলিসেকেন্ড বা ১ সেকেন্ড পর্যন্ত মাইক্রোকন্ট্রোলার স্লিপ মোডে খাকছে। ডিলে শেষ হলে পুনরায় এল.ই.ডি অফ হয়ে আবার মাইক্রোকন্ট্রোলার ১ সেকেন্ড হোল্ড থেকে পুনরায় লুপ করছে। অর্থাৎ প্রতিটি লুপ সম্পন্ন করার জন্য মাইক্রোকন্ট্রোলারকে ২ সেকেন্ড এর বেশি সময় নিতে হচ্ছে।

ম্যাথমেটিক্যালি ব্যাখ্যা করতে গেলে, একটি মাইক্রোকন্ট্রোলার প্রতি সেকেন্ড এ 16Mhz সমপরিমান বা 16,000,000 টি সাইকেল/চক্র সম্পন্ন করে। তাহলে এতে বোঝা যায় যে, প্রতি সেকেন্ড delay() এর জন্য আমরা মাইক্রোকন্ট্রোলার এর ১৬ মিলিয়ন সাইকেল/চক্র নষ্ট করছি। কোনোভাবে এই delay() এর ব্যবহার না করে যদি এই ফ্রিকোয়েন্সিগুলোকে যথাযথ ব্যবহার করা যায় তাহলে এই সময়ে অন্যান্য কাজ করাও সম্ভব। আর এজন্যই আমরা আরডুইনোর বিল্ট ইন millis() ফাংশান ব্যবহার করব।

millis() ফাংশানের ব্যবহার

millis(), হলো একটি সময় মনে রাখার ফাংশান। অর্থাৎ আরডুইনোতে প্রোগ্রাম শুরু হওয়া থেকে এখন পর্যন্ত যতক্ষণ হলো millis() ব্যবহার করে তা মিলিসেকেন্ডে প্রকাশ করা হয়। এটি ব্যবহার করে আমরা delay() এর কাজ করতে পারি কোনরকম প্রোগ্রাম স্থগিত করা ছাড়া। millis() এর জন্য যেভাবে ভেরিয়েবল ডিক্লেয়ার করতে হয়-

unsigned long currentTime = millis();

এখানে, millis() এর ডেটা টাইপ হচ্ছে long। unsigned হলো স্পেসিফায়ার যা দ্বারা অঋণাত্মক(Non-negative) সংখ্যা বোঝানো হচ্ছে। এখন currentTime এই ভেরিয়েবলকে প্রিন্ট করলে আমরা প্রোগ্রাম শুরু থেকে এখন পর্যন্ত মোট সময়কে মিলিসেকেন্ডে এ দেখতে পাব।

আবার অনেকে millis() এর ন্যায় micros() এই ফাংশানটিও ব্যবহার করে থাকে। দুইটাই একই ধরনের ফাংশান, millis() এ আউটপুট হবে মিলিসেকেন্ড এ এবং micros() এ আউটপুট হবে মাইক্রোসেকেন্ড এ। দুইটি ফাংশানই long ডেটা টাইপ এর সর্বোচ্চ বিট পর্যন্ত গিয়ে আবার রিসেট হয়ে 0 থেকে গণনা শুরু করবে। long ডেটা টাইপ এর সর্বোচ্চ বিট 2^32। millis() এর সর্বোচ্চ গণনাকারী বিট কে সময়ের হিসেবে নিম্নোক্তভাবে প্রকাশ করা যায়,

2^32 / 1000 / 60 /60 / 24 = 49.7 

millis() ফাংশনটির সর্বোচ্চ বিট পর্যন্ত পৌঁছাতে প্রায় 50 দিন সময় অতিবাহিত করতে হয়। অপরদিকে micros() ফাংশানটির সর্বোচ্চ বিট পর্যন্ত পৌঁছাতে প্রায় 70 মিনিট সময় অতিবাহিত করতে হয়। অতএব সময়ের হিসেব অনুযায়ী micros() থেকে millis() ফাংশান ব্যবহার করায় শ্রেয়। এবার দেখি delay() এর পরিবর্তে কিভাবে millis() ব্যবহার করা যায়।

unsigned long currentTime;
unsigned long previousTime = 0;
int interval = 1000;

void loop() {
currentTime = millis();
if((currentTime - previousTime) > interval){
  previousTime = currentTime;
  // Lets do something
  }
}

এখানে millis() এর ডেটা স্টোর করার জন্য ২ টি ভেরিয়েবল currentTime ও previousTime এবং delay() এর পরিবর্তে একটি ইন্টিজার ভেরিয়েবল interval। লুপ এর শুরুতেই আমরা millis() এর মাধ্যমে বর্তমান সময় চেক করছি। এবং previousTime এর initial value 0 ডিক্লেয়ার করে দিয়েছি। এবং if কন্ডিশনের মাধ্যমে প্রতি লুপ এ চেক করতেছি currentTime থেকে previousTime কি আমার interval থেকে বেশি হয়েছে নাকি। যেহেতু interval=1000 বা ১ সেকেন্ড সেহেতু currentTime এর value 1000 ক্রস করলেই কন্ডিশান এর কোড রান হবে। আবার কন্ডিশান এ আমরা previousTime কে currentTime এর value ডিক্লেয়ার করে দিচ্ছি। তাহলে পরবর্তী ১ সেকেন্ড পর কন্ডিশানটি আবার কাজ করবে। এভাবে পুরো প্রোগ্রামে delay() এর পরিবর্তে আমরা millis() ব্যবহার করতে পারি।

উপরের delay() ব্যবহৃত এল.ই.ডি অন/অফ প্রোগ্রামটি আমরা millis() ব্যবহার করে করব। তাহলে আরো ক্লিয়ার হওয়া যাবে।

int myLed = 8;
int ledState = LOW;
unsigned long currentTime;
unsigned long previousTime = 0;
int interval = 1000;

void setup() {
  pinMode(myLed, OUTPUT);
  digitalWrite(myLed, ledState);
}
void loop() {
  currentTime = millis();

  if((currentTime - previousTime) >= interval){
    previousTime = currentTime;
    if(ledState == LOW){
      ledState = HIGH;
    }
    else{
      ledState = LOW;
    }
    digitalWrite(myLed, ledState) // Turn the LED on/off
  }
}

এই প্রোগ্রামের মাধ্যমে শুধুমাত্র দেখানো হয়েছে কিভাবে delay() ব্যবহার না করে আমরা আরডুইনো তে সময় নির্ভর প্রোগ্রাম রান করতে পারি। milis() এর ব্যবহার ‍উপরেই ব্যাখ্যা করা হয়েছে। এখন আমরা milis() ফাংশান ব্যবহার করে মাল্টিটাস্কিং এর একটি বাস্তব উদাহরণ দেখব-

মাল্টিটাস্কিং উদাহরণ – ০১

Share This Post

Post Comment