そうだ!Arduinoでヨーグルトメーカーをつくろう!
こんなこと、やります。
- Arduinoでヨーグルトメーカーをつくる
- PTCヒーター、リレーモジュール、OLED、温度センサを使う
- I2Cや1-Wire通信とかやってみる
Arduinoヨーグルトメーカーの構想
はじめに、Arduinoでヨーグルトメーカーをつくるための構想をお話します。
構想
牛乳に種となる少しのヨーグルトを入れ、40℃に温度を保って数時間ほどおくと新しくヨーグルトができます。 これをArduinoを使って実現するために、次のように構想を考えてみました。
まず40℃の一定の温度にするため、ヒーターが必要です。ヒーターのスイッチをオンオフを制御するためには、リレーモジュールが使えそうです。また、温度を測定するために温度センサも必要です。温度表示するモニタとしてはOLEDがよさそうです。
フィードバックとして得た温度によって、冷たければヒーターをオンにして温め、温まりすぎればヒーターをオフにして冷ますといったものです。
空気を温めても意味がない
じつは最初、下の写真のようにヒーターを発泡スチロール保温容器に接着して空気を温めようとしてました。しかし試してみると、36℃程度しか空気の温度が上昇しませんでした。
そこで、( ゚д゚)ハッ!っと気がつきました。
「空気じゃない!牛乳を温めるんだ!」
牛乳を40℃に保てればよいのですから、アルミ容器にヒーターを付けて、牛乳を注げば良いのでは?という考えにたどり着きます。
熱伝導率とは?
熱伝導率とは、熱が高温から低温へ運ばれる現象(熱伝導)による、熱の移動のしやすさをあらわすものです。1秒間に1平方メートルの面積から、1ケルビン伝えるための熱量になります。
物体の状態や温度にもよって変わってきますが、おおよそ次の通りです。
素材 | 熱伝導率[W/(mK)] |
---|---|
アルミ | 221 |
空気 | 0.0241 |
ガラス | 1 |
水 | 0.6 |
この表を見るとわかる通り、アルミが圧倒的に熱伝導率が高く、空気の熱伝導率は低いことがわかります。また、ガラスも意外と熱伝導率は低いですね。
熱伝導率と似て非なる比熱
熱伝導率と似ていて異なるものに「比熱」があります。 比熱とは、単位質量あたりの物質の温度を単位温度上昇させるために必要な熱量のことを表します。物質1kgを、1ケルビン伝えるために必要な熱量となります。
素材 | 比熱[J/(kgK)] |
---|---|
アルミ | 0.880 |
空気 | 1.007 |
ガラス | 0.670 |
水 | 4.183 |
この表から、水をあたためるには、大きなエネルギーを必要とすることが分かります。また、アルミとガラスでは、ガラスのほうが小さいエネルギーで温められることになります。しかし、よく考えてみるとアルミは軽いですから、同じ1kgのアルミとガラスを考えますと「まぁ、そうなのかも」と納得できるのではないでしょうか。
アルミクッカー
幸い、キャンプで使うアルミクッカーやメスティンを持ち合わせております。アルミは熱伝導率がとても優れてますから、ヒータの温度も効率よく牛乳に伝わるはずです。
写真のようにアルミクッカーとヒーターをゴム紐ではさむようにして固定しました。
普段使いにも便利なアルミクッカー
ちなみに私はキャンプだけでなく、普段の料理でアルミクッカーやメスティンを愛用しております。すぐに温まりますから、調理時間も短く済み、ガス代もお得なはず!洗い物も軽くて便利です!アルコールストーブのわずかな燃料でご飯も炊けちゃいます。
つかうもの
ここで、Arduino制御で使う電子部品をまとめておきます。
Arduino
この記事ではPro Microを使いましたが、もちろんほかのArduinoもお使いいただけます。
Arduinoをお持ちでないようでしたら おすすめArduinoどれを選べばいい?Arduinoで電子工作をはじめる方へ をご覧ください。 また、Pro Microの使い方は Pro MicroでArduinoをはじめよう!〜Lチカするまで をご覧ください。
ヒーター
12V電圧で80℃まで発熱可能なPTCヒーターを2つ使用しました。2つのヒーターは並列につないで使用します。
PTCヒーターとは?
PTCヒーターとは、Positive Temperature Coefficientヒーターの略で半導体セラミックを利用したヒーターになります。温度が上がると半導体粒子が膨張して、導電部分が断ち切られて電流が流れにくくなります。この事により、ある温度以上になると急激に電気抵抗が増加するため、PTCヒーター自体で一定の温度に制御されるという特徴があります。 一定の温度に保たれるので、場合によってはマイコンなどの制御の必要がありません。またニクロム線と違って、安全面でも優れていると言えるでしょう。
リレー
WayinTopリレーモジュールのリレーモジュールを使いました。
このリレーの使い方は リレーモジュールの使い方|Raspberry Pi・Arduino(ESP32) で詳しく解説してます。OLED
温度表示ができると便利です。I2C通信のOLEDディスプレイを使用しました。
OLEDの使い方は 【Arduino】OLEDに文字表示【Seeeduino】 をご覧ください。
温度センサ
防水加工されたDS18B20の温度センサを使って、ヨーグルトの中に直接入れて温度測定します。
電源
12V 1.5Aの電源アダプターを使用しました。 また、3端子レギュレータを使って12Vから5Vの安定化電源をつくってArduinoへ電源供給しました。 3端子レギュレータの使い方は、 3端子レギュレータの使い方(5V→3.3V) をご覧ください。
ブレッドボードに刺せる電源ジャックモジュールがあると便利です。ヒーターの端子を電源ジャックのメスに改造して、エフェクタなどで使われるDCケーブルで配線しました。
その他
プルアップのため4.7kΩの固定抵抗を使います。ブレッドボードやジャンプワイヤも使います。
準備
必要なライブラリのインストールや、Arduinoと各センサモジュールの配線を説明します。
必要なライブラリ
DS18B20の温度データを読み取るために、OneWireとDallasTemperatureライブラリをインストールします。
また、OLEDに文字表示をするためu8g2ライブラリをインストールしましょう。
Arduinoとセンサモジュールの配線
Arduinoとセンサモジュールを次のように配線します。ヒーターに供給する電源は12Vで1A以上のものを使用します。 OLEDはI2C通信ですので、ProMicroの場合はSDAを2番ピン、SCLを3番ピンへつなぎます。ArduinoによってSDAとSCLの場所が異なりますので注意してください。
ソースコード
温度が40℃前後になったらリレーをオン・オフにしてヒーターを制御させるプログラムです。
#include <U8g2lib.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#define DS18B20_PIN 9
#define RELAY_PIN 8
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
OneWire oneWire(DS18B20_PIN);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(9600);
sensors.begin();
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_8x13_tf);
u8g2.sendBuffer();
pinMode(RELAY_PIN, OUTPUT);
}
float base_temp = 40.0;
void loop() {
delay(3000);
sensors.requestTemperatures();
float temp = sensors.getTempCByIndex(0);
displayOled(temp);
if(temp < base_temp - 1.0) {
digitalWrite(RELAY_PIN, HIGH);
} else if(temp > base_temp + 1.0) {
digitalWrite(RELAY_PIN, LOW);
}
}
void displayOled(float temp) {
char tempFloatString[10];
dtostrf(temp,3,1,tempFloatString);
char bufTemp[20];
sprintf(bufTemp, "Temp: %s", tempFloatString);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_8x13_tf);
u8g2.drawStr(0, 10, bufTemp);
u8g2.sendBuffer();
}
実験:ヨーグルトをつくってみよう
以上の内容のArduinoヨーグルトメーカーをつくり、実際にヨーグルトが作れるか実験してみました。
2021年10月2日22:20開始
ヨーグルトのタネを大さじ3杯ほどアルミクッカーへ入れます。雪印の「ナチュレ恵み」をタネに使いました。
冷たい牛乳をヒーターで40℃に加熱するのは効率が悪そうなので、あらかじめ40℃程度になるまで牛乳を温めておきます。牛乳は成分無調整の乳脂肪分3.5%以上のものを使いました。
アルミクッカーにヒーターを取り付け、そのまま保温ボックスへ設置します。温度計は、よく消毒してヨーグルトの中へ直接入れました。隙間には断熱材を敷き詰めて、少しでも熱効率をよくしました。
Arduinoヨーグルトメーカーはこんな感じです。その後しばらくようすを観察しました。リレー制御も上手くできたようで、温度が40℃あたりに保たれてます。
翌日9:30終了
一夜あけました。ヨーグルトづくりの開始から、約11時間経ちました。 無事ヨーグルトはできたかな?
\ジャジャン!/
ご覧の通り、見事にヨーグルトができました! 少し水っぽさがありますが、冷蔵庫で冷やしたら固まって、ふわっとした美味しいヨーグルトになりました。
ウマウマです!(^q^)
その後、何度かヨーグルトを作ってみましたが、どうも牛乳の乳脂肪分の多いほうが固まりやすくなるようです。
低温調理への可能性
Arduinoヨーグルトメーカをさらに発展させて、60℃の低温調理もやってみたいですね。低温調理ができれば、鶏むね肉でしっとり美味しいハムがつくれるはずです。 ところで、水を温めてみたところ、58℃までの温度上昇が限界でした。これでも低温調理ができそうですが、欲を言えばヒーターの数をもう1つ増やして火力をアップさせたいです。 ちなみに、自作ヨーグルトメーカーの消費電力を測定してみたところ、12Vで約0.5Aですので6Wほどになりました。
改良:ヨーグルトメーカー Ver2
その後、ヨーグルトづくりを試しているうちに、うっかり5V端子に12V電源をつないでしまい、Pro Microやセンサモジュールを壊してしまいました。ブレッドボードの状態で常用するのはミスが起こりやすいため、回路をケースへ収め、抽象化することにしました。
Pro Microの代わりにSeeeduino XIAOを使用し、温度センサはサーミスタを使ってみました。Seeeduino XIAOの使い方は Seeeduino XIAOでArduino開発をはじめよう をご覧ください。また、サーミスタの詳しい使い方は Arduinoとサーミスタで温度測定 をご覧ください。 ヒーターはDCジャックで、温度センサはステレオミニジャックで抜き差しできるようにしてみました。
納豆をつくってみた
さきほどの写真中の2つのボタンは温度設定するためのものです。これによってヨーグルトだけでなく、納豆も作れるようになりました。納豆の場合は、40℃〜45℃の間で納豆菌が繁殖しやすいようです。
納豆の作り方
- 大豆を1日、水に浸しておく
- 保温容器、ボウル、スプーンなど使うものを煮沸消毒しておく
- 大豆を鍋で柔らかくなるまで蒸す
- 蒸し上がったら、熱いうちにボウルへ移し、市販の納豆を大さじ1入れ、よく混ぜる
- ❹保温容器へ移し、43℃で24時間保温する
- 保温が終わったら、冷蔵庫で1日寝かして完成
ソースコード(ヨーグルトメーカー Ver2)
改良版のヨーグルトメーカーのソースコードを載せておきます。温度センサにサーミスタを使っていることに注意してください。
#include <U8g2lib.h>
#include <math.h>
#define THERMISTOR_PIN 6
#define RELAY_PIN 0
#define BUTTON_MINUS_PIN 1
#define BUTTON_PLUS_PIN 2
const float DIVIDER = 10000.0; // 分圧抵抗10kΩ
const float DAC_MAX = 1023.0;
const float T0 = 273.15;
const float R0 = 27700.0;
const float B = 3435.0;
float calcTemp(float Rt) {
float T_bar = 1/T0 + 1/B * log(Rt/R0);
return 1.0/T_bar - 273.15;
}
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
float baseTemp = 43.0;
float nowTemp = 25.0;
void minusInterrupt() {
// Serial.println("-");
tempUpDown(false);
}
void plusInterrupt() {
// Serial.println("+");
tempUpDown(true);
}
unsigned long lastMillis = 0;
int chatteringThreshold = 200;
void tempUpDown(boolean isUp) {
unsigned long nowMillis = millis();
if((nowMillis - lastMillis) < chatteringThreshold) {
return;
}
lastMillis = nowMillis;
if(isUp) {
baseTemp++;
} else {
baseTemp--;
}
displayOled();
}
void setup() {
Serial.begin(9600);
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_8x13_tf);
u8g2.sendBuffer();
pinMode(RELAY_PIN, OUTPUT);
pinMode(THERMISTOR_PIN, INPUT);
pinMode(BUTTON_MINUS_PIN, INPUT_PULLUP);
pinMode(BUTTON_PLUS_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_MINUS_PIN), minusInterrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(BUTTON_PLUS_PIN), plusInterrupt, FALLING);
}
void loop() {
float Aout = float(analogRead(THERMISTOR_PIN));
Serial.println(Aout);
float Rt = DIVIDER * Aout / (DAC_MAX - Aout);
nowTemp = calcTemp(Rt);
displayOled();
if(nowTemp < baseTemp - 1.0) {
digitalWrite(RELAY_PIN, HIGH);
} else if(nowTemp > baseTemp + 1.0) {
digitalWrite(RELAY_PIN, LOW);
}
Serial.println(nowTemp < baseTemp - 1.0);
delay(3000);
}
void displayOled() {
char tempFloatString[10];
dtostrf(nowTemp,3,1,tempFloatString);
char baseTempFloatString[10];
dtostrf(baseTemp,3,1,baseTempFloatString);
char bufTemp[20];
char bufBaseTemp[20];
sprintf(bufTemp, "Temp: %s", tempFloatString);
sprintf(bufBaseTemp, "Base: %s", baseTempFloatString);
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_8x13_tf);
u8g2.drawStr(0, 10, bufTemp);
u8g2.sendBuffer();
u8g2.drawStr(0, 24, bufBaseTemp);
u8g2.sendBuffer();
}