Tuesday, April 15, 2014

DIY Pick and Place Machine - Part 2

Ok, so we are moving right along with this project.  Parts are coming in weekly, and other parts seem to be endlessly delayed, so we make do.  Since the last post I have been concentrating my CNC PnP education on the following areas:

  • Automagic Z-Axis probing for setting the machines vertical zero position relative to your PCB.
  • Wiring in an emergency stop.  This should have been done before starting the first time.
  • Configuring LinuxCNC's HAL for digital outputs.
  • Investigations into robotic solder dispensing.
Much of this work has been around the back of the machine, so here is a picture of that, and lets discuss.




Above is the back side of the machine.  Along the top is a piece of DIN Rail that extends from the left and right of the ShapeOko frame.  This is where the majority of parts are installed.  Below this, you see a grey vertical surface with parts mounted.  This is a long steel L-Bracket, surplus from some IKEA furniture, that I screwed to the ShapeOko MDF work surface.

Working ( approximately ) from left to right, here is a list of parts:
  1. Green parallel port breakout board.  This gives screw terminal access to your PC parallel port.  To this we attach stepper drivers, digital outputs, digital probe inputs etc. Phoenix Contact P/N: FLKM-D25.
  2. DIN Rail mount Terminal Block.  Multicomp P/N: SPC10564
  3. I colored some of the above terminal blocks red or black with a sharpie.  These are electrically connected with Mulitcomp P/N: SPC11891 jumpers
  4. Big Easy Stepper Drivers - sold by SparkFun P/N: ROB-11876
  5. The two yellow circles are 3-way pneumatic valves.  Clippard.com P/N: EC-3-12 for the valve and P/N: C2-RB18 for a connectorized lead. One of these will be used for solder dispensing/component tape advancing, and the other is for the vacuum pickup system.
  6. Connected to the above valves, via blue tubing ( clippard P/N: 
    URH1-0402-BLT-050 ), is a pressure regulator, clippard P/N: MMR-1N.
  7. The valves and regulator do not come with fittings so I also ordered clippard P/N: 11752-5-PKG
  8. Next you can see a circuit board.  This custom job contains electronics for Opto-isolation, transistor amplification, and Back EMF suppression.  All of which allows us to switch inductive loads like relay coils and solenoids from our PC parallel port safely.
  9. Further to the right is a 12 V DC relay for switching the 110 V AC vacuum pump on and off.  The second set of contacts will eventually drive the vacuum solenoid to either create vacuum in the pickup needle line or vent to atmosphere. I'm not sure if these are available or not, mine is scavenged from an old project Omron P/N: MK2P-S-DC12
  10. On the very far right you can see a blue snubber that is wired across the aquarium ( vacuum ) pump.  I added this to reduce EMI on the 12 V Rail.  It was necessary.  ITW P/N: 104M06QC100.
So, that's kind of an overview of some components, that make the subsystems.  Let's talk a little more about some of the details of setting up the machine and how I intend to make this a useful robot instead of a list of cool parts.  This post will discuss setting up the Z-Axis probing and robotic solder paste dispensing.

Z-Axis Probing:

In case it wasn't already obvious, this entire project has been made so easy by those who have gone before me and were willing to write up their own findings.  Clearly, the best example of this is LinuxCNC, without which, nothing on my machine would be moving this early in the game.  LinuxCNC is powerful and customizable.  And thru adding some text to the configuration files, we can setup the probe functionality built into LinuxCNC, or perhaps more correctly G-Code.

7xCNC.com wrote up an article on how to setup Z-Axis probing.  This will allow me to know how high my pickup needle and solder dispensing needles are relative to the top of my circuit boards.  This is important because later on, when I write G-Code programs for the PnP I will need to reference the top face of the PCB.  Of course you could set the Z-Axis manually, but why would you want to?




Have a look at the picture above, and I will try to explain what happens when we probe the Z-Axis.  The aluminum block you see is 0.75" thick.  The wire connected to this aluminum block via a ring terminal is connected to the PC's parallel port ground.  The alligator clip, clipped to the same electrical point, is connected to the parallel port pin 13 on the other end.  What I just described is a closed switch as LinuxCNC sees it.  If we were to clip the alligator clip to the conductive needle instead, we would have a switch that closes when the end of the needle touches the aluminum block's top face.

If you were to call a probe command in G-Code it may look something like this:
  
G38.2 Z-2.500 F15

G38.2::G38.5 are probing codes.  In the case of the above code it reads: ( G38.2 ) Probe towards work piece, Stop on contact, Signal error if failure. adding ( Z-2.500 ) means that if you get to Z-2.500 before touching the probe surface, stop; something is awry.  The F15 is your feed rate.

So, F15 is fast for probing, right?  Especially when you consider that 7xCNC.com's tutorial implements debouncing for the probe signal.  IIRC, the debounce routine is 100 iterations of the base thread.  Say our base thread runs at 1 mS, well 100 iterations would be 100 mS, and 100 mS at F15 inches per minute equates to 0.0025".  In other words, if you just zoom down into the aluminum block and set Z = zero ( or 0.750" rather ), you will be 2.5 thou too low.  the answer is to slow down that feed rate and consequently decrease the overshoot.

Since we don't want to wait ages for a slow feed rate if we are a long way away from our aluminum probe block, I wrote the G-Code subroutine for probing as below.  If you read the comments you will see that essentially the code quickly probes down to the block, comes up a bit, then probe down slowly to get an accurate Z-Axis reference.

  
o100 sub

( Set current Z position to 0 so that we will always be moving down )
G10 L20 P0 Z0.0

( quickly probe down to touch off plate )
G38.2 Z-3.0 F15

( switch to relative coordinates )
G91

( rapid up 0.1 )
G0 Z0.05

( probe slowly to get a more accurate zero )
G38.2 Z-0.2 f0.5

( set Z0.0 to be 0.75 above work surface - this is due to the touchoff plate thickness )
G10 L20 P0 Z0.75

( switch back to absolute coordinates )
G90

( rapid to Z1.0 - probe tip is now 1" above work surface )
G0 Z1.0

o100 endsub

Below is a video of this Z-Axis probe action.




Now, after making my way thru the probe tutorial above, and modifying the G-Code subroutine for faster probing, I learned enough about how to make buttons appear on my LinuxCNC GUI, and more importantly, make those buttons do something useful.  So, I set out to make some more buttons to speed up the machine setup.  I made buttons for zeroing the X and Y axes as well as one to turn on my solder paste solenoid for 3 seconds to purge any dry solder paste from the needle.




To make this happen, I edited myCNCconfigName.ini such that the HAL UI MDI commands look like below:

 
[HALUI]
# add halui MDI commands here (max 64) 
MDI_COMMAND = o100 call 
MDI_COMMAND = o101 call 
MDI_COMMAND = o102 call 
MDI_COMMAND = o200 call 

Then I edited custom_postgui.hal to contain the following:

 
[HALUI]
# add halui MDI commands here (max 64) 
net remote-o101 halui.mdi-command-01 <= pyvcp.o101
net remote-o102 halui.mdi-command-02 <= pyvcp.o102
net remote-o200 halui.mdi-command-03 <= pyvcp.o200

And finally, I added the following to custompanel.xml

 
[HALUI]
# add halui MDI commands here (max 64) 






So, when you press one of these buttons on the LinuxCNC GUI the respective subroutines below are called:
 
o101 sub

( Set current X position to 0 )
G10 L20 P0 X0.0

o101 endsub

 
o102 sub

( Set current Y position to 0 )
G10 L20 P0 Y0.0

o102 endsub

 
o200 sub

M64 P1 ( DO 1 ON )
G04 P1.0 ( dwell seconds ) 
M65 P1 ( DO 1 OFF )

o200 endsub

I will be revisiting this creation of buttons again soon.  I am thinking of how to probe the X and Y axes instead of manually setting the zeros.


Robotic Solder Paste Dispensing:

To start with this robotic solder paste dispensing problem, I decided to rig up a manual pneumatic dispenser.  With a switch connected to a solenoid, I was able to selectively apply CO2 to my syringe of solder paste.  The solder paste naturally escapes thru the dispensing needle, and the hope is, that the correct amount makes it onto the correct solder pad.




This sounds easy enough.  We have a fixed orifice, and a fixed pressure ( 40 PSI of CO2 ), so we should have a constant flow, and with a constant time, a deterministic volume dispensed.  What I don't have, however, is a fixed viscosity fluid.  My solder paste varies from dry to entirely too wet.  The reason for this, I think is that the paste is 2 years old, and it has a shelf life of 6 months.

All this means is that my time based experiments in this area are largely useless at this point.  I have ordered a new tube of solder paste.  This has proven to be a good learning experience.

Eventually the human operated switch was replaced by an opto-isolated, transistor amplified, and back EMF protected circuit, that means that I can now write G-Code to turn on and off this solenoid for a specific time period with the code:
 
M64 P1   ( turn D0 ON solder solenoid )
G04 P1.5  ( dwell seconds ) 
M65 P1   ( turn D0 OFF - solder solenoid )

Strap the digitally controlled solder paste syringe to the pick and place gantry, and you can do this:

Below is a picture of solder paste dispensing onto a piece of paper.  The 5 dots on the left were dispensed with a 1.5 second period, and for the 5 dots on the right the CO2 solenoid was open for 2 seconds.




Here is a video of the dispensing in action. You can notice that the first pad does not get enough solder dispensed onto it.  Given the viscosity disparity of this expired solder paste tube, and my elected method of application, i'd say these results are pretty good.




While the solder was being placed on the circuit boards, I was hand populating the components.  The resulting boards are just as good as they ever have been using a solder paste screen.  And certainly, one of the coolest features of robotic solder paste application is that I can make new boards while never having to purchase a ~$200 solder paste screen again.




Ok, well I can't think of anything else to talk about on this topic.  It's all pretty prototypical at this point, but I'd say its moving in the right direction.  And if you've made it this far into the reading, thank you; you're doing better than me.

Sunday, March 16, 2014

DIY Pick and Place Machine - Part 1

Well, it sure has been a while since i've posted anything, but that does not mean i've been idling my time away.  One of my projects since my last post has been starting AirPatchCable.com.  AIR Patch Cable was setup because I was disappointed with the selection of Aviation Intercom Recording cables on the market.  Everything was either way over priced, of such poor quality, or both, that I didn't want to plug them into my camera, let alone a planes intercom.

For AIR Patch Cables I designed a cable with capacitive coupling and passive attenuator pad to make interfacing to the airplanes intercom simple and sound great.  To fit everything into the phono jack backshell meant that I had to put the attenuator and capacitive coupling passives onto a circuit board.  Below is a picture of these circuit boards.  P.S. If you or someone you know is a pilot, you should check out AirPatchCable.com.




So, how are all of these SMD circuit boards going to get populated?  Well, to start out, by hand.  That is no easy task,  however, and so I decided to build a robot to make these boards for me while I attend to other things.

In actuality, this machine probably needs supervision, but there are other benefits to robotic assembly even if I have to sit there and supervise the robot.  A robot, or perhaps more accurately named a "Pick and Place Machine" in this case, is unlikely to place a 100 ohm resistor where the 1000 ohm resistor is supposed to go, or put that diode in backwards, thus rendering the entire circuit useless.  Perhaps the biggest benefit is that my eyes and neck will remain in relative comfort.

OK, so this is where we are so far.  I titled this post "... Part 1" because my machine does not pick nor place just yet.  But what I have achieved is a milestone.  I have programmatic computer control over a 3 axis machine.  This would be considered a starting point for many projects.  From here you could make a laser cutter, a CNC mill, a 3D printer, or in my case a pick and place machine.

Lets cut to the chase and put up the video and we can talk about it a little more later.




Below you can see a shot of the overall setup.  I'll break it down a little later.  For now, just enjoy the pics.








In the top pic you can see the mechanical setup and the computer that controls the stepper motors.  The next pic down you can see the stepper motor drivers.  Finally, in the third pic is a photo of the software, LinuxCNC which are the brains of the operation.

An over simplified explanation of operations is that LinuxCNC reads a G-Code program that you wrote.  LinuxCNC then controls the host computers parallel port where the stepper motor drivers are connected.  The stepper motor drivers are electrically connected to the stepper motors which are in turn mechanically coupled to the XYZ or 3 axes of the machine.


Mechanical:

When I first considered making a PnP ( Pick and Place ) machine, I started looking at linear bearings from the usual suspects.  Thompson and Igus, namely.  I quickly found out what I already suspected.  Linear bearings are expensive.  During my search however, I came across a 3 axis mill kit for about $300.

I could not pass this up.  It would suit all of my design criteria for this project and cost less than if I designed my own.  The kit is called a Shapeoko 2, and it is sold by a company called Inventables.  Here is a link the kit.  If you are planning to build the same robot I did, keep in mind I only ordered the mechanical kit as the electronics didn't really suit my needs.

The kit was pretty easy to assemble.  I don't really know how long it took because I did it over the course of a while.  I would strongly consider building future rigs with the "maker slide" linear bearings that Shapeoko 2 uses.  Aluminum extrusions are plenty stiff for this project and I suspect many others.

The mechanical kit from Inventables does not come with all the mechanical components.  I ordered MXL belting and pulleys from ebay to complete the mechanical side of things.


Electrical:

I decided to use the Big Easy Driver for driving my stepper motors.  This is a stepper motor driver designed by Brian Schmalz and sold by Sparkfun Electronics.  Brian was very helpful when I emailed him about some compatibility questions I had.

There is a potentiometer onboard each Big Easy Driver to set the motor current.  Too low and the motor is uncontrollable.  Too high and the driver gets too hot.  This fact must me accomidated for when you are setting up your motors, one by one.

I ordered 5 of the Big Easy Drivers to go with the quantity five, NEMA 17 motors I ordered from ebay.  I am told that NEMA 17 is about the biggest motor the Big Easy Driver should be used for.

I was really impressed with the torque these NEMA 17 motors have when paired with the Big Easy Driver.  I couldn't pinch the 5 mm output shaft with my fingers to stop the motor from turning.  I offer that anecdotal statement in lieu of data sheets or a torque measurement.


Software:

I am using LinuxCNC for stepper control.  I was really impressed with how easy everything was to set up.  I'll go ahead and post a couple of setup photos with parameters I have found to work with the Big Easy Driver.

Oh, LinuxCNC runs on Ubuntu 8.04 or 10.04, so be prepared to downgrade.  Having said that, 10.04 is a dream to work on.  You can even download Ubuntu 10.04 with LinuxCNC pre-compiled.  That's what I did.

Below are some screen short of my configuration thru StepperConf in LinuxCNC.









I wrote a CNC program to control the PnP machine.  I stuck a pen on its Z axis, and below are photos of the result.  Pretty good so far I'd say.  The first word I wrote was Gangsta., because, you know, G-Code.  After that, I had my PnP machine pen the Japanese phrase "Domo arigato", leaving off the presumed "Mr. Roboto".






Next Steps:

OK, so we have computer control of a 3 axis machine now, but what is left to make this a pick and place machine?  Well, quite a bit actually.  I need to tidy up the wiring, and properly mount things like the stepper drivers.  We need a method to feed the SMD tape.  A vacuum needle for picking up the parts.  An "A" axis for rotating the picked up part about the Z axis.  Oh, and I'm planning to make this a robotic solder past dispenser too.  Machine vision is a lofty goal that I may revisit a a tertiary upgrade.

If you have any questions or comments, feel free to leave a comment below or send me an email from the "About Me" section in the right pane.

Saturday, September 28, 2013

LaTeX Airplane Checklist

The use of checklists is one of the tenets of aviation.  We have them for pre-flight inspections all the way thru shut down procedures and even emergency procedures.  Aviation checklists are so pervasive that they have even sprung up a cottage industry around their sale.  You can purchase colorful, durably laminated checklists for around $15, and you can buy iPhone/iPad or Android checklists too.  Although I am iEquipt and Android enabled, at this point I am preferring the paper checklists.

At any rate, if you are a student pilot like myself, you may have been given a few checklists from your CFI or FBO.  And if your FBO is anything like mine, your checklist probably contains some vestigial entries from equipment long gone.  For example, the checklist I was given for my plane had checks for an autopilot system which does not exist.  It also had IFR procedures, but my plane is not currently IFR legal and I doubt it is a priority to make it such.  I found these superfluous entries distracting and they disrupted the flow of my procedures.

Well, for better or worse I am a DIY type of guy, and so I reject the pre-made checklists - both old and new and decided to roll my own using LaTeX.  LaTeX ( pronounced latek ) is a typesetting system primarily used in technical and scientific writing.  I am pretty new to using LaTeX, but the more I use it the more I like it.  My pedagogical interest in LaTeX quickly turned utilitarian and it is rapidly filtering thru my life, both professionally and in academia.  The end result of all this is a really classy looking document with none of the formatting hassle associated with WYSIWYG editors such as MS Word or OpenOffice Text Document.

Here is a LaTeX code snippet from my checklist. I basically just copied the checklist from my FBO, making changes where appropriate.  For example, I tried to maintain consistency in language throughout the list.  My brain is happier when I am not identifying inconsistencies in my checklists.  Having said that, if you see any typos please let me know.  I am also going to ask my CFI to double check the final checklist before we fly next.
  

\subsection{Before Takeoff - Run-Up}

 \begin{enumerate}
 
  \item Cabin Doors and Windows - \textbf{Closed \& Locked}
  \item Parking Brake - \textbf{Set}
  \item Flight Controls - \textbf{Free \& Correct}
  \item Flight Instruments - \textbf{Set}
  \item Fuel Selector Valve - \textbf{ON - Fullest Tank}
  \item Elevator Trim - \textbf{Takeoff}
  \item Mixture - \textbf{Rich or As Required}
  \item Throttle - \textbf{2000 RPM}
   \begin{enumerate}
    \item Magnetos - \textbf{Check}
    \item Carburetor Heat - \textbf{Check}
    \item Engine Instruments \& Ammeter - \textbf{Check}
    \item Suction Gauge - \textbf{Check 5"$ \pm $0.1}
   \end{enumerate}
  \item Throttle - \textbf{Idle, then 1000 RPM}
  \item Radios - \textbf{Set}
  \item Transponder - \textbf{Set, then Altitude}
  \item Throttle Friction Lock - \textbf{Adjust}
  \item Fuel Pump - \textbf{ON}
  \item Lights - \textbf{As Required}
  \item Parking Brake - \textbf{Release}
 
 \end{enumerate}
And the result of this code output looks like this screen cap from the PDF.


Here is a picture overview of the checklist.  You can download a PDF checklist and the LaTeX code to make your own down further.



One of the main advantages to having this template setup is that I can quickly make adjustments to the checklist contents.  If I need to add or clarify anything it is quick and easy and the formatting stays the same.

If you would like a copy of the LaTeX code you can download it here.  You are welcome to download the output from the code aka my checklist, but I imagine you would want to customize your own checklist.  Either way, here is the PDF checklist I made for the plane I usually fly.

Sunday, June 23, 2013

Robotic Instagram Timelapse Video



As you are probably already aware, Instagram has enabled video uploading. You are limited to 3-15 second clips and can't upload previously recorded videos. The record button in the Instagram app is non-latching, so you have to hold the button down all the while you want to record.  At the end, all of your little clips ( up to 15 seconds ) are stitched together into a video ( with sound please remember ) that you can then add a distinctly Instagram-esque filter to and upload.

Working within these boundaries I have devised a method to make timelapse videos using a servo actuated, simulated finger to press the record button in the Instagram app at somewhat deterministic yet not entirely accurate intervals. Let it be said that the future may hold software solutions for timelapse in instagram, but for now, I am making timelapse videos in Instagram before they are cool?




This project had a couple of interesting things. For one, this was my second time using the Arduino platform for prototyping. I had purchased an Uno R3, LCD shield and prototype shield for an upcoming project, but decided to borrow the hardware for the Instagram robot instead. Although I am not a big fan of the abstraction that Arduino provides I was able to quickly prototype with the equipment I listed above. From concept to build to first timelapse video took all of about 4 hours.




In the above photo you can see values on the screen for sv_in which is the servo angle when the simulated finger is pressing the record button.  The variable for interval is milliseconds until the next record button press.  You can also see a 'P' for pause, in the lower right corner which is toggled  'R' for run when a button is pressed.  The servo " in " position and interval time are adjustable by buttons on the front panel.  I guess now would be an appropriate time to mention that the record button press duration is 150 mS.

At any rate, the other interesting part of this project was the simulated finger for pressing the record button. I used some conductive foam, shipped with IC's jammed into the end of an Exacto knife holder. The blade, of course was removed. The handle of the exacto knife was then electrically tied to the negative supply of the Arduino. This activated the screen quite well, however my first hardware design had the simulated finger " swipe " to come into contact with the screen aka tangentially. The Instagram app did not respond to tangential activation and I had to redesign the servo configuration to allow more perpendicular action.

I will post a video of the results as soon as Youtube snaps out of the mood its currently in.  


Saturday, February 16, 2013

Learning to fly and Perl for METAR Decoding




One of the ways I have been occupying myself is with flight training for a private pilot license or more correctly called a private pilot certificate.  It's been off and on lately because I have had to take some time off to focus on other projects, but next month I will be resuming at as fast of a pace as my pocketbook will allow.  Since I needed some pilot/flying related activities to keep my interest during this down time I decided to write a Perl parsing script for aviation weather reports called METAR's.  But, first how did I find myself in the left seat of an airplane for the first time?  Well, read on.

About a year ago as a birthday present I was given a "discovery flight" by my parents.  A discovery flight is where a certified flight instructor sticks you in the pilot seat, guides you to take off and fly a plane  around for about an hour before landing at the airport where you took off from.  This is akin to the "visitation" rooms at the humane society where they let you play with the puppies and cats, all the while knowing that the puppy ( or aircraft, rather ) that you have been playing with is soon to become your highest priority.




That's how it happened with me anyway.  On my discovery flight I pushed the throttle forward.  We soon accelerated to 50 knots and when I pulled the yoke toward my chest, the Cessna 152 parted the runway and I became speechless; my breath had been taken thru amazement of the reality of flight.  It is one thing to understand the physics of flight and totally different to experience it.  General aviation or small aircraft flight isn't anything like the experience of large commercial airplanes.




In fact, I was so taken by this flying that I decided to continue flight lessons, working towards a private pilot certificate.  As I mentioned above I have experienced quite a few training delays along the way including taking time off to start Lakeside Electronics, LLC, so in the interim I wanted to come up with some activities related to flying.




Early on in my flight training I recognized the impact and importance of weather on general aviation or I should say, aviation in general.  There are even aviation specific weather reports such as METARs that pilots access for preflight weather planning.  You can look up a report for an airport near you using their ICAO station identifier code here http://aviationweather.gov/adds/metars/.

Here is an example METAR string from the airport I fly out of in Ann Arbor, Michigan: KARB 021653Z 34015G23KT 10SM OVC033 04/M03 A2996 RMK AO2 SLP150 T00441033.  

As you read the above report you can probably make out what some of the sub-strings mean.  For example, before researching I postulated that " OVC033 " meant overcast, but I did not fathom that the second half was referring to cloud height in 100's of feet.  Could " SLP150 " be something to do with slip?  Nope, Sea Level Pressure - in tens, units and tenths to be added to 1000 hPa no less.  In other words, 15.0 hPa + 1000 hPa = 1015.0 hPa.  However, if the string were a high number like SLP965 you would add that value ( 96.5hPa ) to 900 hPa instead for a reading of 996.5 hPa.  Yes, its a strange little protocol...

Almost certainly I needed to study up on how to interpret this METAR report.  Fortuitously, it would seem, I had concurrently begun learning the programming language Perl.  A perfect storm, it would seem, to write a Perl based parsing script for METAR weather reports and display these data in a more human readable format was afoot.

The goal of course is two fold.  A) To learn Perl and B) to memorize a method of METAR interpretation for when I need to read the raw string.  Quite obviously there are numerable ways to accomplish these tasks.  There also exists METAR decoders and even a Perl Module for this task, but this would violate my goals as set forth and thus decided to write my own Perl METAR parsing script.

When I turned to Google for information about the METAR protocol I found this page http://www.met.tamu.edu/class/metar/quick-metar.html helpful indeed.  If you recall, we discussed the sub-string for sea level pressure above.  There are too, other little gotchas along the way when trying to programmatically decode METAR reports.  For instance, some data are always reported, some data are optionally reported and within the raw string as a whole, the sometimes reported data is intermingled with the always reported data.  I also have reason to believe that the information contained in the remarks ( RMK ) section can partially exist as plain English, and so that is where my parsing stops - before we get to the optional remarks.  I may look into further coding of the remarks, but for now I am satisfied with the script.

This Perl script uses Curl to fetch a METAR string from weather.noaa.gov.  Then it parses the string, does some formatting and a couple of calculations for Celsius to Fahrenheit conversion then writes the data to a text file.  Using a program on my macbook called GeekTools I am able to display the contents of the Perl generated text file on my desktop.  It looks like this on my desktop.



Before continuing, I must say that you shouldn't use this script for flight planning and also, that it is largely untested.  Please report any bugs that you may find.  Part of my ongoing memorization of METAR syntax is to read the string and my scripts output and look for errors.

If you want to play along, install Geektools from the link in the previous paragraph.  You will also want to copy the Perl script from below.  Save the Perl script in a folder somewhere on your computer.  I named my folder "metar" and located in ~/Documents/Weather/.  Start up GeekTools and configure like so...



The command in the above screen cap is "cat ~/Documents/Weather/metar/metar_datafile.txt" without quotes.  Change this as required for your particular path and file name.


Below is the code.  It is definitely a work in progress.  Every time I spot an error I correct it but I haven't seen any errors in a while now.  Let me know if you do.

  
#!/usr/bin/perl -w

# this program gathers METAR data from NOAA, decodes it and does some formatting before writing the data to a text file
# this file is monitored and displayed on my macbook desktop using GeekTools
#
# Under no circumstances should you use this for flight planning.  Also, no guarantee is made that this software even works at all.
#
# Below is an example of the metar_datafile.txt after the curl command.  There are 2 lines as you can see.
#
# 2012/10/27 11:53
# KARB 300153Z AUTO 35018G34KT 10SM OVC095 06/M05 A2978 RMK AO2 PK WND 35034/0144 SLP090 T00561050
#
#

#while( 1 ){
my $ICAO_STATION = "KARB"; # airport nearby

my $raw_metar_data = `curl --silent http://weather.noaa.gov/pub/data/observations/metar/stations/$ICAO_STATION.TXT`;

chomp $raw_metar_data;

my  ( $date_time, $current_metar_line ) = split /\n/,$raw_metar_data;

chomp $date_time;
chomp $current_metar_line;

# put the METAR string into an array 
my @metar_array = split / /, $current_metar_line;
my $array_index = 0;

open (MYFILE, '>metar_datafile.txt'); #open for write >> would be for apend

#
# print the full array we are about to decode separated by spaces
print MYFILE "@metar_array\n";

#
# print the station ID as read
print MYFILE "ICAO Station ID: $metar_array[ $array_index ]\n";
++$array_index;

#
# print the day of the metar transmission
my $day = substr( $metar_array[ $array_index ], 0, 2 );
print MYFILE "Day: $day";

# print ^st, ^nd, ^rd or ^th at the end of the date just for a bit of fun
#my $right_digit = substr( $day, 1, 1 );

#$day = "3";



if( ( scalar $day == 1 ) || ( scalar $day == 21 ) || ( scalar $day == 31 ) ){
 print MYFILE "st\n";
}
elsif( ( scalar $day == 2 ) || ( scalar $day == 22 ) ){
 print MYFILE "nd\n";
}
elsif( ( scalar $day == 3 ) || ( scalar $day == 23 ) ){
 print MYFILE "rd\n";
}else{
 print MYFILE "th\n";
}


#
# print the time of the metar transmission in zulu time aka 0 GMT
my $zulu_hours = substr( $metar_array[ $array_index ], 2, 2 );
my $zulu_minutes = substr( $metar_array[ $array_index ], 4, 2 );
print MYFILE "Report Time ( Zulu ): $zulu_hours:$zulu_minutes\n";

++$array_index;


#
# decode and print report type ( auto or corrected or none )
#
# test String
# $metar_array[ $array_index ] = "COR";


if( $metar_array[ $array_index ] eq "AUTO" ){
 print MYFILE "Report Autonomy: Automatic - No human intervention.\n";
 ++$array_index;
 }
elsif( $metar_array[ $array_index ] eq "COR" ){
 print MYFILE "Report Autonomy: Corected observations.\n";
 ++$array_index;
 } 
else{
 print MYFILE "Report Autonomy: Human observer or Automatic with human oversight.\n";
}


#
# decode and print wind data

print MYFILE "Wind Condition: ";

# the first three characters are either VBR or they contain wind direction
my $wind_direction = substr( $metar_array[ $array_index ], 0, 3 );

# the next two characters always contain wind speed
my $wind_speed = substr( $metar_array[ $array_index ], 3, 2 );

if( $wind_direction eq "VBR" ){
 print MYFILE "Direction variable at $wind_speed knots.\n";
 ++$array_index;
}
# else if the string contains a 'V' for variable wind over 6 knots...
elsif( $metar_array[ $array_index ] =~ /V/ ){
 print MYFILE "Wind from $wind_direction degrees at $wind_speed knots - ";
 my $dir1 = substr( $metar_array[ $array_index ], 9, 3 );
 my $dir2 = substr( $metar_array[ $array_index ], 13, 3 );
 print MYFILE "Variable between $dir1 and $dir2 degrees.\n";
 ++$array_index;
} 
# else if the string contains a 'G' for gust
elsif( $metar_array[ $array_index ] =~ /G/ ){
 print MYFILE "Wind from $wind_direction degrees at $wind_speed knots - ";
 my $gust_speed = substr( $metar_array[ $array_index ], 6, 2 );
 print MYFILE "Gusts to $gust_speed knots.\n";
 ++$array_index; 
}
else{
 print MYFILE "Wind from $wind_direction degrees at $wind_speed knots.\n";
 ++$array_index;
}


#
# decode and print visibility

print MYFILE "Visibility: ";

# remove "SM" from the end of the string leaving the visibility in statute miles
my $visibility = $metar_array[ $array_index ];
chop $visibility;
chop $visibility;

# if the string still contains an 'M' after the chops there is a special case
if( $visibility =~ /M/ ){
 print MYFILE "Less than 1/4 statute miles.\n";
} 
elsif( $visibility eq 9999 ){
 print MYFILE "Greater than maximum recorded value.\n";
}
else{
 print MYFILE "$visibility statute miles.\n";
}
++$array_index;



#
# decode and print runway visual range if reported
# this string should contain a forward slash if it contains runway visual data
#
# test string
# $metar_array[ $array_index ] = "R16/P20000VM211FT";

if( $metar_array[ $array_index ] =~ /\// ){
 
 print MYFILE "Runway Visual Range: ";
 
 my( $runway, $range ) = split /\//, $metar_array[ $array_index ];
 
 # remove the 'R' from the runway number
 $runway =~ s/.//;
 
 # remove "FT" from the range(s)
 chop $range;
 chop $range;
 
 # there is a 'V' in $range_a if the visual range is variable
 if( $range =~ /V/ ){
  my( $range_a, $range_b ) = split /V/, $range;
  print MYFILE "Runway $runway has a visual range between ";
  
  # check for the M or P modifier
  if( $range_a =~ /M/ ){
   #remove the 'M'
   $range_a =~ s/.//;
   print MYFILE "less than $range_a and ";
  }
  elsif( $range_a =~ /P/ ){
   # remove the 'P'
   $range_a =~ s/.//;
   print MYFILE "greater than $range_a and ";
  }
  else{
   print MYFILE "$range_a and ";
  }
  
  if( $range_b =~ /M/ ){
   #remove the 'M'
   $range_b =~ s/.//;
   print MYFILE "less than $range_b feet.\n";
  }
  elsif( $range_b =~ /P/ ){
   # remove the 'P'
   $range_b =~ s/.//;
   print MYFILE "greater than $range_b feet.\n";
  }
  else{
   print MYFILE "$range_b feet.\n";
  }
  
  
  
 }
 else{
  print MYFILE "Runway $runway has a visual range of ";
  
  # check for the M or P modifier
  if( $range =~ /M/ ){
   #remove the 'M'
   $range =~ s/.//;
   print MYFILE "less than $range feet.\n";
  }
  elsif( $range =~ /P/ ){
   # remove the 'P'
   $range =~ s/.//;
   print MYFILE "greater than $range feet.\n";
  }
  else{
   print MYFILE "$range feet.\n";
  }
    
 }
 ++$array_index;
}



#
# decode and print weather phenomena if it exists
#
# test string
#$metar_array[ $array_index ] = "+RAPRTS-DRPL";

my $weather_phenom = $metar_array[ $array_index ];

# if the current string does not contain cloud cover data then it is weather phenomena

if( $weather_phenom !~ "SCK" & $weather_phenom !~ "CLR" & $weather_phenom !~ "FEW" & $weather_phenom !~ "SCT" &
 $weather_phenom !~ "BKN" & $weather_phenom !~ "OVC" & $weather_phenom !~ "VV" )
 {
  print MYFILE "Weather Phenomena: ";
  
  my $string_index = 0;
  my $string_length = length $weather_phenom;
  
  while( $string_index < $string_length ){
  
   my $sub_string = substr( $weather_phenom, $string_index, 2 ); 
   
   if( $sub_string =~ /\+/ ){    
    print MYFILE "Heavy ";
    ++$string_index;
   }
   elsif( $sub_string =~ /\-/ ){
    print MYFILE "Light ";
    ++$string_index;
   }
   #else{
   # print MYFILE "Moderate ";
   #}
   
   $sub_string = substr( $weather_phenom, $string_index, 2 );
   
   # hash lookup
   
   %weather_type = ( "VC" => "Vicinity ",
        "MI" => "Shallow ",
        "PR" => "Partial ",
        "BC" => "Patches ",
        "DR" => "Low Drifting ",
        "BL" => "Blowing ",
        "SH" => "Showers ",
        "TS" => "Thunderstorm ",
        "FZ" => "Freezing ",
        "DZ" => "Drizzle ",
        "RA" => "Rain ",
        "SN" => "Snow ",
        "SG" => "Snow grains ",
        "IC" => "Ice crystals ",
        "PL" => "Ice Pellets ",
        "GR" => "Hail ",
        "GS" => "Small hail ",
        "UP" => "Unknown ",
        "BR" => "Mist ",
        "FG" => "Fog ",
        "FU" => "Smoke ",
        "VA" => "Volcanic ash",
        "DU" => "Widespread dust ",
        "SA" => "Sand ",
        "HZ"  => "Haze ",
        "PY" => "Spray ",
        "PO" => "Well developed dust/sand swirls ",
        "SQ" => "Squalls ",
        "FC" => "Funnel clouds including tornadoes or waterspouts ",
        "SS" => "Sandstorm ",
        "DS"  =>  "Duststorm ",
        );
        
   print MYFILE "$weather_type{ $sub_string }";
   
   # see if there is another weather code
   $string_index += 2;
  }
  
  print MYFILE "\n";
  ++$array_index;
}


#
# decode and print the cloud cover data ( always present )
#
# test string
#$metar_array[ $array_index ] = "BKN120";

print MYFILE "Cloud cover: ";

# if there are multiple cloud conditions which can occur...
while( $metar_array[ $array_index ] =~ /(SCK|CLR|FEW|SCT|BKN|OVC|VV)/ ){
my $sky = 0;
my $cloud_height = 0;
 

if( $metar_array[ $array_index ] =~ /VV/ ){

 $sky = substr( $metar_array[ $array_index ], 0, 2 );
 $cloud_height = substr( $metar_array[ $array_index ], 2, 3 );
}
else{

 $sky = substr( $metar_array[ $array_index ], 0, 3 );
 $cloud_height = substr( $metar_array[ $array_index ], 3, 3 );
}


%sky_condition = ( "SCK" => "Sky Clear ",
     "CLR" => "Clear sky",
     "FEW" => "Few clouds ",
     "SCT" => "Scattered clouds ",
     "BKN" => "Broken clouds ",
     "OVC" => "Overcast clouds ",
     "VV" => "Vertical visibility ",
     );
     
print MYFILE "$sky_condition{ $sky }";

# if $sky has clouds in it then report the cloud height.
# if skies are clear, do not report cloud height

if( $sky =~ /(FEW|SCT|BKN|OVC|VV)/ ){
# cloud height is given in hundreds of feet
$cloud_height *= 100;

print MYFILE " at $cloud_height feet. ";
}
++$array_index;
}   

#
# decode and print the temperature and dewpoint ( always present )

my( $temperature_c, $dewpoint_c ) = split /\//, $metar_array[ $array_index ];

# if it is a negative number
if( $temperature_c =~ /M/ ){
 # remove the 'M' from the temperature
 $temperature_c =~ s/.//;
 $temperature_c *= -1; # and make it a negative number
}

if( $dewpoint_c =~ /M/ ){
 # remove the 'M' from the dewpoint
 $dewpoint_c =~ s/.//;
 $dewpoint_c *= -1; # and make it a negative number
}

my $temperature_f = $temperature_c * 1.8 + 32;
my $dewpoint_f = $dewpoint_c * 1.8 + 32;

print MYFILE "\nTemperature: $temperature_c degrees C / Dewpoint: $dewpoint_c degrees C.\n";
print MYFILE "Temperature: $temperature_f degrees F / Dewpoint: $dewpoint_f degrees F.\n";

++$array_index;


#
# decode and print atmospheric pressure ( always present )
#
# test_string
#$metar_array[ $array_index ] = "Q1234"; 
#$metar_array[ $array_index ] = "A1234"; 

my $atm = $metar_array[ $array_index ];

# if our pressure is reported in mb aka hPa
if(  $atm =~ /Q/ ){

 # remove the 'Q' from the pressure
 $atm =~ s/.//;
 print MYFILE "Atmospheric Pressure: $atm hPa\n";

}

# if our pressure is reported in mb aka hPa
elsif(  $atm =~ /A/ ){

 # remove the 'A' from the pressure
 $atm =~ s/.//;
 
 my $whole_inhg = substr( $atm, 0, 2 );
 my $frac_inhg = substr( $atm, 2, 2 );
 
 print MYFILE "Atmospheric Pressure: $whole_inhg.$frac_inhg inHg\n";

}

++$array_index;



#
# decode and print


close (MYFILE); 

#sleep( 60 );
#}























Ok, onward and upward.  Clear for takeoff.

Wednesday, September 12, 2012

KD8TBW - My HAM Radio Call Sign

I recently took an FCC Exam for radio broadcast privileges.  I passed and as the title suggests my HAM or Amateur Radio Call Sign is KD8TBW or in the NATO Phonetic Alphabet  Kilo, Delta, Eight, Tango, Bravo, Whiskey. 

I decided to take the test after I reading the April 2012 issue of Nuts and Volts Magazine.  On page 68 was an article on how to get your HAM license and the opening question was " If you are interested in electronics and radio communications, why aren't you a HAM? ".  Well I couldn't answer that question and the article had a very compelling list of  "10 things you can do as a HAM " so I set out to change my unlicensed status.

If you are wondering what HAM radio is, why you need a license or what cool things you can do as a HAM then head over to the American Radio Relay League ( ARRL ) website and take a look.  You'll discover many interesting activities that becoming a HAM will open up to you such as talking to astronauts aboard the ISS, bouncing radio signals off the moon or meteor showers and fox hunts with Tape Measure Yagi Antennas for radio direction finding.

You may also discover loosely related projects that don't require a HAM radio license.  For instance, together with my Dad, we have recently begun construction of a Quadrifilar Helicoidal Antenna for recieving APT messages from NOAA Weather Satellites, but more on that one in a later post.

I'm still pretty wet behind the ears with all this HAM radio stuff, but it is providing a good bit of entertainment so far.  I picked up a Kenwood TH-F6A Radio and I even joined a local HAM radio club called ARROW Communications in Ann Arbor.  I'm pretty sure I want to get into a mobile radio for my car so let me know if you have any suggestions on mobile setups.

Tuesday, September 4, 2012

Thor - A Programmable Brake Light Modulator

I have been rather busy developing products for my new company Lakeside Electronics, LLC and as such, haven't had much time to post anything in the way of projects over here.  This is OK however, because despite the massive amount of work involved in bringing a product like Thor to market, it turns out to be pretty fun too. 

Of course, I still have a few irons in the hobby fire, and with Halloween coming up there are bound to be some scary, or at a minimum, vaguely direful ideas cropping up in my yet-to-be-zombified mind.  But, first, I have some microcontrollers to program for a Boy Scout Troop.  I was recently contacted by (them) and I am quite pleased to help them out making Halloween Spooky Eyes.  Anytime someone is interested in learning new things I think it is fantastic.

Ok, so back to Thor - A Programmable Brake Light Modulator and Lakeside Electronics.  If you have been reading my recent posts you are probably already aware of what a brake light modulator is.  If you have any feedback, I'd like to hear it

And finally here is the video for Thor.