HT oven frame voltage-carrying

Joined
Mar 30, 2016
Messages
25
Hello,

since it's my first post, i'd like to introduce myself.
I'm Tolga, 24 years old and from Germany. I've started with knifemaking as a hobby in january this year.

Now to my problem. I built a heat treat oven out of "Schuba FLS L4S" Stones, the Datasheet is linked here http://www.schuba-shop.com/WebRoot/...06-100640104_FF-FL-Stein_L4S_250x124x64mm.pdf .

To give you a view of my oven, i've attached two pictures.
IMG-20160717-WA0017_zpst0e0tazd.jpeg

IMAG1442_zpshvieyqei.jpg


(On the right, there is a contact switch for the door. So no safety issue regarding this.)

Now it comes, that i measured the frame against ground (i didn't get a shock, i was just curious) and to my surprise, the voltage meter displayed 40V.
Since i do the Control and Temperaturemeasurement with an Arduino an a MAX31855 chip, an my chip says, that my type K thermocouple is grounded (which it souldn't be, i cant fin a reason for it) I measured the Voltage of the Thermocouple insulation, too. 140V.

At first, i looked for obvious faults, as the frame could be touching any volatge-carrying cable. But it isn't. The same for the Thermocoupleinsulation.

My second guess was, that the SiO2 in the stones gets conductive, when getting hot enough. But i couldn't measure any conductance of the stones.

My third guess is, that the heating elements are inducing a voltage into the frame and thermocouple. But for now i don't have a way to measure it.

Does any of you have made related experiences with his oven, and might be able to say, in which direction i should investigate?

With kind regards,

Tolga.
 
Last edited:
Welcome to the forums, Tolga. It would help to see how you wired and mounted the control box/PID.
 
Like Rick said, some wiring diagrams and photos of the control would help.

Some places to look:
Check that the TC is not a metal sheath type. It should be open wire, 8 to 10 gauge with ceramic insulators.

Check that the control is wired properly. It is possible to reverse two leads and put the voltage to ground. The circuit may still work fine, but there may be what is called a ground fault.

Make sure the wiring to the coils and SSR are all correct. With the power disconnected, take an ohms reading from them to ground. Neither should read any continuity to ground lower than a megohm. It really should read an open circuit.

Make sure all components are grounded to the same buss. If you read the voltage across two objects that are not grounded to each other, you can often read a significant voltage. This seems strange, but is called a floating ground. By physically grounding the objects together, the floating voltage will disappear.
 
Thank you for your answers so far.

I checked the control wiring. All leads are where they belong.

The Thermocouple is insulated with inconel 600 - Metaltype. Would it help just putting the TC in a ceramic sheath?

I need to check continuity from coils/ssr to ground, while power off.

All parts are grounded to one Bus. (Starground) But still, i'll check ground of everything again. (Regarding Stacys post, and Rick Marchands post below.)

Now the pictures of my wiring:

Controllbox
IMAG1380_zpsesjatwqe.jpg


Schematic
9f096577-16e7-4e24-8d51-df9c30c57bfd_zpsyyiq3vzy.jpg


Connection from controllbox to coils
IMG-20160717-WA0011_zpswdl1ulc3.jpeg


View of everything connected
IMG-20160717-WA0009_zps7gartheh.jpeg
 
Last edited:
Is your kiln frame also grounded? There could be, as Stacy mentioned, a floating ground. That is pretty much all I have to offer for advice. I just checked my kiln(Sugar Creek) and saw that everything, including the the metal sheathing/frame is grounded together
 
There may be something wrong with your measurement. As all part are grounded so even if there is a current leek to the frame it should be 0v on your meter. Unless ground and Neutral were mixed up.
 
Another thing to check: verify that on your outlet, gnd and neutral measure close to 0v. I used to live a a house with a disconnected ground, and it caused a lot of weird issues.

I don't see the ground in your diagram. Is your frame grounded? The frame measures 40v to what reference? If it's not grounded... well, it's dangerous to start with, but it can also be a meaningless voltage (high impedance).
 
The above comment about your ground source and the incoming voltage is one to check.

Also, the schematic shows a relay switch after a DPST main switch (this seems redundant). Check that there is not a shorted pin or internal short between the armature/coil and the DPST contacts. ( Note - This relay could have been eliminated by placing the door switch in the control out line from the Ardino to the SSR. The whole double main switch and relay are triple redundancy. It could have been done with a single main switch in the 72 volt incoming power line, and a door w=switch in the control circuit.).

Is this system running on US wiring, or on some other country? ( filling out your profile would have told me this)

Just a comment, but opening only one leg of the 230 volt line to the coils will leave the other leg hot. You are better off to use two SSRs. With your relay in the door interlock, you have avoided this, but it would have been simpler and cheaper to just use two SSRs.
 
Last edited:
Fwiw, details in the picture background say "Europe" the guys first message said Germany.

I agree, wiring scheme could be simplified & show or verify equipment grounding conductors exist.
 
Well, from what I can tell, you don't seem to have much in the way of sources for grounding your current carrying conductors. Even your control box seems to be made of plastic.

Are you using a digital meter to measure this voltage? It has the potential to be a ghost voltage, induced from the frame that runs parallel to the heaters, which are inductive.

Try measuring current to electrical ground, since current is the real danger, rather than a phantom potential. It would at least rule one thing out.
 
Last edited:
Thank you for all of your answers. I'm glad, that so many want to help me.

I use a digital multimeter, not capable of measuring current.

Things i have checked for now:

continuity from coils to frame while power of: fluctuating between 4Mohm - 30 Mohm - open circuit

continuity from coils/ssr to ground while power off: open circuit

Ground is connected on my outlet.

Is the frame conected to ground? It should be, but wasn't. The cable I used for grounding the frame was somehow damaged, what caused it to being grounded, and not grounded as i was shaking the cable. I changed it, and now i have no Voltage between the frame and ground.

Now to answer some of the other comments.

Im using german wiring with 230V.

There is a mistake in the drawing of my schematic. The voltage converter gets its voltage after the main switch. The Main switch is included in the power inlet of the box (box is out of plastic).
The reason i use an additional relais for turning off the coils is, that i don't believe semiconductors being failsafe. If they fail they tend to becoming conductive. So if i open the door, i don't want to have the possibility of having power on the coils. But Relais aren't that capable of being controlled by a PID so i use only one SSR for control. The additional Main switch for switching the relais (and by that the coils) on and off is used, because i want to be able to manually control if the coils are powered up without having the risk of getting shocked by leaking current cause of a faulty switch. The second advantage of one switch for general power and an other for manually powering up the coils is that i can read the temperature (voltage converter gets power and supplies the control circuit), while the coils aren't connencted.

Since the box is out of plastic, i use the screw holding the cooler of the ssr, as grounding point. From there it goes to the electric cable, connected to the ground of the house wiring.

Picture of the back of the box with cooler and power inlet with main switch.
IMAG1454_zpsm6buytww.jpg


Picture of the inside for showing grounding points (marked with arrows). The arrow above shows the ground connection to the electric cable (which connects to the power outlet of the house).
6033e87c-3261-48b3-8b06-02aa4cf8a03f_zpsabswnqkv.jpg


I missestimatd the size of the housing a lot. But that will be changed another time. For now it's ugly, but works.

The initial problems seems to be solved. I repaired the grounding of the frame and there is no voltage on the frame anymore.
What still bugs me is, that if the frame isn't connected to ground and the coils are turned off, the measurement says about 4 V. If the Coils are turned on, the voltagemeter says about 40V. So the next thing i need to do, is measuring the current of the frame to ground, and investigate the induced voltage by the magnetic field of the coils.
 
Last edited:
... So the next thing i need to do, is measuring the current of the frame to ground, and investigate the induced voltage by the magnetic field of the coils.
No... the next thing would be to harness the power, amplify it AND RULE THE WORLD! Muuha-ha-ha-ha-ha--ha, Muuuuuha-ha-ha-ha-ha.......
 
Actually, the next step is to ensure the ground is secure, run it from an RCD-protected supply (Residual Current Device = GFCI in American English?) and make some knives.

If you really must obsess about it, beg, steal, borrow or buy a clip-on ammeter and measure the current in the ground conductor while it is running. Do it at various temperatures and please let us know the results.

I've always grounded my frames and have therefore not seen the Voltage issue. I did some testing of one of my first ovens with a datalogger and found that the control thermocouple signal became noisy somewhere between the typical tempering range(<400 degC) and typical Austenitizing range (>780 degC) and remained noisy at the higher temperatures. I wondered at the time whether the IFB was becoming slightly conductive. I did not investigate further because the noise was having no apparent effect on performance and there was no safety issue with the frame grounded.

I'm with you on the whole not trusting SSRs to provide isolation thing. I always use a contactor for the same reason you do.

If you change the control enclosure, I'd recommend you use a steel one. It's better for grounding and much better for dissipating heat. Personally, I build the control boxes separate from the ovens and use plugs and sockets to connect everything (power, door switch & thermocouple). That way the same box can control anything I might want to build in the future.
 
Put like 1000ohm resistor between your frame and ground and measure the voltage drop. My guess is the current would be very small. Can you share your arduino code. Im doing same sort of project and looking for elimproment
 
Fortunately all outlets are protected by an RCD. I will definitively let you know about my investigations.

Yes, using a metal box, and plugs for connections was my initital plan, since it makes the whole thing easier. But I was running low on money, and wanted to finish the oven.

I was setting PID parameters and calibrating the themocouple with the curiepoint and NaCl yesterday. After that, i tested the oven on a piece of overheated O1. After thermal cyling and quenching, satisfyingly small grain and subjectively good hardness.

The code comes in a second answer, since the text would be too long.
 
Now to the Arduino Code. I didn't write much of it myself. I used most of the library examples, the linearization code from here https://learn.adafruit.com/calibrating-sensors/maxim-31855-linearization, the serial send/receive part from "br3ttb" from the "Processing Front-End for the PID Library" topic in an Arduino forum. On the time being I'm working on implementing an Autotune function, but it's not finished yet.

Code:
//PID and PID Autotune Library Initialization
#include <PID_v1.h>
#include <PID_AutoTune_v0.h>
#include <SPI.h>
#include "Adafruit_MAX31855.h"
#include <LiquidCrystal.h>
//
#define MAXDO   6
#define MAXCS   7
#define MAXCLK  8
#define relayPin 9
int referenceLow = 769; //for calibration I used the curie point and salt. Temperature is in Celsius.
int referenceHigh = 801;
int tempLow = 769;
int tempHigh = 820;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);
byte ATuneModeRemember=2;
double Input, Output, Setpoint=650; //KP Set initial Setpoint
double kp=10,ki=0.4,kd=0.1; //KP Set intial PID parameters, if you have any.

double kpmodel=1.5, taup=100, theta[50];
double OutputStart=5;

double aTuneStep=750, aTuneNoise=1, aTuneStartValue=750; //KP Set aTuneStep to ensure noticeable heating and cooling from aTuneStartValue
unsigned int aTuneLookBack=200; //KP How far back to look back to find maxima and minima. 
// For Slow processes this will be large, for fast processes, this will be smaller.

unsigned long  modelTime, serialTime;

PID myPID(&Input, &Output, &Setpoint,kp,ki,kd, DIRECT);
PID_ATune aTune(&Input, &Output);

//set to false to connect to the real world
boolean useSimulation = false; //KP Keep false unless simulating

//Tuning?
boolean tuning = false; //KP Keep False


int WindowSize = 1000;
unsigned long windowStartTime;

void setup()
{ 
  windowStartTime = millis();
  pinMode(relayPin, OUTPUT); //KP Set relayPin as Output
    pinMode(MAXCS, OUTPUT);
  pinMode(MAXCLK, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(relayPin, OUTPUT);
  lcd.begin(16, 2);
  if(useSimulation)
  {
    for(byte i=0;i<50;i++)
    {
      theta[i]=OutputStart;
    }
    modelTime = 0;
  }
  
  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);
  
  //Setup the pid 
  myPID.SetMode(AUTOMATIC);

  if(tuning)
  {
    tuning=false;
    changeAutoTune();
    tuning=true;
  }
  
  aTune.SetControlType(0); //KP Set 0 for PI control and 1 for PID control autotuning parameters
  
  serialTime = 0;
  Serial.begin(9600);

}

void loop()
{
          int i = 0; // Counter for arrays
       double internalTemp = thermocouple.readInternal(); // Read the internal temperature of the MAX31855.
       double rawTemp = thermocouple.readCelsius(); // Read the temperature of the thermocouple. This temp is compensated for cold junction temperature.
       double thermocoupleVoltage= 0;
       double internalVoltage = 0;
       double correctedTemp = 0;
 
        // Check to make sure thermocouple is working correctly.
       if (isnan(rawTemp)) {
        correctedTemp = 0;
      }
       else {
          // Steps 1 & 2. Subtract cold junction temperature from the raw thermocouple temperature.
          thermocoupleVoltage = (rawTemp - internalTemp)*0.041276;  // C * mv/C = mV
 
          // Step 3. Calculate the cold junction equivalent thermocouple voltage.
 
          if (internalTemp >= 0) { // For positive temperatures use appropriate NIST coefficients
             // Coefficients and equations available from http://srdata.nist.gov/its90/download/type_k.tab
 
             double c[] = {-0.176004136860E-01,  0.389212049750E-01,  0.185587700320E-04, -0.994575928740E-07,  0.318409457190E-09, -0.560728448890E-12,  0.560750590590E-15, -0.320207200030E-18,  0.971511471520E-22, -0.121047212750E-25};
 
             // Count the the number of coefficients. There are 10 coefficients for positive temperatures (plus three exponential coefficients),
             // but there are 11 coefficients for negative temperatures.
             int cLength = sizeof(c) / sizeof(c[0]);
 
             // Exponential coefficients. Only used for positive temperatures.
             double a0 =  0.118597600000E+00;
             double a1 = -0.118343200000E-03;
             double a2 =  0.126968600000E+03;
 
 
             // From NIST: E = sum(i=0 to n) c_i t^i + a0 exp(a1 (t - a2)^2), where E is the thermocouple voltage in mV and t is the temperature in degrees C.
             // In this case, E is the cold junction equivalent thermocouple voltage.
             // Alternative form: C0 + C1*internalTemp + C2*internalTemp^2 + C3*internalTemp^3 + ... + C10*internaltemp^10 + A0*e^(A1*(internalTemp - A2)^2)
             // This loop sums up the c_i t^i components.
             for (i = 0; i < cLength; i++) {
                internalVoltage += c[i] * pow(internalTemp, i);
             }
                // This section adds the a0 exp(a1 (t - a2)^2) components.
                internalVoltage += a0 * exp(a1 * pow((internalTemp - a2), 2));
          }
          else if (internalTemp < 0) { // for negative temperatures
             double c[] = {0.000000000000E+00,  0.394501280250E-01,  0.236223735980E-04 - 0.328589067840E-06, -0.499048287770E-08, -0.675090591730E-10, -0.574103274280E-12, -0.310888728940E-14, -0.104516093650E-16, -0.198892668780E-19, -0.163226974860E-22};
 
             // Count the number of coefficients.
             int cLength = sizeof(c) / sizeof(c[0]);
 
             // Below 0 degrees Celsius, the NIST formula is simpler and has no exponential components: E = sum(i=0 to n) c_i t^i
             for (i = 0; i < cLength; i++) {
                internalVoltage += c[i] * pow(internalTemp, i) ;
             }
          }
 
          // Step 4. Add the cold junction equivalent thermocouple voltage calculated in step 3 to the thermocouple voltage calculated in step 2.
          double totalVoltage = thermocoupleVoltage + internalVoltage;
 
          // Step 5. Use the result of step 4 and the NIST voltage-to-temperature (inverse) coefficients to calculate the cold junction compensated, linearized temperature value.
          // The equation is in the form correctedTemp = d_0 + d_1*E + d_2*E^2 + ... + d_n*E^n, where E is the totalVoltage in mV and correctedTemp is in degrees C.
          // NIST uses different coefficients for different temperature subranges: (-200 to 0C), (0 to 500C) and (500 to 1372C).
          if (totalVoltage < 0) { // Temperature is between -200 and 0C.
             double d[] = {0.0000000E+00, 2.5173462E+01, -1.1662878E+00, -1.0833638E+00, -8.9773540E-01, -3.7342377E-01, -8.6632643E-02, -1.0450598E-02, -5.1920577E-04, 0.0000000E+00};
 
             int dLength = sizeof(d) / sizeof(d[0]);
             for (i = 0; i < dLength; i++) {
                correctedTemp += d[i] * pow(totalVoltage, i);
             }
          }
          else if (totalVoltage < 20.644) { // Temperature is between 0C and 500C.
             double d[] = {0.000000E+00, 2.508355E+01, 7.860106E-02, -2.503131E-01, 8.315270E-02, -1.228034E-02, 9.804036E-04, -4.413030E-05, 1.057734E-06, -1.052755E-08};
             int dLength = sizeof(d) / sizeof(d[0]);
             for (i = 0; i < dLength; i++) {
                correctedTemp += d[i] * pow(totalVoltage, i);
             }
          }
          else if (totalVoltage < 54.886 ) { // Temperature is between 500C and 1372C.
             double d[] = {-1.318058E+02, 4.830222E+01, -1.646031E+00, 5.464731E-02, -9.650715E-04, 8.802193E-06, -3.110810E-08, 0.000000E+00, 0.000000E+00, 0.000000E+00};
             int dLength = sizeof(d) / sizeof(d[0]);
             for (i = 0; i < dLength; i++) {
                correctedTemp += d[i] * pow(totalVoltage, i);
             }
          } else { // NIST only has data for K-type thermocouples from -200C to +1372C. If the temperature is not in that range, set temp to impossible value.
             // Error handling should be improved.
             
             correctedTemp = NAN;
          }
 
       
 
       }
  //pid-related code
 

  int c = correctedTemp;
  if (c==0){ //Somehow my TC gets grounded at higher Temperature. In this case the Input gets 0°C as Value and affects the PID performance. So I simply filter those 0°C Values with this If line.
    
  } else {
  Input = (((c-tempLow)*(referenceHigh-referenceLow))/(tempHigh-tempLow)) + referenceLow; //Despite the linearization, the displayed temperature seems to be off. While at the Curipoint everything seems to be right, the Salt melts at displayed 820°C (should at 801°C).
  }
 unsigned long now = millis(); 

  
  if(tuning)
  {
    byte val = (aTune.Runtime());
    if (val!=0)
    {
      tuning = false;
    }
    if(!tuning)
    { //we're done, set the tuning parameters
      kp = aTune.GetKp();
      ki = aTune.GetKi();
      kd = aTune.GetKd();
      myPID.SetTunings(kp,ki,kd);
      AutoTuneHelper(false);
    }
  }
  else myPID.Compute();
  
  if(useSimulation)
  {
    theta[30]=Output;
    if(now>=modelTime)
    {
      modelTime +=100; 
      DoModel();
    }
  }
  else //KP This is optimized for Relay output.
  { 
  if(now - windowStartTime>WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if(Output > now - windowStartTime) digitalWrite(relayPin,HIGH);
  else digitalWrite(relayPin,LOW);  
}


    lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("SollTemp: ");
  lcd.print(Setpoint);
  lcd.setCursor(0, 1);
  lcd.print("IstTemp: ");
  lcd.print(c);
  //send-receive with processing if it's time
  if(millis()>serialTime)
  {
    SerialReceive();
    SerialSend();
    serialTime+=500;
  }
}


/********************************************
 * Serial Communication functions / helpers
 ********************************************/


union {                // This Data structure lets
  byte asBytes[24];    // us take the byte array
  float asFloat[6];    // sent from processing and
}                      // easily convert it to a
foo;                   // float array
// getting float values from processing into the arduino
// was no small task.  the way this program does it is
// as follows:
//  * a float takes up 4 bytes.  in processing, convert
//    the array of floats we want to send, into an array
//    of bytes.
//  * send the bytes to the arduino
//  * use a data structure known as a union to convert
//    the array of bytes back into an array of floats

//  the bytes coming from the arduino follow the following
//  format:
//  0: 0=Manual, 1=Auto, else = ? error ?
//  1: 0=Tuning OFF, 1=Tuning ON, else = ? error ?
//  2-5: float setpoint
//  6-9: float input
//  10-13: float output
//  14-17: float P_Param
//  18-21: float I_Param
//  22-24: float D_Param

void changeAutoTune()
{
 if(!tuning)
  {
    //Set the Output to the desired starting frequency.
    aTuneStartValue = Output; //KP Initial aTuneStartValue will be = Output at Toggle
    aTune.SetNoiseBand(aTuneNoise);
    aTune.SetOutputStep(aTuneStep);
    aTune.SetLookbackSec((int)aTuneLookBack);
    AutoTuneHelper(true);
    tuning = true;
  }
  else
  { //cancel autotune
    aTune.Cancel();
    tuning = false;
    AutoTuneHelper(false);
  }
}

void AutoTuneHelper(boolean start)
{
  if(start)
    ATuneModeRemember = myPID.GetMode();
  else
    myPID.SetMode(ATuneModeRemember);
}


void SerialSend()
{
Serial.print("PID ");
  Serial.print(Setpoint);   
  Serial.print(" ");
  Serial.print(Input);   
  Serial.print(" ");
  Serial.print(Output);   
  Serial.print(" ");
  Serial.print(myPID.GetKp());   
  Serial.print(" ");
  Serial.print(myPID.GetKi());   
  Serial.print(" ");
  Serial.print(myPID.GetKd());   
  Serial.print(" ");
  if(myPID.GetMode()==AUTOMATIC) Serial.print("Automatic");
  else Serial.print("Manual");  
  Serial.print(" ");
 // if(myPID.GetDirection()==DIRECT) Serial.print("Direct");
  //else Serial.print("Reverse");
 // Serial.print(" ");
  if(tuning==false) Serial.println("Off"); //KP Added the On/Off for Tuning Toggle
  else Serial.println("On");
}

void SerialReceive()
{
 
  // read the bytes sent from Processing
  int index=0;
  
  byte Auto_Man = -1;
 // byte Direct_Reverse = -1;
  byte Tuning_Mode = -1; //KP Tuning Mode?
  
  while(Serial.available()&&index<26)
  {
    if(index==0) Auto_Man = Serial.read();
    else if(index==1) Tuning_Mode = Serial.read(); //KP Tuning Mode?
    //else if(index==1) Direct_Reverse = Serial.read();
    //else if(index==2) Tuning_Mode = Serial.read(); //KP Tuning Mode?
    else foo.asBytes[index-2] = Serial.read();
    index++;
  } 
  
  // if the information we got was in the correct format, 
  // read it into the system
  if(index==26  && (Auto_Man==0 || Auto_Man==1) && (Tuning_Mode==0 || Tuning_Mode==1))
  {
    Setpoint=double(foo.asFloat[0]);
    //Input=double(foo.asFloat[1]);       // * the user has the ability to send the 
                                          //   value of "Input"  in most cases (as 
                                          //   in this one) this is not needed.
    if(Auto_Man==0)                       // * only change the Output if we are in 
    {                                     //   manual mode.  otherwise we'll get an
      Output=double(foo.asFloat[2]);      //   Output blip, then the controller will 
    }                                     //   overwrite.
    
    double p, i, d;                       // * read in and set the controller tunings
    p = double(foo.asFloat[3]);           //
    i = double(foo.asFloat[4]);           //
    d = double(foo.asFloat[5]);           //
    myPID.SetTunings(p, i, d);            //
    
    if(Auto_Man==0) myPID.SetMode(MANUAL);// * set the controller mode
    else myPID.SetMode(AUTOMATIC);             //
    
   // if(Direct_Reverse==0) myPID.SetControllerDirection(DIRECT);// * set the controller Direction
  //  else myPID.SetControllerDirection(REVERSE);          //
    
    if(Tuning_Mode == 0) tuning=false; // Set Tuning mode on/off
    else tuning=true;
  }
  Serial.flush();                         // * clear any random data from the serial buffer
}
 
Back
Top