در دانشنامههای قبلی با انکودر و نحوهی کار آن آشنا شدید. همچنین چگونگی راهاندازی موتور DC را در آردوینو آموختید. در این مقاله نحوهی محاسبهی سرعت موتور با استفاده از یک انکودر دوار نوری آموزش داده میشود.
قطعات مورد نیاز
نحوهی اتصال سیمها
در تصویر زیر پینهای انکودر موتور jga25-371 مشخص شدهاند. دو پین بالایی ( سیمهای سفید و زرد) مربوط به سیگنالهای خروجی انکودر هستند که در بعضی از محصولات با نام CHA و CHB ( کانال A و کانال B ) نامگذاری شدهاند. پینهای VCC و GND مربوط به تغذیهی انکودر هستند که در این موتور باید 3.3 ولت باشد. پینهای M- و M+ نیز دو سر موتور DC هستند که خروجی درایور موتور به آنها وصل میشود.
نحوهی اتصال سیمها برای راهاندازی موتور و انکودر در شماتیک زیر نشان داده شده است.
کد نویسی
کد نویسی برای حالتی که سرعت و جهت چرخش موتور محاسبه شود انجام شده است. با توجه به اینکه جهت حرکت موتور توسط ماژول l298 و به دلخواه کاربر تنظیم میشود، در اکثر کاربریها نیاز به تشخیص جهت حرکت توسط انکودر نیست و میتوان تنها به محاسبه سرعت موتور پرداخت.
در ادامه توضیحاتی در مورد تابع pulseIn در آردوینو ارائه میشود و سپس کد ذکر شده قرار داده میشود.
تابع pulseIn
برای اندازهگیری فواصل زمانی بین امواج مربعی سیگنالهای خروجی از انکودر در آردوینو راههای بسیار متنوعی وجود دارد. در این پروژه از دستور pulseIn استفاده شده است. این تابع مدت زمان High یا Low بودن یک سیگنال را به واحد میکروثانیه و در بازهی 10 میکروثانیه تا 3 دقیقه به عنوان خروجی میدهد. طبق توضیحات رفرنس آردوینو این تابع سه ورودی لازم دارد: تعیین پین مربوط به سیگنال، انتخاب اندازهگیری زمان برای حالت High یا Low بودن سیگنال و مقداری به عنوان timeout که یک ورودی دلخواه است و بصورت پیشفرض برای یک ثانیه در نظر گرفته شده است. در صورتیکه مدت زمان انتظار تابع برای شروع یکی از حالتهای High یا Low بیشتر از مقدار timeout تنظیم شده باشد، خروجی این تابع صفر خواهد بود.
محاسبه سرعت و جهت چرخش
در این روش پین دیجیتال 2 که به کانال A از انکودر متصل است به عنوان پین اینتراپت در نظر گرفته شده است. مود اینتراپت روی حالت RISING قرار داده شده است. بنابراین هر زمان که خروجی کانال A از پایین به بالا حرکت کند روتین (تابع) اینتراپت فراخوانده میشود.
در روتین اینتراپت بررسی میشود که کانال B در این لحظه در حالت Low قرار دارد یا High و بسته به این موضوع جهت حرکت موتور تشخیص داده میشود (مثبت 1 برای چرخش ساعتگرد و منفی 1 برای پادساعتگرد). جهت درک بهتر این موضوع حتما مقاله آشنایی با انکودر دوار چیست؟ را مطالعه کنید.
CPR موتور استفاده شده طبق اطلاعات درج شده روی موتور 360 است. یعنی سیگنالهای کانال A و B در هر دور چرخش کامل موتور، 360 بار تناوب میکنند. تابع pulseIn تنها زمان Low یا High بودن سیگنال را به عنوان خروجی میدهد، یعنی نصف زمان تناوب سیگنال مربعی. بنابراین حالصضرب خروجی این تابع در مقدار CPR و در عدد 2 زمان چرخش یک دور کامل موتور با سرعت لحظهای که تابع pulseIn فراخوانی شده را در واحد میکروثانیه میدهد. تابع pulseIn در تابع Loop فرخوانی شده است. همچنین در Loop سرعت موتور با توجه به خروجی تابع pulseIn و در نظر گرفتن نسبت چرخدنده و جهت چرخش به واحد دور بر دقیقه محاسبه و پرینت میشود.
در این کد دو تابع setPWM برای تعیین pwm اعمالی به موتور و setDirection برای تعیین جهت چرخش موتور نیز تعریف و استفاده شدهاند.
برای بررسی عملکرد کد، سیگنال pwm به صورت سینوسی به موتور اعمال شده است و نمودار سرعت موتور و pwm اعمالی نمایش داده شده است.
#define _60secInMicrisec 60000000.0f
#define GearRatio 34.0f
#define EncoderCPR 360
#define pi 3.1415f
int ENA=10; // to EnA of L298
int IN1=9; // to IN1 of L298
int IN2=8; // to IN2 of L298
const byte ChA = 2; // to ENA (OutA / ChA) of Encoder
const byte ChB = 3; // to ENB (OutA / ChA) of Encoder
volatile unsigned long _1RevDuration; // Duration of 1 Revolution
float rpm=0; // Motor Speed
volatile int feedbackDirection; // Direction Detected by Encoder
enum desiredDirection{ // Desired Direction
CW = 0, // Clockwise
CCW = 1 // Counter Clockwise
};
float pwm; // PWM to L298
long counter =0; // Counter for Sinusoidal PWM Generation
void setPWM(float outputPWM); // Apply PWM to motor (input between 0-100)
void setDirection(desiredDirection dir); // Select Direction of Rotation
void setup() {
Serial.begin(9600);
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
setDirection(CW); // set Initial Diretion to Clockwise
setPWM(90); // initialize Motor
attachInterrupt(digitalPinToInterrupt(ChA), checkDirection, RISING); // Define Pin ChA as Intrrupt Pin
}
void loop() {
pwm = 80.0f*sin(2.0f*pi*counter/100.0f);
counter += 1;
if (pwm > 0)
setDirection(CW);
else
setDirection(CCW);
setPWM(fabs(pwm));
//delay(100);
_1RevDuration = pulseIn(ChA, LOW,10000)*EncoderCPR*2; // Calculating the Duration of a Revolution in micro seconds
if (_1RevDuration == 0) // Avoiding from Singularity Problem
rpm = 0;
else
rpm = feedbackDirection*_60secInMicrisec/((float)_1RevDuration*GearRatio); // Calculating Motor RPM
Serial.print(rpm);
Serial.print(" ");
Serial.println(pwm);
}
void setDirection(desiredDirection dir){
switch(dir){
case CW:
digitalWrite(IN1,LOW);
digitalWrite(IN2,HIGH);
break;
case CCW:
digitalWrite(IN2,LOW);
digitalWrite(IN1,HIGH);
break;
}
}
void setPWM(float outputPWM){
analogWrite(ENA,outputPWM*255/100);
}
void checkDirection(){
feedbackDirection = -2*bitRead(PIND,ChB)+1;
}
سلام.برنامه نویسیش کجاست؟
میخوام بدونم برای محاسبه سرعت موتور rpm
چه مقدار هایی در هم ضرب و تقسیم میشن تا rpm به دست میاد؟
سلام
در کد نوشته شده PIND در خط ۷۰ جایی تعریف نشده است.