Monday, December 14, 2015

DIY Hot End - Arduino PID control






So I really want a 3D printer.  I am creating some components to mount on my mill as a printing kit.  Possibly something usable by others?  This is how attempted to create my first hot end.

What is a hot end?

This part of a 3d printer is the melting point of the print media.  Most are a print nozzle and heater mounted in an aluminum block.  The media is feed into this block and the media in liquid form comes out the nozzle. I was shocked at the size of the nozzle.  REALLY small.  There is a tube to feed media that is cooled to ensure media melts only near the nozzle.  Fans are typical on the heat sink.


Hot End Hardware

I purchased a low cost clone hot end from amazon.  My thoughts were that I could learn something from a fairly inexpensive product.  The heater is 40 Watt and it contains a 100KOhm 3950 thermistor.


Arduino Hot Heat Control

The next step was how to control the temperature of the hot end.  I had an Arduino Yun available.

 ArduinoYun Official Site


The following is how I fulfilled my fulfill my requirements.

Temperature Measurement 

I have to know the temperature before I can control it. A thermistor (pre-installed in hot end) basically is a resistor that changes value (non-linearly) bases on the temperature.  I found a great explanation of them and how to measure with the arduino. Thanks to 'lady ada' for all the great input.  Well written article. See: How to connect and measure a thermistor with an arduino.   I used a 10K balance resistor.  I do not believe my temperatures are ready correct values yet but the values are moving as I would expect.  I will figure out the scaling and report back. If I build the next hot end it will contain a thermocouple.

<Need Photo of the thermistor here...>

Control of the heater output

The 12VDC 40W heater needs to be regulated.  The cheapest/simplest method I could find was to use a TIP120 NPN transistor.  They are really common and handle a fair amount of power.  I found a great blog/explanation here: How to switch higher current loads with a transistor and arduino.  I use the PWM output to switch the transistor using the built in Arduino PWM.  This seems to work well.  I put an LED between the Output pin and ground to give general visual indication of the output.  The load power is 12VDC.  I also paralleled a small case fan with the 40W heater.  I will most likely move this to another output and base the speed on temperature instead of heater current but I like seeing it spin up and then stop.

<Need photo of the heater here...>

As suggested in the comments, I have updated this project to use a MOSFET. I learned about using them here: High-Power Control: Arduino + N-Channel MOSFET.  I have found it allows more current flow and better heat control.  I used a BUZ91A (amazon item)

A control logarithm (Arduino PID)

The Arduino PID control library is mature and there are some great explanations/insights available.  I learned reading Improving the Beginner’s PID – Introduction.  I am still working on the tuning.  I also created a simple sketch based on the Arduino AutoTune library.  Another great post/tutorial  from the same author (much thanks Brett Beauregard) here that demonstrates his code.  I played with this for a while to get it to work.  You want to play with the step and start point so that the loop can move the output and see resultant changes.  That is how it learns (I think).  Again, I am still tuning/learning but my loop trains in on a temperature quickly enough and stabilizes very well.

Side Note:

Notice the PID goes to full scale (255 is max) in a few seconds of a change.  I think I like this response because I'm sure the plastic melting load will be significant.  I would say starting, stopping and speed changes is when the temperature will be an issue.

Communications of setpoint and status

I use the basic USB serial communications of the Arduino for the moment.  The unit constantly ouputs the current temp, current heater output level and current set point.  The arduino also listens for a single input value that it sets as the new set point when it receives. The near future plan is to add a Rasberry pi to the mill.  Hopefully it will control this set point using a Web API published through the Yun's web functionality.

Notice the PID goes to full scale (255 is max) in a few seconds.  I like this response because I'm sure the plastic melting load will be significant.  I would say starting, stopping and speed changes is when the temperature will be an issue.





Arduino Sketch

This should run on any Arduino.. Enjoy.  Let me know if does you any good and please share improvements.

#include <PID_v1.h>
// Analog output pin
#define outputPin 9
// thermistor analog pin
#define THERMISTORPIN A0
// how many samples to take and average
#define NUMSAMPLES 5
// how long between pid/sampling
#define SAMPLETIME 1000
//Define Variables we'll be connecting to
double Setpoint, currentTemp, Output;
//Specify the links and initial tuning parameters
PID myPID(&currentTemp, &Output, &Setpoint,15,.3,0, DIRECT);
void setup() {
  Serial.begin(9600);
  analogReference(EXTERNAL);
  pinMode(outputPin, OUTPUT);
  //initialize PID setpoint *C
  Setpoint = 110;
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetSampleTime(SAMPLETIME);
  //pid Autotuner
}
void loop() {
  if (Serial.available() > 0) {
    // get incoming byte:
    Setpoint = Serial.parseFloat();
  }
  uint8_t i;
  double average = 0;
  // take N samples in a row, with a slight delay
  for (i = 0; i < NUMSAMPLES; i++) {
    average += analogRead(THERMISTORPIN);
    delay(10);
  }
  average /= NUMSAMPLES;
  currentTemp=resistanceToC(inputToResistance(average));
  myPID.Compute();
  analogWrite(outputPin, Output);

  Serial.print("Set Point: ");
  Serial.print(Setpoint);
  Serial.println(" *C)");
  Serial.print("Temperature: ");
  Serial.print(currentTemp);
  Serial.println(" *C)");
  Serial.print("PID output ");
  Serial.println(Output);
  delay(SAMPLETIME);
}
double inputToResistance(double input) {
  // funtion to convert the input value to resistance
  // the value of the 'other' resistor
  double SERIESRESISTOR = 10000;
  input = 1023 / input - 1;
  return SERIESRESISTOR / input;
}
double resistanceToC(double resistance) {
  // funtion to convert resistance to c
  // temp/resistance for nominal
  double THERMISTORNOMINAL = 118000;
  double TEMPERATURENOMINAL = 25;
  // beta coefficent
  double BCOEFFICIENT = 3950;
  double steinhart;
  steinhart = resistance / THERMISTORNOMINAL;     // (R/Ro)
  steinhart = log(steinhart);                  // ln(R/Ro)
  steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
  steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
  steinhart = 1.0 / steinhart;                 // Invert
  steinhart -= 273.15;   // convert to C
  return steinhart;
}



Basic Diagram


I love EasyEDA.  I will probably order a custom board once I add a few more options to the prototype.  See the diagram in an editable link here: Mill Hot End Control







Looks like this is going to work well.  I may update the post as progress is made.  Thanks for all the great input from those mentioned above and elsewhere.