Tuesday 25 November 2014

Commence Fermentation!

It's been a few weeks but I've managed to get a bunch of work done on the Web UI and the actual management code of the chamber. I finished wiring everything up shortly after the last post and did some tests with a carboy of water. I replaced the ceramic heating bulb with a small Ceramic heater as the bulb was causing a localized hotspot that was melting the foam of my chamber wall, and the Ceramic heater has a built in fan to help push the hot air around the chamber and get it up to an equalized temperature that much more quickly. Since I don't have a working touchscreen for the Beaglebone Black at the moment I've decided to whip up a web page to display data and manage the set point. I built a MySQL database and a simple front-end which allows the temperature monitoring code to push temperature data into the database on a set interval. I then used Google's really awesome graphing UI to draw some pretty graphs on the website. Here's a screencap of it in action.
Super cool Fermentation graph!
The blue line represents the ambient temperature in the chamber and the red line is a measurement from a probe stuck directly into the wort. The wort temp probe controls the heating element, when it drops to 0.3 degrees below the setpoint the heating element is turned on. The heater has a built in thermostat which was originally at 55 degrees C or so, so that's why you see those peaks on the blue chart, I turned it down to 30 degrees and I can see a pretty good response from the wort. That graph is a live view of a 20 gallon ferment from this weekends brewing, so there is a pretty big thermal mass in there and it takes about an hour to raise the wort temperature 1 degree C. I also have a cooling circuit, if the wort ever goes 0.3 degrees above my set point the Beaglebone Black will turn on the cooling circuit and a 5k BTU air conditioner will blast the chamber with cold air to keep the wort at the desired temperature. All the code for the temperature monitor is available on my Github repo Temp Driver Repo I've still got some work to do to pull down the set point from the website, right now it's hard-coded and I haven't found an elegant way to pull that data down yet. The plan is to have ferm schedules, where it will hold at temp x for some time, then ramp up or down to a set point and hold, then cold crash etc. I'll post some pictures of the whole system in action once I've cleaned up the garage a bit.

Friday 7 November 2014

Thanks Crank!

The guys at Crank Software hooked me up with a Hard Float compiled runtime for my board. I'm back in business!
 root@arm:/home/ubuntu/temp_probe# ./temp_driver -c test  
 Setting channel to : test  
 Starting temperature Driver  
 Command >  
 a  
     Ambient temp is 0.000000  
 Command >  
 Command >  
 w  
     Wort Temp is 0.000000  
 Command >  
 Command >  
That's some output showing the temp driver compiled and running on the BBB! Of course I don't have the temp probes connected right now so the values are defaulted to 0, but this means I'm ready to go and should have the interface running this weekend! Thanks Crank!

Thursday 6 November 2014

Temperature Control, here we come.

I finished up the wiring for the temperature probes, they are ds18b20 one-wire probes as I've mentioned earlier, and they are great since they can share a bus with up to 10 devices with no extra effort, just join up the wires, use the pull-up resitor between data and the 3.3V from the BBB and setup your GPIO input pin for the one-wire driver that's provided in the Ubuntu image and you'll be able to read multiple temp probes!

here's some output.


ubuntu@arm:/sys/devices/w1_bus_master1/28-00000449da30$ cat w1_slave
e4 00 4b 46 7f ff 0c 10 ae : crc=ae YES
e4 00 4b 46 7f ff 0c 10 ae t=14250
And the second probe
ubuntu@arm:/sys/devices/w1_bus_master1/28-000004f1d675$ cat w1_slave
ff ff ff ff ff ff ff ff ff : crc=c9 NO
e5 00 4b 46 7f ff 0b 10 83 t=-62
Hey, wait a minute, looks like that was a bad read, notice the crc=c9 NO, that means the crc check on the data read failed. That's a bad temp value and I better make sure to validate the crc before I trust a temp read. Here's a subsequent read that shows a good value.
ubuntu@arm:/sys/devices/w1_bus_master1/28-000004f1d675$cat w1_slave
e4 00 4b 46 7f ff 0c 10 ae : crc=ae YES
e4 00 4b 46 7f ff 0c 10 ae t=14250


Now I'm working on the temp_driver which will read the temp from the one-wire interface and send it to the UI using greio, which is the IPC library that comes with Storyboard. I ran into an issue with the Storyboard Engine though, when I switched to Ubuntu on my beaglebone I switched to a Hard-Float based kernel, and the Storyboard Engines I have aren't Hard-Float compatible, so I can't run Storyboard right now. I'm waiting for my friends at Crank to get me a hard-float compiled Engine and libs so I can finish my driver and get the interface up and running. I'm very close to have a working chamber for the first time in over a year!

Saturday 1 November 2014

I'm Back!

Hard to believe it's been almost a year since I posted, I've had a few things come up that put the project on hold, but I'm ready to start wrenching again.  I've built the physical chamber and done most of the electrical wiring, now I need to get the Beaglebone Black up and  running again and get my software tuned up so I can start controlling some fermentation temps.

I've been mainly working on the physical chamber and I've got a few pictures of that to share.

Ferm Chamber with Rough AC cooling placement
Air Conditioners have their own built in thermostats, and this one doesn't have an option to just run the cooling cycle all the time, so I had to hack the unit up a bit to re-route the very analogue temp probe from the AC out of the chamber and somewhere I could access it to to heat it up when the Beaglebone wants to cool the chamber.  The probe on this unit is a closed loop refrigerant coil that connects to a baffle that is opened and closed when the coolant in the line expands / contracts due to the temperature of the air coming into the unit.  It is normally mounted about 1/3 of the way up from the bottom.  Thankfully the copper is pretty malleable and I was able to bend it without crimping it out the back of the unit.  The end result can be seen here.

Re-Routed probe.
You can see here I managed to get it coming out the back of the unit where I now have easy access to it.  I will build up a little heating circuit using the BBB so that when it wants to cool the chamber it will also heat up this little guy which enables the compressor.  The other option is to just short the compressor to the main power which would always enable the cooling, but that's a bigger operation and if I muck it up it will render the AC unit useless.  I'm all about non-destructive modifications so I'll stick with this method for now.  For the heating I'm thinking I'll use one of these 5V heating pads which should be easy to control from the BBB.

The inside of the chamber is insulated with 1.5" R5.6 Foam insulation from Home Depot.  I used it because it was cheap and easy to work with.  I can always increase the amount of foam if I find the efficiency is bad, a quick test earlier showed no heat gain with a half hour stand and a 15 degree C gradient between ambient air and the chilled chamber air.

Since the unit is in my garage, and I live in Ottawa where the outside air temp can hit -30C I need a way to heat the unit as well, my brewing buddy Steve suggested I use a ceramic bulb like those used for lizard setups, which he happened to have.  So I wired up a hot side SSR controlled circuit and added a ceramic lightbulb outlet to the inside of the chamber that's controlled by this circuit.

Heater bulb outlet and the Temp Probe XLR headers.
You can also see in this picture the temperature probe headers I wired in.  On my old chamber I simply had the temperature probe wires just run through the chamber wall directly, but that can get messy and meant disconnecting them from the board to clean / sanitise them between brews.  This way I can pull them out when not in use and store them easily, then move the beer in, plug in the probes and I'm ready to go. It's also easier to add the probe to the wort before you move the carboy into the chamber ( more headspace for a 16" probe to be inserted ) so now I can put the wort probe into the carboy and then slide it in and plug it in after.  Plus XLR's are pretty damn awesome, I feel a little bit like a Rockstar when I plug them in :).

The last picture is a bit embarassing, but there's a mess of wiring coming out of this thing and I didn't plan the layout very well, I got really excited about getting it hooked up and just kind of ran with it.  For some reason the picture is showing up really small, I'll try to get some better shots for the next post.  This is the outside wall which has the control box for the SSR's, out of the box comes some Romex which connects to the hot and cold side plugs, the AC plugs into the cold side plug and the Light box is wired up in series to the hot plug, so when that circuit is energized the bulb is also turned on.  I may run a line for a small fan at some point for the heating side to help move the air around.

Black box has the SSR and Input voltage, you can see the AC Plugged into the cooling circuit.

I'll have a few more pictures and a new post in the coming days as I get the software side of things ramped up again and start doing some test runs before the inaugural brew.

Monday 24 February 2014

The UI continues to evolve.

Long time no post but the project is far from dead.  I've been doing some other brewery upgrades and brewing a bit to get my pipeline back to an acceptable level so the Fermentation chamber project took a backseat.  I'm going to give a push and see if I can get the initial UI and functionality running.  This will essentially simulate an STC-1000 type setup where you can set the desired temperature and the unit will maintain those temps.  Once that's working well I'll start working on the back-end which allows for building fermentation profiles and submitting them to the unit through a web interface.

I've been working a bit on the front end, I've added a second temp output and graphs for both ambient and wort temp.  The set-point feature is working and allows you to change the set point in tenth of a degree increments.  Right now everything is in Celcius, I'll add an option to switch temps to Fahrenheit.


Here's a quick preview of the new interface.  I realize it's not the prettiest thing, but it's showing the important info for now.  I'll be working on making it look a lot nicer in the coming weeks.

Monday 2 September 2013

The UI is Alive!

I've started working on the UI for the fermentation controller and thanks to Storyboard things are coming together very quickly.  I mentioned Crank Storyboard Suite in my first post and I'm going to go into some detail on how I'm putting together the interfaceand control logic using Storyboard.  As noted in my first post I've been a Crank Software employee since July 2010 and not only is it a really awesome place to work, we produce an incredible tool for designing and deploying UI applications to embedded targets.  A Storyboard deployment consists of two things, the Runtime which is a board specific package of binaries and libraries used to render the Storyboard Project you deploy to the target and the Project, which consists of the exported gapp file and the image assets and scripts.  Storyboard supports a wide variety of CPU/OS/Graphic chipsets.  For the Beaglebone Black I'm running the Linux Codesourcery Armle FBDev runtime, this allows me to run a GUI without having the overhead of X-windows as it renders content directly to the framebuffer on the target.  If my beaglebone image supported the SGX graphics processor and I had the right OpenGLES libraries installed I could also run the OpenGLES_2.0 runtime which would unlock some nifty 3D transition and animation options.  Unfortunately for me the Linux image I'm running doesn't currently support the SGX chipset yet, so I'll be running on FBDev for now.

Storyboard uses a WYSIWYG editor to enable the user to place the controls and graphics by dragging and dropping.  Variable's can be assigned to control data and then updated using either the integrated Lua scripting or by using the greio API provided in the runtime.  The API allows a user to write a native C application that can send data to and receive data from Storyboard, I had originally planned to write a small daemon that would read the 1-wire temperature data and pull up the proper GPIO line to enable the SSR which would switch on the cooling device plugged into it.  After a bit of research I discovered that Rsisto had published a free to use GPIO library for Lua.  Since Storyboard has full support for Lua baked right in, I can simply write all my code as a Lua script, making my application that much simpler as all my code now lives in a single Storyboard project!  I was pretty excited to get started so I whipped up the fastest thing I could, I honestly spent less than 10 minutes putting together the UI you see in the video below, I plan on making it a lot nicer in the coming days, but I wanted to get the bare minimum up to test the GPIO library and to make sure the temperature reporting was also working properly.  Check out the very quick demo below;


It's a little difficult to see in the video but I have a room lamp plugged into the outlet controlled by the SSR, when the GPIO line is pulled High the SSR enables the 110v circuit to complete energizing the plug and anything attached to it.  The idea here is that when we go above a certain set-point we want the fridge that acts as my cooling source to turn on which will drive the temperature in the fermentation chamber down to our set-point and keep it there ( within a couple of tenths of a degree ) so that the wort is fermented at exactly the temperature we want.  I will also be adding a heating element which will be controlled by another SSR which will turn on a heating element of some kind so I can manage my temperature exactly.

And now the Lua code that controls the GPIO and feeds the temperature display on the GUI.

require ("gpio") -- import library
local device_path = '/sys/bus/w1/devices/28-00000449da30/w1_slave'

-- setup the device defaults
local ssr_fired = false
configureOutGPIO(60)
writeGPIO(60,0)

-- timer callback function, read temp every second and update GPIO as required.
function read_temp()
 local f = assert(io.open(device_path, 'r'))
 local t = f:read("*all")
 local temp
 local data_table  = {}
 
 
 f:close()
 for w in string.gmatch(t,"t=*=(%d+)") do
  temp = w
 end
 local report_temp_c = string.format("%.2f",temp / 1000)
 data_table["probeTemp"] = report_temp_c
 gre.set_data(data_table)
 local temp_c = temp/1000
 --print (string.format("Got temp of %s C",temp_c))
 if ( temp_c > 24 ) then
  if ( ssr_fired == false ) then
   local data_table  = {}
   print("Turning on")
   ssr_fired = true
   data_table["Layer1.Cooling_On.grd_hidden"] = 0
   gre.set_data(data_table)
   writeGPIO(60,1)
  end 
 else
  if ( ssr_fired == true) then
   local data_table  = {}
   print("Turning off")
   ssr_fired = false
   writeGPIO(60,0)
   data_table["Layer1.Cooling_On.grd_hidden"] = 1
   gre.set_data(data_table)
  end
 end
 

end
This is a first cut at the logic behind the temperature controller, but all of the magic required to turn on and off the cooling element is already here, I just need to make it a bit smarter. The first thing I'll be adding is some hysteresis so that the system doesn't cycle the mini-fridge on and off constantly as the temperature hovers around the set point. The primary reason for this is that compressors in fridges don't take very well to being cycled on and off frequently. I will be building in a 2 minute delay to prevent burning out the compressor. I also plan on displaying the temperature values in a graph that will update constantly so you can get a quick overview of the fermentation schedule and see if there were any drastic changes due to a heating/cooling system failure. As it stands I've got a nearly functional fermentation controller application and I've spent more time writing this blog entry than I have building the GUI and control logic! I'll be spending the next couple of days polishing the GUI and rounding out the control logic and adding in the graphing of temperature values. After that I'll switch over to building out the Web interface which will allow for the uploading of Fermentation profiles and for controlling and viewing the fermentation from any Internet connected device.

Wednesday 21 August 2013

Device Trees and You!

Linux is pretty awesome, and the fact that I have a board the size of a credit card that can run a full Linux OS is incredibly awesome.  This awesome does come with a bit of a price though.  A stock Beaglebone Black comes with a pre-built version of Angstrom Linux which allows you to boot the Black and setup some software packages like a webserver or a database.  What it doesn't do out of the box is talk to the 1-wire device, the DS18B20 temperature probe I'm using.  To do that you need to define a Device Tree Overlay.  This file, when compiled into your kernel image, will tell the hardware what GPIO pin the signal from the 1-wire device is coming in on.  Here is the .dts file I found on a very helpful site called Hipstercircuits.

 /dts-v1/;  
 /plugin/;  
 / {  
      compatible = "ti,beaglebone", "ti,beaglebone-black";  
      part-number = "BB-W1";  
      version = "00A0";  
      /* state the resources this cape uses */  
      exclusive-use =  
           /* the pin header uses */  
           "P9.22",  
           /* the hardware IP uses */  
           "gpio0_2";  
      fragment@0 {  
         target = <&am33xx_pinmux>;  
         __overlay__ {  
                          dallas_w1_pins: pinmux_dallas_w1_pins {  
                               pinctrl-single,pins = < 0x150 0x37 >;  
                          };  
         };  
      };  
      fragment@1 {  
         target = <&ocp>;  
         __overlay__ {  
               onewire@0 {  
                    compatible   = "w1-gpio";  
                    pinctrl-names  = "default";  
                    pinctrl-0    = <&dallas_w1_pins>;  
                    status     = "okay";  
                    gpios = <&gpio1 2 0>;  
               };  
      };  
      };  
 };  

This file tells the Black that I want the 1-wire input to come in on the P9 Header on pin 22, if you look at the picture in my last post of the Black you can see a green wire going into a header, that's the data line from the DS18B20 going into the 22nd pin on that Header.  There are quite a few GPIO lines on the Beaglebone Black, some of them are reserved by the system already on startup so you need to know which ones are free, I took the .dts file above straight from Hipstercircuits and assumed the person who posted it had done the necessary research to identify that pin 22 wasn't already in use.

If you keep reading the post on Hipstercircuits you'll see they compile the .dts file into a binary .dtbo file, copy it into /lib/firmware on the Black and then enable it with the following command

echo BB-W1:00A0 > /sys/devices/bone_capemgr.9/slots

NOTE: on my Beaglebone Black my /sys/devices did not have a bone_capemgr.9 but a bone_capemgr.8.  I believe that is because I don't currently have a display connected, make sure the path under /sys/devices is correct for you before issuing the command above.

Since I didn't want to have to do this everytime the board booted, and as it seems like the Kernel currently has a bug that prevents loading userland .dtbo files we need to add our device tree to the Kernel by compiling our own.  If you've never compiled a Kernel, it's gotten a lot easier.  You'll need access to a Linux box, I used a Linux Mint 14 machine with no problems and only had to install one program, lzop, to finish the compile with no errors.

To compile the kernel follow the steps on this page, wiki.replicape.com.  Once you can compile a kernel with no errors you need to add the .dts file from above and follow the steps on this Hipstercircuts post.  In my case I had named my .dts file BB-W1-00A0.dts, in device tree language BB-W1 is the name and 00A0 is the version.  So in the section for editing /arch/arm/boot/dts/am335x-bone-common.dtsi you would use BB-W1 for both board-name and part-number and 00A0 for the version.  The manufacturer bit doesn't matter, I used Dallas.  Finally you need to add your compiled .dtbo file to the package which is done by editing kernel/firmware/Makefile and adding


fw-shipped-$(CONFIG_CAPE_BEAGLEBONE) += \
    BB-W1-00A0.dtbo

to the end of the Makefile fw-shipped section.   Recompile your kernel and then follow the instructions on the Kernel compile page for copying the new kernel to the Beaglebone Black.

NOTE: your rootfs/lib/modules/3.8.13-XXXXX-XXXXXXXX will have a different number than the one listed in the compile page, just do an ls -al in rootfs/lib/modules/ and find the version you compiled, mine had two directories, one with a -dirty flag so I left that one alone.  Once you've copied and rebooted your board and hopefully succesfully reconnected do a uname -a and you should see the kernel version report the current date as the compile time, if not you may have mistyped something.  Make sure your uImage symlink in /boot is pointing to your uImage-3.8.13 file.  It should have the date you compiled it as it's datestamp.  When that's done, you should be able to access the device and read a temperature.


root@beaglebone:~# python temp.py 
Temperature is 23.562 degrees

temp.py is a really basic program that simply reads from the 1-wire device that now shows up and translates the value read into a readable temperature.


import time

w1="/sys/bus/w1/devices/28-00000449da30/w1_slave"

while True:
    raw = open(w1, "r").read()
    print "Temperature is "+str(float(raw.split("t=")[-1])/1000)+" degrees"
    time.sleep(1)

NOTE: Your device address will probably differ from the one above, just look at /sys/bus/w1/devices and if you've only got one probe attached whatever address shows up will be your probe.  1-Wire allows multiple devices to be connected to the same pin, so theoretically I could add more probes to the same GPIO and they would show up with their own specific address, accessing the temps from those probes is as simple as changing the w1 variable to point to the new address.  I don't plan on adding more then one probe to CrankBrew so this is a moot point, but for those of you planning on monitoring multiple fermentations this would work really well.