あなたはおいしいビール、Arduinoを助けたいですか

この出版物は別の出版物に触発されています。 「メガブルワリーホームブルワリーのコントローラー」と呼ばれます。 パートI」およびmegadenisによって発行されました



どのようにすべてが始まりましたか?



私は工科大学の学生です。 かつて医科大学で勉強していた友人とカフェに座って、彼らはバーを開くことにしました。 原則として、注目に値する多くのアイデアがありました。 たとえば、音楽のスタイルに応じて角度が変わるダンスフロア...



...しかし、私たちはあなたのビールを醸造しませんか?



数週間後、父の友人が働いていた醸造所から材料を取って、ビールを醸造しました。 しかし、多くの技術プロセスが中断されたため、ビールの代わりに何かがあまり心地よくない匂いで出てきました。



数年後、私はこのプロセスを繰り返し、Arduino UNOを使用して少し自動化することにしました。 そして、何が起こったのか。



まず、インストール全体で何をすべきか。







最初の段落は現在実装されていません。 これまでのところ、実装方法についての考えさえありません。

2番目も実装されていませんが、近い将来、ポンプがebayから配送されるまで待ちます。

3番目のポイントは非常に単純です。



醸造プロセスの準備



バットで水を満たす必要があるというシステムからのメッセージ->プログラムはOKキーが押されるのを待つ->プログラムはarduinoコマンドを送信してソリッドステートリレーをオンにする->ソリッドステートリレーはバット内の1キロワット10をオンにし、温度を37度にして、プログラムにコマンドを送信するすべて調理する準備ができています。 37度の温度を維持します。



水をチェックしたいのですが、センサーは「中国の兄弟」からの出発をまだ待っています。



半自動醸造



原則として、簡単な手順:



-制御プログラムの「ウォームアップ」ボタンを押します。残りの制御ボタンはアクティブではありません。

-ウォームアップ後、プログラムは「すべて準備ができました。調理できます」というメッセージを表示します。

-材料を眠らせ、醸造プログラムを選択します-「ビール醸造」ボタンがアクティブになります。

-「醸造ビール」ボタンを押すと、プロセスが開始されます。

-さらに、システムは情報メッセージを使用して、何をいつ実行するかを定期的に通知します。



指示に従ってください。



手動醸造



このプロセスにより、調理パラメータを設定し、調理サイクルで変更できます。 彼はまだそれに到達していません。



自動調理



これは夢です。 現在、実装するコンポーネントはありません。 不十分なポンプ、水位センサー。 麦汁の密度、若いビールに含まれるアルコールの量などの測定方法がわかりません。 しかし、私は絶望せず、ビールの醸造が次のようになるまで徐々に自動化します。



材料を適切なトレイに入れ、ボタンを押して... 1か月半後、完成したビールを手に入れました。



これはプロセスの簡単な概要です。次に、技術面に移りましょう。



プロセスの技術面



前述のように、arduino UNOは制御マイクロコントローラーの略です。 2つのリレーがそれに接続され、2

デジタル温度計DS18B20



Arduinoは、comポートを介してメインプログラムと通信します。 なぜなら 私はarduinoのリアルタイムのネームプレートを持っていません。視覚的なc#からタイマーを取得する必要がありました。 彼らはプログラムを書いた経験がないので、誰かが突然アイデアを持っている場合、批判は名誉メールです。 いわば、あなたが突然気に入らないものを批判してください。



ここにarduinoのプログラムのテキストがあります
#include <OneWire.h> OneWire ds(8); //     8  int reley1 = 13; int reley2 = 12; int reley3 = 11; int reley4 = 10; int reley5 = 7; //  int reley6 = 6; //     float temp1; float temp2; void setup(void) { Serial.begin(9600); pinMode(reley1,OUTPUT); pinMode(reley2,OUTPUT); pinMode(reley3,OUTPUT); pinMode(reley4,OUTPUT); pinMode(reley5,OUTPUT); pinMode(reley6,OUTPUT); digitalWrite(reley1,LOW); digitalWrite(reley2,LOW); digitalWrite(reley3,LOW); digitalWrite(reley4,LOW); digitalWrite(reley5,LOW); digitalWrite(reley6,LOW); } void loop(void) { if (Serial.available()) { switch (Serial.read()){ case 'i': infuz(); break; case 'p': progrev(); break; case 'a': avariya(); break; case 'v': varka(); break; case 't': temperature(); break; } } } void varka() { digitalWrite(reley6, HIGH); while(Serial.read()!='m') { temperature(); if (temp1 >= 52.00) digitalWrite(reley6,LOW); else digitalWrite(reley6,HIGH); } while(Serial.read()!='n') { //digitalWrite(reley6,HIGH); temperature(); if(temp1>= 62.00) digitalWrite(reley6,LOW); else digitalWrite(reley6,HIGH); } while(Serial.read()!='b') { //digitalWrite(reley6,HIGH); temperature(); if(temp1 >= 75.00) digitalWrite(reley6,LOW); else digitalWrite(reley6,HIGH); } digitalWrite(reley6,LOW); while(Serial.read()!='c') delay(1000); while(Serial.read()!='x') { digitalWrite(reley5,HIGH); temperature(); } digitalWrite(reley5,LOW); } void infuz() { //temperature(); //Serial.available(); while (Serial.read()!='s'){ //    if (temp<=69.50) digitalWrite(reley5,HIGH); else digitalWrite(reley5,LOW); } digitalWrite(reley5,LOW); } void progrev() { while (temp1 <=36.00) temperature(); digitalWrite(reley6,HIGH); digitalWrite(reley6,LOW); //while (temperature() >40.0) //delay(1000); Serial.println('s'); } void avariya(){ digitalWrite(reley1,LOW); digitalWrite(reley2,LOW); digitalWrite(reley3,LOW); digitalWrite(reley4,LOW); digitalWrite(reley5,LOW); } void temperature() { byte i; byte present = 0; byte data[12]; byte addr[8]; byte zator[8] = {40, 23, 218, 43, 6, 0, 0, 22}; //      byte varilka[8] = {40, 255, 240, 115, 59, 4, 0, 234}; //      float celsius; // float temp; boolean gde; if ( !ds.search(addr)) { //Serial.println("No more addresses."); //Serial.println(); ds.reset_search(); delay(250); // return; } if (OneWire::crc8(addr, 7) != addr[7]) { Serial.println("CRC is not valid!"); // return; } ds.reset(); ds.select(addr); ds.write(0x44, 1); // start conversion, with parasite power on at the end delay(840); // maybe 750ms is enough, maybe not // we might do a ds.depower() here, but the reset will take care of it. present = ds.reset(); ds.select(addr); ds.write(0xBE); // Read Scratchpad for ( i = 0; i < 9; i++) { // we need 9 bytes data[i] = ds.read(); } int16_t raw = (data[1] << 8) | data[0]; byte cfg = (data[4] & 0x60); if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms celsius = (float)raw / 16.0; for(i = 0; i<8; i++) { if (addr[i] == zator[i]) gde = true; else { gde = false; break; } } if (gde) { Serial.print("t2 "); //temperatura  temp2 = celsius; Serial.print(temp2); Serial.println(); } else { Serial.print("t1 "); //  temp2 = celsius; Serial.print(temp1); } }
      
      











すべては問題ありませんが、何らかの理由で3番目のセンサーが常に85度を表示します。 理由はまだ言えません。 そして、彼はさらなる自動化のために必要です-冷蔵庫の温度を維持します。



プログラムの機能について簡単に説明します。



プログラムはサブルーチンに分割されており、各ポートは特定のシンボルがcomポートに表示されるとアクティブになります。 たとえば、文字「p」がポートに入ると、「ウォームアップ」モードがアクティブになります。 または、「a」の場合、avariya()ルーチンが呼び出され、すべてがオフになります。 温度()ルーチンが呼び出されると、データはグローバル変数temp1、temp2に書き込まれます。 そこから、彼らは必要なルーチンに入ります。



将来的には、さまざまな種類の料理や月明かりを調理するためのルーチンがあります。



さて、メインの管理プログラムです。



主な管理プログラム



Visual Studio C#で書かれています。



プログラムのソースコード:



プログラムソースコード
 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.IO.Ports; namespace WindowsFormsApplication1 { public partial class Form1 : Form { // String portnumber; SerialPort Port1 = new SerialPort("COM5", 9600); int s=0; public Form1() { InitializeComponent(); } /*private const int CP_NOCLOSE_BUTTON = 0x200; protected override CreateParams CreateParams { get { CreateParams myCp = base.CreateParams; myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON; return myCp; } }*/ private void Form1_Load(object sender, EventArgs e) { label2.Text = Port1.PortName; Port1.Open(); } //  private void button1_Click(object sender, EventArgs e) { if (Port1.IsOpen == false) { try { //     podrugomu.com/node/987 Port1.PortName = label2.Text; Port1.Open(); Port1.Write("Check"); //SerialPort Port2 = new SerialPort("COM4", 9600); //Port2.Open(); //label3.Text = Convert.ToString(Port2.ReadByte()); //   MessageBox.Show("   ", " "); richTextBox1.Text = richTextBox1.Text + "\n" + "   "+" "+DateTime.Now.ToString("HH:mm"); button1.Enabled = false; button2.Enabled = false; button3.Enabled = false; if (Port1.ReadByte() == 1000) { richTextBox1.Text = richTextBox1.Text + "\n" + "   "+" "+DateTime.Now.ToString("HH:mm"); button1.Enabled = true; button2.Enabled = true; button3.Enabled = true; Port1.Close(); MessageBox.Show("   " +" "+ DateTime.Now.ToString("HH:mm")); richTextBox1.SaveFile("CheckLOG.rtf"); } } catch { richTextBox1.Text = richTextBox1.Text + "\n" + "   " +" "+ DateTime.Now.ToString("HH:mm"); MessageBox.Show("   .      ", "Warninig"); richTextBox1.SaveFile("log/Check_"+DateTime.Now.ToString("ddMMyyyy")+".rtf"); } } } //   private void button3_Click(object sender, EventArgs e) { if (Port1.IsOpen == false) { try { //     podrugomu.com/node/987 MessageBox.Show("   ", "WARNING", MessageBoxButtons.OK, MessageBoxIcon.Warning); Port1.PortName = label2.Text; Port1.Open(); Port1.Write("Clean"); MessageBox.Show("   ", " "); button1.Enabled = false; button2.Enabled = false; button3.Enabled = false; if (Port1.ReadByte() == 1000) { button1.Enabled = true; button2.Enabled = true; button3.Enabled = true; Port1.Close(); MessageBox.Show("   "); } } catch { MessageBox.Show("   .      ", "Warninig"); } } } private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) { } private void cOM1ToolStripMenuItem_Click(object sender, EventArgs e) { SerialPort Port1 = new SerialPort("COM1", 9600); // MessageBox.Show("  COM1"); label1.Visible = true; label2.Text = "COM1"; } private void label2_Click(object sender, EventArgs e) { } private void cOM2ToolStripMenuItem_Click(object sender, EventArgs e) { SerialPort Port1 = new SerialPort("COM2", 9600); // MessageBox.Show("  COM2"); label1.Visible = true; label2.Text = "COM2"; } private void cOM3ToolStripMenuItem_Click(object sender, EventArgs e) { SerialPort Port1 = new SerialPort("COM3", 9600); // MessageBox.Show("  COM3"); label1.Visible = true; label2.Text = "COM3"; } private void cOM4ToolStripMenuItem_Click(object sender, EventArgs e) { SerialPort Port1 = new SerialPort("COM4", 9600); // MessageBox.Show("  COM4"); label1.Visible = true; label2.Text = "COM4"; } private void cOM5ToolStripMenuItem_Click(object sender, EventArgs e) { SerialPort Port1 = new SerialPort("COM5", 9600); // MessageBox.Show("  COM5"); label1.Visible = true; label2.Text = "COM5"; } private void cOM6ToolStripMenuItem_Click(object sender, EventArgs e) { SerialPort Port1 = new SerialPort("COM6", 9600); // MessageBox.Show("  COM6"); label1.Visible = true; label2.Text = "COM6"; } private void cOM7ToolStripMenuItem_Click(object sender, EventArgs e) { SerialPort Port1 = new SerialPort("COM7", 9600); // MessageBox.Show("  COM7"); label1.Visible = true; label2.Text = "COM5"; } private void ToolStripMenuItem_Click(object sender, EventArgs e) { } //   private void button2_Click(object sender, EventArgs e) { // if (Port1.IsOpen == false) //{ // try //{ //     podrugomu.com/node/987 //Port1.PortName = label2.Text; //Port1.Open(); switch (label3.Text) { case "  ": MessageBox.Show("   ", " "); Port1.WriteLine("i"); timer1.Start(); break; case "  Cooper": MessageBox.Show("  Cooper ", " "); Port1.WriteLine("v"); timer3.Start(); break; } button1.Enabled = false; button2.Enabled = false; button3.Enabled = false; // button5.Enabled = false; // richTextBox1.Text = Port1.ReadLine()+"\n"; /* if (Port1.ReadLine() == "e\r") { button1.Enabled = true; button2.Enabled = true; button3.Enabled = true; button5.Enabled = true; */ //Port1.Close(); // MessageBox.Show("   "); // } // } // catch //{ // MessageBox.Show("   .      ", "Warninig"); //} // } } private void button5_Click(object sender, EventArgs e) { Port1.Write("p"); button1.Enabled = false; button2.Enabled = false; button3.Enabled = false; timer2.Start(); richTextBox1.Text = richTextBox1.Text + "\n" + "       37 " + " " + DateTime.Now.ToString("HH:mm"); /* Port1.Open(); //Port1.Open(); //richTextBox1.Text = richTextBox1.Text + "\n" + Port1.ReadLine(); Port1.WriteLine("o"); Port1.Close(); */ } private void ToolStripMenuItem_Click(object sender, EventArgs e) { Close(); } private void button4_Click(object sender, EventArgs e) { } private void ToolStripMenuItem_Click(object sender, EventArgs e) { label3.Text = "  "; } private void timer1_Tick(object sender, EventArgs e) { textBox1.Text = Convert.ToString(Convert.ToInt32(s / 60)); textBox2.Text = Convert.ToString(Convert.ToInt32((s))); s++; label5.Text = Port1.ReadLine(); if (s==4200){ //70   4200  timer1.Stop(); //timer2.Start(); //Port1.Open(); Port1.WriteLine("s"); // Port1.Close(); MessageBox.Show("     "); button1.Enabled = true; button2.Enabled = true; button3.Enabled = true; button5.Enabled = true; textBox1.Text = ""; textBox2.Text = ""; } //Port1.Close(); } private void label4_Click(object sender, EventArgs e) { } private void timer2_Tick(object sender, EventArgs e) { label5.Text = Port1.ReadLine(); if (Port1.ReadLine() == "s\r") { timer2.Stop(); MessageBox.Show("   37 .       "); richTextBox1.Text = richTextBox1.Text + "\n" + "    . =37 " + " " + DateTime.Now.ToString("HH:mm"); button2.Enabled = true; } } private void ToolStripMenuItem_Click(object sender, EventArgs e) { Port1.WriteLine("a"); MessageBox.Show("    "); } private void ToolStripMenuItem_Click(object sender, EventArgs e) { Port1.WriteLine("k"); MessageBox.Show("    .  60 "); richTextBox1.Text = richTextBox1.Text + "\n" + "    .  60 " + " " + DateTime.Now.ToString("HH:mm"); } private void timer3_Tick(object sender, EventArgs e) { string s1 = ""; Port1.ReadLine(); if (s1.Substring(0, 2) == "t1") label5.Text = s1.Substring(4, 5); if (s1.Substring(0, 2) == "t2") label9.Text = s1.Substring(4, 5); s++; if (s == 900) { Port1.WriteLine("m"); MessageBox.Show("   62 "); richTextBox1.Text = richTextBox1.Text + "\n" + "   62 " + " " + DateTime.Now.ToString("HH:mm"); } if(s== 2250) { Port1.WriteLine("n"); MessageBox.Show("   78 "); richTextBox1.Text = richTextBox1.Text + "\n" + "   78 " + " " + DateTime.Now.ToString("HH:mm"); } if (s ==2700) { Port1.WriteLine("b"); MessageBox.Show("  ,   "); richTextBox1.Text = richTextBox1.Text + "\n" + "  .   " + " " + DateTime.Now.ToString("HH:mm"); } } private void ToolStripMenuItem_Click(object sender, EventArgs e) { label3.Text = "  Cooper"; } } }
      
      











プログラムは、comポートを介してarduinoと通信します。 唯一のことは、私が勝手に勝てないということです。そのため、comポートに問い合わせるとき、サブプログラムの実行時にプログラムがフリーズしません。 サブプログラムの終了後、プログラムはハングしますが、これまでのところ重要ではなく、プラスでもありません。 愚か者からの保護-特定の手順中に何も押さないでください。



合計、プログラムは



-調理器具を準備します。

-料理;

-作業の簡単なログを作成します(料理の詳細な分析に非常に役立ちます)。

-コントロールコントローラー(arduino UNO)に接続するポートを選択します。

炊飯器を沸騰させ、バットをマッシュします。



ポンプとストローバルブが来たら、さらに自動化します。 それまでは、毎週日曜日に料理プログラムを1つ追加します。 合計で5つのプログラムがあります。 手動モードの実装も順番に待機しています。

彼らが言うように



継続する...





UPD:



ここに醸造所の写真があります



これはダイジェスターです。 私はそれらを2つ持っています。 密閉されたフレームのDS18B20温度センサーは、側面に取り付けられています。

長い間、すべてを接地する必要があることが明かされるまで、arduinoが定期的にハングする理由を理解できませんでした。それは、ケース、センサーケース、およびarduinoにパンチします。



内部の銅管は麦汁をろ過するためのものです。 あなたはそれをより美しくすることができます、しかしそれは場違いでそれを使うほうが良いです。 残念ながら、中国の収集品は急いで送信しません。



結果について話すのは時期尚早です、それが起こったことです





バットの一般的なビューは次のようになります。





従来のコネクタを使用

ダブルコンセントに接続された温度センサーを接続します。 機器を洗う方が便利です。 切断され、バスルームに運ばれた。 洗浄、接続、すべてが機能します。



スケジュールに従ってすべてが発泡していたので、過剰はありませんでした。 そして、最も近い計画は、発酵のためにビールのバッチをマージし、別のものを醸造することです。 レシピは、原則として、arduinoのvarka()ルーチンのコードで見ることができます。



ソレノイドバルブがついに到着しました。 自動化プロセスは続行されます。



All Articles