Thursday, June 09, 2016

Introducing LabVIEW support for Raspberry Pi 2 and BeagleBone Black

For the last 6 months, a friend and I have been working on a really cool project, and now I can finally talk about it.

We've always wanted a way to use LabVIEW to program the amazing Linux-based maker devices like the Raspberry Pi and BeagleBone Black.  It seems like a natural fit for programmers that are new to distributed programming, embedded devices, and Linux.  LabVIEW has been an excellent way to write, debug, and deploy embedded applications over a network with the LabVIEW Real-Time module.

So we set out to port the LabVIEW Real-Time module to the BBB and RPi2.  Mainly this consisted of getting the LabVIEW run-time engine running on the BBB/RPi2 and writing some kind of I/O library to make it easy to do things like reading and writing digital lines, reading analog inputs, and communicating on I2C and SPI buses.

In the end, we got it all working and released it to the public, and it's actually affordable as well ($50 + cost of hardware).  All you need is a copy of LabVIEW 2014, the (free) LINX toolkit, and a BeagleBone Black or Raspberry Pi 2 or 3. See this link for more info.

We also spent some time putting together some respectable tutorials to help people get started.

What will you do with LabVIEW on a BBB or RPi?  I'm looking at automating the beer making process, and I've got some friends that want to use it with rockets and robots and other interesting things...

Sunday, March 20, 2016

Creating a customized image for BeagleBone Black or Raspberry Pi

Recently I wanted to create a customized image for a Raspberry Pi.  Basically, I just wanted to download a stock Raspbian image, install some software, change a few configuration settings, and then put it back together just as I'd gotten from the original image.

This is (or should be) pretty simple but I had trouble finding concise instructions for doing it.  What I found fell into one of two categories: 1) instructions for backing up an image, or 2) really complex instructions for generating an image from scratch.

At first glance the backup instructions (like these) seemed perfect.  You run the equivalent of Linux's dd command and end up with an image file that can be flashed to an SD card on Windows, Linux, or Mac.  Perfect, right?  Maybe not.  Here's a scenario I ran into:  I downloaded an image that would fit on a 4GB SD card, I flashed it on an 8GB card because that's what I had lying around, made my modifications, and created a backup image.  The problem was the image is an image of an 8GB card, so it will no longer fit on a 4GB SD card even though the amount of actual data on the card should allow it to live on a 4GB card.

So here is a process that gives us the ease of the backup process, but with the power to resize things back to the original image size:
  1. Download the latest official image for Raspberry Pi or BeagleBone Black.
  2. Extract the image, flash it, and boot it.
  3. Make whatever changes you want to the image (install software, change configurations, etc.).  Keep all other settings to the defaults, like the hostname, users, and passwords.
  4. Shutdown the target, extract the SD card, and backup the image using one of the methods here.
  5. This will backup the entire SD card, and will likely create an image that will be much too large.  You can shave off the extra unallocated space (basically restore it back to the same size as the stock image download from Step 1), using the steps in the "Shaving the Image" section of this document.
  6. Zip up the finished img file.

Thursday, March 17, 2016

Controlling flow through a wort chiller, part 2

Continuing my series of posts with boring-sounding names, I've got more results from my wort chiller pump.  Last time I was trying to control the flow through the wort chiller such that I can ensure that hot wort gets cooled to a reasonable temperature by the time it leaves the chiller.

To that end, I made a series of flow restrictors, which are just some smaller diameter tubes I could insert in the tube between the chiller and the fermenter vessel.

Flow Restrictors
I made the restrictors out of some wooden dowel rods I had lying around.  Yes, I know that wood is one of the worst materials I could have used for this purpose since it's porous, and therefore could leak air and water and be a wonderful home to unwanted bacteria.  I started with wood because I already had it on hand and I'm a woodworker so I'm better equipped to machine something out of wood. So if the experiment works I'll definitely be re-making the restrictor tube out of metal or food-safe plastic.

To start making the restrictors I found a dowel rod that would fit snugly in the 1/4" ID hose I was using, which I think ended being a 3/8" dowel.  I cut a bunch of 2 inch lengths of dowel and then picked 3 diameters I wanted to try first: 1/8", 3/32", and 1/16".  I clamped each rod in a wooden clamp, checked that it was perpendicular, and used my drill press to drill straight through the center of the dowel.  After that I checked each rod into the drill press and used a file to taper the ends so it would insert into the tubing more easily.  They ended up coming out pretty well, but not perfectly centered which should be fine for this experiment.

Measuring Initial Air Evacuation
Before I got to testing my new flow restrictors I wanted to investigate the initial start of the pumping process.  I suspected that it would take some amount of time to evacuate most of the air from the system before the liquid would start flowing.  To test this I used my usual volume of 16oz. of water to pump, but before the container was empty I poured in another 16 oz. of liquid.  By timing both a 16 oz. and 32 oz. sample, and subtracting the difference between them I should be able to get an idea of the amount of time required to evacuate the air.

For this test I ran the pump full speed at 5 volts.  Here are my results:
16 oz. water0m 41s
32 oz. water1m 06s
delta0m 25s
air evac time0m 16s

Breaking the results down a bit, this means that the time to transfer 16 oz. of water is really about 25 seconds and it takes 16 seconds to remove most of the air from the inside of the pump apparatus.  For the following tests I won't be adjusting for this initialization period, but it's something good to keep in mind.

Full-speed Flow Measurement
For the next round of tests, I kept the pump on full speed at 5 volts for the full duration of time it took to transfer 16 oz. of water.  As you can see in the picture below, I inserted the flow restrictor in the hose that connects the output of the graham condenser to the input of the fermenting vessel.

Here are my results:
restrictor size16 oz. transfer time
none0m 41s
1/8"0m 47s
3/32"1m 02s
1/16"3m 20s

It seems that the restrictors are working though their effect is definitely non-linear.

Modulating the Pump Motor
Next I wanted to try to introduce another variable into the equation, which is to vary the on-time of the pump.  In other circumstances I would use pulse-width modulation to allow a microcontrollers (like an Arduino) to control the motor, but for now I don't want to mess with setting up the motor drive circuitry.  So I'm going to do "human powered" pulse width modulation and just turn the pump motor on and off in terms of seconds.

Here are the patterns I came up with:
pattern numinit periodrepeating pattern
10s10s on, 10s off
220s10s off, 10s on
30s20s on, 20s off
410s10s off, 5s on
510s10s off, 3s on
610s10s off, 2s on

Each pattern has an (optional) init period where the pump is on, with the goal of initially evacuating the air from the system.  After the init period, each pattern has a repeating pattern with the goal of replicating the duty cycle and period based control used in pulse width modulation.

I ran these patterns using the 3/32" restrictor since this restrictor seemed to give the best balance of hole size vs. flow restriction.  I want to keep the hole size as large as possible because I'm concerned that if the hole is too small it will get clogged when I run actual wort through it.

Here are my results with the 3/32" restrictor:
pattern num16 oz. transfer time
11m 14s
21m 11s
31m 12s
41m 21s
51m 33s
62m 46s

So it seems that my simplistic pump motor modulation is working, at least enough to proceed.  I could have tried a pattern with an even shorter on time than pattern 6, but a 2s on time was about the shortest amount of time that I could consistently maintain over over the course of several minutes.

It's worth noting that by the end of my test runs the 3/32" restrictor was allowing a small amount of outside air to be pulled inside the tubing.  I think this may change the results slightly, but I don't think it would have changed things enough to alter my conclusion that the strategy seems viable.

Conclusions and Future Work
The results from using a restrictor while modulating the vacuum pump seems to show enough promise to proceed.  If you multiply out the time to transfer 16 oz. of water with around a 20% duty cycle, it would probably take around 24 minutes to transfer a gallon of wort through the chiller which seems like it should be sufficient to chill down to room temperature.

My next steps are to get my test rig ready to pump some near-boiling water though it, make a 3/32" restrictor out of something more durable than wood, and add some automation to control the vacuum pump motor.

Thursday, January 21, 2016

Controlling flow through a wort chiller, part 1

Now it's time to start putting together my last two experiments in order to control how quickly the wort flows through the chiller.  This will hopefully allow me to control how quickly and efficiently the wort is chilled.

I've added a stainless steel racking cane as an input tube to the condenser tube.  The condenser tube is now better supported with a ring clamp that allows me to keep tube properly supported at an adjustable angle. The tube that leads into the glass jug is just the right diameter to fit snugly in the output of the condenser tube.

As part of this I also want to try and slow down the flow of water through the condenser tube.  I took a simple approach of using a pinch clamp to see how much that restricts the flow.  I then pulled 16 ounces of water and timed how long it took on a stop watch.

table of data
clamp gap(cm) transfer time(s)
open 0:38
0.5 0:38
0.4 0:38
0.35 0:41

Based on the numbers I collected, it seems that the pinch clamp is effectively binary, all off or all on.

Since the pinch clamp didn't work very well, I'm going to try inlining a smaller tube to see if that restricts the flow better.

Tuesday, January 05, 2016

First experiments with a glass wort chiller

The reason I was messing around with vacuum pumps in my last post is so I can pull wort through a new type of chiller.  Now that I've got the pump part somewhat figured out, I did some work on the chiller part.

Unfermented beer (wort) needs to be boiled and then rapidly chilled, since there are some chemicals that form in hot wort that can produce off flavors in the final beer.  Ideally you want to take the wort from 220F to 80F in around 15-30 minutes.  There are various methods and devices that are typically used to do this. 

One method that I have not seen used before is using a graham condenser tube.  This is usually used in chemistry labs to condense vapor into a liquid.  It's basically a spiral glass tube with a larger straight glass tube on the outside.  Cold water is pumped through the outer glass jacket around the inner spiral glass tube to cool it down.  the vapor is passed through the inner spiral tube and it hopefully coalesces into a liquid before coming out the far end of the tube.

The only difference between chilling wort and the usual use-cases for the graham condenser is that liquid, not vapor, would be the input to the inner tube of the condenser.  Besides that the goals are the same: lowering the temperature of the input liquid/vapor.  I bought this graham condenser to try.

Let's talk about some of the temperatures involved.  As I mentioned above the input liquid to the condenser will be close to boiling, about 220F.  The coolant water temp in the outer jacket of the condenser will be ice water probably around 35-40F.  That's a delta of 185F between the coolant and the input wort.  If you subjected a normal piece of glass from your kitchen to this kind of thermal shock it would probably shatter, but in this case the condenser is made of borosilicate glass.  Borosilicate glass is special in that it is made to handle high thermal shocks like this; according to some numbers I looked up online it should be able to handle 320-330F of thermal shock so our 185F of thermal shock is probably OK.  There's even a bit of wiggle room so if I decided to try something like adding salt to the coolant water to lower the temperature down to about 0F, we're still in pretty good shape.

Experimental Setup
I had a cheap submersible fountain pump pushing water through condenser tube, from output to input (opposite direction to the way the hot water will go).  The coolant reservoir is about 1 gallon of normal tap water.  During the tests I had to tip the condenser tube at about 45 deg angle to get the input water to flow through the tube via gravity.  I had several thermometers measuring the temperature of the coolant water reservoir, the temp of the input water, and the output water.  I heated the input water using a tea kettle on my stove.

Trial 1
Coolant water was at 62F and input water was 126F for a delta of 64F.  After passing through the condenser I got an output of 87F.  The temperature delta from the input to output is about 40F.  The coolant water was 64F after processing the hot water, so only a 2 degree increase in the coolant.

Trial 2
Coolant water was at 64F and input water was 143F for a delta of 80F.  After passing through the condenser I got an output of 93F.  The temperature delta from the input to output is about 50F.  The coolant water was 68F after processing the hot water.

Trial 3
This time I put ice in the coolant reservoir.  Coolant water was at 43F and input water was 150F for a delta of 107F.  After passing through the condenser I got an output of 91F.  The temperature delta from the input to output is about 60F.  The coolant water was 48F after processing the hot water.

Next Steps
Dropping 60 degrees in less than a foot with a pretty quick trip through the tube seems like a really good result!  At this point the condenser is showing enough promise to keep going with the experiment.  Next I'd like to tie in the vacuum pump to make it more like the final project I have in mind, and give an easier way to pull hot water through the condenser tube.  As part of that I may need to put some pressure feedback in the vacuum pump line in order to tightly control how quickly the hot water flows through the tube.  So I've got lots of connecting differing diameters of tubing in my future...

Tuesday, December 22, 2015

A non-contact liquid pump

I came up with a way to transfer liquid from one place to another without having the liquid pass through the pump.  My main goal was to come up with something I can use for homebrewing to transfer unfermented beer (wort).  I need something food safe, and the easiest and cheapest way to do that is if the pump has no contact with the wort.

The experiment used a sealed glass jug with a two hole stopper with a tube attached to each hole.  One tube went to a glass of water, and the other was attached to an inexpensive vacuum pump.  The concept behind it is similar to sucking water through a straw.  The vacuum pump lowers the pressure inside the glass jug, which pulls the liquid into the jug.  Another way to look at it is the atmospheric pressure pushes the liquid into the glass jug.

The experiment was a huge success!  The pump transfers water quickly and I even had to stop the pump midway through since it had built up enough of a vacuum.  It's important to note that there is definitely a lag between stopping the pump and when the liquid stops transferring (see the video below).

I measured a few things during the experiment.  Even though the pump I used was rated for 12V, I only used a 5V power supply because I was afraid of pulling the liquid too quickly.  5 volts worked just fine, and I think I'm going to stick with that.  I was able to test that the pump could pull water up to 20 inches; it probably could have done more but that was the most I could test with my rig.  I measured around 200-550 mA of current usage, and it definitely went up as the vacuum in the jug increased.

The two hole stopper is a little ugly, but it works pretty well.

Boring the holes in the stopper was definitely the most difficult part.

Jury-rigged power supply for the pump

Tuesday, November 24, 2015

Re-writing the example code from Chaos and Fractals

I stumbled on an interesting book on fractal algorithms: Chaos and Fractals: New Frontiers of Science.  What made me take notice was that each chapter ended with a short, approachable example program that demonstrates a concept.  The programs also generate some neat-looking fractal diagrams, and IMHO it's always fun to play around with algorithms that generate pictures.

Another interesting point was that, in the first edition of the book, each example program was written in the BASIC programming language. The choice of BASIC doesn't seem so odd with a little historical context.  The book was published in 1992, and around that time there weren't very many good cross-platform programming languages, especially when you consider cross-platform drawing libraries.  But, at the time, BASIC fit the bill.  It could run on DOS-based PCs and Apple IIs, which, at the time, probably covered a pretty good swath of the audience for the book.  Most BASIC dialects also included the LINE and PSET functions which were all the example programs needed to draw the output of all sorts of fractal algorithms.  In hindsight, BASIC seems like a decent choice.  In the second edition of the book, I believe the authors switched to something else like Java applets; I was working from a first edition copy from my local library so I don't know much about the second edition.

I decided it would be a fun exercise to port these example programs to javascript, since that seems to be the new cross platform language of choice in this decade.  I tried to reproduce them as faithfully as possible without any attempt at further optimization, and I tried to use as few non-BASIC language constructs as possible.  I say few as possible, since many BASIC language constructs don't have direct analogous constructs in javascript, for instance GOTOs and labels.  So I present to you below, my implementation of these examples.

I ran into a few caveats during the porting process that are worth mentioning:

  • To view my javascript source, just choose View Page Source and you should be able to look around and find the example code.
  • Most of these algorithms are recursive and I had to get a little imaginative when converting GOTOs and GOSUBs to proper function calls.
  • For displaying the graphical output of each program, I used the HTML canvas object.
  • I tried to leave the BASIC code as comments amongst the javascript code so in case you're following along with the book you'll have some guide posts in the code.
  • The example code uses several different invocations of the LINE and PSET functions, and I had to track down some BASIC language documentation to figure out what the invocations should do.  As a result, it seems that the BASIC dialect used is closest to GW-BASIC and QuickBASIC.
  • The output from the programs for chapters 12 and 13 did not look like the diagrams in the book and I spent quite a bit of time debugging them looking for my error.  In the end I downloaded the DOSBox emulator and a copy of QuickBASIC and ran the programs there.  In both cases, the BASIC code ran but outputted exactly the same result that I got from my javascript version.  So I can only conclude that there is an error either in the code or the diagram printed in the book.
  • Some of the programs take a while to run (especially chapter 12 and 14), and this can lead modern browsers to display errors that the browser tab has hung or otherwise failed.  In the chapter 12 code I tried to mitigate this somewhat by adding chunking code to sleep between chunks of loop iterations.  It's less noticeable in chapter 14, but if you run into issues you can often get around it by just reloading the page and trying again.

Chapter 1: Graphical Iteration
Chapter 2: Sierpinski Gasket
Chapter 3: The Koch Curve
Chapter 4: The Cantor Set
Chapter 5: Iterating the MRCM
Chapter 6: Chaos Game for the Fern
Chapter 7: L-systems
Chapter 8: Cellular Automata
Chapter 9: Random Midpoint Displacement
Chapter 10: Times Series and Error Development
Chapter 11: Final State Diagram
Chapter 12: Rossler Attractor
Chapter 13: Julia Sets
Chapter 14: Mandelbrot Sets