Fog's Controller Project
Moderator: Site Moderator
Fog's Controller Project
Here's my new control box, gents:
For power control, it takes input from a potentiometer, and converts that into duty cycle with a 2 second period going to a 60A SSR which controls my 4500W 240V element. The SSR controls one leg of the 240V, and then the other line to the heater goes to the 30A 3-way light switch, which selects between the other leg of the 240V or neutral to run the element at 120V. Being able to run at the lower voltage means I can get more even heat at lower power.
And then, since there's already this Arduino running, I set it to track three temperatures (Still body, vapor temp, and cooling water output), flash an informative LED, keep track of the water level in my boiler and refill it as needed, and report the data back to the laptop. I just posted my entire build over in the construction forum: viewtopic.php?f=50&t=75162. When I get better at programming, and a bit of data to base it on, there's no reason why I can't set it to track the temperatures and vary the power input accordingly.
Costs were pretty cheap on ebay:
Arduino Nano knockoff $4
60A cheap SSR w heats sink $15
potentiometer $2
3-Way switch $8
Fan salvaged from dead computer
Box salvaged from ?
The weeks of learning how to program it and reprogram it? Priceless!
Not at all pretty, but so cheap and I keep finding things to ask of it. For power control, it takes input from a potentiometer, and converts that into duty cycle with a 2 second period going to a 60A SSR which controls my 4500W 240V element. The SSR controls one leg of the 240V, and then the other line to the heater goes to the 30A 3-way light switch, which selects between the other leg of the 240V or neutral to run the element at 120V. Being able to run at the lower voltage means I can get more even heat at lower power.
And then, since there's already this Arduino running, I set it to track three temperatures (Still body, vapor temp, and cooling water output), flash an informative LED, keep track of the water level in my boiler and refill it as needed, and report the data back to the laptop. I just posted my entire build over in the construction forum: viewtopic.php?f=50&t=75162. When I get better at programming, and a bit of data to base it on, there's no reason why I can't set it to track the temperatures and vary the power input accordingly.
Costs were pretty cheap on ebay:
Arduino Nano knockoff $4
60A cheap SSR w heats sink $15
potentiometer $2
3-Way switch $8
Fan salvaged from dead computer
Box salvaged from ?
The weeks of learning how to program it and reprogram it? Priceless!
Re: Fog's Controller Project
I've stripped out the temperature and water sensor stuff, just leaving the SSR control and potentiometer input -figuring most folks will just want to control power to heaters for cheap. Here's that code for Arduino:
/**Define which pins on the Arduino are for what -and also set the cycle time **/
#define POT_INPUT A2 // NOTE: No ";" on #define
#define HEATER_ON 10 // NOTE: No ";" on #define
#define LED_ON 8 // NOTE: No ";" on #define
#define DUTY_CYCLE_PERIOD 2 // duty cycle period (Seconds)
/** Declare variables **/
int potValue; // Value returned on the pot sweeper (0-1023)
long dutyCycleStartTime; // Time that the current duty cycle started
long currentTime; // milliseconds counter
void setup() /** SETUP: RUNS ONCE And sets up the arduino **/
{
pinMode(POT_INPUT, INPUT); // Set up pot input pin
pinMode(HEATER_ON, OUTPUT); // Set up heater control output pin
pinMode(LED_ON, OUTPUT); // Set up heater control output pin
dutyCycleStartTime = millis();
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
/****** Check on the state of affairs ******/
currentTime = millis();
potValue = analogRead(POT_INPUT);
/****** Check if the duty cycle period is over and restart it if it is******/
if( currentTime - dutyCycleStartTime >= DUTY_CYCLE_PERIOD * 1000) {
dutyCycleStartTime = currentTime;
digitalWrite(HEATER_ON, HIGH);
digitalWrite(LED_ON, HIGH);
}
/****** Check if the heater should be turned off ******/
else if(currentTime - dutyCycleStartTime >= potValue * DUTY_CYCLE_PERIOD ){
digitalWrite(HEATER_ON, LOW); // Turn off heater
digitalWrite(LED_ON, LOW); // Turn off heater
}
}//--(end main loop )---
/**Define which pins on the Arduino are for what -and also set the cycle time **/
#define POT_INPUT A2 // NOTE: No ";" on #define
#define HEATER_ON 10 // NOTE: No ";" on #define
#define LED_ON 8 // NOTE: No ";" on #define
#define DUTY_CYCLE_PERIOD 2 // duty cycle period (Seconds)
/** Declare variables **/
int potValue; // Value returned on the pot sweeper (0-1023)
long dutyCycleStartTime; // Time that the current duty cycle started
long currentTime; // milliseconds counter
void setup() /** SETUP: RUNS ONCE And sets up the arduino **/
{
pinMode(POT_INPUT, INPUT); // Set up pot input pin
pinMode(HEATER_ON, OUTPUT); // Set up heater control output pin
pinMode(LED_ON, OUTPUT); // Set up heater control output pin
dutyCycleStartTime = millis();
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
/****** Check on the state of affairs ******/
currentTime = millis();
potValue = analogRead(POT_INPUT);
/****** Check if the duty cycle period is over and restart it if it is******/
if( currentTime - dutyCycleStartTime >= DUTY_CYCLE_PERIOD * 1000) {
dutyCycleStartTime = currentTime;
digitalWrite(HEATER_ON, HIGH);
digitalWrite(LED_ON, HIGH);
}
/****** Check if the heater should be turned off ******/
else if(currentTime - dutyCycleStartTime >= potValue * DUTY_CYCLE_PERIOD ){
digitalWrite(HEATER_ON, LOW); // Turn off heater
digitalWrite(LED_ON, LOW); // Turn off heater
}
}//--(end main loop )---
Re: Fog's Controller Project
And here's the gist of how the potentiometer input gets hooked up, so the voltage on the middle leg goes between ground and 5V depending on where in the rotation the pot is.
https://www.arduino.cc/en/tutorial/potentiometer" onclick="window.open(this.href);return false;" rel="nofollow
https://www.arduino.cc/en/tutorial/potentiometer" onclick="window.open(this.href);return false;" rel="nofollow
Re: Fog's Controller Project
I wish Arduinos existed 40 years ago when I was really into hobby electronics.
Decent of you to print the command lines, too.
Nice project!
Decent of you to print the command lines, too.
Nice project!
- Oldvine Zin
- Distiller
- Posts: 2431
- Joined: Sat Jun 06, 2015 9:16 pm
- Location: Pacific Northwest
Re: Fog's Controller Project
A better use of your time might be researching here about stilling and trying to control power via still temp.fog wrote:Here's my new control box, gents:
When I get better at programming, and a bit of data to base it on, there's no reason why I can't set it to track the temperatures and vary the power input accordingly.
Be safe
OVZ
- Yummyrum
- Global moderator
- Posts: 8620
- Joined: Sat Jul 06, 2013 2:23 am
- Location: Fraser Coast QLD Aussie
Re: Fog's Controller Project
Nice one fog .
You must have been doing your research ....Pleased you left out the thermometers .
Thanks for the code ... I’ve not used Arduinos so that is cool to see .
Many folk show Auduinos doing stuff but I think you are the first to show code . ... thanks .
When you get proficient with the code , I’d love to see you convert the PWM to a Burst fire mode algorithm .
This spreads the on/off cycles more evenly throughout the 2 second or thereabouts time frame reducing surge boiling .
Don’t ask me how ... I want you to work the code out and show me how . ... my brains not up for it.
You must have been doing your research ....Pleased you left out the thermometers .
Thanks for the code ... I’ve not used Arduinos so that is cool to see .
Many folk show Auduinos doing stuff but I think you are the first to show code . ... thanks .
When you get proficient with the code , I’d love to see you convert the PWM to a Burst fire mode algorithm .
This spreads the on/off cycles more evenly throughout the 2 second or thereabouts time frame reducing surge boiling .
Don’t ask me how ... I want you to work the code out and show me how . ... my brains not up for it.
My recommended goto .
https://homedistiller.org/wiki/index.ph ... ion_Theory
https://homedistiller.org/wiki/index.ph ... ion_Theory
Re: Fog's Controller Project
Thanks for the feedback, Yummyrum. The length of the duty cycle is easy to change -down to less than 1/100's of a second. I just felt it would be easier on the SSRs to not pulse them all the time. What do folks feel is the upper reasonable frequency of cycling the heat to prevent surge boiling in a boiler volume of 3 liters?
-
- Bootlegger
- Posts: 138
- Joined: Thu Mar 07, 2013 9:48 pm
Re: Fog's Controller Project
2 seconds cycle time is fine for my keg boiler and wavy ultra low density element. Probably has a lot to do with the the thermal mass of the heating element.fog wrote: ↑Mon Aug 05, 2019 7:10 pm Thanks for the feedback, Yummyrum. The length of the duty cycle is easy to change -down to less than 1/100's of a second. I just felt it would be easier on the SSRs to not pulse them all the time. What do folks feel is the upper reasonable frequency of cycling the heat to prevent surge boiling in a boiler volume of 3 liters?
-
- Novice
- Posts: 30
- Joined: Wed Jun 20, 2018 3:10 pm
Re: Fog's Controller Project
Just to put my input in - if you had more sensors, you could check for things like if the column temp value is over some thing and the coolant temp is under some thing, shut off the element ?
just messing with buckets and steel and copper.
Re: Fog's Controller Project
Thanks for the feedback.
Johnnywhiskey, yes, and in my case I'm driving a boiler, so the the heat mass is even greater.
BillyPrefect, I have sensors for the boiler, for the vapor temp at the top of the head, and for the cooling water. Ideally, I'll program the arduino as a PID to reduce the duty cycle as the cooling water comes up to being too hot. I've heard 135 deg F is the upper limit? Theoretically I could also program a rest at 168 deg F and get the methanol mostly out...
Johnnywhiskey, yes, and in my case I'm driving a boiler, so the the heat mass is even greater.
BillyPrefect, I have sensors for the boiler, for the vapor temp at the top of the head, and for the cooling water. Ideally, I'll program the arduino as a PID to reduce the duty cycle as the cooling water comes up to being too hot. I've heard 135 deg F is the upper limit? Theoretically I could also program a rest at 168 deg F and get the methanol mostly out...
Re: Fog's Controller Project
I would like to see the code with the thermometers in.
I think you would want to avoid upping the frequency too much when using with a SSR. Many have "zero crossing" circuitry that makes them only turn on and off when the power sine wave is crossing the zero point. I am not an electronics guru but feel that this could cause unpredictable results with frequencies above 20 or 30 Hz particularly if the frequency and duty cycle end up being some kind of multiple of the 60Hz mains supply here in North America or 50Hz in much of the rest of the world.Yummyrum wrote: ↑Sat Aug 03, 2019 7:20 am When you get proficient with the code , I’d love to see you convert the PWM to a Burst fire mode algorithm .
This spreads the on/off cycles more evenly throughout the 2 second or thereabouts time frame reducing surge boiling .
Don’t ask me how ... I want you to work the code out and show me how . ... my brains not up for it.
Re: Fog's Controller Project
@NiteHawk, here's the full code. The temp probe coding is a little more complicated than it needs to be because I wanted each sensor to be on it's own bus, so I could swap sensor locations depending on the still setup. And, yes, I see no reason to up the SSR duty cycle length above 1 Hz.
/******
V10 includes
* time reporting
* bypass of the water sensor/fill system when pin 7 is grounded
* water level triggered by delta as well as pure threshold
******/
#include <OneWire.h>
#include <DallasTemperature.h>
int oneWirePins[]={3,4,5}; //OneWire DS18x20 temperature sensors on these wires
const int oneWirePinsCount=sizeof(oneWirePins)/sizeof(int);
#define BOILER_BUS 3 // Boiler temp probe
#define HEAD_BUS 4 // Head temperature probe
#define COOLING_BUS 5 // cooling water temperature probe
OneWire ds18x20[oneWirePinsCount];
DallasTemperature sensor[oneWirePinsCount];
#define POT_INPUT A1 // For heater duty cycle control input
#define WATER_SENSOR A4 // For reisistance measurement across water probe
#define HEATER_ON 11 // Output to SSR for heater
#define WATER_FILL_ON 9 // Output to SSR for solenoid valve
#define LED_ON 13 // LED indicator
#define WATER_SENSOR_SELECTOR 7 //If LOW, bypass the water sensor for running stills withouot sensors
#define WATER_SENSOR_THRESHOLD 640 // Voltage threshold from sensor Depends on water characteristics and series resister
#define WATER_SENSOR_DELTA 80 // Sensor change required to trigger
#define DUTY_CYCLE_PERIOD 2 // heater duty cycle period (Seconds)
#define REPORT_PERIOD 6 // length of time between serial reports
// Set up variables
int potValue; // Value returned on the pot sweeper (0-1023) to determine duty cycle
long dutyCycleStartTime; // Time that the current duty cycle started
long reportCycleStartTime; // Time that the current report cycle started
long currentTime; // milliseconds counter
long startTime; // Time the unit starts up
boolean heaterEnabled = 0; // Only actuate heater when tank is full of water so it doesn't burn out
int pastWaterReading1 = WATER_SENSOR_THRESHOLD; // Use past readings to note change in current reading and trigger filling
int pastWaterReading2 = WATER_SENSOR_THRESHOLD;
int pastWaterReading3 = WATER_SENSOR_THRESHOLD;
int pastWaterReading4 = WATER_SENSOR_THRESHOLD;
void setup() /****** SETUP: RUNS ONCE ******/
{
Serial.begin(9600); // start serial port
Serial.print("============Ready with ");
Serial.print(oneWirePinsCount);
Serial.println(" Sensors================");
Serial.println("Time:\tBoler:\tHead:\tCooling:\tWater Sensor:\tDuty Cycle:\tHeater On");
pinMode(BOILER_BUS,INPUT_PULLUP);
pinMode(HEAD_BUS,INPUT_PULLUP);
pinMode(COOLING_BUS,INPUT_PULLUP);
pinMode(WATER_SENSOR_SELECTOR,INPUT_PULLUP);
pinMode(POT_INPUT, INPUT); // Set up pot input pin
pinMode(WATER_SENSOR, INPUT); // Set up pot input pin
pinMode(HEATER_ON, OUTPUT); // Set up heater control output pin
pinMode(WATER_FILL_ON, OUTPUT); // Set up heater control output pin
pinMode(LED_ON, OUTPUT);
dutyCycleStartTime = millis();
reportCycleStartTime = dutyCycleStartTime;
startTime = dutyCycleStartTime; // Sychronize your watches, boys!
DeviceAddress deviceAddress; //Set up the temp sensors
for (int i=0; i<oneWirePinsCount; i++) {;
ds18x20.setPin(oneWirePins);
sensor.setOneWire(&ds18x20);
sensor.begin();
if (sensor.getAddress(deviceAddress, 0)) sensor.setResolution(deviceAddress, 12);
}
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
/****** Check on the state of affairs ******/
currentTime = millis();
potValue = analogRead(POT_INPUT);
/****** Check if the duty cycle period is over and restart ******/
if( currentTime - dutyCycleStartTime >= DUTY_CYCLE_PERIOD * 1000) {
dutyCycleStartTime = currentTime;
if(heaterEnabled){
digitalWrite(HEATER_ON, HIGH);
}
/****** Check water level and fill, if necessary ******/
int currentWaterSensorReading = analogRead(WATER_SENSOR);
if (digitalRead(WATER_SENSOR_SELECTOR) && (currentWaterSensorReading > WATER_SENSOR_THRESHOLD || currentWaterSensorReading - pastWaterReading4 > WATER_SENSOR_DELTA)) { //If water level is low:
digitalWrite(WATER_FILL_ON,HIGH); // Turn on the water
digitalWrite(LED_ON, HIGH);
heaterEnabled = 0; //Disable heater
digitalWrite(HEATER_ON, LOW);
}
else {
digitalWrite(WATER_FILL_ON,LOW); // If it's not, Turn it off
digitalWrite(LED_ON, LOW);
heaterEnabled = 1;
}
pastWaterReading4 = pastWaterReading3; // Update the past readings
pastWaterReading3 = pastWaterReading2;
pastWaterReading2 = pastWaterReading1;
pastWaterReading1 = currentWaterSensorReading;
}
/****** Check if the heater should be turned off ******/
else if(currentTime - dutyCycleStartTime >= potValue * DUTY_CYCLE_PERIOD ){
digitalWrite(HEATER_ON, LOW); // Turn off heater
}
/****** Check if it's reporting time ******/
if( currentTime - reportCycleStartTime >= REPORT_PERIOD * 1000) {
reportCycleStartTime = currentTime;
Serial.print((startTime-currentTime)/1000/60);
for (int i=0; i<oneWirePinsCount; i++) { // call sensors.requestTemperatures() to issue a global temperature
sensor.requestTemperatures(); // request to all devices on the bus
}
for (int i=0; i<oneWirePinsCount; i++) {
float temperature=sensor.getTempCByIndex(0);
if(0 < temperature < 120) {
Serial.print(temperature); }
Serial.print("\t");
}
Serial.print(analogRead(WATER_SENSOR));
Serial.print("\t");
Serial.print(potValue, 1);
Serial.print("\t");
Serial.println(heaterEnabled);
}
}//--(end main loop )---
/******
V10 includes
* time reporting
* bypass of the water sensor/fill system when pin 7 is grounded
* water level triggered by delta as well as pure threshold
******/
#include <OneWire.h>
#include <DallasTemperature.h>
int oneWirePins[]={3,4,5}; //OneWire DS18x20 temperature sensors on these wires
const int oneWirePinsCount=sizeof(oneWirePins)/sizeof(int);
#define BOILER_BUS 3 // Boiler temp probe
#define HEAD_BUS 4 // Head temperature probe
#define COOLING_BUS 5 // cooling water temperature probe
OneWire ds18x20[oneWirePinsCount];
DallasTemperature sensor[oneWirePinsCount];
#define POT_INPUT A1 // For heater duty cycle control input
#define WATER_SENSOR A4 // For reisistance measurement across water probe
#define HEATER_ON 11 // Output to SSR for heater
#define WATER_FILL_ON 9 // Output to SSR for solenoid valve
#define LED_ON 13 // LED indicator
#define WATER_SENSOR_SELECTOR 7 //If LOW, bypass the water sensor for running stills withouot sensors
#define WATER_SENSOR_THRESHOLD 640 // Voltage threshold from sensor Depends on water characteristics and series resister
#define WATER_SENSOR_DELTA 80 // Sensor change required to trigger
#define DUTY_CYCLE_PERIOD 2 // heater duty cycle period (Seconds)
#define REPORT_PERIOD 6 // length of time between serial reports
// Set up variables
int potValue; // Value returned on the pot sweeper (0-1023) to determine duty cycle
long dutyCycleStartTime; // Time that the current duty cycle started
long reportCycleStartTime; // Time that the current report cycle started
long currentTime; // milliseconds counter
long startTime; // Time the unit starts up
boolean heaterEnabled = 0; // Only actuate heater when tank is full of water so it doesn't burn out
int pastWaterReading1 = WATER_SENSOR_THRESHOLD; // Use past readings to note change in current reading and trigger filling
int pastWaterReading2 = WATER_SENSOR_THRESHOLD;
int pastWaterReading3 = WATER_SENSOR_THRESHOLD;
int pastWaterReading4 = WATER_SENSOR_THRESHOLD;
void setup() /****** SETUP: RUNS ONCE ******/
{
Serial.begin(9600); // start serial port
Serial.print("============Ready with ");
Serial.print(oneWirePinsCount);
Serial.println(" Sensors================");
Serial.println("Time:\tBoler:\tHead:\tCooling:\tWater Sensor:\tDuty Cycle:\tHeater On");
pinMode(BOILER_BUS,INPUT_PULLUP);
pinMode(HEAD_BUS,INPUT_PULLUP);
pinMode(COOLING_BUS,INPUT_PULLUP);
pinMode(WATER_SENSOR_SELECTOR,INPUT_PULLUP);
pinMode(POT_INPUT, INPUT); // Set up pot input pin
pinMode(WATER_SENSOR, INPUT); // Set up pot input pin
pinMode(HEATER_ON, OUTPUT); // Set up heater control output pin
pinMode(WATER_FILL_ON, OUTPUT); // Set up heater control output pin
pinMode(LED_ON, OUTPUT);
dutyCycleStartTime = millis();
reportCycleStartTime = dutyCycleStartTime;
startTime = dutyCycleStartTime; // Sychronize your watches, boys!
DeviceAddress deviceAddress; //Set up the temp sensors
for (int i=0; i<oneWirePinsCount; i++) {;
ds18x20.setPin(oneWirePins);
sensor.setOneWire(&ds18x20);
sensor.begin();
if (sensor.getAddress(deviceAddress, 0)) sensor.setResolution(deviceAddress, 12);
}
}//--(end setup )---
void loop() /****** LOOP: RUNS CONSTANTLY ******/
{
/****** Check on the state of affairs ******/
currentTime = millis();
potValue = analogRead(POT_INPUT);
/****** Check if the duty cycle period is over and restart ******/
if( currentTime - dutyCycleStartTime >= DUTY_CYCLE_PERIOD * 1000) {
dutyCycleStartTime = currentTime;
if(heaterEnabled){
digitalWrite(HEATER_ON, HIGH);
}
/****** Check water level and fill, if necessary ******/
int currentWaterSensorReading = analogRead(WATER_SENSOR);
if (digitalRead(WATER_SENSOR_SELECTOR) && (currentWaterSensorReading > WATER_SENSOR_THRESHOLD || currentWaterSensorReading - pastWaterReading4 > WATER_SENSOR_DELTA)) { //If water level is low:
digitalWrite(WATER_FILL_ON,HIGH); // Turn on the water
digitalWrite(LED_ON, HIGH);
heaterEnabled = 0; //Disable heater
digitalWrite(HEATER_ON, LOW);
}
else {
digitalWrite(WATER_FILL_ON,LOW); // If it's not, Turn it off
digitalWrite(LED_ON, LOW);
heaterEnabled = 1;
}
pastWaterReading4 = pastWaterReading3; // Update the past readings
pastWaterReading3 = pastWaterReading2;
pastWaterReading2 = pastWaterReading1;
pastWaterReading1 = currentWaterSensorReading;
}
/****** Check if the heater should be turned off ******/
else if(currentTime - dutyCycleStartTime >= potValue * DUTY_CYCLE_PERIOD ){
digitalWrite(HEATER_ON, LOW); // Turn off heater
}
/****** Check if it's reporting time ******/
if( currentTime - reportCycleStartTime >= REPORT_PERIOD * 1000) {
reportCycleStartTime = currentTime;
Serial.print((startTime-currentTime)/1000/60);
for (int i=0; i<oneWirePinsCount; i++) { // call sensors.requestTemperatures() to issue a global temperature
sensor.requestTemperatures(); // request to all devices on the bus
}
for (int i=0; i<oneWirePinsCount; i++) {
float temperature=sensor.getTempCByIndex(0);
if(0 < temperature < 120) {
Serial.print(temperature); }
Serial.print("\t");
}
Serial.print(analogRead(WATER_SENSOR));
Serial.print("\t");
Serial.print(potValue, 1);
Serial.print("\t");
Serial.println(heaterEnabled);
}
}//--(end main loop )---
Re: Fog's Controller Project
Thanks Fog. I will have a closer look at the code to see if it will work for my purposes.
Re: Fog's Controller Project
As a side note, I used 1/8 stereo jacks for my temp probes and they're not hot-swappable. As you push the plug in or take it out it shorts out the circuit causing damage to the arduino if the system is powered up. Next time I'll use phone jacks instead.
Re: Fog's Controller Project
I use auber PID controller for my still (controller from the brewery since evidently I can't be bothered to build one dedicated to the still). It runs a 2 second cycle. When running in flute mode I do notice some surge early in the heat up, by the time the column is stacked it seems to stop, the plates stay at the same fill level. I wouldn't want to run a lot still this way but it's fine for my 2 plate thing.
XLR connectors work very well for this sort of controller: positive locking, easy to solder up, cheap, durable and usually include their own strain releif. If you damage a line or need a longer one its easy to un-solder them and reuse.
xs12 connectors also work if you need something more space conscious, but I dont like them as well.
XLR connectors work very well for this sort of controller: positive locking, easy to solder up, cheap, durable and usually include their own strain releif. If you damage a line or need a longer one its easy to un-solder them and reuse.
xs12 connectors also work if you need something more space conscious, but I dont like them as well.
:)