My condensation management setup worked!

@dewbane,

First, Welcome to the Hobby-Machinist!

Second, what a great way to jump in and share! Very cool project!

Some questions:
Is your system also Arduino based?
If so, what board did you use? and is the display integrated to the Arduino board or something you add-on?
Can you post a link to the temp sensors and heating pads you used?
Were there already libraries to support those parts, or did you write your own code?

I am not out to steal/recreate your idea, just very curious.

Thanks,
-brino
 
I used an Elegoo Uno R3 Arduino clone with a prototype expansion shield. The shield provided enough tie-ins for power and ground wires to run everything. I used a SunFounder 20x4 display with I2C backpack board (four-wire hook up), an AM2302 for temperature and humidity, and two DS18B20 as temperature sensors. For power control, I went with IoT Relay boxes from Digital Loggers for convenience and elegance.

I had a lot of trouble sourcing the kind of heaters I wanted at a reasonable cost. I finally found the right form factor at Banggood, and they were less than $8 each. If I had paid $40 I would have gotten a Chinese heater either way, so we're giving this a shot. Last but not least, I used telephone wire to extend everything, and I wired it all through a pair of VGA connectors that had the pins expanded out to screw terminals. Wiring a bunch of things using idential red/green/yellow/black wires was fun to keep straight. The DS18B20 require a 4.7 kOhm pull-up resistor wired between data and power, and I simply soldered these in where my wires entered the connector terminals, with a little heat shrink tubing to protect them from shorting out by accident.

Here is the sensor bundle tangle (resistors are inside that plug):
20180303_071944.jpg


The DS18B20 are One Wire sensors that can share a bus, but I had plenty of unused data pins and it was less complicated to wire them into separate buses. Each sensor has a unique address, which means you can address them individually on the same bus, but it also means you can't swap a component without changing the address in code.

Here are the parts that got installed into the case. Actually, this is an old picture. The resistor ended up in the plug, and I moved the relay wires from pins 0 and 1 to pins 10 and 11. Something, somewhere was interfering with 0 and 1, which took me forever to figure out. I never did figure out what. Moving the wires to different pins got everything working, and I lived happily ever after:

20180303_072010.jpg

There are public libraries for all components. So many public libraries that finding one that worked for me was one of the hardest challenges For the curious, here's the code. I didn't invest effort making it elegant, because I didn't really expect to post it in public, but I don't really see any reason not to publish it. What, I was going to manufacture these things? Not on your life!

Incidentally, I went live with the system with the 5-second delay, because I never uploaded the code again after changing it to a 60-second delay. I was worried about switching things off and on too rapidly, but the sensors an heaters are both slow, and I think this will be fine as is.

/*
Dewbane Condensation Management System

Prevents condensation on equipment by keeping its temperature
elevated above the dew point. This system is designed to manage
one lathe and one mill from a single unit.

Copyright (c) 2018 D. Michael McIntyre
michael@highlanddragonforge.com

This code was developed for an Arduino Uno R3 using the following:
1 AM2302 temperature and humidity sensor
2 DS18B20 temperature sensors (on separate buses for convenience)
2 IoT Relay enclosed high-power power relay
4 100W silicone heaters (2 per machine)

Lathe: yellow zip ties

The theory of operation is as follows:
* poll AM2302 to get temperature in Celsius and relative humidity
* use temperature and humidity to calculate dew point
* for equipment 1, equipment 2 do
* poll the DS18B20 for the equipment n
* turn off IoT relay for equipment n heaters if lathe is above dew point
* else turn on IoT relay for equipment n heaters
* update LCD display to reflect current status
* loop infinitely

*/


#include "cactus_io_AM2302.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "cactus_io_DS18B20.h"


// set the LCD address to 0x27
LiquidCrystal_I2C lcd(0x27, 20, 4);

// pin defines
#define AM2302_PIN 2 // temp/humidity data pin
#define LATHE_T_PIN 8 // lathe temp data pin
#define MILL_T_PIN 9 // mill temp data pin
#define LATHE_R_PIN 10 // lathe heat relay
#define MILL_R_PIN 11 // mill heat relay

// set to 60000 for production, 5000 for debugging
//#define LOOP_DELAY 60000
#define LOOP_DELAY 5000

// Create DS18B20 objects
DS18B20 LATHE(LATHE_T_PIN);
DS18B20 MILL(MILL_T_PIN);

bool latheHeat = false;
bool millHeat = false;
float dewPoint = 0.0;
float displayTemperature = 0.0;
float displayHumidity = 0.0;
float latheTemperature = 0.0;
float millTemperature = 0.0;

// degree symbol
byte degreeSymbol[8] = {
0b00110,
0b01001,
0b01001,
0b00110,
0b00000,
0b00000,
0b00000,
0b00000
};

// Initialize DHT sensor for normal 16mhz Arduino.
AM2302 dht(AM2302_PIN);

void setup() {
// set relay pins as output and turn them off
pinMode(LATHE_R_PIN, OUTPUT);
pinMode(MILL_R_PIN, OUTPUT);
digitalWrite(LATHE_R_PIN, LOW);
digitalWrite(MILL_R_PIN, LOW);


Serial.begin(9600);
Serial.println("Dewbane by Highland Dragon Forge");
Serial.println("Initializing AM2302...");

dht.begin();

Serial.println("Initializing DS18B20 lathe sensor...");
LATHE.readSensor();

Serial.println("Initializing DS18B20 mill sensor...");
MILL.readSensor();

Serial.println("Initializing display...");
// initialize the lcd
lcd.init();
// turn on the backlight
lcd.backlight();
// create degree custom character
lcd.createChar(0, degreeSymbol);
}

void loop() {
// read AM2302 to get temperature and humidity
//
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
dht.readHumidity();
dht.readTemperature();

// Check if any reads failed and exit early (to try again).
if (isnan(dht.humidity) || isnan(dht.temperature_C)) {
Serial.println("DHT sensor read failure!");
return;
}

// calculate our dew point
dewPoint = dewPointFast(dht.temperature_C, dht.humidity);
displayTemperature = dht.temperature_F;
displayHumidity = dht.humidity;

// read lathe temperature
LATHE.readSensor();
latheTemperature = LATHE.getTemperature_C();

// read mill temperature
MILL.readSensor();
millTemperature = MILL.getTemperature_C();

// toggle heaters
processHeat();

// update the display at the end of each loop
updateDisplay();

// Wait 60 seconds before looping, to give everything time to settle before
// a new round of decision making
delay(LOOP_DELAY);

}

// reference: http://en.wikipedia.org/wiki/Dew_point
double dewPointFast(double celsius, double humidity) {
double a = 17.271;
double b = 237.7;
double temp = (a * celsius) / (b + celsius) + log(humidity*0.01);
double Td = (b * temp) / (a - temp);
return Td;
}

// quick hack to figure out how many spaces to use for a number
int len(float data) {
if (data > 100.0) return 3;
else if (data > 10.0) return 2;
else if (data > 1.0) return 1;
else if (data < -100.0) return 4;
else if (data < -10.0) return 3;
else if (data < -1.0) return 2;
}

float convF(float data) {
return data * 1.8 + 32;
}

void updateDisplay() {
int row = 0;
lcd.setCursor(0,row);
lcd.print(" [Dewbane] ");
lcd.setCursor(0, row);
int temp = (int) displayTemperature;
int humi = (int) displayHumidity;
lcd.print(temp);
lcd.print((char)0);
lcd.print("F");
lcd.setCursor((20 - len(humi) - 1), row);
lcd.print(humi);
lcd.print("%");

row++;
lcd.setCursor(0,row);
lcd.print("Dew Point:");
float dpF = convF(dewPoint);
// move cursor to right minus string length
lcd.setCursor((20 - len(dpF) - 2), row);
int intF = (int) dpF;
lcd.print(intF);
lcd.print((char)0);
lcd.print("F");

row++;
lcd.setCursor(0, row);
lcd.print("Lathe ");
int l = (int) convF(latheTemperature);
lcd.print(l);
lcd.print((char)0);
lcd.print("F "); // intentional trailing spaces
lcd.setCursor(16, row);
if (latheHeat) lcd.print("HEAT");
else lcd.print(" OK ");

row++;
lcd.setCursor(0, row);
lcd.print("Mill ");
l = (int) convF(millTemperature);
lcd.print(l);
lcd.print((char)0);
lcd.print("F "); // intentional trailing spaces
lcd.setCursor(16, row);
if (millHeat) lcd.print("HEAT");
else lcd.print(" OK ");

}

// keep the equipment at least 1.0 C above the dew point at all times
void processHeat() {
if (latheTemperature <= (dewPoint + 1.0)) {
// turn on heat
digitalWrite(LATHE_R_PIN, HIGH);
latheHeat = true;
} else {
// turn off heat
digitalWrite(LATHE_R_PIN, LOW);
latheHeat = false;
}

if (millTemperature <= (dewPoint + 1.0)) {
// turn on heat
digitalWrite(MILL_R_PIN, HIGH);
millHeat = true;
} else {
// turn off heat
digitalWrite(MILL_R_PIN, LOW);
millHeat = false;
}
}
 
What, I was going to manufacture these things? Not on your life!

I bet you could find a few customers here.....

Incidentally, I went live with the system with the 5-second delay, because I never uploaded the code again after changing it to a 60-second delay. I was worried about switching things off and on too rapidly, but the sensors an heaters are both slow, and I think this will be fine as is.

If you have the heaters and sensors placed well, then the thermal mass of the machines will slow the feedback down substantially.

I gotta say I am very impressed with your system. It's got an actual need, some research, applied science, real novelty.
Well done!
..and thanks for sharing so much detail it is appreciated.

/rant on
I get really frustrated with the avalanche of microprocessor and especially IoT projects that don't do anything useful.
So many projects seem to be done "because they can" not because it fills a need (1).
I don't need my frig to talk to my toilet, it's rediculous!
(1) okay maybe the benefit of some of those projects is for the person to learn about the system, that's great I support education, but to act like it's useful and gonna help society and save the world come on, open your eyes!
/rant off

I hope you keep us updated with the beta testing. ;)

Thanks!
-brino
 
I bet you could find a few customers here.....
I've been mulling it over, but there are a lot of things to work through to develop a real commercial product. Maybe I should set up a Kickstarter or something.
I gotta say I am very impressed with your system. It's got an actual need, some research, applied science, real novelty.
Well done!
..and thanks for sharing so much detail it is appreciated.
I didn't do it first, but I did it prettier.
I get really frustrated with the avalanche of microprocessor and especially IoT projects that don't do anything useful.
That's why it took me so long to do a project, even though I always could have. Really, this just reflects the approach I've always taken to everything. I've never been a fan of exercises and sample problems. Give me a real problem I can get my hands on, and I can probably figure it out.
 
I can't imagine this is a large power use. Can you give info regarding the heaters you used? The only thing that occurred to me is that you may want heaters in the xy table too.
They're 100 watt "oil pan heaters" straight from China. I have definite concerns about not putting a heater directly on the tables, but there just isn't anywhere to mount one except up top. The underside is all open air and screw. I do have a 5" vise on this little mill/drill, and there is a big overhang where I could mount a heater there. I think the power cord would be in my way constantly, and it could potentially make the job even harder when I eventually add DRO.

The base of the casting is much to narrow for the heater, which is roughly 4" square. I could put one under the base, but we'll see how it does before I throw away all the time I spent dialing in the tram.
 
Very clever idea! Good job! Also, when you get back to us, maybe give an insight on what your before and after electric bill looks like?
I wasn't heating with electricity before, so all I can do is add to the electric bill. It was always going to cost something to protect my equipment, and this just has to be cheaper than my alternatives. It would be interesting to add a clock to my system and track how much time it's actually running the heaters. I could get an approximate idea without spending money on a meter.

How much this costs will depend entirely on the weather, which is wildly variable year to year. The beauty of this system is that my equipment will be above the dew point naturally probably 80% of the time. Even if I heated the entire space, I couldn't guarantee, say, 68 degrees would always be above the dew point. Right now it's 29 out there, but the dew point is 13 and the equipment is at about 30, so it's not burning any watts except the trickle to power the electronics.

20180308_041820.jpg
 
A couple further thoughts:

FYI, pins 0 and 1 on that form of Arduino board are the serial pins, so they don't behave as normally expected for digital I/O.

Using a relay box, you don't want the relay cycling too much, so you would be well served by adding some hysteresis to the switching algorithm. In other words, define a dead band around the desired temperature, and turn the heater on if below that dead band, but don't turn it off until above the dead band. That stops short cycling.

An even better approach to heating is to use a PID algorithm, which will maintain a steady temperature rather than waiting for it to rise and fall. The idea is finding the correct duty cycle for the heater, so that it may spend 30% of the time on, pulsing heat, to maintain your desired temperature. There are PID libraries available for Arduino. When I did this for a heater, I modified the PID routine to include a feed-forward term, allows you to predict the control effort and use that as a starting point. You can look at my code if you are interested. But with a PID controller, you need to use a solid-state relay because you will be cycling the heaters on/off a lot more. For something like you are doing, you might still use a one-minute cycle time, as the system response is very slow. It would just give you a more consistent temperature for the machine.

As you add features to your code, you will want to change to a more independent timing arrangement, rather than using delay. That way you can have several things happening and not have the timing of one affect another. I have used libraries for this, like MSTimer2, but you can do it by just tracking when something last happened and comparing to the current time, millis(), as explained here.
 
FYI, pins 0 and 1 on that form of Arduino board are the serial pins, so they don't behave as normally expected for digital I/O.
If I had caught this detail it would have saved time.
Using a relay box, you don't want the relay cycling too much, so you would be well served by adding some hysteresis to the switching algorithm.
Definitely a concern. The code already aims higher than the minimum target temperature (one degree Celsius is a bigger jump than one degree Fahrenheit) with this in mind. The temperature sensors are all slow to reflect changes, and the machines are large thermal masses that won't change temperatures rapidly, so in practice I have some hysteresis in the system. If it proves insufficient, I definitely need to add more.
An even better approach to heating is to use a PID algorithm, which will maintain a steady temperature rather than waiting for it to rise and fall.
The target temperature is a moving target that varies moment to moment with atmospheric conditions. PID algoritms seem to be for things like automotive cruise control, and this system needs to do the equivalent of changing the set speed continuously. I'm not sure that would be a good fit, but could be missing the point.
The idea is finding the correct duty cycle for the heater, so that it may spend 30% of the time on, pulsing heat, to maintain your desired temperature.
Duty cycle is a real concern, and the current design is basically rolling the dice and hoping the heaters never burn out. I have no idea what their rated duty cycle is.[/quote]But with a PID controller, you need to use a solid-state relay because you will be cycling the heaters on/off a lot more.[/quote]I thought all relays were solid state?
As you add features to your code, you will want to change to a more independent timing arrangement, rather than using delay. That way you can have several things happening and not have the timing of one affect another. I have used libraries for this, like MSTimer2, but you can do it by just tracking when something last happened and comparing to the current time, millis(), as explained here.
I'm hoping to walk away and spend my time making things with the equipment. Tweaking the software would be painful at this point. Of course we all know I'm going to have to tweak it sooner or later, because that's the nature of software.

Thanks for the input, and I did look through your code. Food for thought!
 
Back
Top