【失敗】ペットボトルを暖めるホルダーが欲しい

## はじめに
暖かい飲み物は、机に置いておいてもすぐに冷めてしまう。

机上でペットボトル等を保温しておける製品はAmazonで何種類か見つけたが、怪しい中華製ばかり・・・
仕組みは難しくないだろうし、自作してみようと考えた。

## 目次
- [作ったもの](#作ったもの)
- [ハード設計](#ハード設計)
- [プログラム作成](#プログラム作成)
- [完成](#完成)
- [動作確認](#動作確認)
- [課題点](#課題点)

## 作りたかったもの
机の上でペットボトルを暖めておけるホルダー

## ハード設計
・全体構成
下図のような構成で作ることにした。
M5Stickに付けた温度センサでペットボトルの温度を読み取り、その値をもとにヒーターの電源をON/OFFして温度を調整する。この調整はPWMのDutyをPID制御して行う。
可変抵抗を回すと設定温度を変えられる。
今回引き出しの中にあったヒーターが200Ωのものであったため、それに合わせてヒーター電源は45Vとした。大体10Wくらいあればいいだろうという見積もり。
![circuit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925524/141ef49d-219d-b9e9-2885-413cda04c442.png)


・温度センサ
たまたま手元にあったM5Stick用のMLX90614ハットを使用した。
非接触であるため、温度制御対象（ペットボトル）を密着させる必要はなく、使い勝手がいい。
https://www.switch-science.com/products/6067
[M5Stickにハットを付けた写真を挿入]

## プログラム作成
下記のプログラムで動かす。
ただし、PIDのゲイン（KP、KI、KD）は最終形状で温度推移を見ながら適宜調整する。
また、最後のdelayは実働の様子を見て調整し、大体1秒ごと計測するようにしたい。
```php:pet_warmer.py
#include <M5StickCPlus2.h>
#include <Wire.h>

#define PWM_PIN 32
#define PWMCH 0
#define ADC_PIN 33

//Define maximum target temperature
#define TEMP_OBJ_MAX 80

//Define gain values for PID control
#define KP 1
#define KI 1
#define KD 1

float dp, di, dd;
float dp_pre;
float time_width = 1;
int loop_count;

uint16_t adc_dummy;
String display_text_set;
String display_text_now;

void setup() {
    M5.begin();
    Wire.begin(0, 26);
    Serial.begin(115200);

    pinMode(PWM_PIN, OUTPUT); //Prepare PWM
    ledcSetup(PWMCH, 100, 8);
    ledcAttachPin(PWM_PIN, PWMCH);

    pinMode(ADC_PIN, ANALOG); //Prepare ADC

    //Initialize valiables
    loop_count = 0;
    dp = 0;
    di = 0;
    dd = 0;
    dp_pre = 0;

    M5.Lcd.setRotation(1);
    M5.Lcd.setTextColor(WHITE);
    M5.Lcd.setTextSize(5);
    // M5.Lcd.clear(BLACK);
    M5.Lcd.setCursor(0, 40);
}

//PID Control
int pid_calc(int temp_set, float temp_now){
  float duty = 0;

  dp = (float)temp_set - temp_now; 
  dd = (dp - dp_pre) / time_width;
  di = di + (dp + dp_pre) * time_width / 2;
  duty = KP * dp + KI * di + KD * dd;

  //Serial.printf("dp: %.2f, dd: %.2f, di: %.2f, duty: %.0f, ", dp, dd, di, duty);
  
  dp_pre = dp;
  return (int)duty;
}

void loop() {
    float temp_now = 0;
    int temp_now_int = 0;
    int temp_set = 0;
    int adc_val = 0;
    int pwm_duty = 0;
    
    Serial.printf("%d, ", loop_count); //DEBUG

    //Measure target temperature
    for(int i=0; i<4; i++)
    {
      Wire.beginTransmission(0x5A);
      Wire.write(0x07);
      Wire.endTransmission(false);
      Wire.requestFrom(0x5A, 2);
      adc_dummy = Wire.read();
      adc_dummy |= Wire.read() << 8;
      temp_now += adc_dummy * 0.02 - 273.15;
      delay(100);
    }
    temp_now /= 4;

    //Read set temperature
    for(int i=0; i<4; i++)
    {
      adc_val += analogRead(ADC_PIN);
      delay(100);
    }
    adc_val /= 4;
    temp_set = (adc_val * TEMP_OBJ_MAX) / 4096;

    //Calculate PWM duty
    pwm_duty = pid_calc(temp_set, temp_now);
    if(pwm_duty > 255)
      pwm_duty = 255;
    else if(pwm_duty < 0)
      pwm_duty = 0;
    ledcWrite(PWMCH, pwm_duty);

    //Initialize LCD and display temperature
    M5.Lcd.fillScreen(BLACK);

    display_text_set = "SET: " + (String)temp_set;
    M5.Lcd.setCursor(5, 5);
    M5.Lcd.print(display_text_set);

    temp_now_int = (int)temp_now;
    display_text_now = "NOW: " + (String)temp_now_int;
    if(temp_now_int < temp_set)
      M5.Lcd.setTextColor(RED);
    else if(temp_now_int > temp_set)
      M5.Lcd.setTextColor(BLUE);
    M5.Lcd.setCursor(5, 75);
    M5.Lcd.print(display_text_now);
    M5.Lcd.setTextColor(WHITE);

    Serial.printf("%.2f\n", temp_now); //DEBUG
    loop_count++;

    //Wait
    delay(100);
    M5.update();
}
```

## 完成
まずは動作部だけの状態。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925524/9b72c4eb-59ad-ad8a-a036-fdc0c4938a8c.png)

適当にケースを作って完成。
ヒーターはとりあえず机に落ちていたものを使ったため、寸法は足りていない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925524/12ab2017-b720-7e80-bb6e-54fcc783efe9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925524/f0f67d1c-8367-9b7e-032c-380f33ccf139.png)

## 動作確認
早速、冷ましておいた「あたたか～い」飲み物を暖めてみる。
ホルダーに入れてヒーターとM5Stickの電源を入れ・・・

![250407235433942.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3925524/4df886cf-74eb-4fc1-a9f5-993ef3db8569.jpeg)

溶けました。
PETGの軟化温度は80℃くらいあるけれども、それでは足りないらしい。
肝心のペットボトルの温度は室温20℃に対して22℃までしか上がらず。


## 課題点
+ 容器の耐熱性が足りない。

+ ヒーターの電源電圧が高い。

余裕があれば改修していきたい。