Final project - Derek Covill
Carbon ply - the open source carbon fibre curing oven
Here's the final result!
Here's a link to my final project slide and video presentation:
final project slide: presentation.png
final project video: presentation.mp4
And here are the files to download:
download a .zip file with all the CAD part+assembly files here.
And you can download the buttons.stl file here.
And you can download a .zip file with all the Eagle PCB design files here.
download the manual temperature control programme .ino file to download
download the 85 degree curing cycle programme .ino file here.
download the programme using PID to control temperature .ino file here.
Contents
- Summary
- Background
- Scope
- Smart thermostat
- Sketches, CAD and sketch models
- Early PCBs, programs and low power experiments
- Interface design
- PCB design
- High power experiments
- Designing the heating assembly
- Basic measurement and control
- Programming the OLED display
- Programming the buttons
- Fabrication and assembly of casing and final product
- Full BOM list and parts made
- Logo design and fabrication
- Future developments
- Acknowledgements
- Licencing statement
Project Summary
Here are two final project videos, I wasn't sure which one to go with.
Here's what was I did, with links to respective weekly assignments:
- laser cut (or CNC) ply casing
- 3D printed ABS motor housing:
- moulded and cast + 3D printed PLA logo linked to w10 assignment
- designed, CNC milled and stuffed ATMega32U4 PCB
- designed electrical system to use 24 V 200W heating element controlled via relay and 24 V DC brushed fan, linked to both w11 input, and w12 output assignments
- used I2C to get 4-pin OLED display to display key data
- local interface to turn on and set required temperature (thermostatically controlled)
- input control programme from .csv file, linked to w13 assignment
- arduino PID control programme controls temperature
- python script to plot live temperatures using serial communications linked to w13 assignment
Background
I was quite inspired by Denis Terwagne's 2017 final project
which was a physics tinking kit, to provide a cleverly designed platform for students to play with various aspects relating to physics theory.
I teach product design and development, prototyping and CAD/CAE, but one of the areas I want to focus on in the coming years is electronic prototyping, so I would like my final project to be a electronic product design kit that supports students' learning and experimenting as they prototype with electronics. It would also be great to compile some useful resources in this area. My colleague, Dr Jerome Leary has produced a
useful site for digital fabrication tools
and something to complement this for our students would be ideal. I would like to produce some fabacademy style resources for my design project modules (DP401 beautiful project, DP402 durable project, DP403 usable project, DP404 digital fabrication methods, DP504 digital fabrication project).
The main one to focus on will be the DP403 project, and I'd like to develop a small customised PID controlled carbon fibre curing oven for small carbon fibre samples. It will be something like this (here's the link), only smaller since we only really work with small samples.
Here are some samples we've produced lately using the large Carbolite oven. The problem we have at the moment is that the curing cycle for these carbon parts is a whole day (9-14 hours), so if we can have a small oven design specifically for the samples we need for our materials testing labs, then we can free up the oven for other projects, like forming shapes in acryllic etc.
Here are a few ducks we've recently moulded in a two part mould - we use this as a teaching exercise with our first year product designers. The idea is that we can do more of this kind/scale of work with my oven...we may even develop several ovens!
here's an example of the typical curing cycle that we need for our prepreg samples. They can even go down to a cycle with a maximum temperature of only 80deg C, with still some very strong parts - the only down side is that the glass transition temperature of the parts will be lower if you cure it at a lower temperature curing cycle.
And there's also a low temperature curing cycle, which I will aim for with my oven.
Project scope
This project will produce a small carbon fibre curing oven that is built up in stages (ultimately as a learning kit) using spiral development to help students learn the basics of electronics, programming and heat power/energy. From this, they can learn the basics needed to help them design toasters, kettles, bread makers, thermostats, heaters, etc. The basic specification for this is that it should:
1. Connect a small heating device with a power supply and switch to heat up a small thermal mass.
2. The original idea was to use a potentiometer to control the amount of heat given off. This later changed to have buttons on an interface panel
3. Add a small motorised fan with switch and potentiometer to control cooling of the device, originally it was going to be something like the one below, but I soon realised that with higher temperatures (> 80 degrees C), this may be a problem so I've opted for a better, steel solution as shown later on.
4. Develop a temperature measuring circuit to indicate when a set temperature is reached, originally I was going to use a thermister or thermocouple like the one shown here, but the easiest way to start with was to use an active temperature sensor. Later as further development I'd like to use a thermistor, and put this into a Wheatsone bridge to linearise the temperature output.
5. Integrate all the above steps with a relay to control the heater using a thermostat, here's an example relay circuit (although this was for a much higher voltage than I'll need as I'll only need about 24 V...I think):
6. Possibly add a timing circuit to allow the system to be turned off after a set time and to programme a detailed curing cycle for carbon fibre. Here's an example timing circuit I can learn from:
7. Later on, connect the system to the internet to control it using a basic web based input and also to allow for monitoring with live feedback.
8. Develop an app to set the temperature and time of the thermostat. https://www.figma.com might be useful for the UX/interface of the app. I was quite inspired by the TADO smart thermostat and smart radiators that I have now installed in my house.
9. Include PID control and develop an algorithm to improve the performance of the thermostat and turn it into a 'smart' thermostat with model predictive control. Include graphs, theory, calculators for energy/cost too. Here's an example of a project that I found where they developed their own PID controller:
Smart thermostat
I've recently installed a smart thermostat into my house (Tado), and have been really impressed by this. It has really got me thinking about how the algorithm works, but it's also made me realise that I can use this as a learning tool for my students to learn about heat, control, and electronics.
Early sketches, CAD and sketch models
here's a quick sketch of the carbon fibre curing oven.
here's a quick sketch of the inside of the carbon fibre curing oven. Note power supply should probably be 24V, not 12V.
and here's a quick sketch showing how the outside might look.
and how the layers might be constructed using a reflective insulation foil, layer of foam insulation, then a ply outer.
For the CAD week, I produced a basic assembly of crude parts (definately not to scale):
I then exploded the view, so all the parts can be seen.
I then thought I'd put this into a technical drawing to show the Bill of Materials (BOM).
Then later I redid this to be the correct scale:
Here's my first basic sketch model:
Early heating and control experiments
As part of the embedded programming, input, output, and interface weeks I tried to dovetail these exercises with my final project. So the output of my input+output weeks was a simple thermostatic control circuit, which included a thermistor to measure the temperature, a relay to turn on an LED and a heater if the temperature was below a preset value. Of course for my final project I will be using a much bigger heating element (240W=24V x 10A), but the principle is the same. I did all this using the board that I made in the input devices week.
As part of the interface and applications programming week, I tried to start planning the workflow for my project. Here's the latest:
Also, here's where I've got to in loading idle2.7 and python2.7, opening the file, and generating the realtime graph of the serial data (which ultimately will be temperature):
It's given me a few things to think about, including:
- do I have a lid on top, or a door on the side (like a kitchen oven)...? side is better for heat loss, but lid is better for viewing if on a desktop!
- should I have a small separate compartment to control heat better?
- small DC computer fans will not work well at the temperatures I'll be using...I need better fans or a different solution, perhaps drive it using a motor that's in the 'cool' area, with a long shaft on a bearing? that could work, or should I simply use the skin of an existing oven?
- having a servo/solenoid to open or close an orifice might help with active cooling, and it might be a good idea to include a fan on this too
- having an extra insulation level so the layers are: stainless/fibre/multicore/ply...is ideal.
Interface design
And you can download the buttons.stl file here.
PCB layout
and here is the eagle PCB board layout file
and here is the eagle PCB board schematic file
and here is the outline.png file
and here is the traces.png file
And you can download a .zip file with all the Eagle PCB design files here.
High power experiments
Now moving on to some simple experiments with a 200W (24V) heater I acquired. Note that I'm only using a 15V power supply here. What was very interesting here is that as the heating element heats up (above 150 degrees C), the current drops drastically, meaning that it stops putting heat power into the oven. My hypothesis is that this is because there is no air circulating, so if we put a fan in it should draw the heat away from the heater and hence put more heat into the oven!
And then to look at adding a fan to see how this influences the system...and yes, by adding the fan to take away heat from the surfaces of the heater, it allows the heater to draw more current and hence provide more heat power into the oven. i.e. I will definately need a fan!
Then I did a quick test to see how quickly this heating element in this setup would heat the inside of the oven. It turned out to be about 2 degrees/minute, which is all I will need for my oven. And this is with a lower voltage (perhaps as low as half of the power), with the door ajar and with only a little insulation. But the load is lower (ie no mould inside the oven to heat up), but even still I think this power should be suffient. Note that I also have a second 200W heater if needed, but if I include that also I will need to make sure the power supply can deal with the current of both.
Belt and pulley drive system?
The thinking here was that it would be great to use a steel fan to avoid any chance of it melting in the oven, and this might allow us to work at higher temperatures down the line. I also wanted to try this with some quick experiments while the existing metal fan was connected in the oven casing I had, just to see if I could learn something. So with the help of my trusty CAD and 3DP guru Ollie we came up with a simple 1:1 pulley drive system to test it out
while we could get it to drive by hand and with the low speed motor (10s of RPM), there is far too much friction here, and the tension needed would mean that we'd really need to step down the motor to a slower speed, increasing the torque...but we do need a high speed (1000's of RMP), so this doesn't seem like it will work at all.
Time to change direction here, and accept the lower temperature cycles which is fine, and go with a plastic fan. To start with I'll experiment with an impeller and 9-24V DC RS-385SA permanent magnet brushed motor I pulled off an old hair dryer that I reverse engineered in class last year. Here's another useful link for it, and you can also get it from ebay for about £3...about It spins at 21,000 RPM and is a beauty! The next step is to design the housing for this.
Designing the heating assembly
Basic measurement and control
The next step was to get the relay working to allow me to control the heating. I had a REAL panic here, a bit of a brain explosion, thinking that I needed a 24 V relay to control the 24 V heating/fan system. Actually, I only needed the little 5 V relay that I'd been using all along, since it's the 5 V input that's specified, that's what counts. The output can be almost anything, AC, DC, and a wide range of voltages.
Here's the one I SHOULDN'T use.
Then I needed to get the temperature measured, so I could then control the heating using a basic bang-bang thermostatic control programme.
I should note that I had REAL issues here with the LM35 active temperature sensor. I thought I was doing myself a favour by starting with this, since it should have given a nice analog temperature reading without much fuss. The opposite was true, the readings were all over the place, and it was fiddly to work with (the female leads didn't connect to the pins).
So after a few hours of messing around with those guys, I went back to the old thermistors. I used a 100k Ohm NTC EPCOS 3950 thermistor that I bought from ebay. They were good because they had longer wires. Here are the specs:
Glass Encapsulated for Long Term Stability & Reliability Size: φ1.25mm×2.0mm Resistance Accuracy: 1% Temp. Range: −40°C to 270°C Lead (Pb)-free and RoHS Compliant 1m wire Head diameter: 1.2mm Resistance: 100Kohm + / -1% B value: 3950 + / -1% Accuracy: + / -1% Lead Length: 32 + /-5mm Operating temperature range:-50~+260°C Thermal time constant (τ): τ=10 - 17 s ( in still air) Thermal dissipation constant (δ): δ=1.1 - 1.6mW/°C ( in still air) Operating temperature range:-50~+260°C Insulation resistance 50MΩ or over by DC500V megge (between glass and lead wire)
Programming the 0.96" I2C Serial 128X64 4-pin OLED LCD Display
It was a bit of a faff to get the OLED working, mostly because all the syntax was all completely new to me. It took about 3 hours from start to finish. I downloaded and added the U8g2 libraries (Sketch > include libraries > ZIP) from here.It also has some good examples in there, e.g. Printing hello world was the first one I used. Here is the code that worked for me:
/* HelloWorld.ino Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/) Copyright (c) 2016, olikraus@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include#include #ifdef U8X8_HAVE_HW_SPI #include #endif #ifdef U8X8_HAVE_HW_I2C #include #endif U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 3, 2); //this is the constructor for my OLED. Note that the U8G2_R0, and U8X8_PIN_NONE are options that can vary the display e.g. rotation, starting point. Pin 3=SCL, Pin2=SDA. /* U8glib Example Overview: Frame Buffer Examples: clearBuffer/sendBuffer. Fast, but may not work with all Arduino boards because of RAM consumption Page Buffer Examples: firstPage/nextPage. Less RAM usage, should work with all Arduino boards. U8x8 Text Only Example: No RAM usage, direct communication with display controller. No graphics, 8x8 Text only. This is a page buffer example. */ void setup(void) { u8g2.begin(); } void loop(void) { u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,24,"Hello World!"); } while ( u8g2.nextPage() ); //delay(1000); }
Note that the following code is needed after the u8g2.begin(); in the void setup(). This allows us to print variables.
u8g2.enableUTF8Print();
I thought I'd take stock, I've now managed to get the screen working, displaying the current temperature, and the set temperature (currently this a set value defined in the code, but using buttons to set the set temperature is the next step!). Here's the code for this, noting that the OLED works, the LEDs come on/off as I'd like, the thermistor reads the temperature nicely, the relay
It's also worth noting that I had a problem with some of the LEDs not being as bright as the others, and it's because I didn't define them as OUTPUT pins in the setup!!! e.g. pinMode(powerledPin,OUTPUT);
Here's the code that's working so far.
#include#include #ifdef U8X8_HAVE_HW_SPI #include #endif #ifdef U8X8_HAVE_HW_I2C #include #endif U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 3, 2); const int relayPin = 12; const int powerledPin = 13; const int heaterledPin = 5; const int programmedledPin = 10; int powerled = HIGH ; int heaterled = HIGH; int programmedled = HIGH; int setTemp = 35; int ThermistorPin = A1; int Vo; float R1 = 10000; float logR2, R2, T; float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07; float powervoltage=5;//define the power supply voltage. void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); pinMode(relayPin,OUTPUT); pinMode(powerledPin,OUTPUT); pinMode(heaterledPin,OUTPUT); pinMode(programmedledPin,OUTPUT); u8g2.begin(); u8g2.enableUTF8Print(); } // the loop routine runs over and over again forever: void loop() { u8g2.firstPage(); digitalWrite(powerledPin,HIGH); Vo = analogRead(ThermistorPin); R2 = R1 * (1023.0 / (float)Vo - 1.0); logR2 = log(R2); T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); T = T - 273.15; Serial.print("Temperature: "); Serial.println(T); // read the input on analog pin 0: //int sensorValue = analogRead(A1); // print out the value you read: //Serial.println(sensorValue); int counter=0; //If there is a big sound nearby, make the led light for one second. if(T LESS THAN SYMBOL setTemp) { digitalWrite(12,HIGH); digitalWrite(heaterledPin,HIGH); digitalWrite(programmedledPin,HIGH); } else { digitalWrite(12,LOW); digitalWrite(heaterledPin,LOW); } do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,25,"Current: "); u8g2.setCursor(70, 25); u8g2.print(T); u8g2.drawStr(0,50,"Set: "); u8g2.setCursor(70, 50); u8g2.print(setTemp); } while ( u8g2.nextPage() ); delay(2000); }
Noting that I've now solved the LED brightness inconsistencies as mentioned above, by declaring the OUTPUT (and also now the INPUT) pins as OUTPUT/INPUT.
Programming the buttons
First things first, it's worth me noting what the button pins are:
mode button = pin A5; linked to LED = pin 13 (toggle between modes) up button = pin A4 down button = pin A3
The first step here was the modify the generic arduino tutorial example for Debounce to include TWO buttons, one for my DOWN and one for my UP button. With a bit of tweaking I managed to get this to work, without too many hiccups. I did have a REAL fright though, as after trying to load a programme (one using the screen) the arduino IDE started to NOT recognise my board. But I re-burned the bootloader, and it seemed to start working again. Phew!
Here's the test code I used to get the counter to go up and down with the up/down buttons. THis could be easily transferred to my 'setTemp' variable, to define the target temperature for the oven when it's on the manual control setting.
// constants won't change. They're used here to set pin numbers: const int downbuttonPin = A4; // the number of the pushbutton pin const int upbuttonPin = A3; // the number of the pushbutton pin const int ledPin = 13; // the number of the LED pin // Variables will change: int ledState = HIGH; // the current state of the output pin int downbuttonState; // the current reading from the input pin int lastdownbuttonState = LOW; // the previous reading from the input pin int upbuttonState; // the current reading from the input pin int lastupbuttonState = LOW; // the previous reading from the input pin int counter; // the following variables are unsigned longs because the time, measured in // milliseconds, will quickly become a bigger number than can be stored in an int. unsigned long lastdownDebounceTime = 0; // the last time the output pin was toggled unsigned long downdebounceDelay = 50; // the debounce time; increase if the output flickers unsigned long lastupDebounceTime = 0; // the last time the output pin was toggled unsigned long updebounceDelay = 50; // the debounce time; increase if the output flickers void setup() { pinMode(downbuttonPin, INPUT); pinMode(upbuttonPin, INPUT); pinMode(ledPin, OUTPUT); // set initial LED state digitalWrite(ledPin, ledState); } void loop() { // read the state of the switch into a local variable: int downreading = digitalRead(downbuttonPin); int upreading = digitalRead(upbuttonPin); // check to see if you just pressed the button // (i.e. the input went from LOW to HIGH), and you've waited long enough // since the last press to ignore any noise: // If the switch changed, due to noise or pressing: if (downreading != lastdownbuttonState) { // reset the debouncing timer lastdownDebounceTime = millis(); } if ((millis() - lastdownDebounceTime) > downdebounceDelay) { // whatever the reading is at, it's been there for longer than the debounce // delay, so take it as the actual current state: // if the button state has changed: if (downreading != downbuttonState) { downbuttonState = downreading; // only toggle the LED if the new button state is HIGH if (downbuttonState == HIGH) { ledState = !ledState; counter=counter + 1; Serial.println(counter); } } } // set the LED: digitalWrite(ledPin, ledState); // save the reading. Next time through the loop, it'll be the lastdownbuttonState: lastdownbuttonState = downreading; ////UP BUTTON STARTS HERE if (upreading != lastupbuttonState) { // reset the debouncing timer lastupDebounceTime = millis(); } if ((millis() - lastupDebounceTime) > updebounceDelay) { // whatever the reading is at, it's been there for longer than the debounce // delay, so take it as the actual current state: // if the button state has changed: if (upreading != upbuttonState) { upbuttonState = upreading; // only toggle the LED if the new button state is HIGH if (upbuttonState == HIGH) { ledState = !ledState; counter=counter - 1; Serial.println(counter); } } } // set the LED: digitalWrite(ledPin, ledState); // save the reading. Next time through the loop, it'll be the lastdownbuttonState: lastupbuttonState = upreading; }
I then rolled this out to the wider programme to control the temperature using a simple thermostatic control programme, including the OLED screen too. I also updated the screen settings to not include a remaining time line. One issue I have is that it refreshes too quickly (40ms), and I can't slow this down (yet...it's late! maybe tomorrow). The issue is that I can't delay the programme, otherwise it will miss the event if I press the button....anyways, the rest of it seems to work well, reading temperature, turning on/off the relay, displaying it all on the OLED, buttons working to increase/decrease the Target temperature. Here is the .ino file to download and here's the working code in full:
/* This programme uses the 85 degree low temperature curing cycle to programme the Atmega32U4 chip on the carbon ply carbon fibre curing oven. */ #include#include #ifdef U8X8_HAVE_HW_SPI #include #endif #ifdef U8X8_HAVE_HW_I2C #include #endif //constructor for the OLED screen U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 3, 2); //defining the constant variables for the pins const int relayPin = 12; const int powerledPin = 13; const int heaterledPin = 5; const int programmedledPin = 10; const int modebuttonPin = A5; const int downbuttonPin = A4; const int upbuttonPin = A3; const int ThermistorPin = A1; //turning on the power LED and programmed LED int powerled = HIGH ; int heaterled = LOW; int programmedled = HIGH; int timeMins = 0; //current time in minutes int timeLeft = 900; //amount of time left in programme. //variables for button press/debounce int downbuttonState; // the current reading from the input pin int lastdownbuttonState = LOW; // the previous reading from the input pin int upbuttonState; // the current reading from the input pin int lastupbuttonState = LOW; // the previous reading from the input pin // the following variables are unsigned longs because the time, measured in // milliseconds, will quickly become a bigger number than can be stored in an int. unsigned long lastdownDebounceTime = 0; // the last time the output pin was toggled unsigned long downdebounceDelay = 50; // the debounce time; increase if the output flickers unsigned long lastupDebounceTime = 0; // the last time the output pin was toggled unsigned long updebounceDelay = 50; // the debounce time; increase if the output flickers //set initial target temperature int setTemp = 20; //may need to be float in some programmes? //set initial variables used to calculate temperature int Vo; float R1 = 10000; float logR2, R2, T; float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07; float powervoltage=5;//define the power supply voltage. //SETUP void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); //Define pins to be used as output pinMode(relayPin,OUTPUT); pinMode(powerledPin,OUTPUT); pinMode(heaterledPin,OUTPUT); pinMode(programmedledPin,OUTPUT); //Define pins to be used as input pinMode(modebuttonPin,INPUT); pinMode(downbuttonPin,INPUT); pinMode(upbuttonPin,INPUT); pinMode(ThermistorPin, INPUT); //initialise the u8g2 OLED screen u8g2.begin(); //allow printing of variables on the screen u8g2.enableUTF8Print(); } // the loop routine runs over and over again forever: void loop() { digitalWrite(powerledPin,HIGH); digitalWrite(programmedledPin,LOW); int downreading = digitalRead(downbuttonPin); int upreading = digitalRead(upbuttonPin); Vo = analogRead(ThermistorPin); R2 = R1 * (1023.0 / (float)Vo - 1.0); logR2 = log(R2); T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); T = T - 273.15; //T=23.5; //Serial.print("Temperature: "); //Serial.println(T); timeMins = millis()/1000/60; //setTemp = 20; Serial.println(setTemp); if(T (less than)setTemp) { digitalWrite(relayPin,HIGH); digitalWrite(heaterledPin,HIGH); } else { digitalWrite(relayPin,LOW); digitalWrite(heaterledPin,LOW); } //display current and set temperatures u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,20,"Current: "); u8g2.setCursor(70, 20); u8g2.print(T,1); u8g2.drawStr(100,20,"C"); u8g2.drawStr(0,40,"Target: "); u8g2.setCursor(70, 40); u8g2.print(setTemp); u8g2.drawStr(100,40,"C"); //u8g2.drawStr(0,60,"Remain:"); //u8g2.setCursor(70, 60); //u8g2.print(timeLeft); //u8g2.drawStr(100,60,"mins"); } while (u8g2.nextPage()); delay(40); //BUTTON PRESS SECTION // check to see if you just pressed the button // (i.e. the input went from LOW to HIGH), and youve waited long enough // since the last press to ignore any noise: // If the switch changed, due to noise or pressing: //DOWN BUTTON SECTION if (downreading != lastdownbuttonState) { // reset the debouncing timer lastdownDebounceTime = millis(); } if ((millis() - lastdownDebounceTime) > downdebounceDelay) { // whatever the reading is at, it's been there for longer than the debounce // delay, so take it as the actual current state: // if the button state has changed: if (downreading != downbuttonState) { downbuttonState = downreading; // only toggle the LED if the new button state is HIGH if (downbuttonState == HIGH) { //ledState = !ledState; setTemp=setTemp - 1; Serial.println(setTemp); delay(1200); } } } // set the LED: //digitalWrite(ledPin, ledState); // save the reading. Next time through the loop, it'll be the lastdownbuttonState: lastdownbuttonState = downreading; //UP BUTTON STARTS HERE if (upreading != lastupbuttonState) { // reset the debouncing timer lastupDebounceTime = millis(); } if ((millis() - lastupDebounceTime) > updebounceDelay) { // whatever the reading is at, it's been there for longer than the debounce // delay, so take it as the actual current state: // if the button state has changed: if (upreading != upbuttonState) { upbuttonState = upreading; // only toggle the LED if the new button state is HIGH if (upbuttonState == HIGH) { //ledState = !ledState; setTemp=setTemp + 1; Serial.println(setTemp); delay(1200); } } } // set the LED: //digitalWrite(ledPin, ledState); // save the reading. Next time through the loop, itll be the lastdownbuttonState: lastupbuttonState = upreading; }
The next step was to create a separate programme that was the 85degree low temperature curing cycle. I plan to integrate it with the above programme, using a hold button for 3 seconds to switch modes, but for the time being I'll keep them separate to keep the code manageable. Below is the full working code to go through the full 15-hour low-temperature curing cycle, and here is the .ino file to download.
/* This programme uses the 85 degree low temperature curing cycle to programme the Atmega32U4 chip on the carbon ply carbon fibre curing oven. */ #include#include #ifdef U8X8_HAVE_HW_SPI #include #endif #ifdef U8X8_HAVE_HW_I2C #include #endif //constructor for the OLED screen U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE, 3, 2); //defining the constant variables for the pins const int relayPin = 12; const int powerledPin = 13; const int heaterledPin = 5; const int programmedledPin = 10; const int modebuttonPin = A5; const int downbuttonPin = A4; const int upbuttonPin = A3; const int ThermistorPin = A1; //turning on the power LED and programmed LED int powerled = HIGH ; int heaterled = LOW; int programmedled = HIGH; int timeMins = 0; //current time in minutes int timeLeft = 900; //amount of time left in programme. //set initial target temperature int setTemp = 0; //may need to be float in some programmes? //set initial variables used to calculate temperature int Vo; float R1 = 10000; float logR2, R2, T; float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07; float powervoltage=5;//define the power supply voltage. //SETUP void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); //Define pins to be used as output pinMode(relayPin,OUTPUT); pinMode(powerledPin,OUTPUT); pinMode(heaterledPin,OUTPUT); pinMode(programmedledPin,OUTPUT); //Define pins to be used as input pinMode(modebuttonPin,INPUT); pinMode(downbuttonPin,INPUT); pinMode(upbuttonPin,INPUT); pinMode(ThermistorPin, INPUT); //initialise the u8g2 OLED screen u8g2.begin(); //allow printing of variables on the screen u8g2.enableUTF8Print(); } // the loop routine runs over and over again forever: void loop() { digitalWrite(powerledPin,HIGH); digitalWrite(programmedledPin,HIGH); Vo = analogRead(ThermistorPin); R2 = R1 * (1023.0 / (float)Vo - 1.0); logR2 = log(R2); T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); T = T - 273.15; //T=45; //Just used for debugging Serial.print("Temperature: "); Serial.println(T); timeMins = millis()/1000/60; setTemp = 20; //enter first ramp up to 70degC at 1deg/min increments while (setTemp less than 70){ setTemp = setTemp+1; timeLeft=900-setTemp; Serial.println(setTemp); int counter = 1; //begin thermostatic loop with 1.2 second cycle while (counter less than= 50){ if(T less than setTemp){ digitalWrite(relayPin,HIGH); digitalWrite(heaterledPin,HIGH); } else { digitalWrite(relayPin,LOW); digitalWrite(heaterledPin,LOW); } //display current and set temperatures u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,20,"Current: "); u8g2.setCursor(70, 20); u8g2.print(T,1); u8g2.drawStr(100,20,"'C"); u8g2.drawStr(0,40,"Target: "); u8g2.setCursor(70, 40); u8g2.print(setTemp); u8g2.drawStr(100,40,"'C"); u8g2.drawStr(0,60,"Remain:"); u8g2.setCursor(70, 60); u8g2.print(timeLeft); u8g2.drawStr(100,60,"mins"); } while (u8g2.nextPage()); delay(1200); counter=counter + 1; } } //hold at 70 degrees until 4h50mins while (timeMins less than 290){ setTemp = 70; timeMins = millis()/1000/60; Serial.println(setTemp); int counter = 1; //begin thermostatic loop with 1.2 second cycle while (counter <= 50){ if(T less than setTemp){ digitalWrite(relayPin,HIGH); digitalWrite(heaterledPin,HIGH); } else { digitalWrite(relayPin,LOW); digitalWrite(heaterledPin,LOW); } //display current and set temperatures u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,20,"Current: "); u8g2.setCursor(70, 20); u8g2.print(T,1); u8g2.drawStr(100,20,"'C"); u8g2.drawStr(0,40,"Target: "); u8g2.setCursor(70, 40); u8g2.print(setTemp); u8g2.drawStr(100,40,"'C"); u8g2.drawStr(0,60,"Remain:"); u8g2.setCursor(70, 60); u8g2.print(timeLeft); u8g2.drawStr(100,60,"mins"); } while (u8g2.nextPage()); delay(1200); counter=counter + 1; } } //ramp up to 85degC until 4h58 while (timeMins less than 298){ setTemp = setTemp+(2/12); timeMins = millis()/1000/60; Serial.println(setTemp); int counter = 1; //begin thermostatic loop with 1.2 second cycle while (counter less than = 50){ if(T less than setTemp){ digitalWrite(relayPin,HIGH); digitalWrite(heaterledPin,HIGH); } else { digitalWrite(relayPin,LOW); digitalWrite(heaterledPin,LOW); } //display current and set temperatures u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,20,"Current: "); u8g2.setCursor(70, 20); u8g2.print(T,1); u8g2.drawStr(100,20,"'C"); u8g2.drawStr(0,40,"Target: "); u8g2.setCursor(70, 40); u8g2.print(setTemp); u8g2.drawStr(100,40,"'C"); u8g2.drawStr(0,60,"Remain:"); u8g2.setCursor(70, 60); u8g2.print(timeLeft); u8g2.drawStr(100,60,"mins"); } while (u8g2.nextPage()); delay(1200); counter=counter + 1; } } //hold at 85 degrees until 14h15mins while (timeMins less than 855){ setTemp = 85; timeMins = millis()/1000/60; Serial.println(setTemp); int counter = 1; //begin thermostatic loop with 1.2 second cycle while (counter less than = 50){ if(T less than setTemp){ digitalWrite(relayPin,HIGH); digitalWrite(heaterledPin,HIGH); } else { digitalWrite(relayPin,LOW); digitalWrite(heaterledPin,LOW); } //display current and set temperatures u8g2.firstPage(); do { u8g2.setFont(u8g2_font_ncenB10_tr); u8g2.drawStr(0,20,"Current: "); u8g2.setCursor(70, 20); u8g2.print(T,1); u8g2.drawStr(100,20,"'C"); u8g2.drawStr(0,40,"Target: "); u8g2.setCursor(70, 40); u8g2.print(setTemp); u8g2.drawStr(100,40,"'C"); u8g2.drawStr(0,60,"Remain:"); u8g2.setCursor(70, 60); u8g2.print(timeLeft); u8g2.drawStr(100,60,"mins"); } while (u8g2.nextPage()); delay(1200); counter=counter + 1; } } //natural cool until 15 hours while (timeMins less than 900){ setTemp = 0; delay(60000); timeMins = millis()/1000/60; } setTemp = 0; }
PID temperature control
Here is the first attempt at using PID temperature control using the PID library in the Arduino IDE.
And here's the code for this.
#include#define RelayPin 12 //Define Variables we'll be connecting to double Setpoint, Input, Output; int Vo; float R1 = 10000; float logR2, R2, T, rawdata; float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07; float powervoltage=5;//define the power supply voltage. const int ThermistorPin = A1; //Specify the links and initial tuning parameters PID myPID(andInput, andOutput, andSetpoint, 2, 5, 1, DIRECT); int WindowSize = 5000; unsigned long windowStartTime; void setup() { pinMode(RelayPin, OUTPUT); windowStartTime = millis(); //initialize the variables we're linked to Setpoint = 30; //tell the PID to range between 0 and the full window size myPID.SetOutputLimits(0, WindowSize); //turn the PID on myPID.SetMode(AUTOMATIC); } void loop() { Vo = analogRead(ThermistorPin); R2 = R1 * (1023.0 / (float)Vo - 1.0); logR2 = log(R2); T = (1.0 / (c1 + c2*logR2 + c3*logR2*logR2*logR2)); T = T - 273.15; Input = T; myPID.Compute(); /************************************************ turn the output pin on/off based on pid output ************************************************/ unsigned long now = millis(); if (now - windowStartTime > WindowSize) { //time to shift the Relay Window windowStartTime += WindowSize; } if (Output > now - windowStartTime) digitalWrite(RelayPin, HIGH); else digitalWrite(RelayPin, LOW); delay(500); Serial.println(T); }
And here's the direct comparison with bang-bang, which was noticably quicker to reach the set temperature of 30 degrees.
Here's a graph of the comparison, showing that a) the PID took MUCH longer to get up to the target temperature, and b) that the PID steady state value (with the current control variables) was actually not quite as good as the original bang-bang!
And here is the spreadsheet with the raw data for downloading.
Fabricating casing and assembling product
One of the most important functional tests was to get the PCB mounted with the front sub-panel. So I laser cut a thinner panel to mount the PCB on (3mm MDF), so it could be slotted into the main front panel (12mm).
This allowed me to test the buttons, the OLED, and how this all sat within the main casing assembly.
And you can download the buttons.stl file here.
Time to start cutting the panels for the casing, which I used 12mm MDF, with a simple finger jointed construction.
Then to test the front panel, to make sure the buttons slide in and out freely enough. I also printed some grey, more rubbery buttons that were all tied together with a plate at the back. This was too stiff, so when one button was pressed, all were pressed, so I ended up using these but cutting them into separate buttons.
Then to test the positioning and mounting of the PCB behind the front panel with regard to the mounting holes, the LED connecting tubes and the buttons too.
I had to adjust the front panel to get things to fit meaning I had to remove (for the time being) the text for the LEDs which was a shame, but is something I'll add back into mach 2.
Then I created a simple mount to sit behind the OLED to stop the pins from bending and to protect it from being pushed back behind the front panel. Here it is screwed in behind the OLED.
Front panel testing to make sure things can move uninhibited.
Then to put all the panels together. Our G-clamps wouldn't go around the length and girth of the casing, so I used some reasonable masses to press down and hold it together while it set with PVA.
Then to test that the buttons, to make sure it all works together, and the PCB holds in place when the buttons are pressed against it. Few!
Once the front panel and the route for the cabling had been fully tested I could glue it all together and voila!
I then did some basic functional tests to check that the mould we firstly want to test that it fits inside and can be connected to the vacuum pump with some room to spare.
And you can download a .zip file with all the CAD part+assembly files in here.
Full bill of materials (BOM) and parts made
Raw materials and components, sources and costs...Bill of Materials
Classification | Part name | Source | Cost per item | Number required |
---|---|---|---|---|
ELECTRONICS | ATMega32U4 | FABLAB INVENTORY | £3.32 | 1 |
RED LEDS: 1206 | FABLAB INVENTORY | £0.24 | 3 | |
22 OHM RESISTOR: RES-US1206FAB | FABLAB INVENTORY | £0.007 | 2 | |
499 OHM 1206 RESISTOR | FABLAB INVENTORY | £0.007 | 3 | |
RES-US1206FAB 680 OHM RESISTOR | FABLAB INVENTORY | £0.007 | 1 | |
10K OHM RESISTOR1206 RESISTOR | FABLAB INVENTORY | £0.007 | 3 | |
10uF CAP-US1206FAB CAPACITORS | FABLAB INVENTORY | £0.24 | 1 | |
1uF CAP-US1206FAB CAPACITORS | FABLAB INVENTORY | £0.24 | 2 | |
0.1uF CAP-US1206FAB CAPACITORS | FABLAB INVENTORY | £0.24 | 1 | |
18pF CAP-US1206FAB CAPACITORS | FABLAB INVENTORY | £0.24 | 2 | |
CSM-7X-DU 16 MHZ CRYSTAL | FABLAB INVENTORY | £0.88 | 1 | |
MINI-B USB CONNECTOR | FABLAB INVENTORY | £0.77 | 1 | |
CONNECTORS (FTDI) | FABLAB INVENTORY | £0.02 | 1 | |
SPST_TACT-EVQQ2 BUTTONS | FABLAB INVENTORY | £0.34 | 3 | |
24V 10 A RELAY | EBAY | £3.23 | 1 | |
6 pin OLED SCREEN | amazon | £4.95 | 1 | |
HEATING SYSTEM | MAO5 - 5 V DC FAN | EBAY | £4.49 | 1 |
24 V DC, 10 A HEATING ELEMENT | EBAY | £4.88 | 1 | |
24 V DC, 10 A Universal Regulated Switching Power Supply | INDUSTRY MALL - EBAY - https://www.ebay.co.uk/itm/181881169501 | £12.99 | 1 | |
3pin active temperature sensor | ebay | £0.96 | 1 | |
MAIN CASING | 13 MM HIGH TEMPERATURE INSULATION, 6 X 61cm x 366cm x 13mm | EBAY | £30.00 | 1 |
MAIN CASING | CARBON FIBRE VINYL COATING | EBAY | £6.26 | 1 |
what parts and systems will be made? and what processes will be used? Fabrication processes and materials
Sub assembly | Part name | Material | Fabrication process | Number required |
---|---|---|---|---|
MAIN_CASING | FRONT_CONTROL_PANEL | 2 MM PLY | LASER CUT | 1 |
FRONT_CONTROL_PANEL | 2 MM PLY | LASER CUT | 1 | |
FRONT_TOP_PANEL | 2 MM PLY | LASER CUT | 1 | |
FRONT_BOTTOM_PANEL | 2 MM PLY | LASER CUT | 1 | |
SIDE_PANEL | 2 MM PLY | LASER CUT | 2 | |
BACK_PANEL | 2 MM PLY | LASER CUT | 1 | |
TOP_PANEL | 2 MM PLY | LASER CUT | 1 | |
BOTTOM_PANEL | 2 MM PLY | LASER CUT | 1 | |
BUTTONS | SILICONE | CAST | 1 (3 BUTTONS) | |
FEET | PLA | 3D PRINTED | 4 | |
HEATING SYSTEM | 2 MM PLY | LASER CUT | 1 |
Logo design and fabrication
I thought it would be a nice touch to make a few 3D logos to put on the final product, using a variety of techniques, so I did this as part of the moulding and casting week, but I also made a 3D printed version.
Future developments
I really want to expand this to build more of this myself in the future, and one of the things I'd love to try is to make my own heating elements by winding Nichrome wire. Here are a couple of really great video resources. THe second video is of someone who built their own foundry - lots of good lessons from there!
I might also include other things into the final project as part of this suite of resources:
some links:
- good project in terms of presentation, and light display http://archive.fabacademy.org/archives/2016/fablabtorino/students/440/project/P03/present.html
- open source PID controller: https://makezine.com/2012/01/11/open-source-pid-controller/
- PID controlled oven: http://www.instructables.com/id/PID-Temperature-Controlled-Oven/
- Interesting paper on testing smart thermostats: file:///Users/macbook/Downloads/sustainability-09-01462-v2.pdf
Licencing statement
(c) June 2018. This work may be reproduced, modified, distributed, performed, and displayed for any purpose, but must acknowledge "Carbon Ply". Copyright is retained and must be preserved. The work is provided as is; no warranty is provided, and users accept all liability.
Acknowledgements
A big thank you to all who have supported me throughout this journey this year: it has been enriching, enjoyable and challenging. So a big thank you to...
- my wife Sarah, daughter Ellen and new son Joshua, your patience and support has got me through this.
- Luiz, for your tireless efforts to support us all, your clarity of mind and innovation to help solve problems...and willingness to be a sounding board for my many underdeveloped lines of thinking.
- Kelly, for all your support and guidance...and for finding a way to give us all this opportunity in the first place!
- Steven, for his unwavering support, flexibility and willingness to cover my back to help me squeeze this in.
- Ollie, for his unflinching support to help design and make parts almost instantly on demand that are right first time, and for his constant stream of innovative ideas.
- Jon and Gary for their regular support and advice throughout.
- all my fablab colleagues - now friends, I have thoroughly enjoyed working with you, I have learned a huge amount from all of you, and look forward to working with you all in the future!