آموزش آردوینوپروژه های آردوینو

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

در اتوماسیون و کنترل صنعتی ، کنترل کننده PID به یکی از معتبرترین الگوریتم های کنترلی تبدیل شده است که می تواند برای تثبیت پاسخ خروجی هر سیستمی اجرا شود. PID مخفف Proportional-Integral-Derivative است. کنترل کننده های PID را می توان در طیف وسیعی از کاربردهای صنعتی و تجاری یافت مثلا برای تنظیم فشار ، حرکت خطی و بسیاری از متغیرها استفاده می شوند. کنترل کننده دما PID رایج ترین کاربردی است که می توانید در اینترنت پیدا کنید. بدون کنترل کننده PID ، انجام کار به صورت دستی می تواند یک روند خسته کننده باشد.

پیشنهاد میکنم قبل از خاندن ادامه مطلب، مقاله کنترل کننده PID را بخوانید.

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

مفهوم موتور رمزگذار (انکدر) بسیار ساده است، یک موتور DC که یک روتاری انکدر به آن متصل است.

انکدر موتور

در موتور رمزگذار ، یک روتاری انکدر بر روی موتور DC نصب می شود که با سرعت یا موقعیت شافت موتور را بازخورد می دهد. انواع مختلفی از موتورها در دسترس است و همه آنها می توانند انواع مختلفی از پیکربندی رمزگذار ها را داشته باشند مانند افزایشی یا مطلق ، نوری ، توخالی ، مغناطیسی و … انواع مختلفی از موتورها برای انواع مختلف کاربردها ساخته می شوند. نه تنها موتورهای DC بلکه بسیاری از سروو موتور ها ، استپ موتور ها و موتورهای AC دارای رمزگذار داخلی هستند. در تصویر بالا ، یک موتور رمزگذار از نوع آهنربای دائمی N20 را مشاهده می کنید که با کمک گیربکس متصل ، دور خروجی را به 15 کاهش می دهد. همچنین می توانید دو سنسور هال متصل به PCB را مشاهده کنید. این سنسورهای هال جهت چرخش موتور را می گیرند و با کمک میکروکنترلر می توانیم آن را خیلی راحت بخوانیم.

مدار موتور انکدر دار با کنترل کننده PID

اصل کار این مدار بسیار ساده است و در زیر توضیح داده شده است.

مدار موتور انکدر دار با کنترل کننده PID

مدار بسیار ساده است. ما موتور رمزگذار N20 را داریم که دارای شش پایه است ، پین ها به عنوان M1 ، M2 برچسب گذاری می شوند که برای تأمین انرژی موتور استفاده می شوند. این یک موتور بسیار کوچک است که دارای قدرت 3.3 ولت است. ما پین های VCC و GND را داریم که برای تغذیه مدار رمزگذار استفاده می شود. برای تغذیه مدار رمزگذار ، باید 5 ولت به آن بدهید درغیر اینصورت ، مدار رمزگذار به درستی کار نخواهد کرد. بعد ، PIN_A و PIN_B موتور را داریم. این دو پایه مستقیماً به رمزگذار متصل می شوند. با خواندن وضعیت این پایه ها ، ما می توانیم RPM را به راحتی اندازه بگیریم ، این موتور 15RPM N20 دارای نسبت دنده 1:2098 است که به این معنی است که شافت اصلی موتور باید 2098 بار بچرخد تا شافت کمکی یک بار بچرخد. PIN_A و PIN_B به پایه 9 و پایه 10 آردوینو متصل شده اندکه هر دو پایه های PWM هستند. پین های انتخاب شده باید از قابلیت PWM برخوردار باشند در غیر این صورت کد کار نمی کند. کنترل کننده PID با کنترل PWM موتور را کنترل می کند.

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

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

کنترل انکدر موتور با آردوینو و کنترلر PID

  • آردوینو نانو
  • N20 Encode Motor
  • BD139 – دو عدد
  • BD140 – دو عدد
  • BC548 – دو عدد
  • مقاومت 100R – دو عدد
  • مقاومت 4.7K – دو عدد
قطعات مورد نیاز را از فروشگاه قطعات آیرنکس تهیه کنید.

کد آردوینو برای کنترل کننده موتور رمزگذار فعال PID

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

#include <PIDController.h>
#define ENCODER_A 2 
#define ENCODER_B 3
#define MOTOR_CW 9
#define MOTOR_CCW 10

بعد ، ما مقادیر __Kp ، __Ki و __Kd را برای کد خود تعریف میکنیم. این سه ثابت وظیفه تنظیم پاسخ خروجی کد ما را دارند. در این مرحله ، لطفا توجه داشته باشید که برای این پروژه ، من از روش آزمون و خطا برای تنظیم ثابت ها استفاده کرده ام ، اما روش های دیگری نیز وجود دارد که کار را بسیار خوب انجام می دهند.

#define __Kp 260 // ثابت تناسب P
#define __Ki 2.7 // ثابت انتگرال I
#define __Kd 2000 // ثابت مشتق D

حالا ما تمام متغیرهای لازم را که در این کد مورد نیاز است ، تعریف کردیم. ابتدا متغیر encoder_count را داریم که برای شمارش تعداد وقفه های ایجاد شده استفاده می شود. بنابراین تعداد چرخش ها را می شمارد. بعد ، ما یک متغیر صحیح unsigned int را تعریف کرده ایم که مقداری را که در مانیتور سریال قرار داده ایم ذخیره می کند. در مرحله بعد ، ما یک متغیر نوع char را با عنوان incomingByte تعریف کرده ایم که داده های سریال ورودی را به طور موقت ذخیره می کند. بعد ، ما مهمترین متغیر را در این کد تعریف کرده ایم و آن متغیر motor_pwm_value پس از محاسبه داده ها از طریق الگوریتم PWM است که در این متغیر ذخیره شده است. هنگامی که این متغیرها تعریف می شوند ، ما یک نمونه برای کنترل کننده PID ایجاد می کنیم. پس از انجام این کار ، می توانیم به تابع ()setup برسیم.

volatile long int encoder_count = 0; // مقدار فعلی انکدر
unsigned int integerValue = 0; // مقدار سریال ورودی (حداکثر 65535)
char incomingByte; 
int motor_pwm_value = 255; 
PIDController pid_controller;

در تابع setup، پین های ENCODER_A و ENCODER_B را به عنوان ورودی اختصاص داده ایم و پین های MOTOR_CW و MOTOR_CCW را به عنوان خروجی تعریف کرده ایم. در مرحله بعد ، ما ENCODER_A را به عنوان وقفه اختصاص داده ایم و در حالت RISING ، این کد encoder() را فراخوانی می کند. سه خط بعدی مهمترین قسمت کد هستند زیرا ما کنترلر PID را با روش start () فعال کرده ایم و همچنین کنترلر را با مقادیر Kp ، Ki و Kd تنظیم می کنیم. و سرانجام ، ما حد خروجی کنترل کننده PID خود را تعیین کرده ایم.

void setup() {
  Serial.begin(115200); // آغاز کردن ارتباط سریال
  pinMode(ENCODER_A, INPUT); // ENCODER_A ورودی
  pinMode(ENCODER_B, INPUT); // ENCODER_B ورودی
  pinMode(MOTOR_CW, OUTPUT); // MOTOR_CW خروجی
  pinMode(MOTOR_CCW, OUTPUT); // MOTOR_CW خروجی
  attachInterrupt(digitalPinToInterrupt(ENCODER_A), encoder, RISING);
  pidcontroller.begin();
  pidcontroller.tune(__Kp , __Ki , __Kd); // پیکربندی PID
  pidcontroller.limit(-255, 255); // حداقل و حداکثر
}

در قسمت loop ابتدا بررسی می کنیم داده های سریال در دسترس هستند یا خیر. اگر داده سریال موجود باشد ، مقدار عدد صحیح را تجزیه کرده و در متغیر int ذخیره می کنیم. بعد ، یک کاراکتر ‘/ n’ داریم که وارد می شود. ما آن را در متغیر inomingByte قرار می دهیم ، و این متغیر را با دستور if بررسی می کنیم ، اگر درست باشد ، به loo[ ادامه می دهیم ، بعد با pidcontroller نقطه هدف (integerValue) را تنظیم می کنیم.

اگر در مورد این مطلب سوالی دارید در قسمت نظرات بپرسید

ما متغیر motor_pwm_value را داریم و مقادیر PID را محاسبه کرده و در این متغیر قرار می دهیم. اگر این مقدار بیشتر از صفر باشد ، ما تابع motor_ccw (motor_pwm_value) را فراخوانی می کنیم و مقدار را منتقل می کنیم ، در غیر این صورت ، تابع motor_cw (abs (motor_pwm_value)) را فراخوانی می کنیم. این پایان بخش حلقه ما است.

void loop() {
  while (Serial.available() > 0) {
    integerValue = Serial.parseInt(); // قرار دادن داده ها در integerValue
    incomingByte = Serial.read(); // قرار دادن کاراکتر /n
    pidcontroller.setpoint(integerValue); 
    Serial.println(integerValue); // نمایش مقدار در سریال مانیتور
    if (incomingByte == '\n')
      continue;
  }
  motor_pwm_value = pidcontroller.compute(encoder_count);  
  Serial.print(motor_pwm_value); // نمایش مقدار در سریال مانیتور
  Serial.print("   ");
  if (motor_pwm_value > 0) // اگر مقدار motor_pwm_value بیشتر از 0 باشد
    MotorCounterClockwise(motor_pwm_value);
    MotorClockwise(abs(motor_pwm_value));
  Serial.println(encoder_count);// نمایش آخرین مقدار انکدر در سریال مانیتور.
}

تابع encoder وقتی رخ می دهد که وقفه های RISING در ENCODER_B رخ دهد. دستور را دوباره با if (digitalRead (ENCODER_B) == HIGH) بررسی می کنیم. وقتی true شد ، متغیر Encoder_count افزایش می یابد. در غیر این صورت ، کاهش می یابد.

void encoder() {
  if (digitalRead(ENCODER_B) == HIGH) //اگر ENCODER_B  در حالت HIGH باشد
    Encoder_count++; // افزایش مقدار
  else // در غیر اینصورت
    Encoder_count--; // کاهش مقدار
}

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

void motor_cw(int power) {
  if (power > 100) {
    analogWrite(MOTOR_CW, power);
    digitalWrite(MOTOR_CCW, LOW);
  }
// هر دو پین LOW میشوند
  else {
    digitalWrite(MOTOR_CW, LOW);
    digitalWrite(MOTOR_CCW, LOW);
  }
}

عملکرد موتور انکدر با PID و آردوینو

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

void motor_ccw(int power) {
  if (power > 100) {
    analogWrite(MOTOR_CCW, power);
    digitalWrite(MOTOR_CW, LOW);
  }
  else {
    digitalWrite(MOTOR_CW, LOW);
    digitalWrite(MOTOR_CCW, LOW);
  }
}

موارد موجود در فایل : سورس کامل ، کتابخانه مورد نیاز

5 (4 نفر)

برای دریافت مطالب جدید کانال تلگرام یا پیج اینستاگرام ما را دنبال کنید.

محمد رحیمی

محمد رحیمی هستم. سعی میکنم در آیرنکس مطالب مفید قرار بدهم. سوالات مربوط به این مطلب را در قسمت نظرات همین مطلب اعلام کنید. سعی میکنم در اسرع وقت به نظرات شما پاسخ بدهم.

2 نظر

  1. یونس گفت:

    سایت باحالی داری که کلی چیز واسه یاد گرفتن توی سایتت گذاشتی.ممنون واسه اموزشهای خوبت

    1. محمد رحیمی گفت:

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

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

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *