{"id":419,"date":"2012-11-26T10:00:11","date_gmt":"2012-11-26T16:00:11","guid":{"rendered":"https:\/\/www.foell.org\/justin\/?p=419"},"modified":"2015-11-08T14:15:44","modified_gmt":"2015-11-08T20:15:44","slug":"arduino-kegerator","status":"publish","type":"post","link":"https:\/\/www.foell.org\/justin\/arduino-kegerator\/","title":{"rendered":"Arduino Kegerator"},"content":{"rendered":"<p>From touring Miller &amp; Budweiser breweries, I noticed both sites have caves &#8211; which have steady year-round temperatures. I assume the caves were used to lager, which means &#8220;storage&#8221; in German. \u00a0Lager yeasts, unlike ale yeast which ferment at room temperature, do their primary fermentation in the mid-50 degree\u00a0range. \u00a0During secondary fermentation the temperature is dropped steadily to slowly deactivate the yeasts. \u00a0Back in the day, the barrels could be moved deeper into the cave day-by-day to slowly lower the temperature from the mid-50s down to almost freezing (35\u00b0F).<\/p>\n<h2>Yogurt Maker?<\/h2>\n<p>I had an idea to automate this process using an Arduino, especially after reading\u00a0<a title=\"Yobot Arduino Yogurt Maker\" href=\"http:\/\/makeprojects.com\/Project\/Yobot%3A+Arduino+Yogurt+Maker\/499\/1#.UIS3ZFKe58Q\">Chris Reilly&#8217;s Arduino yogurt maker<\/a>\u00a0from\u00a0<a title=\"MakeZine\" href=\"http:\/\/makezine.com\/25\/\">Make Magazine volume 25<\/a>. \u00a0Everything I&#8217;ve done here was based on that, so I&#8217;ll assume you&#8217;ve read it.<\/p>\n<p>Lagering is essentially the same process except instead of using a heat source (crock-pot), we use a cooler (refrigerator). \u00a0Getting the refrigerator to maintain temps above 40\u00b0F can be tricky, so normally an external\u00a0<a title=\"Johnson Controls Digital Thermostat Control Unit\" href=\"http:\/\/amzn.to\/1WHhMYH\">temperature regulator<\/a>\u00a0is used. \u00a0But this requires me going out to the fridge every day to lower the temperature by one degree. \u00a0So why not automate it? \u00a0Laziness FTW!<br \/>\n<!--more--><br \/>\nThe parts list for this project are almost exactly the same as the yogurt maker, so I won&#8217;t reprint them, but here are some changes\/additions:<\/p>\n<ul>\n<li>The cited relay board was discontinued by SparkFun and is now called the\u00a0<a title=\"Beefcake Relay Control Kit (SparkFun)\" href=\"https:\/\/www.sparkfun.com\/products\/11042\">Beefcake Relay Control Kit<\/a><\/li>\n<li>1x 10k\u03a9 resistor &amp; 1x 330\u03a9 resistor (optional &#8211; for reference voltage calculation)<\/li>\n<\/ul>\n<div>While the parts list is essentially the same, the schematic is a little different as I used the button &amp; speaker a little differently and added a voltage divider to do some base voltage calculation.<\/div>\n<div><\/div>\n<div>The schematic &amp; code can be found in my <a title=\"Lager Maker (GitHub)\" href=\"https:\/\/github.com\/jrfoell\/lager_maker\">GitHub Lager Maker<\/a> project.<\/div>\n<h2>The Hardware<\/h2>\n<p>A friend of mine once said:<\/p>\n<blockquote><p>You software guys wouldn&#8217;t know a piece of hardware if it bit you in the ass.<\/p><\/blockquote>\n<p>I&#8217;m a software guy, so this is mostly true. \u00a0Programming for Arduino is probably the closest thing I&#8217;ll ever get to <a title=\"real-time computing (Wikipedia)\" href=\"http:\/\/en.wikipedia.org\/wiki\/Real-time_computing\">real-time programming<\/a>, and yes hardware and its real-world properties did present some issues. \u00a0For my project, I tried to use both a <a title=\"NTC Thermistor (Jameco)\" href=\"http:\/\/www.jameco.com\/webapp\/wcs\/stores\/servlet\/ProductDisplay?freeText=207037&amp;langId=-1&amp;storeId=10001&amp;productId=207037&amp;search_type=jamecoall&amp;catalogId=10001&amp;ddkey=http:StoreCatalogDrillDownView\">cheap thermistor<\/a> and a <a title=\"TMP36 Temperature Sensor (SparkFun)\" href=\"https:\/\/www.sparkfun.com\/products\/10988\">TMP36 temperature sensor<\/a>. \u00a0They each presented different problems:<\/p>\n<h3>TMP36<\/h3>\n<p>While this initially seemed to be the most accurate, there were problems. \u00a0First there is apparently an issue when the Arduino making readings on analog pins without waiting long enough in-between, some residual voltage may remain &#8211; and skew the next reading (<a title=\"Temp Read vs. Loop Delay (adafruit)\" href=\"http:\/\/forums.adafruit.com\/viewtopic.php?f=25&amp;t=11597#p83438\">see graph here<\/a>). \u00a0Even if that&#8217;s fixed by <a title=\"Accurate TMP36 readings using 3.3v (adafruit)\" href=\"http:\/\/learn.adafruit.com\/tmp36-temperature-sensor\/using-a-temp-sensor\">moving to a better 3.3v reference voltage<\/a> (or by simply waiting long enough between reads), there was still another issue&#8230;<\/p>\n<p>As soon as any other circuits were added to the Arduino (like the relay controller) the readings of the TMP36 would be skewed &#8211; see <a title=\"TMP36 Comment (SparkFun)\" href=\"https:\/\/www.sparkfun.com\/products\/10988#comment-4f03b9c0ce395f5c4e000000\">Gunther&#8217;s comment<\/a>. \u00a0I don&#8217;t know enough about electronics to know if I should fix this with some pull up (down?) resistors or what. \u00a0If someone knows better, I&#8217;m interested in not only the fix, but how\/why the fix works.<\/p>\n<h3>NTC Thermistor<\/h3>\n<p>The only issue I have with thermistors is&#8230; MATH! \u00a0To calculate temperature using one of these you can do a couple of things:<\/p>\n<ol>\n<li>Generalize the temperature based on the table given in the datasheet<\/li>\n<li>Calculate the temperature using the <a title=\"Steinhart-Hart (Wikipedia)\" href=\"http:\/\/en.wikipedia.org\/wiki\/Steinhart-Hart\">Steinhart-Hart equation<\/a><\/li>\n<li>Calculate the temperature using the <a title=\"Beta parameter (Wikipedia)\" href=\"http:\/\/en.wikipedia.org\/wiki\/Thermistor#B_or_.CE.B2_parameter_equation\">Beta-parameter equation<\/a><\/li>\n<\/ol>\n<p>The <a title=\"Jameco 207037 10k NTC Thermistor Datasheet\" href=\"http:\/\/www.jameco.com\/Jameco\/Products\/ProdDS\/207037.pdf\">datasheet<\/a> for my thermistor gave a Beta value, but not the A, B, &amp; C constants needed to do the Steinhart-Hart calculations &#8211; but those can determined by plugging in 3 known temperature\/resistance values from the datasheet here:\u00a0<a href=\"http:\/\/www.capgo.com\/Resources\/Temperature\/Thermistor\/ThermistorCalc.html\">http:\/\/www.capgo.com\/Resources\/Temperature\/Thermistor\/ThermistorCalc.html<\/a>.<\/p>\n<p>Since the datasheet indicates the Beta constant, I went that route, except to determine temperature, you need to solve this equation:<\/p>\n<p><a href=\"http:\/\/en.wikipedia.org\/wiki\/Thermistor#B_or_.CE.B2_parameter_equation\"><img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=T%3D%7BB%5Cover+%7B+%7B%5Cln%7B%28R+%2F+r_%5Cinfty%29%7D%7D%7D%7D&#038;bg=ffffff&#038;fg=000&#038;s=2&#038;c=20201002\" alt=\"T={B&#92;over { {&#92;ln{(R \/ r_&#92;infty)}}}}\" class=\"latex\" \/><br \/>\n<\/a><\/p>\n<p>I have the Beta (B) parameter, and I&#8217;ll know the resistance (R) at the time of measurement, but WTF is <img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=r_%5Cinfty&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"r_&#92;infty\" class=\"latex\" \/>? A math teacher friend pointed out to me that I don&#8217;t need to know or care about what <img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=r_%5Cinfty&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"r_&#92;infty\" class=\"latex\" \/> represents, and instead just solve for it using a known temperature\/resistance:<\/p>\n<img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=r_%5Cinfty%3D%7BR%5Cover%7Be%5E%7B%28B%2FT%29%7D%7D%7D&#038;bg=ffffff&#038;fg=000&#038;s=2&#038;c=20201002\" alt=\"r_&#92;infty={R&#92;over{e^{(B\/T)}}}\" class=\"latex\" \/>\n<p>In pseudocode solving looks like:<\/p>\n<p><code>r_sub_inf = resistance \/ (pow(e,(b \/ temperature)))<\/code><\/p>\n<p>I solved this for a few temperatures &amp; resistances from the datasheet and took an average. \u00a0Or you can experiment with various\u00a0<img decoding=\"async\" src=\"https:\/\/s0.wp.com\/latex.php?latex=r_%5Cinfty&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002\" alt=\"r_&#92;infty\" class=\"latex\" \/> values you get to see what gets you closest to an accurate temperature reading.<\/p>\n<p>Also, there&#8217;s heat created when voltage is sent through the thermistor, and the datasheet gives a &#8220;Thermal Dissipation Constant.&#8221; \u00a0To account for this I <a title=\"Temperature measurement using Arduino\" href=\"http:\/\/disipio.wordpress.com\/2009\/07\/17\/temperature-measurement-using-arduino-and-a-thermistor\/\">subtracted a few degrees from the measurement based on this constant<\/a>.<\/p>\n<p>Even after all this was said and done, my temperature readings were low compared to a trusted reference thermometer. \u00a0So I simply created an offset constant to bring things more in line. \u00a0I can&#8217;t (and won&#8217;t) guarantee this offset will be the same over the entire range of the thermistor, but it works for me \ud83d\ude41 \u00a0Again if anyone can provide insight on a better way to remedy this, I&#8217;m all ears.<\/p>\n<h2>Software<\/h2>\n<p>I made a datatype called a\u00a0<em>stage<\/em> which contains a start temperature, end temperature and duration. \u00a0You can add as many stages as you&#8217;d like. \u00a0For lagering there&#8217;s typically two (or three) stages:<\/p>\n<ol>\n<li>Primary Fermentation (~two weeks)<\/li>\n<li>Secondary Fermentation (~2-3 weeks)<\/li>\n<li>Conditioning (~3-4 weeks)<\/li>\n<\/ol>\n<p>Times indicated above were for the most recent kit I brewed: <a title=\"American Lager Kit (Northern Brewer)\" href=\"http:\/\/www.northernbrewer.com\/shop\/american-lager-extract-kit.html\">American Lager from Northern Brewer<\/a>.<\/p>\n<p>I set my stages up like this:<\/p>\n<pre>const int stageNum = 5;\r\nstage stages[stageNum] = {\r\n  \/\/primary fermentation\r\n  { 56, 56, 2 * week1 },\r\n  \/\/split secondary fermentation into 3 stages\r\n  { 56, 49, week1 },\r\n  { 49, 42, week1 },\r\n  { 42, 35, week1 },\r\n  \/\/conditioning (ready to drink)\r\n  { 35, 35, 3 * week1 }\r\n};<\/pre>\n<p>The reason I split secondary fermentation into 3 is so I can have &#8220;checkpoints.&#8221; Just incase the power goes out or something, I can re-start closest to where I left off.<\/p>\n<p>The button &amp; speaker act to switch stages and report the current stage &amp; temperature. \u00a0If you press the button quickly, the speaker will beep\u00a0<em>n<\/em>-times in a mid-tone to indicate the stage number, then in a low tone:\u00a0<em>x<\/em> long tones for the first digit of the current temperature, and <em>y<\/em>\u00a0short tones for the second digit of the current temperature. \u00a0Then in a high tone the same process will repeat for the current target temperature.<\/p>\n<p>Holding the button down for more than 3 seconds will cause the Arduino to advance to the next stage. \u00a0It will then report the new stage number, current temperature and target temperature as described above.<\/p>\n<p>Otherwise the Arduino will just run through all of the stages as indicated until it reaches the end. \u00a0At which time the device (refrigerator) will shut off, so it might be good to leave an extra long conditioning stage just in case you forget \ud83d\ude42<\/p>\n<div class='kindleWidget kindleLight' ><img decoding=\"async\" src=\"https:\/\/www.foell.org\/justin\/wp-content\/plugins\/send-to-kindle\/media\/white-15.png\" \/><span>Send to Kindle<\/span><\/div>","protected":false},"excerpt":{"rendered":"<p>From touring Miller &amp; Budweiser breweries, I noticed both sites have caves &#8211; which have steady year-round temperatures. I assume the caves were used to lager, which means &#8220;storage&#8221; in German. \u00a0Lager yeasts, unlike ale yeast which ferment at room temperature, do their primary fermentation in the mid-50 degree\u00a0range. \u00a0During secondary fermentation the temperature is&hellip; <a href=\"https:\/\/www.foell.org\/justin\/arduino-kegerator\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[41,36,1,3],"tags":[37,75,39,38],"class_list":["post-419","post","type-post","status-publish","format-standard","hentry","category-arduino","category-beverages","category-business","category-casual","tag-beer","tag-github","tag-homebrew","tag-lager"],"aioseo_notices":[],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts\/419","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/comments?post=419"}],"version-history":[{"count":58,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts\/419\/revisions"}],"predecessor-version":[{"id":2145,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/posts\/419\/revisions\/2145"}],"wp:attachment":[{"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/media?parent=419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/categories?post=419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.foell.org\/justin\/wp-json\/wp\/v2\/tags?post=419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}