Saturday, January 7, 2017

How to find the water depth in a well ... with a cell phone!

Have a water well? Want to figure out how deep the water level is? So did I, so I made an overly complicated contraption to do so. But before I get into that, there's a much, much easier way to figure it out. You simply need to time the echo of a loud noise traveling down the well and back, and use the speed of sound in air to estimate the length the sound traveled. To accomplish that, the hardware you need is a cell phone... and that's it.

Begin recording a video (or just sound) on the phone. Place the cell phone on top of the well, then knock the top of the well with your knuckles or with an object. You should be able to hear the echo of the knock reverberating in the well. Stop recording the video, then load it to a computer. Convert the video or sound recording file to a .WAV sound file (there's several places online that will do this, I used this one). Open the resulting .WAV file with a program that allows you to visualize the sound waveform. I used Audacity (here).

I made a short video showing how to use the Audacity program here:



Zoom in on the knock sound, and if it all worked out, you should be able to see high amplitude echoes well above the background noise level. Use the software to measure the time between the leading edge of the initial sound and the leading edge of any echoes you observe.




I like the Audacity program because if you choose the Selection tool from the top toolbar and click and drag within the waveform area, the Selection start and end time is given in the box at the bottom, with a precision of one thousandth of a second.


In my case, the echoes were about 0.060 seconds apart. Next, we need to translate that to a distance. The gas in the well above the water should have a composition close to air, so we can assume the speed of sound is that of air. The speed of sound varies with temperature. The temperature of the air in the well is probably closer to the ground temperature than the ambient temperature, so assuming 72 F (yep, it's hot here), that gives me a speed of sound of about 1130 ft/s or 344 m/s from the table here.

Then, it's a simple matter of multiplying the echo interval by the speed of sound to find the total distance that the sound traveled each echo.

Sound travel distance = speed x time
Sound travel distance = 1130 feet/second x 0.060 seconds
Sound travel distance = 68 feet

Don't forget that the sound has to travel down the well, reflect off of the water, and travel back up the well before you hear the echo. The total travel distance for the sound is therefore twice the water depth. Divide the total travel distance by two and that will give you the water depth!

Depth = Total travel distance / 2
Depth = 68 feet / 2 = 34 feet


One little caveat here - we're assuming that the echo we're hearing is from the surface of the water, and not the sound bouncing off of a change in the diameter of the well or some trash stuck higher up in the well. To confirm that the echo response is indeed the water, try running the pump for a few minutes and measuring the water depth again. The water level will fall while the pump is running in most wells, so you should see a slight increase in the water depth in the second measurement. If you don't see a decrease, either the water level is not drawn down appreciably while the pump is running, or there is an obstruction higher up in the well that the sound is echoing off of, masking the water level.

And there you have it! I bet the salesman didn't tout the high precision water well depth estimating capabilities of your phone when you bought yours! The next time you upgrade, be sure to insist on this feature, along with the ability to make phone calls!

For my next trick, I want to be able to log the well depth over a period of time, and watch as it rises and falls as the pump is turned on and off. Since I don't want to sit there whacking the well all day, I'm putting together a microcontroller datalogger to do the whacking, listening, and data interpretation. More on that next time.

Saturday, November 5, 2016

Arduino 4-20 mA input

This is a quick discussion of how to feed a 4-20 mA signal into an Arduino. Looking for 4-20 mA output from an Arduino? See here.

I bought a pressure transmitter off of ebay that outputs a 4-20 mA current signal, because I like to live it up. The 4-20 mA current is very common in industrial control systems, so it's relatively easy to find various transmitters with this output. However, an Arduino can't natively read a current signal with its analog input pins - they measure voltage. We need to convert this current signal to a voltage. Fortunately, this is a piece of cake to do with a simple circuit.


Precious peppy pressure


The transmitter I bought is a Setra 209 model (datasheet here). It takes a 9-30V input, and acts as a current controller to put out a 4 to 20 milliamp signal proportional to the pressure it senses, with a span of zero to 100 psig. Plotting it out:



We can use a simple resistor circuit to generate a voltage readable to the Arduino that is proportional to the current. The Arduino AnalogRead function gives a 0-1023 value output proportional to the measured voltage on the analog input pin, with 0 corresponding to 0V or Ground (duh) and 1023 corresponding to the reference voltage (5V for the plain jane Arduino if nothing's connected to the Aref pin).


That's really it. I don't think electronics gets any easier than this.

The standard Arduino's analog input pins can read zero to 5 volts. If 5 volts is our maximum signal at 20 milliamps, that requires a resistance of 250 ohms:


R = V/I

R = 5 V/ 0.02 A = 250 ohms

If this were instead a 3.3V microcontroller, we'd require a 165 ohm resistor to read the full range output by the same math. Whichever reference voltage, you can use a lower resistor, but it cuts down the readable span.

We can now convert the measured voltage back to whatever units our signal is in. To do this, we just need a little algebra! We can plot an x-y chart, where the x-axis is the measured current/voltage/AnalogRead output and the y-axis is the process variable (pressure in this case). 

I live my life by the principles of slope intercept form

Usually, a precision resistor is used for the reference resistor, with a low temperature coefficient (change in resistance with temperature), but for my purposes, an ordinary resistor suffices. I had a nominally 220 ohm resistor I measured as 217 ohms actual resistance, and a 33 ohm resistor that measured true, which combined in series gave 250 ohms. We don't need exactly the correct resistance, though - we can compensate in code. Here's everything breadboarded up - not much to it:


The transmitter worked like a champ, with the measured signal tracking the manual gauge I had connected to it as I varied the pressure.


One other nice feature of the 4-20 mA signal scheme is that the low end of the signal output is 4 milliamps, not zero. This makes it easy to detect errors, as happened on the above data logging run when I bumped the wire around 10,000 milliseconds in. The raw reading went to zero, when it should have bottomed out at about 200 if it were a real zero signal. This tells me that something is up with the wiring at this point, and the data can't be trusted. If I wrote a program to use this transmitter reading as an input, I would know to handle any zero signal readings as an error, not as a true data point.


Here's the code: 
float PressureReading;     
float ResistorValue = 250;  //reference resistor resistance
float Pmax = 100;           //Max of process variable range
float Pmin = 0;             //Min of process variable range
float Vref = 5;             //Reference voltage for AnalogRead


void setup() {
    Serial.begin(9600);
    Serial.println("Time, Raw reading, Corrected reading");
}

void loop() {
  Serial.print(millis());
  Serial.print(",");

  //Read the voltage across the reference resistor
  PressureReading = analogRead(A3);
  
  Serial.print(PressureReading);
  Serial.print(",");

  //Convert the voltage signal to a pressure reading
  PressureReading =(Pmax-Pmin)*Vref/(1023*ResistorValue*(0.02-0.004))*(PressureReading-1023*0.004*ResistorValue/Vref);

  Serial.println(PressureReading);
  
  delay(500);
  
}

Sunday, October 30, 2016

DIY Signal to Pressure Transducer

I was bored, so I made a home-built signal to pressure transducer. You can use this sort of thing to control the position of a pneumatically actuated valve, among other sundry uses. It works by balancing the flow of air in to a chamber through a needle valve with flow of air out of the chamber through a solenoid valve. The solenoid valve can be quickly opened and closed. By adjusting the relative amount of time the solenoid valve spends open and closed, the pressure in the chamber can be precisely controlled.




The maximum rate at which air can leave the chamber must be balanced with the maximum rate that air can enter the chamber so the output can be varied over a wide range. The maximum exit rate is dictated by the size of the hole the air can flow through when the solenoid valve is wide open. I used a Clippard EV-3-12 solenoid valve I had sitting around, which from the given air consumption rate (0.6 scfm at 100 psi supply pressure), has a roughly 0.025" flow path. I wanted a slightly lower air consumption rate, so I made my own 1/64" (0.016") orifice fitting by filling a 10-32 fitting with epoxy and drilling a 1/64" hole in the set epoxy.

Nothing to sneeze at - you'll lose the drill bit!
1/64" hole? How in the world do you do that? With a 1/64" drill bit of course! I got a couple of these TINY bits for just this sort of occasion. A handy dandy orifice flow calculation shows that this should have a 0.25 scfm air consumption when choked from 100 psig,

The air inlet area must be even smaller than this if it will allow pressures to be controlled over a wide range. Luckily a needle valve I have can be slightly cracked open to just allow enough flow that allows a good range output with decent (5-10 second) re-pressurization times.

The solenoid valve takes 12 volts to open. An IRF510 transistor connected to an Arduino's digital output pin allows the amount of time the solenoid valve spends open and closed to be adjusted to change the equilibrium pressure in the chamber. You can't just use the Arduino PWM output to throttle the valve, though - the on/off frequency used by the PWM pins is way, way faster than the amount of time the valve takes to open and close (which is 5-10 milliseconds from the valve specs). When the output signal to the valve is greater than 50%, I programmed the valve to spend 20 milliseconds off, followed by a variable amount of time on proportional to the output signal. Vice versa for when the output is less than 50%.

I then connected the pressure chamber to the pneumatic actuator of a ball valve I had sitting around.  Although flow control with a ball valve is usually a pretty dicey affair (not that I haven't seen it done), this ball valve should now be able to somewhat precisely control flow! I see another day of boredom avoided with that!

Here's the whole shebang in action:




Sunday, August 21, 2016

Cheap pressure transmitter hack attempt...and failure

Looking for a low cost pressure transducer, I came across these mini digital tire pressure gauges. I thought there might be some signal on its circuit board I could extract to read the pressure from another device. Let's crack it open and see!

The gauge is a Slime brand, model 20268

First things, the device comes with a Schrader valve type fitting to connect to a tire stem to read the pressure. I wanted to connect it to an NPT fitting, so I filled the Schraeder valve connection  point with epoxy. Once it set, I drilled and tapped a 10-32 hole, for which I had adapters to NPT fittings.




On the inside, the device has a pressure sensor chip directly on its main circuit board, which is exposed to the pressure tap. An o-ring seals the circuit board to the pressure tap in a half-torso'd attempt to keep leaks to a minimum. Interesting.

Under the cover


Other side of the circuit board. Note the pressure sensor chip with the O-ring around it. Not the tightest seal, but I guess it really doesn't need to be for measuring a tire's pressure.

Back side of the plastic case - the o-ring fits in the circular groove at the top.
Putting the gauge back together and applying air pressure, it read right in line with my air compressor's gauge. It does appear to latch the highest reading it observed, keeping that reading even after the pressure was removed. This makes sense for a tire pressure sensor - you may not be in a position to easily read the gauge when pressing it against a tire valve stem, but it will retain the reading after you remove it from pressure.

See the force over area!
 
The foolproof way to read a pressure off of the board would be to read the LCD signal points. I really didn't want to eat up 12ish digital inputs and then code an interpreter that converted the LCD signal to a number, so I continued trying to find some sort of output signal on the board.

There are several test points on the circuit board, but I couldn't discern any useful signal from any of them that seemed to vary with the applied pressure. Striking out on them, I attempted to go straight for the sensor chip. I soldered wires directly to the "S+" and "S-" test points, which I took to be the sensor output. Hooking these up to an Arduino's analog input points, I couldn't see any discernible signal when I varied the pressure - they gave a ~1V output for 200 milliseconds, followed by 1 second at 0V, repeated, regardless of the applied pressure. 

Putting the gauge back together, the gauge no longer works - only reads zero now, regardless of applied pressure. I suppose I probably fried something when soldering on to the test points, or inadvertently applied a voltage somewhere that fried the sensor, so this one is a strikeout. There are several other cheap tire pressure gauge models out there, so I may try again with another.

Hey, $7 for a weekend of tinkering ain't a bad deal.


Saturday, July 23, 2016

Arduino-Cryocooler Handshake!

Just look at this!

The curved traces are "artistic" or something
That's my first attempt at having a printed circuit board manufactured, and it turned out mostly okay! I had breadboarded-up an Arduino-cryocooler interface circuit, and was dreading wiring it up using perfboard. I'd heard of the numerous small-quantity PCB manufacturers around these days and decided to try one out, Seeed Studio. I drafted up the circuit in Fritzing, a free PCB CAD program, uploaded the Gerber file output to the Seeed Studio website, and ordered 5 (the minimum quantity) boards for $19. Three to six weeks later, the boards showed up, apparently after a wild weekend in Singapore, looking just like I'd drafted! I soldered one up, powered it up...and realized I'd omitted one trace wire and one resistor.
Whoopsie! Good thing I'm a very forgiving customer to myself.
A couple Whoopsie Wires later and it was transmitting an external thermocouple reading to the cryocooler! It does this by simulating a resistance between two pins on the cryocooler's main control board. These pins are normally connected to the thermistor in the Superlink's Dewar. This thermistor's resistance varies between roughly 5 to 12 kiloohms in the normal working temperature range of the cryocooler. I made a circuit consisting of a 12K resistor in parallel with two optoisolators, one in series with a 12K resistor and one in series with an 800K resistor. Both optoisolators are controlled by an Arduino PWM pins, and open/close the path to give an effective resistance that corresponds to the proper temperature. A capacitor is installed across the positive and negative leads to smooth out the PWM pulses.


Two optoisolators are used because when I tried with just one, the Arduino's 8-bit PWM output wasn't fine enough to adequately control the output when the temperature was close to the lower end of the range. The second optoisolator is in series with a much higher value resistor, and thereby contributes a much smaller signal to the output. Playing around with the values, 800K was approximately the correct value to make the fine output roughly linear between the coarse pulses, giving it roughly 12 bits or so of usable PWM output range, which is fine enough for this purpose. I used optoisolators rather than transistors because I don't know what's going on in the thermistor measuring circuit - I didn't want to take any chances with frying anything on either side with weird voltages.

The Arduino (actually an Ardweeny arduino clone) also connects to the cryocooler's serial interface to read the temperature it just attempted to transmit to the cryocooler, correcting it if it's off. It also reads the power output to the cryocooler. I added a nice little OLED display to show the measured temperature, temperature reported by the cryocooler, and the cryocooler power, so it doesn't need to be hooked up to the computer to read these values. I also added an on/off switch to allow me to soft shut down the cryocooler through its software before turning off its power. This should help avoid damage from hard stops.

The OLED in Alluring Aqua
I now have a self-contained, mobile liquid air generating machine! First order of business is to (of course...) make liquid nitrogen ice cream! I can't wait to see how the most expensive bowl of ice cream I've ever had tastes! After that, it's back to the drawing board to work up a way to liquefy gases other than air.



Update: Aw hell ya

I've loaded the board design (with corrections to my original errors) and the Arduino code here.

The other parts of the quixotic Cryocooler quest are here - Part 1 and Part 2 and Part 3 and Part 4

Saturday, March 19, 2016

Simplified Superlink Interface!

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

tl;dr - Here's a program for interfacing with a Superconductor Technologies Superlink

There's a lot of data pumped out by the cryocooler while it's operating, including various temperatures, voltages, power consumption, et cetera. Unfortunately, I could only access that data through the manufacturer's software, which won't run on anything beyond Windows XP. I have a 10 year old laptop that will run it, but I mean c'mon, it's a ten year old computer. I'm not sure how much longer ol' Speed Turtle here is going to keep on staying critical-failure-free.

High Technology
Besides, I'd ultimately like a way to replace the cold-side temperature measurement the cryocooler uses with a different device, which would be greatly simplified if the device measuring the temperature can see what it's transmitting to the Superlink.

The System Status Portal software turns out to be a pretty face for the serial back-and-forth between the computer and the Superlink. The link runs at 19200 baud, 8 data bits, zero parity, no flow control. I ran a serial monitor program while the computer had the software open and talking to the Superlink, and it showed that the back and forth looked something like this:

Request: 3/13/2016 9:59:32 PM.57264 (+0.2567 seconds)

 3C 53 59 20 4F 50 3D 22 4F 4B 22 2F 3E 0D 0A      <SY OP="OK"/>.. 

Answer: 3/13/2016 9:59:32 PM.57264 (+0.0000 seconds)

 3C 53 59 20 4F 50 3D 22 4F 4B 22 2F 3E 0A         <SY OP="OK"/>.  

Request: 3/13/2016 9:59:32 PM.60364 (+0.0000 seconds)

 3C 54 4D 20 4F 50 3D 22 47 54 22 20 4C 43 3D 22   <TM OP="GT" LC="
 43 52 22 2F 3E 0D 0A                              CR"/>..         

Answer: 3/13/2016 9:59:32 PM.60364 (+0.0000 seconds)

 0D 3C 54 4D 20 4F 50 3D 22 47 54 22 20 4C 43 3D   .<TM OP="GT" LC=
 22 43 52 22 3E 30 20 30 20 31 38 20 33 35 3C 2F   "CR">0 0 18 35</
 54 4D 3E 0A                                       TM>.            

Request: 3/13/2016 9:59:32 PM.63364 (+0.0000 seconds)

 3C 54 4D 20 4F 50 3D 22 47 54 22 20 4C 43 3D 22   <TM OP="GT" LC="
 41 43 22 2F 3E 0D 0A                              AC"/>..         

Answer: 3/13/2016 9:59:32 PM.63364 (+0.0000 seconds)

 0D 3C 54 4D 20 4F 50 3D 22 47 54 22 20 4C 43 3D   .<TM OP="GT" LC=
 22 41 43 22 3E 41 43 42 20 33 20 41 43 39 20 31   "AC">ACB 3 AC9 1
 30 3C 2F 54 4D 3E 0A 0D                           0</TM>..    

The interaction consists of query strings sent by the computer that are returned with the data requested. Pouring through the decompiled code for the System Status Portal (what can I say, I live a wild life), I managed to figure out which query strings returned the data I was interested in. Turns out, if you want to find the cold side temperature and cooler rejection temperature, you ask:

<TP OP="GT" LC="MS"/>

which is responded to with something like:

<TP OP="GT" LC="MS">F 6D80 3BE8 4D60 3C78</TP>

Each of those five hex numbers in the middle there correspond to five different measurements it's returning. Turns out the cold side wide range temperature is the second one (6D80) and the cooler rejection temperature is the third one (3BE8). That hex number is pretty meaningless, though. Pouring through more of the System Status Portal code, I found the formulas it used to convert those numbers to actual temperatures. The formula is:

Temp = (5 * (hex string converted to decimal)/32768 - Offset)/Gain

where for the cold wide range temperature, the offset is 5.814 and the gain is -0.01559. There's a different offset and gain for the rejection temperature and the other temperatures returned. Convert the two-letter parts of the query string ("TP", "OP", "LC", "MS") to their ASCII equivalent hex codes (TP=5450) and then convert that to a decimal number (hex 5450 = 21584), and search the System Status Portal code for that decimal number to work through the logic to find which data points are revealed by which query strings!

Similarly, the cooler power draw can be elucidated with the proper query string and formula, as can every other measurement that shows up in the System Status Portal. In addition to reading measurement values, the System Status Portal can also change the operating state of the cooler, switching it between manual mode where the cooler can be shut off and automatic mode, where the cooler will automatically ramp up power as the cold side temperature declines, keeping the cooler within its safe operating limits. This is accomplished with another query string,

<TP OP="ST" LC="SM">1 4</TP>

will set the cooler to manual shutdown mode, while

<TP OP="ST" LC="SM">0 4</TP>

will turn it back to automatic mode.

I needed an excuse to brush off my infantile Python skills, so I wrote a user interface that will allow you to see the cold side wide range temperature, cooler rejection temperature, cooler power, and status. You can also toggle between Manual Shutdown mode and Automatic mode, so you can shut down the cryocooler safely without the System Status Portal program. I've loaded the Python code to github - you'll need Python installed (I used version 3.5), along with the Tkinter and pySerial libraries to run it. I've only tested it on my Windows 10 computer, but it appears to work pretty well. Here it is on Github. There's a lot of room for improvement and expansion, so if you want to add functionality, go for it!




I next plan to replace the cold side temperature measurement with an external thermocouple, using an Arduino to simulate a resistance to send the temperature measurement to the Superlink. I'll then use the serial handshake to allow the Arduino to talk to the Superlink to read the temperature it's trying to simulate, allowing it to precisely control its output to make sure the Superlink is seeing the same temperature it is.

Friday, February 12, 2016

A goofy 1000 psi air compresor...using a pressure washer

Hey, not all projects have to be practical, right? Sometimes, you just start putting things together and end up with something like this:


For reasons that ultimately led to my cryocooler purchase, I wanted to have a source of quite high pressure (~1000 psi) air. Most ordinary utility air compressors top out at about 150 psi, which, working in the oil and gas industry, seems like small potatoes. I wanted some pressure, I'm talking ANSI 600 class at least. In my line of work, we use devices called blowcases to pump liquids using high pressure gas. They're convenient when you need to pump a liquid to relatively high pressures and don't have any utility electric power, but do have a source of high pressure gas. I figured I could do this in reverse, taking a source of high pressure liquid to pressurize a gas.




The "compressor" works by allowing gas from a lower pressure source (a shop air compressor capable of 150 psi discharge pressure) to enter the compression chamber. Water is then pumped in from the bottom, compressing the gas and allowing it to flow into a reservoir. Once the water reaches a high-level sensing line, the flow of water in is stopped and the water is drained out the bottom. The cycle is then repeated until the pressure in the reservoir is the desired pressure. The level is sensed by a magnet wire inserted into the chamber through a hole drilled in a plug, and then epoxied in place. An Arduino was used to sense when the resistance between the chamber walls and the sensing wire fell, indicating that the water level had reached the wire (good thing mildly impure water is a good conductor). The Arduino then switches a pair of automated valves via a solenoid valve to shut off flow from the pressure washer and drain the chamber. After a set time, the valves are switched again and the cycle repeats. Here's a terribly shaky video explanation of the contraption. Yes, that (was) my kitchen. No, that floor no longer haunts my dreams. Never buy a house, but that's another anthology.



A nice thing about living in an oil field (there are a small handful) is that the local plumbing supply store sells Schedule 80 A106 Grade B pipe capable of withstanding well over 1000 psi and 3000 psi rated fittings. I bought some 2" pipe nipples, and couplings, bushings, and tees. From McMaster Carr (truly the greatest retailer in the solar system), I bought some 1/4" NPT fittings and steel tubing. Off of ebay, I found some reasonably priced 1000 and 2000 psi rated ball valves equipped with pneumatic actuators and an Asco solenoid valve. One happened to be installed as fail open and the other as fail closed, which made it possible to control both valves with the single solenoid valve (although it's pretty easy to switch the fail position on pneumatic actuators of this type). Hooking the pressure washer up to the 2000 psi actuated valve and using the 1000 psi valve to drain the chamber, the contraption actually worked to get up to beyond 900 psi!

pics or it didn't happen

Granted, it did turn out to be quite a pain in the butt to set up, and the time to pressurize the air was quite long, so why in the world of alabaster did I want to do this? At the time, I was thinking the easiest way I could generate liquid air was to allow high pressure air to go through a Joule Thompson expansion to cool it down to liquefying temperatures. However, to JT straight to a liquid, you need to get on top of the liquid envelope on the pressure-enthalpy diagram, that is to say pressurize it beyond its critical pressure, which for air is about 37 atmospheres or 550 psi. After that, you still need to chill it down to about 150K and then JT it to get it into the liquid envelope, but I figured 150K would be easier to achieve than 80K. Turns out, not really, I never got a way to get to those temperatures until I got my cryocooler, which could get all the way to 80 K anyways. It was a fun proof of concept nonetheless.