carlisle_bob
Well-Known Member
.....
Edit: Oops, carlisle_bob beat me to it!
Hi
Yea, but yours probably answered the actual question being asked ...
Bob
.....
Edit: Oops, carlisle_bob beat me to it!
Actually, both of your replies were extremely helpful. I think I'm at the step where I need to get the program to recognize the DS18B20's output as a setpoint. I plan on using 2 IF statements for the program, one for heating and one for cooling, rather than a PID. Just so you guys know, I have zero experience with any type of programming. I'm pretty comfortable working with the wiring side of the project, as my background is as an aviation electrician.
// declare which pins you're using to hook up your relays
// right now, i've set heating to pin 2 and cooling to pin 3
// but you can change these to whatever is convenient
const int heaterPin = 2;
const int coolerPin = 3;
// declare your target temperature
// at some point, you'll want to have the ability to change
// this without recompiling the program. but for now we'll
// hardcode it in
float tempSetpoint = 68.0;
void setup() {
Serial.begin(9600)
pinMode(heaterPin, OUTPUT);
pinMode(coolerPin, OUTPUT);
//******DS18B20 setup stuff**********
}
void loop() {
float tempReading = //**get your DS18B20 reading**
if (tempReading > tempSetpoint) {
digitalWrite(heaterPin, LOW);
digitalWrite(coolerPin, HIGH);
}
else if (tempSetpoint > tempReading) {
digitalWrite(coolerPin, LOW);
digitalWrite(heaterPin, HIGH);
}
}
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer = { 0x28, 0x7D, 0x7E, 0x11, 0x04, 0x00, 0x00, 0x2A }; //I got the address of my sensor from another program I found online
const int heaterPin = 8; // I have LED's plugged in instead of my relays
const int coolerPin = 10;
float setpoint = 28.0;//I'm not sure what this
void setup(void)
{
// start serial port
Serial.begin(9600);
pinMode(heaterPin, OUTPUT);
pinMode(coolerPin, OUTPUT);
sensors.begin();
sensors.setResolution(insideThermometer, 10);
}
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC == -127.00) {
Serial.print("Error getting temperature");
} else {
Serial.print("C: ");
Serial.print(tempC);
Serial.print(" F: ");
Serial.print(DallasTemperature::toFahrenheit(tempC));
}
}
void loop(void)
{
if (tempReading > tempSetpoint) {//I added this IF statement from your suggestion
digitalWrite (heaterPin, LOW);
digitalWrite (coolerPin, HIGH);
}
else if (tempReading < tempSetpoint) {
digitalWrite (heaterPin, HIGH);
digitalWrite (coolerPin, LOW);
}
delay(2000);
Serial.print("Getting temperatures...\n\r");
sensors.requestTemperatures();
Serial.print("Inside temperature is: ");
printTemperature(insideThermometer);
Serial.print("\n\r\n\r");
}
Okay, so I was able to add in your code to the one I had copied and pasted to read the sensor, but I guess I need to add something so that it recognizes the tempReading and tempSetpoint commands. Here's what I've got so far.
here's the arduino PID library if you want to play around with it. It's actually rather user friendly only hard part really comes in when deciding on the control constants, but that it kinda fun to play around with.
http://arduino.cc/playground/Code/PIDLibrary
Edit: Oh and a thread on using the autotune library as well
https://www.homebrewtalk.com/f235/pid-settings-arduino-based-hlt-328239
It's a nice library, and I use it on several different projects. I never got the autotune to give me values that I was happy with, but it can be good for getting into the right ballpark.
Just to clarify, though...PID control will work for the light bulb heating, but not for any compressor-based cooling like a fridge.
It's a nice library, and I use it on several different projects. I never got the autotune to give me values that I was happy with, but it can be good for getting into the right ballpark.
Just to clarify, though...PID control will work for the light bulb heating, but not for any compressor-based cooling like a fridge.
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress insideThermometer = { 0x28, 0x7D, 0x7E, 0x11, 0x04, 0x00, 0x00, 0x2A }; //I got the address of my sensor from another program I found online
const int heaterPin = 8; // I have LED's plugged in instead of my relays
const int coolerPin = 10;
float tempSetpoint = 68.0;//Will this differentiate between deg F and C?
void setup(void)
{
// start serial port
Serial.begin(9600);
pinMode(heaterPin, OUTPUT);
pinMode(coolerPin, OUTPUT);
sensors.begin();
sensors.setResolution(insideThermometer, 10);
}
void printTemperature(DeviceAddress deviceAddress)
{
float tempC = sensors.getTempC(deviceAddress);
if (tempC == -127.00) {
Serial.print("Error getting temperature");
} else {
Serial.print("C: ");
Serial.print(tempC);
Serial.print(" F: ");
Serial.print(DallasTemperature::toFahrenheit(tempC));
}
}
float tempC = sensors.getTempC(DeviceAddress);// I get the error here. I added this from the suggestions, but is
//tempC already defined above, or is that only valid for the 'void printTemperature' bit?
float tempReading = DallasTemperature::toFahrenheit(tempC); //I added the 'float' as well. Am I right in thinking that tempReading needs to be recognized as a variable?
void loop(void)
{
if (tempReading > tempSetpoint) {//I added this IF statement from your suggestion
digitalWrite (heaterPin, LOW);
digitalWrite (coolerPin, HIGH);
}
else if (tempReading < tempSetpoint) {
digitalWrite (heaterPin, HIGH);
digitalWrite (coolerPin, LOW);
}
delay(2000);
Serial.print("Getting temperatures...\n\r");
sensors.requestTemperatures();
Serial.print("Inside temperature is: ");
printTemperature(insideThermometer);
Serial.print("\n\r\n\r");
}
float tempC = sensor.getTempC(insideThermometer);
float tempReading = DallasTemperature::toFahrenheit(tempC);
It works! So excited, now I just have to fine tune it. So I'm guessing if I use Bob's suggestions, I'll use 4 IF statements. 2 for heating and 2 for cooling? That should prevent the overcycling I would think.
hausofstrauss said:Hey, I'm late to the conversation and without reading all of the posts, have you guys seen this:
http://www.elcojacobs.com/uberfridge/
From the first post, this looks like exactly what you are trying to do and what I'm trying to get done in my spare time
It has been mentioned on here before, but I can't find the link just yet.
I've only got a Arduino single-stage temp controller using a powertail from SparkFun for my mini-fridge lagering chest, but I just bought another fridge last night so I can have two going at one time. I need to quickly build up the other controller so I can be ready for the dual Oktoberfest brew this weekend. Ultimately, I want to have one master controller with the submersed temp probes and predictive control like the UberFridge.
Very cool. I'd like mine to do that eventually, maybe with a webcam so I can watch my beer ferment. My conical has a port that would be perfect for a thermowell, so I'll be able to monitor the actual liquid temp too. I'll have to decide whether I use the air temp or liquid temp for the actual setpoint
Tracking the liquid temp will only let you see exactly why your beer tastes like ass because it rose 10+F over your air temp during the active phase. Using air as an input would only be effective as a supplemental input in a multi-input loop, which would be too much work to create/tune anyway.Yeah, plus I'll have multiple fermenters in the chamber. I definitely want to track the liquid temp, but I think I'll use the air temp to set it. Maybe an average of 5 sensors in different areas of the chamber.
Hi
If you decide to control to liquid temp, be very careful of how you do it. The lag / phase margin / damping factor (how every you want to describe it) is going to be a problem with a tight control spec. Since the liquid does not change temperature very fast, a multi loop control likely is your best approach. That's getting a bit down the road from a basic control loop.
Not at all saying it's a bad idea, just that it's a bit harder than it looks.
Bob
if (tempReading > 69) {
digitalWrite (heaterPin, LOW);
digitalWrite (coolerPin, HIGH);
}
else if (67.5 < tempReading < 68.5) {
digitalWrite (heaterPin, LOW);
digitalWrite (coolerPin, LOW);
}
else if (tempReading < 67) {
digitalWrite (heaterPin, HIGH);
digitalWrite (coolerPin, LOW);
Using liquid temp presents no problems as long as you don't want to control to an exact temp with no variation whatsoever, which is nearly impossible anyway, especially with an active fermentation over the complete ferment.
The slow response of the liquid allows for very small temp differential settings. It would only be a problem if your heat input (neg or pos) is not much larger than the ferming beer's needs. Most fridges/freezers have more than enough power to control a ferment- by a factor of 10 (~40W-400W). The main issue is compressor cycling and hot start protection (ASD).
Additional thermal mass at ferm temp provides even better control. There is the possibility of the thermal mass causing undershoot (too cold) for later phases if it got too cold during the active phase, but it is rare in my experience. If it really bothered you, it is easily solved with a dual stage controller to kick on a heater for the end of ferment. Usually unnecessary, though.
So to add a dead band, I was going to add this statement for the meat of my program. Can I link IF statement like that or is there something else I should use?
PHP:if (tempReading > 69) { digitalWrite (heaterPin, LOW); digitalWrite (coolerPin, HIGH); } else if (67.5 < tempReading < 68.5) { digitalWrite (heaterPin, LOW); digitalWrite (coolerPin, LOW); } else if (tempReading < 67) { digitalWrite (heaterPin, HIGH); digitalWrite (coolerPin, LOW);
const float setpoint = 68.0;
const float deadband = 0.5;
void loop() {
if (tempReading > setpoint) {
digitalWrite(heaterPin, LOW);
}
else if (tempReading < setpoint) {
digitalWrite(coolerPin, LOW);
}
if (tempReading > (setpoint + deadband)) {
digitalWrite(coolerPin, HIGH);
}
else if (tempReading < (setpoint - deadband)) {
digitalWrite(heaterPin, HIGH);
}
}
Okay, I set up your code into the original and it works fine. I take it that later I could set up a way to change the setpoint and deadband variables with buttons or something, so I don't have to rewrite the code every time. Now I need figure out how to set up a multiple sensor network, and a way to log everything.
Okay, I set up your code into the original and it works fine. I take it that later I could set up a way to change the setpoint and deadband variables with buttons or something, so I don't have to rewrite the code every time. Now I need figure out how to set up a multiple sensor network, and a way to log everything.
carlisle_bob said:Hi
As you network them up, be sure to include some "what if the network is down" protection in the code. It's easy to put that off as a do it later task. Usually later turns into never or it's a major re-write when you do get around to it. Much better to include at lest some basic checks and protection right from the start.
Bob
Is overswing a big problem for people? My fridge must have really low thermal mass, or something. I just stick a probe on the side with a bit of insulation and do a .5 degree deadband. An elaborate formula has just never been necessary for me.
I read his stuff about a year ago, but haven't checked what his latest incarnation looks like. He seemed single mindedly focused on trying to do everything with the control equation/logic. He also had to hand tune every batch- not exactly a generalized control system. Adding simple physical improvements like I mentioned earlier could improve his system even further. Also, like I mentioned previously, taping to the side of the vessel under some insulation mimics what his control system does- predictive input. The only difference is you can do it with a $25 ebay temp controller and some foam, and just need to change the insulating factor to vary the predictive input.If you read a lot about the UberFridge, what he did was have temperature measurement of the liquid and the air. He then wrote some logic into the PLC that did predictive control. Essentially working out the thermal response of each batch. He's got all sorts of graphs showing the validation of his design. It was a really well laid out project and I'm grateful for him sharing it all.
I used the fermenter example because it is the more general/difficult case, and also because fermenting was specifically mentioned in the post immediately preceeding my post, as well as being the subject of the last few pages..Hi
Since most people are controlling something other than a fermenter, it's not a very good example of what they are trying to do.
It is actually quite easy to do reasonably tight control (0.1F) of a normal keg sitting in a keggerator. There is a very large body of theory that lets you set it up. It can be done without unduly cycling compressors *or* wearing them out by running too long on each cycle.
Bob
I am a big fan of overkill. There is a difference, though, between state of the art, and making the best out of what you have.I believe it boils down to "over-engineering is fun!"
Like if something gets disconnected or a sensor fails? I think the code that I started with had something that would send an error message to the serial port if the sensor returned -127 deg C or something like that. I take it to mean that a failed sensor will return that value? So I'm guessing that the way the code sits now, I'd get the error message, but it would keep the heat on. Sounds like a potential fire hazard. Maybe I could hardwire a thermal fuse in there to cut power if a temp gets above a set value, say 80 deg F. Is that what you mean or is there something else?
carlisle_bob said:Hi
Sensor failure is something that's also worth thinking about.
With a network, the issues are usually with data buffering. If it goes into the buffer, but doesn't go out... there's only so much ram. The same sort of thing thing applies on the input side, gizmo looks for command input, waits , repeats. No network = a lot of repeats and waits. There are only so many CPU cycles.
Bob
What to do when a sensor goes out depends heavily on what the sensor was reading.So I'd want something that would take a faulty sensor out of the equation? Like if it returns an obviously wrong value, it stops using that sensor to cycle the heater and cooler?
Enter your email address to join: