Monday, December 28, 2015

Liquid air!

Here is part 2 of the Cryocooler Saga! You can see Part 1 and Part 3 also. 


It works! Here's my first liquefied air! I'd removed the cryocooler from the Superlink and mounted it in a wooden frame to hold above a thermos to collect the air in. Here's how I put it together.

After removing the cryocooler from the Superlink, I built a wood frame to allow the stock fan on the Superlink to blow air through the cooling fins on the heat rejection side. He's a scrappy fellow.

This thing's walls are probably more sound than some of them in my house. Not that that's saying much.

The hole in the base is (approximately) the size of the cooling fins, forcing air to flow through them.

I made a trap door on the bottom to divert air blowing out the bottom away from the cold finger. It's just a few pieces of aluminum sheet screwed to the wood, with 1/8" luan for the trap door. The luan sheets can be separated to insert the cryocooler flange, then closed around it to divert most of the air away. I didn't make any special effort to make it a tight seal. We aren't trying to freeze all of Gotham City here, absolute efficiency isn't really one of my goals at the moment.



The cooler's control program requires that the cold side temperature be measured to control the power input to the cooler. I figured out that the only pins on the wiring harness that goes to the Dewar that tell the control board what the temperature is are the pair on the fourth from the bottom. The control board appears to have a constant-current circuit that attempts to put 0.1 mA through the pins and measures the voltage. At ambient temperature, the resistance is roughly 5.6 kilohms, so my best guess is that the temperature sensing element in the dewar is a thermistor that is specifically designed for accuracy at about 80K. Putting a 10K potentiometer between the pins allows you to gradually lower the "measured" temperature of the cold side for the control board to allow it to cool down. I plugged a couple stackable headers into the connector to use as sacrificial pins so I don't damage the original circuit board's pins.


I don't want to damage the cooler by trying to ramp it down too aggressively though, so I tried a few ways to measure the temperature of the cold head. A kitchen thermometer gave up at about -40 degrees. I had a Type K thermocouple with a MAX6675 amplifier, but that chip can't read below zero C. I ended up buying a MAX31855K from Sparkfun, which allegedly can go to -200 C, right about where we want it. More on that later. I put a cheapo coffee travel mug under it and fired'er up! 


Aaaaand, not much happened, other than the mug sweating like a cynophobe at the Westminster Kennel Club. Turns out that insulation is a feature that some mugs lack, albeit they compensate with sweet wood paneling. I tried supplemental insulation (a layer of bubble wrap, four layers of floor underlayment insulation, and a towel for good measure), and that allowed the cold finger to get down to 133 K as measured by the newly improved thermocouple, but nothing was in the mug upon removing it from the cooler.




I broke down and bought the mug that claimed the longest time to keep its contents cold/hot that was available at my local Wally World, which ended up being a Thermos brand. I put it in and cranked it down. It hit a brick wall about 133 K also, which I though was strange, because the temperature had been dropping fast when it hit that temperature. I let it go about half an hour before guessing that perhaps the thermocouple calibration wasn't quite on and perhaps it was indeed in the 80-90K range and was stuck because it was condensing air.



Sure enough, when I took it off, I had a good bit of liquid in the bottom! Cold diggity dogg!


A few improvements in the works - I plan to calibrate the thermocouple by placing it in the original Dewar and then cooling it down with liquid air and monitoring the "real" measured temperature as reported by the cooler board when connected to the dewar to make a calibration curve for this thermocouple. Ultimately, I'd like to send a proper signal back to the control board so it can control the cooldown itself, by either finding the proper thermistor to connect or spoofing the signal to the control board. I also plan to fabricate some sort of assembly to decently isolate the cold head and thermos from the atmosphere, so I can introduce gases I want to liquefy into the thermos without air contamination.


Sunday, December 6, 2015

Cryocooler

HO-LY-FA-ZO-LI. I'm on the brink of accomplishing one of my long-time desires - having a device capable of creating liquid nitrogen OUT OF THIN AIR (or 253-foot-above-sea-level air at least). Why? Why not, of course! How? Let's go there.

I'm now the proud owner of a Stirling cycle refrigerator (or cryocooler) capable of cooling something down to the neighborhood of 77 Kelvin, or 320 degrees Fahrenheit below zero. Assuming you're reading this on Earth, your atmosphere consists of something like 78% nitrogen, 21% oxygen, and 1% argon and other gases. By cooling down air to somewhere between 77 K (nitrogen's boiling point) and 90 K (oxygen's boiling point), air will begin to condense into a liquid mixture of nitrogen and oxygen. Trouble is, the coldest day in the chilling depths of South Texas winter is about 280 K, or about 200 degrees K or C too hot. Luckily, at the intersection of cell phones and superconductors, there was reason for a company called Superconductor Technologies to manufacture a fine piece of thermodynamics known as a Stirling Cycle Cryocooler.



Now that everybody has fourteen cell phones and smart watches apiece blasting out radio waves constantly, cell towers must be able to filter out all of the noise in order to provide service for each device. It turns out, for reasons I won't even pretend to give a hilariously naïve explanation of, that superconductors can help do a fantastic job of filtering only the target radio signal and amplifying it. Back in the 80's, some sharp grad students discovered that certain materials lose all resistance at temperatures as high (hah) as liquid nitrogen's boiling point. This finally culminated in the purpose for the folks at Superconductor Technologies to attempt to create a compact, reliable, low-ish cost refrigeration device capable of getting down to those temperatures, in order to cool superconducting filters. They did it so well that today you can buy ten year old devices on Ebay for $600 or so that are still perfectly functional. The ghost of Carl von Linde is probably beaming with joy. That these pieces of surplus telecom equipment had within them these cryocoolers was discovered by tinkerer extraordinaire Ben Krasnow and documented over at his blog, which is where I got my inspiration.

I bought a Superlink 850 superconducting filter off of ebay, which includes a Stirling cryocooler rated up to 150W input power. Like any refrigerator, it has a hot end and a cold end. The working fluid is high pressure helium. The piston and displacer are shuttled back and forth by a solenoid linear motor. Here's a paper that describes the workings.

The Superlink - some disassembly required

When I first received the cooler, I powered it up with a variable power supply (it needs about 27VDC to run) but the unit didn't cool. The seller was able to put me in touch with another cryocooler enthusiast who was able to help teletroubleshoot the problem down to a blown power transistor on the control board - shout out to Andrew for graciously donating his Friday night helping out a total stranger.

The toasted transistor kindly left a chalk outline around its dead body to identify himself.
After the seller shipped a new board, the cooler worked just as intended. Besides the troubleshooting, Andrew also offered some valuable tips about the cooler's operation, including a suggestion to use a 36V power supply adjusted down to the acceptable range of the cooler. I bought one off ebay capable of 11 amps output and able to adjust down as low as 28V out of the box, which is in the acceptable input voltage range.

I have some work to do to get it into a functioning air condensing machine, but it'll be fun along the way!

(Edit: Here's Part 2 and Part 3 of the Cryocooler Saga. Part 2 is pretty darn cool!)

Tuesday, August 4, 2015

Supercritical Propane

If Superman were a thermal fluid, he'd be a supercritical one! Supercritical fluids are one of those fascinating things in nature that you never see in everyday life and therefore for which our intuition can just fail miserably. You'd never think that at some point, a fluid would have an identity crisis and a gas would stop being a gas and a liquid would stop being a liquid, and the fluid would decide to mish mash up properties of both into a completely different phase.

I've seen (and done) supercritical CO2 before, but I'd never seen supercritical propane attempted. Propane's critical point is 97 degrees C (206 F) and 42 atmospheres pressure (616 psi). It's a little hotter and a little lower pressure than CO2's critical point, but the temperature is tantalizingly close to the boiling point of water, meaning it's a piece of cake to attain - just drop a sample in a vat of boiling water! The 42 atmospheres pressure is a little trickier - luckily I had sitting around a 1/2" 2000 psi rated ball valve (from ebay) and - even better - a 1750 psi rated sight glass! It's no fun if you can't see it!


I transferred some propane into this contraption by connecting it to a small propane torch tank with an adapter that had 1/8" NPT threads. I opened the propane tank to the contraption and then disconnected and depressurized it to purge a good bit of the air out. I reconnected the tank and then dunked the sight glass end in a cup of ice water, which reduced the pressure on that end and caused propane to flow from the cylinder into the valve/sight glass combo. I let it flow in until the chamber between the ball and the sight glass was about half full of liquid propane. Closing the ball valve trapped the liquid propane on the sight glass side of the valve, and I disconnected the propane tank.




I filled a one liter flask with water and wired up a harness to suspend the ball valve in the water. Heating the water subsequently heated the propane in the valve. Once it hit about 190 F, the propane in the chamber began to boil. As the temperature rose, the liquid fraction appeared to decrease, and finally, about 207 F, it disappeared completely - supercritical! At that point, the vapor and liquid phases decided to settle their differences like Rocky and Apollo, and they should have the same surface tension (none), density, should be miscible with other fluids, et cetera. They become the best of friends, alike in every way. But then Ivan Drago killed... ok this analogy is getting out of hand.


Here it goes! I apologize for the nerdy commentary - actually no, I take that back because this is awesome.

So what's really going on in here? As the pressure and temperature get closer and closer to the critical point, the differences in all properties between the gas and liquid phases start to get smaller and smaller. The density of the liquid phase decreases, while the density of the gas increases. The viscosities likewise approach each other. Then, suddenly, the difference between the two vanishes abruptly. Through the transition, it drags a couple of properties of each. For instance, the surface tension, which is basically what makes a liquid a liquid, disappears, making the fluid gas-like in that sense. The fluid has no tendency to stick together anymore, and is completely miscible (mix-able) in any proportion with any other gas or supercritical fluid. Some liquid-like properties are dragged through too - a supercritical fluid can have strong solvating power, dissolving other substances. These weird properties lead to many of the ways supercritical fluids are used, like in dry cleaning, for their strong solvating power - making them good at getting rid of oily stains on clothes, mixed with their lack of surface tension - making them able to get into all nooks and crannies to dissolve tough-to-get-at stains. Best of both worlds - ain't it great when you can have it all? Sometimes Mother Nature throws us a bone - and looks damn fine doing it in that squeaky clean getup.

Edit: Here's a slightly better video of the transition



Sunday, August 2, 2015

DIY Rotovap

I wanted to do some vacuum evaporation projects, so I built a DIY rotovap. This certainly ain't a laboratory grade, strong solvent resistant, low leakage setup, and it has very few speed settings (currently "On" and "Off"), but it does indeed work at allowing vacuum distillations to be carried out, recovering a distinct overhead product and bottoms product.


The evaporation chamber is a Mason jar with a 3/4" x 1/2" PVC bushing epoxied to the lid. I used two electrical conduit locknuts to hold the fitting in place while the epoxy set.



To rotate the evaporation chamber, I mounted an electric motor in a wood frame and mounted a section of 1/2" CPVC pipe in a pillow block bearing. I connected the bearing to the motor shaft with a series of small plastic gears.



I left one section of the CPVC un-cemented on top of the bearing, to allow the pipe to be removed from the bearing. Adding a bit of teflon tape to the pipe before pressing it into the coupling gives a "good enough" vacuum seal.


The heating method for the Mason jar originally gave me trouble. At first, I considered a laboratory hot plate, but was put off by their high cost, and the difficulty I expected to experience in getting uniform heating on the jar. I then realized that I was an idiot, as I already had an electric skillet that I could put a pot of water on to uniformly heat the jar. I tried this, but was less than impressed with the amount of heat I could transfer into the jar. It was also a cumbersome setup. While at the store looking for a smaller, higher heat output hot plate, I realized I was a double mega idiot, and that I had a crock pot that could do exactly what I wanted, with a pretty good heat output to boot. What's more, it's relatively easy to control the temperature in the crock pot over the timescales on which the distillation runs by adjusting the heat setting on the pot.

The next tricky part was the method to give a vacuum-tight seal while allowing continuous rotation. The method I ended up on was to use a compressed air quick connect fitting. These are available at any hardware store at a low cost (about $5 for the male and female components). I used a 1/4" fitting. It does have a rather small restriction through the fitting which isn't ideal for vacuum pressures, but again it works "good enough" for this non-high-vacuum setup. It does have a fair bit of resistance to rotation, which is why the motor I ended up using was so large - a first draft used a smaller motor that couldn't overcome the resistance of the quick connect fitting. The motor I used has a gear reducer that reduces the rotation rate to about 60 rpm, giving it high enough torque to overcome the resistance. It remains to be seen how well the quick connect fitting holds up with use, but they're pretty darn cheap and could be replaced easily.

The overhead business side is the handled by a filter flask. In operation, the flask sits in a bath of ice water to condense the overhead vapors and collect them. This is the only actual piece of lab glassware in the entire setup, and I used it because I had one on hand. I could just as well have modified another Mason jar to the task. A section of PVC extends down nearly to the bottom to force the heated vapors to come into close contact with the cold walls. If the flow didn't contact the vessel walls, a good portion of the overhead product would go straight out the side port to the vacuum pump, which would be bad for the pump and bad for the recovery of the overhead product.


I originally had some difficulty with the sealing element between the filter flask and the PVC, but then fortuitously discovered that a 3/4" PVC compression coupling's rubber gasket is perfectly sized for this filter flask's mouth diameter. A flexible hose connects the filter flask to my Harbor Freight vacuum pump.

Here's a dry run showing everything working together:



Here's a hot run with the first generation (aka dumb) heating method for the boiling jar.


My first run was to distill some tea - I wanted to make some tea concentrate to use in other recipes. It was a technical success, in that I was able to concentrate the tea to a much stronger concentration, with an overhead product that tasted like plain water. The concentrate was decidedly non-tasty, though, so it might not have been a recipe success. I'm not sure if this is because I got the fluid too hot during the distillation - the whole point of vacuum distillation is that you can boil the liquid at a lower than normal temperature. I plan to try again, we shall see if tea-asty product will result!




Monday, July 27, 2015

Yet Another Arduino Magnetic Levitator

I'd wanted to build a magnetic levitator since high school. I finally got off my butt and got around to putting one together recently. It was totally worth the effort and is thoroughly, as the kids say, the bee's knees. Here's how I put it together.

The general plan is to have an electromagnet whose magnetic field strength varies with the distance the magnetic levitating object, such that the distance is maintained constant. The distance from the levitating object is monitored with a Hall effect sensor. A second Hall effect sensor on the top of the electromagnet detects the magnetic field from the electromagnet and corrects the first sensor's reading to remove the influence of the electromagnet. The current through the coil is constantly adjusted to maintain a proper distance.



First, the electromagnet. I had a steel bar about 20 cm long by 1 cm diameter laying around. A soft iron core would have been better, but not free. I had several small spools of magnet wire, including 22, 26, and 30 AWG wire. The power supply I planned to use was a ATX power supply with 3.3V, 5V, and 12V taps. According to the Wikipedia page, magnet wire can typically handle 2.5-6 A/mm^2, depending on surroundings. Assuming the least conservative ampaciy, this corresponds to:

30 AWG: Current = 6 A/mm^2 * 0.0509 mm^2 = 0.3 A
200 feet at 103 ohm/1000 ft -> about 21 ohms resistance

V = I R = 0.3 * 21 = 6.3 V

26 AWG: Current = 6 A/mm^2 * 0.129 mm^2 = 0.8 A
75 feet at 40.81 ohm/1000 ft -> about 3.6 ohms resistance

V = 0.8 * 3.6 = 2.9 V

22 AWG: Current = 6 A/mm^2 * 0.326 mm^2 = 2.0 A
40 feet at 16.14 ohm/1000 ft -> about 0.65 ohms resistance

V = I R = 1.3 V

Ampere's law says that the strength of the magnetic field is proportional to the number of turns times the current through the wire. Since we want the maximum magnetic field we can get, if we multiply the lengths I had on hand by the max current in each wire, we get:

30 AWG : 0.3 A * 200 ft = 60

26 AWG : 0.8 A * 75 ft = 60

22 AWG : 2.0 A * 40 ft = 80

To get the strongest magnetic field, I should have chosen the 22 AWG wire. However, the length of wire I had has a max voltage of only 1.3 V, which would be rather difficult to control with a power supply with a minimum output of 3.3 volts. I'd need to keep the PWM down to a low level just to limit the current through the wire, leaving less room for control. The 30 AWG and 26 AWG wire should give the same magnetic field strength with voltages much closer to what the power supply puts out, so I arbitrarily chose the 30 AWG wire to use for the magnet.

I wrapped the steel bar with the 200 feet of the 30 AWG wire, which on a 1 cm diameter should have been a bit short of 2000 or so turns.

L = 200 ft 
= 6096 cm 
= # turns * circumference per turn 
= # turns * Pi * diameter

# turns = 6096 cm/ Pi / 1 cm 
= 1940 turns

Since there were several layers of wire on the bar, the actual number of turns is probably somewhat smaller, but should be good enough.

I wrapped the coil by placing the bar in the chuck of a drill, taping the beginning of the wire to the bar, and running the drill, similar to this. I didn't take any particular care to make sure it wrapped smoothly, since Ampere don't care if it looks pretty, as long as it's got the loops.

Loopalicious

Once I had the electromagnet coil wound, I made a wooden frame to mount the electromagnet in. I drilled a hole through a 1x2 and cut a slit through the hole and the wood. I then drilled a hole on the short side and put a machine screw through the hole, and attached a wing nut on the opposite end. This let me tighten down on the coil to hold it in place.

I placed the coil in the frame and attached two linear Hall effect sensors I'd bought from Digikey. These sensors output a 0-5V signal based on the strength of the magnetic field in their vicinity. The Hall sensor on the top of the electromagnet measures the strength of the magnetic field from the electromagnet. The Hall sensor measuring the distance to the floating magnet will also see the magnetic field from the electromagnet. Since we vary the strength of the electromagnet's field to keep the floating magnet steady, we need to compensate for this field to get a good estimate of the actual distance to the floating magnet. This could probably also be accomplished by running the electromagnet through its full current range and measuring the Hall reading at each point, then creating a calibration curve from these readings, but I chose to go the two-sensor route.



Tip - twist wires together with a drill to keep them organized. I first saw it here.


The circuit itself is pretty darn simple. It's just an n-Mosfet to control the coil, a flyback diode, two Hall sensors, and a potentiometer to adjust the distance between the floating magnet and the bottom of the electromagnet.

I'm proud of this soldering job. So fresh and so clean clean! Outkast would be proud, were he a worker in an electronics factory.




I used the Arduino PWM function to control the n-Mosfet to turn the coil on and off. The real heart of the project is the controller to take the Hall reading and output a PWM current to the coil. The controller has to work crazy fast, adjusting the current hundreds of times per second to keep the magnet stable. I ended up using a PID library to manage the calculation. Getting the PID parameters right took more time than the rest of the project combined. The final parameters have the coil power buzzing around like a pissed off yellowjacket, but at least it works!


I used the serial port to download Hall sensor readings and power output data to tweak the parameters. This chart is how the position of the magnet moves while floating with the final, working, PID parameters. I pulled the magnet out at the very end of this snapshot. The time axis on this chart is in milliseconds, so this entire span is only about a second and a half. Note how quickly the controller has to react to changes in the magnet position - it crosses the setpoint (of 150) about 40 times per second.

Another thing - the duty cycle of the coil while it's floating is only about 60%, meaning that, on average, the coil is only on about 60% of the time. This means that we can actually get away with a higher peak current through the coil than originally premised. Using the full 12V output from the power supply while the magnet is floating causes the coil to get a little warm, but definitely not hot enough to be concerning.

Here it is in action!



Here's the code:
>#include <pid_v1.h>  //PID control library

int Coil = 5; //PWM output pin that controls transistor for coil

double Setpoint, Input, Output; //PID variables

int PotPin = A2;    // select the input pin for the potentiometer

int TimeConst = 1;  //PID calculation frequency in milliseconds

int potValue = 0;  // variable to store the value coming from the pot

//Specify the links and initial tuning parameters for PID controller
double Kp=5, Ki=4, Kd=.069;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

int HALLA = 0; //Pin for reference hall effect sensor on top of coil

int HALLB = 1; //Pin for hall effect sensor on bottom of coil

int StopThreshold = 100; //Threshold below set point at which magnet will be turned off (if the floating magnet falls off or is removed, don't leave the coil just going full blast)

float CALSLOPE; //Slope of calibration curve for hall sensors

float CALINTERCEPT; //intercept of calibration curve for hall sensors

//variables for hall effect sensor calibraction
float CALSLOPEtemp = 0; 
float CALINTERCEPTtemp = 0;
float XA;
float YA;
float XB;
float YB;

float CorrectedVal; //Compensated hall reading

int Power; //Coil PWM variable

void setup(){
   //Reset PWM frequency to the coil pin to 62500/16 = 3906 Hz
  setPwmFrequency(5, 16);
  
  //Set PID sample time to defined value. Default is 200 ms, which is way too slow.
  myPID.SetSampleTime(TimeConst);
  
  Serial.begin(115200); //Need to transmit serial at 115200 bps to keep up  
  
//Calibrate sensors by reading them when the coil is off, then reading them while coil is on. This allows you to compensate for the coil's magnetic field and just identify the magnetic field due to the floating magnet.
 for (int i=0; i < 10; i++){
  digitalWrite(Coil, LOW);
  delay(100);
  XA = analogRead(HALLA);
  YA = analogRead(HALLB);
  
  analogWrite(Coil, 255);
  delay(100);
  XB = analogRead(HALLA);
  YB = analogRead(HALLB);
  
  //Two point slope-intercept form
  CALSLOPE = (YB-YA)/(XB-XA);
  CALINTERCEPT = (YA-CALSLOPE * XA);
  
  CALSLOPEtemp = CALSLOPEtemp + CALSLOPE;
  CALINTERCEPTtemp = CALINTERCEPTtemp + CALINTERCEPT;
 }
 
 //Average slope and intercept
 CALSLOPE = CALSLOPEtemp / 10;
 CALINTERCEPT = CALINTERCEPTtemp/10;
  
  Serial.println(CALSLOPE);
  Serial.println(CALINTERCEPT);
  
  digitalWrite(Coil, LOW);
  
  //arbitrary starting setpoint. We'll reset it as soon as we enter the loop
  Setpoint = 45;
    //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop(){
   //Read potentiometer to get setpoint desired
  potValue = analogRead(PotPin);
  Setpoint = map(potValue, 0, 1023, 0, 255);
  
   //Read hall effect sensors five times in a row, take average corrected reading
  for (int i=0; i < 5; i++){
    CorrectedVal =CorrectedVal + CALSLOPE * analogRead(HALLA) + CALINTERCEPT - analogRead(HALLB);
  }
  CorrectedVal = CorrectedVal / 5;
  
  //Turn off coil if the magnet is nowhere nearby
  if (CorrectedVal < Setpoint - StopThreshold) {
    digitalWrite(Coil, LOW);
  } else {
    //Otherwise, do PID control to keep floating magnet at setpoint
    Input =CorrectedVal;
     myPID.Compute();
     //Take PID output and apply to coil
     Power = Output;
     analogWrite(Coil, Power);
     //Print out timestamp, coil power, corrected hall effect reading, and target set point for hall effect reading.
    Serial.println(String(millis()) + ", "+String(int(Power)) + ", " + String(int(CorrectedVal))+ ", " + String(int(Setpoint)));  
  }
}

void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x7; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }

}

Tuesday, July 21, 2015

Foot controlled TIG welding with 80 Amp Harbor Freight welder

I have a cheapo 80 amp Harbor Freight DC welding machine for which I'd purchased a TIG torch and adapted it as I'd seen explained here to a scratch start TIG machine. It worked pretty well for a cost of less  than $500 all said and done, including the argon tank, but it was a bear starting and stopping because I couldn't adjust the amperage on the fly easily. The end of the weld would always be iffy because I had to lift off while at full power, leaving the hot metal without shielding gas and sometimes leaving holes in the welds and sometimes allowing a lot of oxygen contamination.

I saw this video here where a home-made on-off foot pedal made with a car battery knife switch is demonstrated. Seeing that flipped a switch in my head and I though hey - wouldn't it be neat to just put a potentiometer on the hinge of that foot pedal and somehow use that signal to adjust the amperage? This is essentially what commercial welding foot pedal controllers do, but they're generally crazy expensive, at least several hundred dollars. I fiddled with adjusting the amperage dial while welding and it seemed to work and the machine didn't seem to complain. I couldn't find anywhere on the vast reaches of the internet that advised against it, so I figured that I could hook up a servo to the dial and rotate the servo in accordance with the desired amperage, using an Arduino to control the servo and read the pot.

I get the rubegoldbergidity of using a potentiometer to control a servo to control a potentiometer. Alternatively, I could have opened up the welding machine and tapped the amperage control potentiometer, and put a circuit around it that would spoof the potentiometer reading. I was leery of making any permanent modifications to the welding machine wiring, but I may yet go back and do this.

I started by making the foot pedal. I bought a car battery disconnect switch here and mounted it to the foot pedal (itself just a few pieces of scrap wood with a hinge). I mounted a standard 10K potentiometer with a knob on the other side.




On the welding machine, I drilled a hole in the case to mount the servo body, and attached the servo actuator to the welding machine amperage knob with the highly advanced "Rubber Band" technique. The servo actuator has holes in in, through which I placed small nails and tightened them around the knob with the rubber band. The servo can slip on and off of the welding machine very easily like this.



Code wise, it's pretty simple. I used a Makershield I had sitting around with a 5V regulator already wired in to power the servo, and the foot pedal potentiometer is measured with one of the analog pins. When a button on the shield is pressed, it enters a learning mode for ten seconds. During that time, it records the maximum and minimum readings of the potentiometer and maps those to the minimum and maximum servo positions.

The full 10 amp to 80 amp range is a little more than 180 degrees on the welding machine so it's not quite capable of swinging the machine's full range, but it does allow a much better degree of current control than before. Using a 270 degree servo would allow the full range to be used.

How well does it work? See it in action!





Here's the code:
#include <Servo.h>

Servo myservo;

int angle = 0;  //servo angle

int potpin = 0;  //pot connected to Analog Pin 0

int potval;      //potentiometer reading

int btn = 4;  //digital pin 4 is button on MakerShield. This button, when pressed, will reset the high and low range of the potentiometer and re-map those to the servo's working range.

long RangingTime = 10000; //time during which pedal will learn its range

int highrange = 268; //default value for high range of pot

int lowrange = 104; //default value of low range for pot

int LED =5;    //LED is lit when arduino is learning new potentiometer range

int servopin = 6;  //Servo connected to pin 6

long ButtonPressTime;  //For debouncing learning button

void setup()
{

  myservo.attach(servopin); 
 // Serial.begin(9600);
  pinMode(btn, INPUT); 
  pinMode(LED, OUTPUT);

}


void loop()
{
  //button press for setting high and low range of pedal
  
  if (1-debounce(btn)){
    
    digitalWrite(LED, HIGH);
    ButtonPressTime = millis();
    highrange = 0; //reinitialize high and low range
    lowrange = 1024;
    while(millis() < ButtonPressTime + RangingTime){
       
      potval = analogRead(potpin);
      if (potval > highrange){
        
        highrange = potval;
        
      }else if (potval < lowrange){
        lowrange = potval;
      }
    }
    
    digitalWrite(LED, LOW);
    
   // Serial.print("High Range = ");
   // Serial.println(highrange);
    
  //  Serial.print("Low Range = ");
  //  Serial.println(lowrange);
  }

  potval = analogRead(potpin);
  if (potval > highrange){
    potval = highrange;
  }else if (potval < lowrange){
    potval = lowrange;
  }
  
  //Convert the pot reading to a servo angle, turn the servo to that angle. This servo is a 180 degree servo, but I cut it a bit short to keep it from straining at the end.
  angle = map(potval, lowrange, highrange, 0, 170);

  myservo.write(angle);

  //Serial.println(potval);

  //poll every 200 milliseconds. If this time is too short, the servo gets a bit twichy
  delay(200);


}

boolean debounce(int pin){
 boolean state;
boolean previousState;
const int debounceDelay = 10;
previousState = digitalRead(pin);
  for(int counter = 0; counter < debounceDelay; counter++)
  {  
    delay(1);
    state = digitalRead(pin);
    if(state != previousState)
    {
      counter = 0;
      previousState = state;
    }
  }
  return state;
  
}

Sunday, June 21, 2015

Arduino 4-20 mA output

Need an Arduino to output a standard 4 to 20 milliamp signal for a control loop? Here's how!

Note: Looking for how to input a 4-20 milliamp signal to an Arduino? This link here is what you're looking for.

At work, we had a surplus Fisher D4 control valve with an i2P transducer that we weren't sure was functional. Of course, we could have had one of our instrument techs test it, but where's the fun in that? After work I whipped up a circuit powered by an Arduino that would do the trick. 

According to the transducer's documentation, the equivalent circuit is a 40 ohm resistance with a 4 volt drop, and the current supply should be able to supply at least 30 milliamps and have a maximum voltage of 30V. Doing the math, 

V = IR

V = 0.03 A * 40 ohms = 1.2 V

Adding the 4 volt constant drop, we'll need at least 5.2 volts available across the transducer. Since we'll have some additional resistive loss in the circuit, we'll need to use a transistor to switch the Arduino's 5V output to a higher voltage.

Now how do we get the Arduino to apply a specific voltage across the transducer to give it the desired current? Some of the Arduino digital pins can do pulse width modulation that applies 5V to the circuit for a time and then zero volts for a time, but we want a smooth voltage output to give a smooth current, not bang-bang control. We can use an RC circuit to transform the on-off signal into a smooth output. This site here has a nice writeup of how to use an RC circuit with an Arduino to output a given voltage. It links to a RC-PWM simulator here that you can use to estimate the values of a resistor and capacitor needed for a reasonably smooth output. I had a 100 microfarad capacitor on hand and paired with a 100 ohm resistor, it looked good enough.



So now we need some way of making sure we know how much current we're putting through the circuit. If we can measure the current in the circuit, we can adjust the PWM output to the circuit until we get the desired current. We can accomplish this by putting a resistor of a known resistance in the circuit and measure the voltage drop across it. The Arduino can read a 0-5V voltage with its analog input pins. The bigger the resistor we use, the larger the voltage drop we can read and the better the resolution we'll get on measuring the current. At the maximum of 20 mA we want it to read, the biggest resistor we can use is:

R = V/I

R = 5 V/ 0.02 A = 250 ohms

220 ohm was the closest I had on hand. You'll want to measure the actual resistance to use in the code - the resistor I had was actually 217 ohms, so that's what I used in the code. This resistor does need to be the last element in the circuit above ground so that the voltage you measure at the high end is the true voltage drop across the resistor. Measuring the current like this does mean that we'll need to switch the circuit with a transistor on the high side. A p-mosfet like this guy will be appropriate.


Since the source voltage will be quite a bit higher than 5V, we'll need an n-mosfet to apply the full source voltage to the gate when switching. It in turn can be switched by one of the Arduino's PWM pins. Here's my full circuit, including a dummy load for troubleshooting and some resistors to keep the mosfets happy (I'll be honest, I can't remember why I included the 100K one).


With this full circuit and the transistor fully open, the resistance across the circuit is 100 + 40 (transducer itself) + 220 = 360 ohms. At a full 20 mA, the voltage drop across the resistive elements here will be:

V = 0.02 * 360 = 7.2 volts

Add in the constant 4 volt drop across the transducer, and we'll need a power supply that outputs at least 11.2 volts in order to power the circuit through its full 4 to 20 mA range. A 12V power supply should work swimmingly.

I controlled the current-supply circuit with pin 3, and an indicator LED  with pin 11. I read the reference resistor's voltage with analog pin 1. I included a potentiometer to adjust the current set point.

In order to adjust the PWM output to generate the desired current, I used the Arduino PID library. It's probably overkill, but it does the trick. It also easily compensates for changes in the transducer load resistance or power supply input. After getting it to work on a breadboard, I soldered it all up:


We tested it out on a valve, and sure enough it worked! Move the potentiometer and the stem moved up and down as the transducer received the signal and applied the proper pressure to the valve's topworks.

There's probably far more elegant ways to accomplish the same thing, but this did do the trick for me. 


Here's the code:
 //This sketch works to output a 4 to 20 milliamp signal by measuring the resistance across a reference resistor and adjusting the PWM output to a transistor with a PID controller to match a setpoint from a potentiometer.  
 #include <PID_v1.h> //PID library  
 #define TRANSISTOR 3 //n-Mosfet digital pin  
 #define LED 11 //LED digital pin  
 #define POTPIN 0  // Analog input pin for the potentiometer  
 #define REFRES 1 //referece resistor analog input pin  
   
 float val = 0;    // variable to store the value coming from the potentiometer  
   
 char buffer[11];  
   
 int Rref = 217; //resistance of reference resistor  
   
 float Vref = 0; //measured voltage across reference resistor  
   
 float MeasCurrent = 0;  
   
 int counter = 0;  
 double Setpoint, Input, Output;  
   
 //Specify the links and initial tuning parameters for the PID loop. I didn't use a very scientific method to choose them, I just varied them until it worked. These could probably be optimized 
 double Kp=1, Ki=30, Kd=.02;  
 PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); //initialize the PID  
   
 void setup(){  
   pinMode(TRANSISTOR, OUTPUT);  
   pinMode(LED, OUTPUT);  
   Serial.begin(9600);  
     
   //Arbitrarily start the PID at 12 mA  
   Setpoint = 12;  
   
   //turn the PID on  
   myPID.SetMode(AUTOMATIC);  
     
   //Header for debugger  
   Serial.println("Time (ms), Setpoint (mA),PID output,Measured voltage across reference resistor (V), Measured current (mA)");  
 }  
    
   
 void loop(){  
     
  //take ten measurements of the reference resistor and potentiometer and average them   
   counter = 0;  
   val = 0;  
   Vref = 0;  
   while(counter < 10){  
    counter = counter + 1;  
    val = val + analogRead(POTPIN);  // read the value from the potentiometer  
    Vref = Vref + analogRead(REFRES); // read the value from the reference resistor  
    delay(1);  
   }  
   val = val/10;  
   Vref = Vref/10;  
     
   //Convert the measured potentiometer setting to a 4 to 20 mA set point for the PID loop  
   Setpoint = mapfloat(val, 0.0, 1023.0, 4.0, 20.0);  
     
   //Calculate the current in milliamps from Ohm's law. The 0-1024 analog reading corresponds to 0 to 5V on the pin. This assumes your reference voltage is 5V, if you change that, you'll need to change the formula.  
   MeasCurrent = Vref/1024.0/Rref*1000.0*5.0;  
     
   //Feed the PID loop with the measured current.  
   Input = MeasCurrent;  
   //print out everything for the debugger. Time, PID setpoint, PID output, measured voltage, and measured current. Separate with commas so you can put it into a spreadsheet and sort it out as comma separated values  
   Serial.print(millis());  
   Serial.print(",");  
   Serial.print(Setpoint);  
   Serial.print(",");  
   Serial.print(Output);  
   Serial.print(",");  
   Serial.print(Vref*5/1024.0);  
   Serial.print(",");  
   Serial.println(MeasCurrent);  
     
   //Run the PID  
   myPID.Compute();  
     
   //Take the PID output and apply it to the transistor pin  
   analogWrite(TRANSISTOR, Output);  
     
   // Adjust the brightness of the LED to the setpoint with PWM   
   analogWrite(LED, mapfloat(Setpoint, 4.0, 20.0, 0, 255));  
     
   //wait 20 milliseconds before looping again  
    delay(20);    
   
 }  
   
 //The normal map function uses longs, we need floats - from http://forum.arduino.cc/index.php?topic=3922.0  
 float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)  
 {  
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;  
 }