今回はライブラリ「PID_v1_bc」を盛り込んでPIDのオートマチック制御をさせてみた。
やり方は「Google Gemini」に教えてもらった。
以下、Arduinoのスケッチ。Python の受けは、これまで通りの「Data_from_Arduino_vF.py」。
// 0.2秒ごとにAnalog出力をしています。
// Duty比(%)と設定温度だけ変えてください。
// 対応するPythonコードは"Data_from_Arduino_vF.py"です。
// 2024.07.31 by Kero
// 温度センサDS18B20の設定(以下のサイトからもらいました。感謝)
// https://github.com/matmunk/DS18B20?tab=readme-ov-file
#include <PID_v1_bc.h>
#include <DS18B20.h> // センサからの読み込み値はセ氏温度です
DS18B20 ds18(2); // センサの黄線はArduinoの端子2につなぎます
// PID制御の設定。Google Gemini に教えてもらいました。
double Setpoint, Input, Output;
PID myPID(&Input, &Output, &Setpoint, 2, 5, 1, DIRECT); // P=2, I=5, D=1
// ディスプレイLCDの設定
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
// 変数割り当て
int SSR = 6; // SSRのアドレス
float sett = 60; // 設定温度
float Duty; // Duty比
// Duty比からアナログ用値に変換
// 変数宣言
String ds18C; // センサからの読込は文字列変数「ds18C」に入ります
float ds18CV; // その文字列を実数に変換して入れる変数です
void setup() {
Serial.begin(9600); // 通信速度セットアップ
// PIDの初期化
Setpoint = sett; // 設定温度
myPID.SetOutputLimits(0, 255); // 出力範囲を0から255に設定
myPID.SetMode(AUTOMATIC); // Google Gemini の言う通り。
// LCDディスプレイ用セットアップ
lcd.init();
lcd.backlight();
// ピンモードを「出力」に設定
pinMode(SSR,OUTPUT);
}
void loop() {
// DS18センサから読み込み(とにかくこう書くようです)
while (ds18.selectNext()) {
ds18C = ds18.getTempC(); // 文字列でds18Cに読み込み
ds18CV = ds18C.toFloat(); // 文字列を実数に変換
Serial.println(ds18C); //シリアルモニタに温度を文字列として出力
}
// PIDの計算
Input = ds18CV;
myPID.Compute(); // Dのための前値はどうなっているの?
// ヒーターの出力
analogWrite(SSR, Output);
Duty = map(Output, 0, 255, 0, 99);
// LCDへADT温度とDuty比の表示
lcd.setCursor(0,0);
lcd.print("TempSD18= ");
lcd.print(ds18C);
lcd.setCursor(15,0);
lcd.print("C");
lcd.setCursor(0,1);
lcd.print("Duty = ");
lcd.setCursor(10,1);
lcd.print(Duty);
lcd.setCursor(15,1);
lcd.print('%');
delay(200); // 0.2秒そのまま
}
【結 果】
以下のグラフのようになりました。横軸:時間(分)、縦軸:温度(℃)です。
1.30℃あたりから60℃になるまでに15分程度かかる。
2.残念ながら、オーバーシュート(最初の過剰温度上昇)やハンチング(凸凹振動)が大きすぎる。
これまでにPIDを使わないやり方に比べ、オーバーシュートは大きすぎ、ハンチングの振幅はアナログ(PWM)出力の場合より大きく、デジタル出力(デジタルOUTPUT)の場合と同程度と思われる。
3.オートマチックにしないで、パラメータを変えてみる必要がある。
今日はこれまで。