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

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

در این مقاله تصمیم گرفتیم یک بخاری مبتنی بر کنترلر PID بسازیم که می توان از آن برای کنترل دمای انتهای داغ پرینتر سه بعدی استفاده کرد و یا با کمی تغییر دستگاه می تواند دمای یک هویه لحیم کاری DC را کنترل کند. اگر بهینه سازی بیشتری انجام دهید می توانید یک ترایاک را کنترل کنید یا می تواند RPM یک موتور AC یا یک عنصر گرمایش AC را کنترل کنید.

قبلا ما یک پروژه کنترل انکودر موتور با PID ساختیم که میتوانید آن را هم بررسی کنید.

کنترلر PID دما چیست؟

همانطور که از نام آن پیداست یک کنترل کننده PID دما با دما سر و کار دارد، کنترل دمای PID یک الگوریتم کنترل حلقه بسته است که دقت فرآیند را بهبود می بخشد. کنترل دمای PID با استفاده از یک فرمول ریاضی برای محاسبه تفاوت بین دمای فعلی و نقطه تنظیم کار می کند. و سپس تلاش می‌کند تا توان مورد نیاز را برای اطمینان از ثابت ماندن دمای هدف ارائه کند، این کار اثرات زیست‌ محیطی را کاهش می‌ دهد.

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

مانند هر کنترل PID، ابتدا باید از خروجی یا کاری که می‌خواهیم کنترلر انجام دهد آگاه باشیم، برای این پروژه می‌خواهیم دمای خاصی از المنت گرمایشی را حفظ کنیم (این دما را با کمک چرخش روتاری تنظیم می‌ کنیم) بنابراین برای حفظ دما باید دما را خارج کنیم، برای این منظور از ترموکوپل نوع K به همراه آی سی مبدل K-Cold-Junction-Compensated به دیجیتال MAX6675 استفاده می کنیم که می تواند صد ها درجه سانتیگراد را اندازه گیری کند. وقتی دمایی را که می‌خواهیم به دست آوریم تنظیم کرده‌ ایم و یک بازخوانی بی‌درنگ از مقدار دما داریم، کنترل‌کننده می‌تواند مقدار خطا را محاسبه کند و با کمک کنترل انتگرالی و مشتق متناسب، سیستم می‌تواند به هدف خود برای این پروژه دست یابد. ما یک سیگنال PWM را با مقدار خروجی محاسبه شده کنترل خواهیم کرد.

نحوه کار آی سی ترموکوپل MAX6675 K

نحوه کار آی سی ترموکوپل MAX6675 K

وظیفه ترموکوپل تشخیص اختلاف دما بین دو سر سیم ترموکوپل است. اتصال داغ ترموکوپل را می توان از 0 درجه سانتی گراد تا +1023.75 درجه سانتی گراد خواند. انتهای سرد (دمای محیط بردی که MAX6675 روی آن نصب شده است) فقط می تواند از -20 درجه سانتیگراد تا +85 درجه سانتیگراد متغیر باشد. در حالی که دما در انتهای سرد در نوسان است، MAX6675 همچنان به دقت تفاوت دما را در انتهای مخالف حس می کند. MAX6675 تغییرات دمای محیط را با جبران اتصال سرد حس می کند و آن را تصحیح می کند. این دستگاه با استفاده از یک دیود سنجش دما، دمای محیط را به ولتاژ تبدیل می کند. برای اندازه‌گیری دمای واقعی ترموکوپل، MAX6675 ولتاژ خروجی ترموکوپل و دیود حسگر را اندازه‌گیری می‌کند. مدار داخلی دستگاه، ولتاژ دیود (حسگر دمای محیط) و ولتاژ ترموکوپل (حسگر دمای راه دور منهای دمای محیط) را به تابع تبدیل ذخیره شده در ADC برای محاسبه دمای اتصال داغ ترموکوپل می‌رساند. عملکرد بهینه MAX6675 زمانی حاصل می شود که محل اتصال سرد ترموکوپل و MAX6675 در یک دما باشند. MAX6675 شامل سخت افزار تهویه سیگنال برای تبدیل سیگنال ترموکوپل به ولتاژ سازگار با کانال های ورودی ADC است. ورودی های T+ و T به مدار داخلی متصل می شوند که باعث کاهش خطاهای نویز از سیم های ترموکوپل می شود. اطلاعات بیشتر را می توانید در دیتاشیت آی سی MAX6675 بیابید.

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

در این پروژه از سنسور ترموکوپل نوع K MAX6675 برای خواندن اطلاعات دما از ترموکوپل استفاده می کنیم و در این قسمت به کمک شماتیک تمامی جزئیات را توضیح می دهیم. اجازه دهید یک مرور مختصر از آنچه در این مدار اتفاق می افتد به شما ارائه دهم. MAX6675 یک ماژول مبدل K-ترموکوپل به دیجیتال با جبران اتصال سرد است و طبق شماتیک زیر به آردوینو متصل می شود. برق به کمک منبع تغذیه +5 ولت آردوینو به مدار تأمین می شود. همچنین برای تنظیم دما و تغییر حالت‌ ها، از یک روتاری انکودر استفاده می‌کنیم.

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

صفحه نمایش OLED 28X64 داده های دما را نشان می دهد و همچنین دمای تنظیم شده را نشان می دهد. مثل همیشه، ما از آردوینو به عنوان مغز پروژه استفاده می کنیم. با فشار دادن دکمه روی روتاری انکودر، می توانیم بین دو حالت سوئیچ کنیم، یکی تنظیم دما و دیگری برای نظارت بر ترموکوپل.

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

اجزای مورد نیاز برای ساخت بخاری کنترل‌ شده PID مبتنی بر MAX6675 در زیر لیست شده‌اند، ما این مدار را با اجزای بسیار عمومی طراحی کردیم که فرآیند ساخت را بسیار آسان می‌کند.

  • آردوینو نانو
  • صفحه نمایش OLED 128 x 64
  • روتاری انکودر
  • ماژول MAX6675
  • ترموکوپل نوع K
قطعات مورد نیاز را از فروشگاه قطعات آیرنکس تهیه کنید.

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

کد کامل استفاده شده در این پروژه در انتهای صفحه قرار داده شده است. پس از افزودن فایل های هدر و فایل های مورد نیاز، باید بتوانید به طور مستقیم کد آردوینو را بدون هیچ خطایی کامپایل کنید. می‌توانید کتابخانه کنترل‌کننده PID، کتابخانه MAX6675، کتابخانه AAdafruit_SSD1306 در فایل دانلودی قرار داده شده اند.

توضیح ساده ای از کد به صورت کامنت در سورس کد قرار داده شده است و در این قسمت کمی بیشتر به آن می پردازیم. ابتدا با گنجاندن تمام کتابخانه های مورد نیاز شروع می کنیم، پس از آن، تمام پین های لازم برای خواندن وضعیت انکودر، درایو سنسور دمای ترموکوپل، نمایشگر OLED و MAX6675 را تعریف می کنیم. پس از انجام این کار، ما تمام مقادیر Kp، Ki و Kd را تعریف می کنیم و همه متغیرهای مورد نیاز را ایجاد میکنیم.

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

#define __Kp 30 // Proportional constant
#define __Ki 0.7 // Integral Constant
#define __Kd 200 // Derivative Constant

بعد، همه متغیرهای مورد نیاز را اعلام می کنیم و سه نمونه برای PID یکی برای OLED و نمونه آخر برای ترموکوپل ایجاد می کنیم. متغیر clockPin و clockPinState، debounce و encoder_btn_count هر چهار مورد برای خواندن داده‌ها از روتاری انکودر استفاده می‌شوند. temperature_value_c بازخوانی دما را از ترموکوپل را ذخیره میکند، در نهایت encoder_btn_count تعداد دفعات فشار دادن دکمه روتاری انکودر را ذخیره میکند.

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <PIDController.h>
#include "max6675.h"
// تعیین پین های روتاری انکودر
#define CLK_PIN 3
#define DATA_PIN 4
#define SW_PIN 2
// MAX6675 پین های
#define thermoDO 8
#define thermoCS 9
#define thermoCLINE 10
// Mosfet پین
#define mosfet_pin 11
// فعال سازی سریال
#define __DEBUG__
#define SCREEN_WIDTH 128 // عرض نمایشگر
#define SCREEN_HEIGHT 64 // ارتفاع نمایشگر
#define OLED_RESET -1 // پین ریست
int clockPin; // کلاک انکودر
int clockPinState; // وضعیت کلاک انکودر
int set_temperature = 1; // با چرخش روتاری انکودر تغییر میکند
float temperature_value_c = 0.0; // ذخیره مقدار دما
long debounce = 0; // تاخیر برای دیبانس
int encoder_btn_count = 0; // بررسی وضعیت دکمه روتاری انکودر
MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); // ایجاد نمونه برای MAX6675 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);// ایجاد نمونه برای Oled
PIDController pid; // ایجاد نمونه برای PID

بعد، ما تابع setup را داریم. در تابع setup، ابتدا سریال مانیتور را برای اشکال زدایی فعال می کنیم، اما متد Serial.begin() در بین دستور #ifdef و #endif قرار داده می شود تا پس از تکمیل کد ما به راحتی بتوانیم مانیتور سریال را غیرفعال کنیم.

همچنین اگر در مورد این مطلب سوالی داشتید در انتهای صفحه در قسمت نظرات بپرسید
void setup() {
#ifdef __DEBUG__
  Serial.begin(9600);
#endif

در مرحله بعد، ما تمام پین های مورد نیاز خود را به عنوان ورودی و خروجی برای کار پروژه خود تنظیم کرده ایم.

pinMode(mosfet_pin, OUTPUT); // پین ماسفت
  pinMode(CLK_PIN, INPUT); // پین کلاک روتاری انکودر
  pinMode(DATA_PIN, INPUT); //Eپین داده روتاری انکودر
  pinMode(SW_PIN, INPUT_PULLUP);// پین دکمه روتاری انکودر

در مرحله بعد، کنترل کننده PID را با فراخوانی متد begin() نمونه PID مقداردهی اولیه می کنیم. سپس، با استفاده از روش setpoint() نقطه تنظیم را اضافه می کنیم، الگوریتم PID سعی می کند با کنترل خروجی به مقدار مورد نظر برسد. در مرحله بعد، متد tune() را فراخوانی می کنیم، اینجاست که همه مقادیر __Kp، __Ki، و __Kd را قرار می دهیم. در نهایت، ما یک محدودیت برای کنترل کننده PID تعیین می کنیم. این محدود کننده اجازه می دهد تا خروجی محاسبه شده در محدوده مورد نظر باشد و این تضمین می کند که خروجی از سطح معینی که 255 برای مقدار PWM ما است فراتر نرود.

pid.begin();          // شروع کار PID
pid.setpoint(150);    // تعیین نقطه هدف
pid.tune(__Kp, __Ki,__Kd);    // مقدار دهی PID
pid.limit(0, 255);    // ایجاد محدوده برای PID

در مرحله بعد، بررسی می کنیم که آیا صفحه نمایش در دسترس است یا نه، اگر نمایشگر در دسترس باشد، کد ادامه می یابد، و اگر نمایشگر در دسترس نباشد، خطا تشخیص داده میشود.

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
#ifdef __DEBUG__
    Serial.println(F("SSD1306 allocation failed"));
#endif
    for (;;); // ایجاد یک حلقه دائمی
}

در مرحله بعد، نمایشگر را تنظیم می کنیم. سپس PID Temperatur Control را در نمایشگر چاپ می کنیم و با تاخیر 2 ثانیه کار را به پایان می رسانیم.

display.setRotation(2); //چخش نمایشگر
display.display(); //پیکربندی اولیه نمایشگر
display.clearDisplay(); // پاکسازی موارد موجود در صفحه
display.setTextSize(2); // تعیین سایز متن
display.setTextColor(WHITE); // تعیین رنگ 
display.setCursor(48, 0); //تعیین مکان نما
display.println("PID"); // تعیین متن
display.setCursor(0, 20);//تعیین مکان نما
display.println("Temperatur"); // تعیین متن
display.setCursor(22, 40); //تعیین مکان نما
display.println("Control"); // تعیین متن
display.display(); // اپدیت نمایشگر
delay(2000); // تاخیر 2 ثانیه ای

سپس تابع set_temp() را داریم. در این تابع دمای بخاری را تنظیم می کنیم و وضعیت دکمه را بررسی می کنیم، اگر وضعیت دو بود، ابتدا صفحه نمایش را پاک کرده و اندازه متن را تنظیم می کنیم و دمای تنظیم شده را روی نمایشگر چاپ می کنیم. در مرحله بعد، تابع read_encoder() را داریم همانطور که از نام آن پیداست، وضعیت روتاری انکودر را می‌خوانیم و بررسی می‌کنیم که انکودر در جهت عقربه‌ های ساعت یا خلاف جهت عقربه‌ های ساعت می‌چرخد. در نهایت، وضعیت دکمه انکودر را بررسی می کنیم و می توانیم بین حالت تنظیم دما و حالت مانیتور سوئیچ کنیم.

void set_temp(){
  if (encoder_btn_count == 2) // بررسی وضعیت دکمه
  {
    display.clearDisplay(); // پاکسازی نمایشگر
    display.setTextSize(2); // تعیین سایز متن
    display.setCursor(16, 0); //تعیین مکان نما
    display.print("Set Temp."); // تعیین متن
    display.setCursor(45, 25); //تعیین مکان نما
    display.print(set_temperature); // تعیین متن
    display.display(); // بروزرسانی نمایشگر
  }
}

void read_encoder() // 
{
  clockPin = digitalRead(CLK_PIN); // خواندن وضعیت پین کلاک
  if (clockPin != clockPinState && clockPin == 1) { // اگر یک باشد یعنی در خلاف جهت عقربه های ساعت میپرخد
    if (digitalRead(DATA_PIN) != clockPin) set_temperature = set_temperature - 3;  // کاهش مقدار
    else set_temperature = set_temperature + 3; // در غیر اینصورت افزایش مقدار
    if (set_temperature < 1 )set_temperature = 1; // اگر مقدار کمتر از یک شود دوباره یک میشود
    if (set_temperature > 150 ) set_temperature = 150; //اگر مقدار بیشتر از 150 شود دوباره 150 میشود.
#ifdef __DEBUG__
    Serial.println(set_temperature); // چاپ مقادیر در سریال مانیتور
#endif
  }
  clockPinState = clockPin; // ذخیره آخرین وضعیت پین کلاک
  if ( digitalRead(SW_PIN) == LOW)   //اگر سیگنال دریافتی پایین باشد یعنی دکمه فشرده شده
  {
    if ( millis() - debounce > 80) { //ایجاد دیبانس
      encoder_btn_count++; // افزایش مقدار
      if (encoder_btn_count > 2) encoder_btn_count = 1;
#ifdef __DEBUG__
      Serial.println(encoder_btn_count);
#endif
    }
    debounce = millis(); // بروزرسانی داده دیبانس
  }
}

در نهایت، ما تابع loop خود را داریم. در تابع loop ما تابع read_encoder() و set_temp() را فراخوانی میکنیم، این توابع به صورت پیوسته فراخوانی می شوند و در loop، حالت دکمه را نیز بررسی می کنیم و اگر روی یک تنظیم شد، دما را از ترموکوپل از طریق روش محاسبه نمونه PID می خوانیم و قرار می دهیم. هنگامی که محاسبه انجام شد، مقادیر محاسبه شده را مستقیماً در تابع analogWrite قرار می دهیم که سیگنال PWM را خارج می کند. هنگامی که همه چیز انجام شد، ما فقط صفحه نمایش را به روز می کنیم و این پایان بخش کد را نشان می دهد.

void loop()
{
  read_encoder(); //فراخوانی تابع انکودر
  set_temp(); // فراخوانی تابع تنظیم دما
  if (encoder_btn_count == 1) // بررسی وضعیت دکمه
  {
    temperature_value_c = thermocouple.readCelsius(); // خواندن دما
    int output = pid.compute(temperature_value_c);    // استفاده از کنترلر PID
    analogWrite(mosfet_pin, output);           // تنظیم خروجی PWM
    pid.setpoint(set_temperature); // استفاده از نقطه تنظیم PID
    display.clearDisplay(); // پاک سازی نمایشگر
    display.setTextSize(2); // تنظیم سایز متن
    display.setCursor(16, 0); // تنظیم مکان نما
    display.print("Cur Temp."); // چاپ متن
    display.setCursor(45, 25);// تنظیم مکان نما
    display.print(temperature_value_c); // چاپ دما
    display.display(); //نمایش مقادیر
#ifdef __DEBUG__
    Serial.print(temperature_value_c); // چاپ دما در سریال مانیتور
    Serial.print(" "); // چاپ یک فضای خالی
    Serial.println(output); // چاپ خروجی
#endif
    delay(200); // تاخیر 200 میلی ثانیه ای
  }
}

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

برای تست مدار از تنظیمات زیر استفاده می شود، همانطور که می بینید، من مولتی متر Meco 450B+ خود را برای نمایش چرخه وظیفه سیگنال PWM خروجی که از پین 11 آردوینو است وصل کرده ام. و به عنوان بخاری از یک اکسترودر پرینتر سه بعدی که حاوی المنت حرارتی 12 ولتی است استفاده کرده ام، برای تغذیه آردوینو از منبع تغذیه 5 ولت لپ تاپ و برای تامین برق المنت گرمایشی از منبع برق 12 ولتی خارجی استفاده کرده ام.

حال برای تنظیم دما باید دکمه روتاری انکودر را فشار دهید سپس دمای مورد نظر الگوریتم PID را تنظیم کنید. در ادامه یک بار دیگر دکمه روتاری انکودر را فشار دهید تا تغییرات دائمی شود. سپس بخاری شروع به گرم شدن می کند و می توانید ببینید چرخه وظیفه PWM نیز افزایش می یابد، من دما را روی 64 درجه سانتی گراد تنظیم کرده ام.

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

پس از رسیدن به دمای مورد نظر، چرخه وظیفه PWM کاهش می یابد و زمانی که کنترلر می خواهد خطا را جبران کند و دما را افزایش دهد، می توانید یک لبه خاص را در چرخه وظیفه PWM مشاهده کنید.

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

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

دانلود فایل های پروژه

5/5 - (1 امتیاز)

برای دریافت مطالب جدید کانال تلگرام یا پیج اینستاگرام آیرنکس را دنبال کنید.
تصویر از محمد رحیمی

محمد رحیمی

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

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

نشانی ایمیل شما منتشر نخواهد شد.