<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>https://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>https://jackxiang.com/post//</link>
<title><![CDATA[Raspberry Pi sous vide water bath,Improved temperature control for Raspberry Pi sous vide。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[产品管理]]></category>
<pubDate>Mon, 19 Aug 2013 12:42:35 +0000</pubDate> 
<guid>https://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	I’ve been very happy with the results from my Raspberry Pi controlled water bath for sous vide cooking, but I knew that the control loop could be improved. Past runs show fairly continued oscillation:<br/>Roast beef temps2<br/>Roast beef run at 60C<br/>I’ve been keeping track of the average power for my control loop, which has been coming out at 22%. So i modified the code to have a bias of 22%, and here’s the result:<br/>Test run at 55C<br/>Test run at 55C<br/>Overall much more stable. The occasional hiccups are probably caused by the remote socket failing to receive off commands. There’s a 3C overshoot at the start, which I hope to have fixed by entering the control loop from initial warm up 3C earlier. <br/><textarea name="code" class="c" rows="15" cols="100">
import os
from subprocess import Popen, PIPE, call
from optparse import OptionParser
from time import sleep
def tempdata():
&nbsp;&nbsp;&nbsp;&nbsp;# Replace 28-000003ae0350 with the address of your DS18B20
&nbsp;&nbsp;&nbsp;&nbsp;pipe = Popen([&quot;cat&quot;,&quot;/sys/bus/w1/devices/w1_bus_master1/28-000003ea0350/w1_slave&quot;], stdout=PIPE)
&nbsp;&nbsp;&nbsp;&nbsp;result = pipe.communicate()[0]
&nbsp;&nbsp;&nbsp;&nbsp;result_list = result.split(&quot;=&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;temp_mC = int(result_list[-1]) # temp in milliCelcius
&nbsp;&nbsp;&nbsp;&nbsp;return temp_mC
def setup_1wire():
&nbsp;&nbsp;os.system(&quot;sudo modprobe w1-gpio &amp;&amp; sudo modprobe w1-therm&quot;)
def turn_on():
&nbsp;&nbsp;os.system(&quot;sudo ./strogonanoff_sender.py --channel 4 --button 1 --gpio 0 on&quot;)
def turn_off():
&nbsp;&nbsp;os.system(&quot;sudo ./strogonanoff_sender.py --channel 4 --button 1 --gpio 0 off&quot;)
#Get command line options
parser = OptionParser()
parser.add_option(&quot;-t&quot;, &quot;--target&quot;, type = int, default = 55)
parser.add_option(&quot;-p&quot;, &quot;--prop&quot;, type = int, default = 6)
parser.add_option(&quot;-i&quot;, &quot;--integral&quot;, type = int, default = 2)
parser.add_option(&quot;-b&quot;, &quot;--bias&quot;, type = int, default = 22)
(options, args) = parser.parse_args()
target = options.target * 1000
print (&#039;Target temp is %d&#039; % (options.target))
P = options.prop
I = options.integral
B = options.bias
# Initialise some variables for the control loop
interror = 0
pwr_cnt=1
pwr_tot=0
# Setup 1Wire for DS18B20
setup_1wire()
# Turn on for initial ramp up
state=&quot;on&quot;
turn_on()
temperature=tempdata()
print(&quot;Initial temperature ramp up&quot;)
while (target - temperature &gt; 6000):
&nbsp;&nbsp;&nbsp;&nbsp;sleep(15)
&nbsp;&nbsp;&nbsp;&nbsp;temperature=tempdata()
&nbsp;&nbsp;&nbsp;&nbsp;print(temperature)
print(&quot;Entering control loop&quot;)
while True:
&nbsp;&nbsp;&nbsp;&nbsp;temperature=tempdata()
&nbsp;&nbsp;&nbsp;&nbsp;print(temperature)
&nbsp;&nbsp;&nbsp;&nbsp;error = target - temperature
&nbsp;&nbsp;&nbsp;&nbsp;interror = interror + error
&nbsp;&nbsp;&nbsp;&nbsp;power = B + ((P * error) + ((I * interror)/100))/100
&nbsp;&nbsp;&nbsp;&nbsp;print power
&nbsp;&nbsp;&nbsp;&nbsp;# Make sure that if we should be off then we are
&nbsp;&nbsp;&nbsp;&nbsp;if (state==&quot;off&quot;):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;turn_off()
&nbsp;&nbsp;&nbsp;&nbsp;# Long duration pulse width modulation
&nbsp;&nbsp;&nbsp;&nbsp;for x in range (1, 100):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (power &gt; x):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (state==&quot;off&quot;):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state=&quot;on&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(&quot;On&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;turn_on()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (state==&quot;on&quot;):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state=&quot;off&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(&quot;Off&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;turn_off()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(1)
</textarea><br/>http://blog.thestateofme.com/2013/05/12/improved-temperature-control-for-raspberry-pi-sous-vide/<br/>Temperature control for a sous vide water bath is a popular application for hobbyist microcontroller kits, with lots of well documented projects out there. My favourite is the Sous Vader – if only for the attention to detail in the decal on the box.<br/>I’ve been planning my own for a little while, and got some DS18B20 temperature probes a little while ago. The long Easter weekend break finally brought me some time to progress the project.<br/>Danger – High Voltage<br/>I have an old slow cooker that’s perfectly good for doing pot roast. It’s been falling to bits for some time, and I’ve patched it up with a Sugru sample I got at Monkigras. I had thoughts of hacking it directly (and perhaps even building in a Raspberry Pi), but common sense took hold and I decided on a route that didn’t involve directly manipulating mains electricity.<br/>To turn the slow cooker on and off I got hold of a radio controlled mains socket from Maplin – they’re available without the controller (which I didn’t need) for £7.99.<br/>I found a library to control the remote socket on github – Raspberry Strogonanoff (thanks Duncan McGregor, and a clever choice of project name). This uses a Sparkfun 434MHz RF Link Transmitter (which as suggested by Duncan I got from Protopic).<br/>Getting Raspberry Strogonanoff working was the easier part of the whole set up. Having looked at the socket to establish that it was set to channel 4 button 1 I simply ran this line to turn it on:<br/>sudo ./strogonanoff_sender.py --channel 4 --button 1 --gpio 0 on<br/>and this to turn it off again:<br/>sudo ./strogonanoff_sender.py --channel 4 --button 1 --gpio 0 off<br/>Getting control<br/>A water bath is a good example of a control system. The water and pot collectively have quite a high specific heat capacity, and there’s quite a bit of latency between turning off power and the rise in temperature stopping. The standard way of dealing with this is to use a PID Controller (see this explanation for a BBQ application for something more straightforward than the Wikipedia article). The Sous Vader seems to have worked with just a PI controller (effectively D=0), so I tried that first. There is a python implementation of a PID controller, which I didn’t spend the time to integrate.<br/>Tuning the control loop<br/>This is the tricky and time consuming part. In theory there should be a nice library out there that figures out correct settings for P, I and D based on observed data, but in practice it seems that most people resort to manual tuning.<br/>The hardware<br/>I started out with things on a breadboard using my usual home made Pi Cobbler, but as I want to use this in the kitchen I’ve created a more permanent setup using a Ciseco Slice of Pi, which at £3.90&nbsp;&nbsp;is a very inexpensive small project board. I used one of the header strips in the Slice of Pi kit as a place to plug in the 434MHz transceiver and the temperature probes (so it would be easy to use parts in other projects). It was then simply a case of soldering some connecting wires to the appropriate power (5v for the transceiver and 3.3v for the DS18B20), GPIO (0 for the transceiver and 7 for the DS18B20) and GND:<br/>The system pictured above has an Edimax WiFi dongle so that I can control and monitor the whole thing when it’s in the kitchen..<br/>The software<br/>Update 14 Apr 2013 – the code (slightly improved over what’s below) is now available on GitHub along with (hopefully comprehensive) installation instructions.<br/>It’s not especially pretty, but seems to be doing the job:<br/><textarea name="code" class="c" rows="15" cols="100">
import os
from subprocess import Popen, PIPE, call
from optparse import OptionParser
from time import sleep
def tempdata():
&nbsp;&nbsp;&nbsp;&nbsp;# Replace 28-000003ae0350 with the address of your DS18B20
&nbsp;&nbsp;&nbsp;&nbsp;pipe = Popen([&quot;cat&quot;,&quot;/sys/bus/w1/devices/w1_bus_master1/28-000003ea0350/w1_slave&quot;], stdout=PIPE)
&nbsp;&nbsp;&nbsp;&nbsp;result = pipe.communicate()[0]
&nbsp;&nbsp;&nbsp;&nbsp;result_list = result.split(&quot;=&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;temp_mC = int(result_list[-1]) # temp in milliCelcius
&nbsp;&nbsp;&nbsp;&nbsp;return temp_mC
def setup_1wire():
&nbsp;&nbsp;os.system(&quot;sudo modprobe w1-gpio &amp;&amp; sudo modprobe w1-therm&quot;)
def turn_on():
&nbsp;&nbsp;os.system(&quot;sudo ./strogonanoff_sender.py --channel 4 --button 1 --gpio 0 on&quot;)
def turn_off():
&nbsp;&nbsp;os.system(&quot;sudo ./strogonanoff_sender.py --channel 4 --button 1 --gpio 0 off&quot;)
#Get command line options
parser = OptionParser()
parser.add_option(&quot;-t&quot;, &quot;--target&quot;, type = int, default = 55)
parser.add_option(&quot;-p&quot;, &quot;--prop&quot;, type = int, default = 8)
parser.add_option(&quot;-i&quot;, &quot;--integral&quot;, type = int, default = 2)
(options, args) = parser.parse_args()
target = options.target * 1000
print (&#039;Target temp is %d&#039; % (options.target))
P = options.prop
I = options.integral
# Initialise some variables for the control loop
interror = 0
pwr_cnt=1
pwr_tot=0
# Setup 1Wire for DS18B20
setup_1wire()
# Turn on for initial ramp up
state=&quot;on&quot;
turn_on()
temperature=tempdata()
print(&quot;Initial temperature ramp up&quot;)
while (target - temperature &gt; 3000):
&nbsp;&nbsp;&nbsp;&nbsp;sleep(15)
&nbsp;&nbsp;&nbsp;&nbsp;temperature=tempdata()
&nbsp;&nbsp;&nbsp;&nbsp;print(temperature)
print(&quot;Entering control loop&quot;)
while True:
&nbsp;&nbsp;&nbsp;&nbsp;temperature=tempdata()
&nbsp;&nbsp;&nbsp;&nbsp;print(temperature)
&nbsp;&nbsp;&nbsp;&nbsp;error = target - temperature
&nbsp;&nbsp;&nbsp;&nbsp;interror = interror + error
&nbsp;&nbsp;&nbsp;&nbsp;power = ((P * error) + ((I * interror)/100))/100
&nbsp;&nbsp;&nbsp;&nbsp;print power
&nbsp;&nbsp;&nbsp;&nbsp;if (power &gt; 0):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pwr_tot = pwr_tot + power
&nbsp;&nbsp;&nbsp;&nbsp;pwr_ave = pwr_tot / pwr_cnt
&nbsp;&nbsp;&nbsp;&nbsp;pwr_cnt = pwr_cnt + 1
&nbsp;&nbsp;&nbsp;&nbsp;print pwr_ave
&nbsp;&nbsp;&nbsp;&nbsp;# Long duration pulse width modulation
&nbsp;&nbsp;&nbsp;&nbsp;for x in range (1, 100):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (power &gt; x):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (state==&quot;off&quot;):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state=&quot;on&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(&quot;On&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;turn_on()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (state==&quot;on&quot;):
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;state=&quot;off&quot;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print(&quot;Off&quot;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;turn_off()
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(1)
</textarea><br/>Conclusion<br/>I’ve not had the chance to use the water bath for cooking yet, but I’m very much looking forward to trying out a few steaks and maybe some Sunday roasts. I’ll report back on the results.<br/>来自：http://blog.thestateofme.com/2013/03/31/raspberry-pi-sous-vide-water-bath/<br/>参考：<br/>http://blog.thestateofme.com/2013/01/28/ds18b20-rpi/<br/>http://www.flashingleds.net/sousvader/sousvader.html<br/>自己参考：<br/>（1）Raspberry Pi PWM编写的方法：<br/>http://jackxiang.com/post/6591/<br/>（2）树莓派Raspberry和ds18B20接合,可以接多个Ds18B20：http://jackxiang.com/post/6588/
]]>
</description>
</item><item>
<link>https://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] Raspberry Pi sous vide water bath,Improved temperature control for Raspberry Pi sous vide。]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>