Mash Monitor

Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum

Help Support Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
you guys realize that you have given me a brewing woody?!!!!

I am so geeked up about this! When all the bugs are worked out I am DEFINITLY going automated steam!!!

I love how brewing brings together such an immense knowledge base from all across the spectrum. Electronics, welding, physics, etc. this is truly a temple of knowledge!

You guys rock!
 
Instead of trying to match really small flow rates with a throttle valve, I was going to use a water level switch and turn my pump on and off. I'll put a check valve in the intake line to keep the line full as well.

As far as sparging goes, I am going to try no stir batch sparging with my manual setup. It could be automated by putting a solenoid valve on the outlet of the MLT. It would be pretty easy to program fill-wait-dump, fill-wait-dump into the controller. I'd probably do 4 cycles and use less water than the normal 2 cycle batch sparge.
 
Hey, great work - I really like your UI! I built a little monitor console for my mash temp controller - it simply listens to the serial port and plots the data recieved. Definately not as sophisticated as yours.

I used LM34 and a PIC ADC to monitor the temp, but that's all on the controller side. If you're plotting serial data too, want to trade source code? Mine is in VB however. I still think the graphing on mine is a little weak so I need to revise it sometime soon.

mashmaster_screen_small.jpg
 
Do you plan on any re-circulation for clarification? or just hoping that without stiring, you won't disturb the grain bed too much...
 
If one wanted to control flow you could look for Belimo brand proportional damper actuator that takes a 0-10V control signal or look for the floating type control that uses up/down control inputs from relays and couple it to a ball valve. For the manual control folks look for Dwyer VFB type flow meters in the 6-60 GPH range for sparge in and wort out flows.
 
MadWeezel said:
Cool - I found some thermistors on their site yesterday as well. I figured for the price, I couldn't go wrong. This looks like a little bit better option...wonder why it didn't show up when I searched the keyword, "temperature."

Jameco is a great company - I ordered most of my stir plate components through them, and I was always happy with the service.
 
I don't remember where I got mine, I've had a bag of 30 of them for a while... They're NTC, so non-linear... I'm thinking about switching to the LM34 for ease of use and accuracy...

I've used Digikey for years for all my electronic stuff...
 
I just finished my brewery automation and I see this. My first thought was I NEED IT!! but now Im trying to figure out how helpful it really is.

How does it help on brew day or do you just use it as a reference afterwards?
 
Monster Mash said:
How does it help on brew day or do you just use it as a reference afterwards?
The software in the OP was simply a monitor with datalogging, such that one could accurately measure the temperature of the mash in real time while keeping a log of temperatures over time (to get a graphical representation of heat losses and/or save a very detailed mash profile).

The follow-on posts (mine included) suggest broadening the scope of the software to include electronic control of brew equipment.
 
Which of the software packages available would be the easiest to use to build an application with graphics that would enable one to use the opto 22 optomux hardware with serial communications. Last programming efforts were when 5.25" disks were common and borlands turbo pascal was new about 2 decades ago.
 
kladue said:
Which of the software packages available would be the easiest to use to build an application with graphics that would enable one to use the opto 22 optomux hardware with serial communications. Last programming efforts were when 5.25" disks were common and borlands turbo pascal was new about 2 decades ago.
I HIGHLY recommend Java. The development platform is free (JDK), and it even has a free Windows GUI builder (Netbeans). There's a serial comm library for Java that supposedly works well. I haven't used it yet, but I will be experimenting with it sometime soon.

The language itself is quite different from Pascal in that it is object oriented. A bit of reading on the Sun website and a look at the plentiful example code should straighten that out for you. The basic logic and conditional statements are much the same as you've experienced before. If you've ever used C, the curly bracket scheme will look familiar, but I think the language is a bit more intuitive to use.

The other advantage of Java is that it is cross-platform capable - you can develop your program in Windows and have it run sucessfully on Mac or Unix systems. The serial library might be more platform specific, though - only time will tell with that.

The disadvantage of Java is that it is compiled at runtime in the JRE (Java Runtime Environment), so it tends to be a little slow to start, and there is a bit more memory cost than would otherwise be associated with the same program as a straight executable. It's really not a concern with the simple tasks we're trying to perform here.
 
I HIGHLY recommend Java. The development platform is free (JDK), and it even has a free Windows GUI builder (Netbeans). There's a serial comm library for Java that supposedly works well. I haven't used it yet, but I will be experimenting with it sometime soon.

I highly recommend Java too ! Install Eclipse with the visual editor and writing Java is like writing Visual Basic code, only in Java. (www.eclipse.org)

I'm using Java and USB for another project and I've got all the bugs out of using libusbJava. The Arduino board uses USB, so its a natural fit.

I'm too busy to do anything with this now, but in a few months I'll get back to it.

My applications will be written using the SWT libary, btw. It has buttons and Windows and textboxes, etc. I did a chart on the weekend that works great.
 
Thank you both for the software recomendations, have downloaded and installed the Java software. Now comes the fun part, learning a new programming language, but it will give me something to do at night until this Intel job is finished and i can return to Oregon and assemble the new system. The only upside to being in arizona and managing another instrument install job, is the leftover tubing and fittings from both the instrument and tool install work.
 
brewman, how's libusb treating you? Are you able to connect to an Arduino board through it?

All of the reading I've done suggests that the Arduino USB board shows up as a serial comm port, so I've been working on serial communication in Java. Unfortunately, I only have a Windows machine at the moment, and Sun gave up on a Windows implementation of javax.comm at least 4 years ago, so I've downloaded the GNU comm library at http://www.rxtx.org. I've managed some very simple code with it, and it appears to work very well. My Arduino board should show up next week, and I'll have more info then.
 
brewman, how's libusb treating you? Are you able to connect to an Arduino board through it?

libusbJava works well. I haven't connected to the Arduino board. I am working with another board for another project and it works well for that. No problem.


All of the reading I've done suggests that the Arduino USB board shows up as a serial comm port, so I've been working on serial communication in Java. Unfortunately, I only have a Windows machine at the moment, and Sun gave up on a Windows implementation of javax.comm at least 4 years ago, so I've downloaded the GNU comm library at http://www.rxtx.org. I've managed some very simple code with it, and it appears to work very well. My Arduino board should show up next week, and I'll have more info then.

Yeah, I guess it is going to work that way, ie Widows (Linux) will automatically create a USB driver for a serial device. I used rxtx about 2 years ago with a USB serial device and there were bugs. Hopefully they have been fixed since then. It worked fine with a regular serial port, but not with a USB serial port. *fingers crossed*
 
Sweet! I've got Java/RxTx working with an IOGear USB/Serial adapter and a null modem cable between my desktop and laptop. It seems to work very well - no bugs noted, but I haven't transferred more than a few bytes at a time. I'll post some screen shots later.
 
Time to hook up to the Arduino board !

Just a note... if we are going to share code, we should all work with the same Java libraries. I'll be using SWT because I've used it for other projects and it works well. Its part of the eclipse.org project.

I'm brewing tonight, but if I get done early and I'm bored I'll hook onto my board and test it.
 
I've pretty much abandon the USB idea since the only benefit I see to it is that it would power the controller, but since it can only supply 500mA, that's not enough to drive the relays and solenoids, so I'll probably just stick with rs232...

Since I know nothing of Java, I'll probably continue with Boralnd C++ builder, but I'd be more than happy to share that code if anyone wants it... I haven't made much progress lately on the software though, trying to put together the 'water heater' but having trouble mounting the heating element....

Seems that if I have the free time, I end up brewing instead of working on this.. :)
 
Screen shots as promised. The Mash Monitor app was running on my desktop. My laptop ran the Arduino Emulator, showing digital pin values on one side and analog pin values on the other. For some reason, my emulator code has about a 5% receive error rate. I'm not really interested in debugging it any further, though, since the actual board will be here soon.

Here's the virtual setup:
Digital Pin 0: Relay controlling the steam vessel heating element (HI = on)
Digital Pin 1: Relay controlling the steam solenoid valve (HI = open)
Analog Pin 0: Steam pressure sensor (multiply by .02 to get actual PSI)
Analog Pin 1: Mash temperature sensor (multiply by .18 and add 32 to get actual degrees F)

The correction factors are a rough guess since I don't have the actual sensors yet.
The screen shots were taken at separate times, so the values don't correlate exactly between the pictures, but you get the idea.

4688-serialmashmonitor.JPG
4688-arduinoemulator.JPG


brewman ! said:
Just a note... if we are going to share code, we should all work with the same Java libraries. I'll be using SWT because I've used it for other projects and it works well. Its part of the eclipse.org project.
I'm pretty happy with NetBeans, the swing library, and RxTx. I'll try to keep my code organized and commented, and most of my serial comm classes don't directly reference the GUI. RxTx mirrors javax.comm, so you can just import javax.comm.* instead of gnu.io.* if you're on a Linux/Solaris platform. So, it should be pretty easy to share code at some point.
Jer said:
I've pretty much abandon the USB idea since the only benefit I see to it is that it would power the controller, but since it can only supply 500mA, that's not enough to drive the relays and solenoids, so I'll probably just stick with rs232...
The Arduino USB board shows up as a serial port - you use RS232 serial comm to interact with it. The solid state relays I have on order with Jameco take about 5VDC@3mA to switch up to 280VAC@40A. I'm confident that USB can handle a few of those.
 
It works, it works!

I got the Arduino board and components today, and I couldn't wait to hook it up! My Mash Monitor software only required minor changes, and it was really easy to program the Arduino. I had something working within a few minutes of connecting the board.

Here's a pic of my first test actually controlling a heating element (SWMBO's hair dryer) hooked up to house current. The software works! It's not very elegant (yet), but it automatically controlled the hair dryer to maintain a user-selectable temperature across the LM34 sensor.

4688-arduinotest.JPG
 
Here's a portion of my code. I didn't include the automatically generated GUI code and Swing objects. I also didn't include the Main class because it only initiates the GUI, and everything is triggered from event listeners tied to it. As such, you can't just compile and run this code - you need a GUI or command line interface initialized by the missing Main class.

It's not the most elegant code, but you can see how to read and write to/from the Arduino. I'm fairly happy with this portion of the code, though I'll probably clean it up a bit. Future changes will include a separate procedure for making the serial connection (rather than including it in the GUI initialization), less hard coding of things like pin numbers and transfer functions, and more user control over the entire board (rather than just two digital pins).

Code:
package mashmonitor;
import java.util.*;
import javax.swing.*;
import gnu.io.*;
import java.io.*;
import java.math.BigDecimal;
/**
 * Application to monitor and/or control mash temperatures during beer brewing
 * Intended for use with an Arduino USB/Serial board
 * Has built in ability to almost completely control an Arduino board
 *
 * @author  Yuri
 *
 * NOTE: When comments reference bits within a byte,
 *       they are numbered 0-7, with 7 being the 1's place
 */

public class MashMonitorUI extends javax.swing.JFrame implements SerialPortEventListener{
    //"constant" declarations
    private static final String PORT = "COM3"; //which comm port to open
    private static final int HIGH = 1;
    private static final int LOW = 0;
    
    //transfer functions for 10 bit input from Arduino board
    //first number is a multiplier, second number is additive
    private static final double[][] aPinTransferFunctions = {{.25,.02,0,0,0,0},{32,0,0,0,0,0}};
    private static final int STEAMPRESSURE = 1;
    private static final int MASHTEMP = 0;
    private static final int STEAMHEAT = 13;
    private static final int MASHHEAT = 12;
    
    private static InputStream in; //input stream of serial port
    private static OutputStream out; //output stream of serial port
    private static int[] aPins = new int[6];
    private static double[] sensorValues = new double[6];
    private static Boolean isAutomated = false; //variable to determine the control state
    private static SerialPort serialPort = null; //serial port on which to connect
    private static TempController controller; //control class that does most of the work here
    private static boolean successfulTransfer = false; //first successful data transfer sets this true
    
    /** Creates new form MashMonitorUI */
    public MashMonitorUI() {
        initComponents();
        //open a serial port with an event listener
        //perhaps this code should be a separate procedure
        //so that the user can try to re-establish the serial connection
        //on the port of his/her choice if serial communication fails
        try {
            //find the port
            CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(PORT);
            //open the port
            serialPort = (SerialPort)portId.open("MashMonitor", 2000);
            //set the port up for communication
            serialPort.setSerialPortParams(9600,serialPort.DATABITS_8,serialPort.STOPBITS_1,serialPort.PARITY_NONE);
            //set the input and output stream variables
            in = serialPort.getInputStream();
            out = serialPort.getOutputStream();
            //add an event listener
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
            jLabelStatus.setText("Listening on port: "+portId.getName());
        } catch (Exception e) { //catch everything
            jLabelStatus.setText("ERROR: "+e.toString()+" - "+e.getMessage());
        }
    }
    //hande serial events - read only
    //wait for 14 bytes of data before reading (corresponding to each analog pin)
    //two "wrapper" bytes of all 1's surround
    //2 bytes per value, upper 8 bits first, followed by lower 2 bits (to get 10 bit precision)
    public void serialEvent(SerialPortEvent event) {
        if (event.getEventType()== SerialPortEvent.DATA_AVAILABLE) {
            int[] tempArray = new int[aPins.length * 2 + 2]; //an array to hold all input
            try {
                //wait for 14 bytes
                if (in.available() >= tempArray.length) {
                    for (int i = 0; i < tempArray.length; i++) {
                        tempArray[i] = in.read();
                    }
                    //if the first and last bytes aren't all 1's (255), discard everything
                    if ((tempArray[0] & tempArray[tempArray.length - 1]) != 255) {
                        while (in.available() > 0) {
                            in.read();
                        }
                        //else, read the bytes into the values for the sensors
                    } else {
                        for (int i = 0; i < aPins.length; i++) {
                            aPins[i] = (tempArray[i * 2 + 1] << 2) + tempArray[i * 2 + 2];
                        }
                        if (!successfulTransfer) {
                            successfulTransfer = true;
                            jLabelStatus.setText("Data transfer initiated.");
                        }
                    }
                    updateSensorValues();
                }
            } catch (Exception e) {
                successfulTransfer = false;
                jLabelStatus.setText(e.toString()+": "+e.getMessage());
            }
        }
    }
    
    //write data to the Arduino
    //dPin holds the pin number to change
    //state is the digital state to set the pin (HIGH or LOW)
    private static void serialUpdate(int dPin, int state) {
        try {
            //write a single byte command
            //bits 5 and 6 hold the pin number
            //bit 7 holds the pin state
            out.write((dPin << 1) + state);
        } catch (Exception e) {
            successfulTransfer = false;
            jLabelStatus.setText("Serial write failed.");
        }
    }

    //very brute force code to set sensor values
    //would be nice if controls were somewhat user-assignable against values
    //perhaps an init text file could be incorporated to save settings
    //instead of hard coding controls against values
    private static void updateSensorValues() {
        for (int i = 0; i < aPins.length; i++) {
            sensorValues[i] = aPins[i] * aPinTransferFunctions[0][i] + aPinTransferFunctions[1][i];
        }
        jProgressBarMash.setValue((int)sensorValues[MASHTEMP]);
        jLabelMashActualTemp.setText(Integer.toString((int)sensorValues[MASHTEMP]));
        jProgressBarSteam.setValue((int)sensorValues[STEAMPRESSURE]);
        
        //how to round double values in Java
        BigDecimal bd = new BigDecimal(sensorValues[STEAMPRESSURE]);
        bd = bd.setScale(2,BigDecimal.ROUND_UP);
        jLabelSteamActualPressure.setText(bd.toString());
    }
 
Good work, Yuri.

I think that in order to keep the host code reasonable one is going to have to add more functionality to the microcontroller. For instance, most of your temp control loop could be programmed to run on the micro. Then one could set up a few messages such as one to turn the temp control on, one to turn it off and one to get the current status, which would include the current temp.

If one just uses the micro as a fancy I/O board with the IO routines, its going to get complicated quick and if the USB connection is ever lost the whole process will crash. When I do something like this, the micro does most of the heavy lifting and the PC is "just" the GUI.

Nevertheless, good work on getting started.
 
brewman ! said:
If one just uses the micro as a fancy I/O board with the IO routines, its going to get complicated quick and if the USB connection is ever lost the whole process will crash. When I do something like this, the micro does most of the heavy lifting and the PC is "just" the GUI.
I've already begun to figure that out. I was sending some pretty complex messages to the micro, and it was getting all kinds of receive errors. Now I send a single byte whenever I need a state change on a digital pin.

Also, I was looping both the host and micro code - that was a mess. Now the micro loops (sending a sensor update every 100ms - way faster than required), and the host just listens, with an occasional command sent.

I tend to agree that the automated control should probably exist on the micro itself. Although, you could allow the user to "map" sensors to digital control more easily with logic in the host software, allowing more flexibility.

At any rate, I really dig the world of "physical computing." This is fun!
 
I've done a lot of this and the easiest way is to embed the brains in the micro.

Lets use your temp control loop as an example.

The host sends the micro a message. Lets say its MASH_TEMP_CONTROL_ON, with the setpoint for the control, lets say 150F.

The micro does the control loop. So it decides when to turn the relay on and off all by itself.

Every 250ms or so or whenever it needs to know, the host send the micro a MASH_TEMP_STATUS message. When the micro receives this, it replies with a MASH_TEMP_STATUS_REPLY message that gives the status (OK, ERROR, etc.) as well as the current temp, say 152F.

When the host doesn't want the micro to control temp anymore, it sends MASH_TEMP_CONTROL_OFF.

Compartmentalizing things like this really simplifies them. Now there are only 2 loops in the system. One is on the host and its just to update things. Or when the user pushes a button. The other loop is on the micro and it just does its control thing and replies to the host.

As soon as you get the host in the control loop it gets real messy. PC operating systems weren't designed to be real time control systems, except maybe real time Linux. But that is beyond the scope of this project.

I'm sorry I don't have time to work on this more. I feel badly that you are working on this alone. If you have questions ask.
 
brewman ! said:
I'm sorry I don't have time to work on this more. I feel badly that you are working on this alone. If you have questions ask.
Don't sweat it at all. I'm really enjoying the project. The learning curve is pretty steep, but that's a good thing. I look forward to sharing more of my results, and I can't wait to see what you guys come up with.
 
Are you guys going to have your program do a step mash and control all the valves and burners? I found this forum because I have been think of doing the same thing, you guys are much farther ahead of me though.

Dave
 
Yuri_Rage said:
Don't sweat it at all. I'm really enjoying the project. The learning curve is pretty steep, but that's a good thing. I look forward to sharing more of my results, and I can't wait to see what you guys come up with.


:confused:

Is anyone else feeling like they've drank too much??

Honestly seeing this stuff I wish I would have taken some programming classes or something. I'm just completely clueless about this.

Yuri - will you be selling this once it functions correctly?
 
Todd said:
Yuri - will you be selling this once it functions correctly?
Not sure if I'll sell it or not. I might consider it, but it'll be pricy, and I'll really have to put a lot of thought into making it somewhat universal.
 
Are you guys going to have your program do a step mash and control all the valves and burners?

I am going to. Its probably not going to happen until fall now though. I'll see how things go this summer.
 
Same here. I'm going to try and get it ready for its first run this weekend. I have a bit of work to do before then. Right now I have a pile of wires and some unfinished code in front of me.
 
My project for next winter is to learn C++ and the visual C environment. I really need another language in my repertoire.

Awesome stuff guys. After I learn C, I need to learn hardware.
 
Visual C++ sucks for occasional development. There is nothing visual about it and you are always dealing with handles and really weird, complicated structures.

If you want something to allow you to build Windows GUIs, I recommend C++ Builder, which is visual, ironically, Visual Basic, which is again visual or Java via Eclipse with the Visual Editor package.

Another option is to use QT, but then you have to develop in Linux (using Kdevelop or similar) but what you develop will run on Windows.
 
Brew day is tomorrow! It's almost midnight, and I just finished wiring what I need to test this concept under actual conditions. The software is still REALLY rough, but it will automatically maintain a mash temperature as long as there is steam available. The software will control the boiler heating element, but I have to manually click to turn it on and off while monitoring the pressure. That will be automated soon enough, I just ran out of time tonight.

Here are the latest pictures. I wanted to put this into an old desktop computer tower, but I can't find the one I thought I had stashed. So, I hacked together a wooden crate for now. With the present wiring, I can control one 220V circuit and two 110V circuits while monitoring two sensors. At some point, I'm going to add the capability for up to six sensors and four(ish) 110V circuits. This should be enough to get me through tomorrow, though.

4688-mashmonitorwiring.JPG


4688-mashmonitorwiring1.JPG
 
Unofficial results are in!

The steam rig works REALLY well. However, stirring is a MUST! I thought I'd ruined my beer when I heated the mash from 95 degrees F (the rest was unnecessary, except to test the steam concept) to 145 degrees F. It only took 5 minutes for the temperature to register 145, but then it kept climbing to 180(!!!) with the steam turned off. The top of the mash was still cool enough to stick my finger into it, so I decided to stir...aggressively. The temperature reading quickly dropped to 150, then 145, so all was well. I just had a REALLY hot spot. The system requires quite a bit of attention (stirring), though it was intended to be automatic. Guess I need to incorporate a mash rake...

Anyway, I think it turned out fine. Everything worked as well as could be expected, and I think I overshot 75% efficiency (haven't gotten a corrected OG reading yet, but it's looking a bit high).

The obligatory pictures:

4688-automaticsteammashing.JPG


4688-automaticsteammashing1.JPG
 
kladue said:
congratulations on the succesful test run, were you able to track boiler pressure during steam injection.
Absolutely! I was maintaining 11-12 psi with the valves closed. During injection, the pressure would drop to 8 psi fairly quickly, then drop slowly after that. I had at least 10 minutes of steam at any given time, which was more than required for each mash step.

I was not able to successfully track the volume in the mash tun. The steam would create bubbles in the mash, making the mash tun look more full than it actually was. As soon as I started recirculating, the level dropped quite a bit. I don't think I added much water (via steam) to the mash during the entire process.
 
With most of the liquid tied up in the mash was the steam injection very noisy aside from the warmup snaps and pops. I suppose if one wanted to do the math you could figure out the water/steam necessary to move the heat into the mash. Do you have any plans to reduce the steam flow to maintain boiler pressure.
 
Back
Top