jmcnelly

Single Cell Battery Simulator

I recently came upon design challenge for designing a single-cell battery simulator. I started having a lot of fun with the project–by the time it was done, I figured it was worth documenting as a good example of my hardware and software design workflow. As of the time of writing this post, I’m quite happy with what I made, but I’m hoping that in a few years I can look back at this post in a “look at how far I’ve come!” kinda way. We’ll see! Here’s to learning new things in the future.

The Challenge

The following text in italics is taken from the challenge. Some unimportant details are removed for clarity.

Battery management system (BMS) is one of the critical systems used in electric aircraft to
monitor the status and the health of the battery. To test the performance of the BMS, a battery
simulator is needed.

As shown in the following figure, the designed simulator is controlled by an MCU and it
communicates with a computer via serial communication. The cell voltage can be set from the
computer. The balancing current can be supplied, measured and reported to the computer by
the simulator.

An isolated 5 VDC voltage source is given.
● The cell voltage can be adjusted in the range of 2.5 V to 4.5 V via MCU with tolerance of
±5%.
● The simulator can supply and measure the balancing current (current flowing out of the
simulated cell) up to 200 mA with tolerance of ±10%.

What I Made

The challenge really only asked for a rough schematic, but I had a strong hankering for a good analog project and hadn’t touched my op amp drawers for too many months, so I got working on a circuit that I could build with what I had available in the workshop.

After considering various topologies based on linear regulator ICs (not enough headroom) or switching power supplies (didn’t have the chips on hand), I decided that one of the easiest ways to tackle the battery simulator challenge was to build what is essentially a juiced-up op-amp. The circuit would use a generic rail-to-rail op-amp for control, but would drop unwanted voltage from the 5V supply using an external power BJT and an associated drive circuit. While not very energy efficient, this circuit looked like it could be pretty simple and cheap to build, and would meet the relatively modest power requirements of the challenge quite easily. An added bonus was that by using a dual rail-to-rail op amp, I could dedicate the unused op amp circuit to high side current sensing! For compute, I used a Pi PIco since it was readily available, cheap, and I had already built out a docker environment for programming and testing for the RP2040 as a target.

During my design of the battery cell simulator, I added some opto-isolators to allow multiple battery cells to be chained together. I became very curious about whether my design for daisy-chaining cells into a simulated battery pack would work, and decided to build out the motherboard that would allow multiple battery cells to be supplied with isolated 5V power and daisy-chained such that they could communicate with each other and their output voltages would be presented in series. I designed the motherboard such that each of the battery cell circuits could be inserted as a vertical card, and created a 3D-printed enclosure to house the motherboard and all of its installed cards. I bootstrapped an indicator LED for each cell by heat-forming a PMMA optical fiber into a light pipe and affixing one fiber over each Pi Pico’s status LED.

The full design process, stream-of-consciousness debugging and all, is recorded in my design notebook document. Some quick links:

Project Github Repository

Datasheets

I documented the completed devices at the multi-cell (Cellsim 4S) and single-cell (SCBS-Pico) levels to capture things before they sublimated from my brain and to dust off the technical documentation skills. There’s something satisfying about writing datasheets!

Posted by jmcnelly, 0 comments
Etching PCBs at Home for Fun and Profit

Etching PCBs at Home for Fun and Profit

As of the time of writing this post, I’ve been chasing the dream of etching circuit boards at home for at least four years. After flopping around between various techniques for years (including CNC milling with two separate machines and lots of mods), I think that I’ve finally settled on a techniqe that is low cost, reliable, and fast enough that it can compete with hand-soldered prototypes in many scenarios.

What I want in a home PCB fabrication solution:

  • Fast: Should be faster than hand-soldering a circuit if I need more than one copy, including time required for schematic capture / layout / etc.
  • Cheap: Should cost under $5/PCB in raw materials.
  • Consistent: Needs to have process yield well above 80-90%. If I’m etching a PCB and not buying it, usually it means that I need ultra quick-turn and can’t sit a round to futz with the process until it works.

To Mill, or to Etch?

My initial attempts at PCB fabrication relied on CNC milling, which I attempted with a rather floppy CNC router intended for woodworking (Millwright M3) and later a custom modified 1610 CNC Mill from Amazon. I experimented with many varieties of v-shaped engraving bits and even some fine-tipped router bits, but was never able to achieve perfect consistency in trace isolation, even after doing my best to stiffen up the machines, reduce runout, and implement high resolution mesh surface levelling using bCNC. In the end, after many broken bits, and many more crappy and inconsistent PCBs, I abandoned CNC milling in favor of chemical etching, which turned out to be much cheaper, more consistent, and much faster (4 minutes to etch a complex board vs 40min+ to mill it board).

CNC Milling has many tempting features up front, including the apparent process simplicity, but in my experience it ultimately lost out to Chemical Etching as the more effective process for PCB fabrication. Some reasons why are included in the table below.

ParameterCNC MillingChemical Etching
Required Equipment– CNC mill– Laser printer
– Laminator
– PCB etch tank
– Drill press
Chemicals?No, but you will spray FR4 and copper dust everywhere. You can control it by milling under mineral oil, but that gets incredibly gross very quickly (just ask my mutilated shop vac hose that will forever be filled with copper / fiberglass / mineral oil dust goo).Yes. Ferric Chloride. OOooo scary (not actually that bad if you follow proper safety precautions). One batch of Ferric Chloride will last you for many years of hobbyist etching, so not a frequently replaced item.
Consumable Materials– Copper-clad PCB blanks
– Drill bits
– Thermal transfer paper
– Copper-clad PCB blanks
– Kapton tape
– Toner reactive foil
– Drill bits
ReliabilityLow
It’s very difficult to get the PCB surface exactly level, and since the copper-clad layer is so thin (~30um), it’s very easy to end up not fully milling some traces unless the PCB is milled at a large depth. If using a v-bit, a large milling depth results in large gaps between traces, reducing design flexibility.
Medium-High
Very tight trace/space fabrications are possible (I’ve gotten down to 0.2mm clearance between traces), but process reliability heavily relies on some key details that determine the results of the thermal transfer and PCB etch steps (surface treatment, etchant temperature, mask sealing, etc).
Full test still recommended, some boards may need to be touched up with some solder or have traces separated with an X-acto knife.
Time to Etch One PCB10-40+ minutes
Depending on complexity (machine needs to mill out each trace individually).
~4 minutes
All traces are etced simultaneously. Etch time may need to be extended if a large volume of copper is removed, but shouldn’t need more than around 10 minutes with well heated and agitated etchant.
Time to Etch N PCBsN*(10-40+ minutes)
More PCBs means more traces to mill. Not much benefit is had when scaling up to more copies of the same PCB.
~4 minutes
Etching a panel takes only marginally longer than etching a single board (you’re limited only by the etch rate of the Ferric Chloride solution).
Minimum Trace / Space Achieved by John0.4mm/0.4mm0.2mm/0.2mm

The John McNelly PCB Etch Process™

My PCB etching process draws heavily from what electronics hobbyists have been doing in their garage for many decades, but I figured that it would be nice to share my list of materials and specific techniques in order to flatten the learning curve a bit for anyone else looking to try out etching PCBs at home. Links in the tables below are Amazon Affiliate links to products that I have personally used (or as close a substitute as I can find if the original listing is no longer available). All proceeds go to the Fun Project Fund!

Equipment List

Equipment ItemDescription
Laser PrinterThere is some debate about what printer is best for this process, but helpful resources exist from providers of off-the-shelf PCB etching kits. There are some rumors that Brother printers don’t work well for the toner transfer process, but I’ve had good luck with mine (DCP-L2540DW) in the process described in this page. It’s important to use a genuine toner cartridge for printing mask layers, since resolution and perfect coverage make a big difference. I use a genuine Brother TN660 toner cartridge. Note that this only works with monochrome laser printers, not color laser printers!
Thermal LaminatorA good temperature-controlled thermal laminator is essential for getting toner to properly transfer onto the PCB blanks. You will need something with enough heat output to bring a PCB blank up to temperature (copper is a fantastic heatsink), spring-loaded rollers that can widen enough to accommodate a PCB (1.6mm thickness), and a high enough maximum temperature that it can allow toner to re-fuse properly. I bought a Tamerica TCC330 pouch laminator for this job and it works great. I use it with the temperature setting cranked all the way up and still need to do 6+ lamination passes on a PCB to make sure that it’s evenly heated.

Having a pouch laminator is also nice for non PCB-reasons, since you can always us it to, like, laminate stuff. I’ve used mine to laminate labels for industrial electronic equipment, laminate menu board signs for a farmers’ market stand, and toner transfer decorative foil onto custom letterhead as a gift for a friend! If getting a laminator seems too extra, other hobbyists have had good luck using clothes irons, and I’ve considered using one of the heat presses intended for application of vinyl stickers onto t-shirts but haven’t had a chance to try it out yet.
Shear BrakeI’ve found that by far the easiest, cleanest, and most reliable method of cutting FR4 PCBs is by using a mini benchtop shear brake. The shear brake’s clean shearing action allows you to easily cut PCBs down straight lines with minimal kerf, allowing clean separation of closely spaced panels and preventing the generation of potentially nasty FR4 dust. A sheared PCB edge looks very similar to an edge cut using a v-groove cutting wheel, in that it looks slightly “hairy” with some exposed FR4 fibers. Running the freshly cut edge of a PCB across some sand paper cleans things up quite nicely!

I don’t recommend using a shear brake on multi-layer PCBs where there is a risk of deforming the board and crushing internal structures like vias, but it works great on single-sided boards (or multilayer boards that you don’t care much about). In addition to depanelizing my homebrew PCBs, I use my shear brake to cut protoboard down to custom sizes, and also to cut plain FR4 into shapes for use in other projects. I also use my shear brake to cut and bend brackets out of aluminum sheet metal, which has come in handy a few times!
Drill PressA good drill press is essential for drilling vias and through holes on home-etched PCBs. Many of the drill bits necessary for component through holes have a very fine diameter (<1mm), so drilling them with a handheld drill is very difficult. Fortunately, there’s no need for a huge drill press here, and reasonably priced benchtop models exist with sub-0.1mm runout! I bought an 8-inch benchtop drill press on Amazon a few years ago and have used it to drill many many holes in homebrew PCBs, from 6mm diameter all the way down to ~0.4mm. It’s also come in handy for woodworking and light metalworking on many occasions.

Since many of the PCB drill bits are intended for use at high RPMs and plunge rates, I configure the belts to run the drill bit at the maximum possible speed (~3000rpm). I highly recommend using a thin piece of wood as a spoil board when drilling PCBs to minimize the risk of hitting the drill press base plate or blowing out the bottom of the PCB (for larger holes).

Good alignment of the drill bit to the hole drill position is essential for good results. Newer and fancier drill presses can be found with adjustable laser crosshairs that might assist with accuracy, but I’ve been able to get “good enough” results with a carefully calibrated eyeball and the assistance of a magnetic sewing machine light stuck to the side of my drill press.
Paper CutterScissors work just fine, but I have enjoyed using a paper cutter to shave off a few extra seconds of cutting thermal transfer paper and toner reactive foil to size.
Secondary Chemical ContainerHaving a secondary container for your etching workbench is a really good idea, as it helps protect against inevitable spills (ferric chloride stains everything, acetone is nasty, liquid tin smells like farts, etc). Through some obvious but unwritten laws of probability, it is widely understood that a workbench that is well prepared for a chemical spill will never have one, but a workbench cluttered with valuable items and unprotected against a chemical spill will breed frequent catastrophes (particularly if it’s being used unprotected “just this once”). Anyways, I found that these silicone mats for protecting the cabinets under kitchen sinks work really well as secondary containers.

Materials List

Consumable ItemDescription
Thermal Transfer PaperI use generic yellow thermal transfer paper from Amazon. It runs about $20 for 100 sheets, and I cut the sheets into small PCB-sized sections and tape it onto printer paper with Kapton tape, so I usually can get well more than one PCB out of a single page of transfer paper.
Toner Reactive FoilToner Reactive Foil (TRF) aka “Toner Fusing Foil” is a thin plastic film that bonds to printed toner when heated in a thermal laminator. It is used in the etch mask sealing step for PCB fabrication, but comes in a variety of colors (including shiny ones), and can be used for greeting cards, stationery, etc with foil patterns.

TRFs are available in a wide variety of colors, from craft stores (e.g. Minc brand) or commercial printing suppliers. I usually use white TRF for my etch process, but other colors should work just as well.
Copper-Clad PCB BlanksThere are a number of good vendors of copper-clad FR4 PCB blanks on eBay and Amazon, but I’ve had especially good luck with PCBs from Paramount CCL, as they’ve always been consistent in dimensions and quality, arrive well-packaged, and show up clean and shiny. I’ve also had very good luck soldering with their boards, as the copper cladding is well bonded to the substrate and survives reflow and rework operations without issue (I work with leaded Sn63Pb37 solder).

Key parameters to look for:
– Thickness: 1.6mm (62mil)
– Plating: 1oz/36um (1.4mil)

Single-Sided PCBs
4x3in (good for small projects)
4x6in (good for medium projects or panels)

Double-Sided PCBs
4x3in (good for small projects)
Kapton TapeKapton tape’s chemical-proof, heat-resistant, and residue-free properties make it extremely useful in just about all parts of the PCB etch process. I use Kapton to secure thermal transfer paper fragments to copy paper for printing the toner mask with a laser printer, for holding thermal transfer paper to PCB blanks during lamination, and for masking off portions of copper that I don’t want to be removed during the chemical etch process. It’s also very useful for heat-shielding various components during hot air rework.

Brand-name Kapton tape is pretty pricey, but I’ve found that many of the generic brands on Amazon labelled as “Polyimide Tape” work just as well. I use 0.75in Polyimide Tape for most purposes, and 3in Polyimide Tape for masking entire faces of 4x3in PCBs (for instance, if I want to have a ground plane on the non-etched side of my PCB).
Fine-Grit Sanding SpongeI use a fine grit sanding sponge to lightly abrade the surface of a fresh copper-clad PCB blank in order to provide a better surface for the thermally transferred toner to bond to. Anything in the ballpark of 200 grit should be OK.
KimwipesKimwipes are lightly abrasive cleaning wipes that are perfect for preparing copper PCB blanks for thermal transfer after light sanding (I give things a thorough cleaning with a wipe soaked in isopropyl alcohol). Kimwipes are also useful for generic cleaning tasks around the lab; some wipes and a pump dispenser bottle filled with 70% IPA is a match made in EE heaven.
Isopropyl AlcoholI use Isopropyl Alcohol (IPA) to remove any surface coatings and contaminants from the fresh PCB blanks before the thermal transfer process. Small amounts of grease / anti-oxidation coatings / whatever can make it hard for the thermally transferred toner to stick to the copper properly. I recommend using ~70% IPA so that you have a good chance of removing contaminants that are soluble in either alcohol or water (I’ve found that 70% IPA often cleans better than 99%, for instance).
AcetoneThe nasty stuff. Use in a well-ventilated area and keep away from children and burny things. This is used to remove the toner mask and toner reactive foil after chemical etching is complete. I’ve had good luck sourcing acetone from my local Home Depot, and use it with blue shop towels to scrub down PCBs and remove etch mask residue.
PCB Drill BitsGood drill bits for PCB via and hole drilling are different from most drill bits found in Home Depot, as they are manufactured from carbide (fiberglass can be very abrasive) and have a necked-down portion of the shaft where the standard 1/8″ shaft transitions to the much smaller diameter cutting body. Most high quality drill bits will also include a color-coded collet that indicates their diameter and allows them to be easily indexed into a drill collet with a consistent tip position.

There are a large number of low-quality drill bits available that are made with low quality materials like high speed steel, but carbide drill bits from reputable manufacturers like Kyocera are available used and new for very reasonable prices. My favorite vendor is drillman1 (now Oliver Tool Company) on eBay, who specializes in selling high quality PCB drill bits.

My standard set of micro drill bit sizes is included in the list below. I always recommend getting extra drill bits, especially of the smaller sizes, as they break pretty easily.

– For drill sizes 2.0mm and above (e.g. mounting holes), a regular metric drill bit set can be used.
1.75Y (0.0689in/1.75mm)
#54 (0.0550in/1.40mm)
1.20Y (0.0472in/1.20mm)
#58 (0.0420in/1.0mm)
#68 (0.310in/0.8mm)
– PCB drill bits smaller than 0.8mm are often not worth dealing with, in my experience. They snap easily and there isn’t much application for ultra-fine vias in home-etched PCBs.
Laminating Pouch CarrierI use laminating pouch carriers to protect toner reactive foil from getting sucked into the rollers during the etch mask sealing thermal lamination step. I do not recommend using them during the toner thermal transfer operation as they significantly slow the heat transfer, but they are very useful for managing thin and finicky foils like TRF. These are available from commercial suppliers or from Amazon. DIY versions can be made by folding a piece of heavyweight paper in half, but lack the interior silicone coating that stops adhesives from sticking. I usually cut my pouch carriers down in length so that they are more closely matched to the size of my PCB blanks, to avoid waiting extra time for the whole pouch carrier to go through the rollers during every lamination cycle.

Step 1: Etch Mask Thermal Transfer

The first step in the PCB fabrication process is transferring a mask of what we dont want to etch onto our copper-clad PCB blank. This is done by thermally transferring toner from a laser printer using the steps below.

  1. Print front copper and edge cuts layers onto a piece of copy paper, with the following parameters:
    • If printing the primary (front) side of the board, the mask must be mirrored. This is because the mask will be reversed when it is thermal-transferred onto the PCB blank; the top side of the copy paper is like the adhesive side of a sticker that will be transferred to the PCB. If printing the secondary (back) side of the board, the mask must not be mirrored, since the EDA software generates plots looking down through the primary side of the board.
    • Use 1:1 scale and center the mask pattern on the copy paper.
    • Set drill holes to be printed as a “small mark” so that the hole doesn’t end up oblong if the drill bit isn’t perfectly centered.
  2. Mark the end of the page that came out of the printer first with a small arrow in ballpoint pen or sharpie. This indicates your feed direction, and is important for later!
  3. Verify the mask is in the correct orientation (mirrored or not mirrored). The easiest way to check this is to add lettering to the copper (REV letter, PCB name, etc) and check the orientation of the text after printing.
  4. Verify the mask scaling in X and Y with calipers using the edge cuts or other prominent PCB features. It’s best to measure the longest known X or Y dimension you can verify in order to make sure scaling on the printer and printer driver is correct. Use printer drivers directly from the manufacturer if available (auto-installed Microsoft CUPS drivers often mangle scaling in unintuitive ways—I’ve had things print at 95% scale and only realized it when components didn’t fit)!
  5. Cut a rectangle of thermal transfer paper slightly larger than the mask pattern and position it above the mask pattern printed onto the copy paper. Mount the transfer paper shiny side up to the copy paper with a piece of Kapton tape along the transfer paper edge closer to the feed direction symbol you drew in step (2). Make sure that the Kapton tape completely covers the edge of the leading edge of the transfer paper and has no wrinkles!
  6. Thoroughly wipe down the thermal transfer paper with a fresh Kimwipe. This removes any dust and is essential for slightly roughening the surface to get the toner to stick better. If this step is skipped, there is a high probability of parts of the mask rubbing off of the thermal transfer paper as you align it to the PCB, causing traces to be broken or shifted!
  7. Feed the copy paper into your printer, feed-direction symbol first. If your printer has a slot for inserting envelopes or other specialty papers that don’t fit into the standard size paper tray, I’ve found that it makes this step much more convenient, since you won’t have to constantly open and close the paper tray, and the paper can be inserted into the slot print-side-up.
  8. Print the mask pattern onto the thermal transfer paper. Use the darkest toner setting your printer has, and use a thicker paper setting in order to make sure that the toner has enough heat to properly fuse to the thermal transfer paper. These settings are usually available through the printer driver if using a proper driver provided by the printer manufacturer.
  9. Remove the thermal transfer paper with the printed mask pattern from the copy paper backing. Make sure that no part of the pattern was accidentally printed on the Kapton tape or missed the thermal transfer paper and ended up on the copy paper backing!
  10. Prepare a PCB blank for thermal transfer by lightly sanding it with a fine (>=200) grit sanding sponge to rough up the surface, and then cleaning it thoroughly with a Kimwipe dampened with 70% isopropyl alcohol. This will create more surface area for the toner to bond to, and will remove sanding residue and other contaminants that could prevent the toner from creating a good bond with the surface of the copper plating.
  11. Fasten the thermal transfer paper to the PCB blank with Kapton tape, with the toner side against the copper plating. Ensure that the Kapton tape does not overlap any portion of the thermal transfer paper with toner mask, as this could inhibit the thermal transfer process.
  12. Set the laminator to maximum temperature, and feed in the PCB blank with attached thermal transfer paper. Alternate which section of the laminator you use, and alternate copper side up / down orientation (if board is single sided) in order to not cool down one section of the rollers too much. Run the PCB blank through the laminator ~6 times or until the toner has fused completely to the copper plating on the PCB blank.

Remove the thermal transfer paper backing from the PCB blank. If this does not remove cleanly, you can soak the PCB blank in water and gently scrub away the paper backing.

Once thermal transfer is complete, you should end up with something like this:

Step 2: Etch Mask Sealing

Even when the toner is printed at maximum darkness, there are still teeny gaps in many of the solidly filled areas. Etching a PCB with a pure toner etch mask will result in traces and floods having a “speckled” appearance, which under a microscope can be seen as a very large number of small holes in the copper resulting from etchant finding its way through gaps in the toner mask. One common solution to this would be to run the mask through the printer multiple times to lay down another coat of toner, but the indexing of the paper to the print head  is very low precision and the mask wouldn’t overlap itself precisely. A better solution is to seal the toner with a solid layer of Toner Reactive Film (TRF). TRFs are thin films designed to bond to toner particles when heated, and are often used for decorating greeting cards or stationery. Greeting cards with gold foil designs are usually made by printing the foil design in toner, and then laminating a layer of gold foil TRF to the toner pattern. TRFs are available in commercial flavors as well as DIY arts and crafts flavors (Michael’s and other craft stores carry TRFs under the Minc brand). TRFs come in a variety of colors, but for the purposes of chemical etching, they all work just fine. I generally use white TRF since it’s cheap and widely available, and could be used for white silkscreen if I use green soldermask over my copper traces.

  1. Cut a section of TRF large enough to cover the thermal transferred toner pattern on the PCB blank.
  2. Align the TRF over the toner pattern, with the dull side of the TRF against the copper. Place the TRF and PCB blank into a lamination carrier.
  3. Set the laminator to maximum temperature. Pass the lamination carrier through the laminator ~3 times (or until TRF is completely fused) leading with the carrier seam, alternating roller location and up / down orientation for even heating.
  4. Peel back the TRF plastic backing to reveal the TRF bonded to toner. All sections of toner should be completely covered with TRF.

This is what a PCB with a sealed etch mask pattern looks like before etching.

Step 3: Etching

Once the etch mask has been sealed, it’s time to remove all of the non-masked copper from the PCB! I’ve found that Ferric Chloride works great for this and is widely available, but other chemical solutions exist to do the same thing. Etch speed is heavily dependent on temperature, agitation, and etchant/copper concentration, so it can be difficult to get a consistent etch if these factors vary across the surface of the PCB. Some hobbyists etch their boards in glass Tupperware filled with a thin layer of Ferric Chloride that they slosh back and forth by tipping the Tupperware container, but this can take 20-45 minutes to get a complete etch. If the etch rate varies across the board, some traces in faster-etching portions can be over-etched due to their exposed copper sides getting eaten from under the sealed mask layer. It’s best to have a fast, consistent etch and remove the board as soon as etching is complete. Some hobbyists experiment with fancy spray-etching machines and different solutions, but I’ve found that a vertical etch tank kit with a heater and an aquarium bubbler has worked great for my purposes. These kits take a lot of etchant (2 liters), but that amount of etchant can be used for many many PCBs. I’ve used the same etchant solution for over 2 years–etch times have extended slightly as the solution gets saturated with copper, but this has not created any issues for me.

  1. Fill the etch tank to the required level. If the etch tank was previously filled and has had its fluid level lowered due to evaporation, top it off with distilled water and stir thoroughly.
  2. Plug in the etch tank heater and allow the solution to get up to an even temperature (stir gently if required). You can tell that the solution has reached its proper temperature when the heater shuts off (stops glowing).
  3. Drill a hole for a wire hanger onto the PCB blank, outside the bounds of the PCB design (or better yet, use a mounting hole within the PCB design for this purpose).
  4. Mask off any additional (non toner-sealed) copper that you would like to preserve using Kapton tape. Ensure that there are no bubbles or wrinkles around the edges that could allow etchant solution to creep underneath.
  5. Activate the aquarium bubbler to begin agitating the etchant solution.
  6. Mount the PCB blank to a plastic-coated wire hanger and lower it into the etchant solution. Make sure that the PCB isn’t sucked up against the sidewall of the container on the copper side, as this will inhibit the etch process.
  7. Check on the PCB periodically and remove it from the etchant solution as soon as all exposed copper has been etched away. Rinse the PCB under clean water to stop the etch.
  8. Soak a shop towel in Acetone and slowly but firmly scrub the PCB to remove the toner and TRF etch mask. You should be left with shiny copper and clean-looking FR4 where the copper was removed. If you have black toner smears on the FR4, add more acetone and scrub again, allowing ample time for the acetone to penetrate the etch mask layer.

This is what an etched PCB looks like. Note the black toner smears (I didn’t scrub properly when removing the etch mask layer).

Step 4: Plating (Optional)

If this PCB is intended for long-term use and you are concerned about copper oxidation for aesthetic purposes, or if you have concerns about copper oxidation inhibiting solderability after reflow, you can tin-plate the traces using a liquid tin solution. This takes just a few minutes, but I usually don’t bother as the vast majority of the PCBs that I manually etch are usually ultra quick-turn prototypes that will be used for testing and then replaced with a properly fabricated design.

If tin plating isn’t your cup of tea, you can mimic a HASL finish by going over each trace with a blob of solder on a soldering iron. This leads to a slightly uneven surface finish that can make soldering surface mount parts problematic, but works just fine for most applications.

  1. Place the etched PCB into a glass Tupperware filled with a thin layer of liquid tin solution (enough to cover the PCB). Agitate the PCB and solution with a silicone brush.
  2. Once the PCB is completely plated (or you have waited the proper length of time based on the liquid tin solution instructions), remove the PCB from the liquid tin solution and rinse it under clean water.

Example of a tin plated PCB.

Step 5: Drilling

I find that it’s easiest to perform all drilling immediately after etching and when the PCBs are still panelized in order to increase surface area for handling the PCB (it’s hard to hold a very small PCB down while drilling it), and to allow through holes to be used for indexing silkscreen to the board in step (6).

  1. Drill out the holes marked on the PCB’s etch mask using the drill size indicated on the PCB drill map (or the next available larger drill bit size).
  2. If making a 1.5-sided board (etched copper on one side, solid ground plane on the other side), use a large drill bit (~3mm) to counter-sink any non-grounded holes on the ground plane side. This will prevent the leads of through hole components from shorting to the ground plane when this is not desired. The counter-sink should just deep enough to go through the copper layer but not too deep into the FR4.
Example of a partially assembled 1.5-sided board. Note the isolation holes around non-grounded through holes (see unpopulated trimmer pot footprint in top left).

Step 6: Silkscreen (Legend)

Adding a silkscreen (aka. Legend) layer to the etched PCB is extremely helpful for labelling components with reference designators, indicating component polarities, and labelling pins and testpoints. I usually use a simple toner silkscreen layer, and have found that it adheres best to bare FR4 and solid copper floods. Silkscreen items that need to be printed over narrow copper traces often don’t transfer properly, as the variations in altitude between the tops of the copper traces and the face of the FR4 substrate cause the thermal lamination process to be incomplete, leaving fragments of silkscreen stuck to the thermal transfer paper instead of the PCB. A winning combination is a single-sided PCB with toner silkscreen on the FR4 side of the board indicating through hole component footprints and pinouts for through hole connectors that are exposed on that side. I use silkscreen on single-sided SMD designs as well, but need to be careful to not overlap any traces with my reference designators or labels.

  1. Print a silkscreen layer onto thermal transfer paper that has been prepared using the same process as step (1). Ensure proper scaling, orientation, etc.
  2. Align the silkscreen layer to the PCB by shining a light through
  3. Thermal transfer the silkscreen onto the etched PCB using the same process as step (1).

Step 7: Depanelization

PCBs can be depanelized using a number of methods, including v-scoring (with an honest -to-god V-scoring machine or with a janky box-cutter-and-straightedge setup), sawing, routing, etc. My method of choice since first trying it out a few years ago has been to use a mini benchtop shear brake, as it produces the least amount of dust and gives me effortless straight cut lines each time. The shear brake is also useful for a number of other crafty tasks, so it’s nice to have around!

  1. Use a shear brake to carefully depanelize PCBs from the PCB blank.
  2. Give each edge of the depanelized PCBs a few passes with medium-grit (~160 grit) sandpaper to remove any burrs or loose fiberglass hairs.
Panel of PCBs before depanelization (note x-out PCB that failed inspection / test).
Depanelized PCBs.

Step 8: Heat and Serve

After the PCBs are fabricated, you can solder components on with a soldering iron or reflow oven. Nothing much to say here, I just wanted to have the “Heat and Serve” heading because I thought it was funny.

Home-Etched PCB Gallery

Posted by jmcnelly, 0 comments
Halloween 2022: The DTV (Department of Treat Vending)

Halloween 2022: The DTV (Department of Treat Vending)

For Halloween 2022, we wanted to top our previous record attempt for “Most Complicated Way to Make Trick-Or-Treaters Suffer in a Haunted Maze of Endless Bureaucracy”, and settled on the perfect idea: the DMV.

With some slight candy-adjacent-holiday themed rebranding, ten yards of cubicle fabric, over $1k in off-theshelf and government-surplus IT equipment, and a sizable band of willing volunteers, the California DTV (Department of Treat Vending) was born.

The DTV

The DTV (Department of Treat Vending) is responsible for issuing Treat Licenses (which look kind of like California driver’s licenses, but with a cat instead of a bear, random memes in the watermark, and no personally identifying information other than first name and favorite color) to trick-or-treaters. Holders of a Treat License may present their card at any participating DTV branch (currently just the one) in order to acquire a full-size candy bar.

Example of a DTV-issued treat license.

Of course, acquiring an ID card is not a simple process. In order to acquire an ID card (and the associated candy bar), trick-or-treaters must arrive at the DTV and wait in line for a Request For Candy (RFC) form. At the end of the RFC form line, each trick-or-treater is provided with a clipboard and an RFC form corresponding to the type of candy bar they wish to receive a Treat License for, as well as an auto-generated ticket number corresponding to their slot in the DTV ticketing system. The number of RFC forms is tied to the number of available candy bars of each kind, so after a few hours of operation, many DTV branches may run out of the more popular variations of the RFC form.

RFC forms are available for a number of candy bar variants. The different types of ID forms are listed below.

  • Twix: RFC-53-TW
  • M&M’s: RFC-53-MM
  • Snickers: RFC-51-SN
  • Sour Punch Straws: RFC-68-SP
  • Skittles: RFC-67-SK
  • KitKat: RFC-53-KK
  • Reese’s: RFC-52-RS

Each RFC form has identical fields except for Section 3 (Verification), which varies by form type.

Once a trick-or-treater has received a ticket number and an RFC form, they proceed to the waiting area where they fill out their RFC form with the relevant details and wait for their number to be called by the automatic ticket calling system. Current wait time and ticket numbers being served are displayed on the ticketing system display, and new tickets are automatically verbally announced by the ticketing system when they are called. The ticketing system also displays a delightlful collection of advertisements and Public Service Announcements on the screen to keep trick-or-treaters entertained and informed while thye wait.

After a trick-or-treaters’ ticket number has been called by the ticketing system, they must proceed to their assigned service counter. Upon arriving at the service counter, the trick-or-treater’s RFC application is reviewed, and may be approved or denied based on the information provided. If the RFC application is denied, the trick-or-treater may be asked to correct the deficiencies in their form and return to the counter with another ticket number, or fix their RFC form at the counter. If the RFC application is approved, the service counter attendant creates a Treat License ID card using the information included on the RFC form, and may take an ID photo of the applicant for use on the card if the applicant consents.

Once a standard Treat License ID has been printed, the trick-or-treater is handed back their application form (stamped with “Approved” and relevant service desk information), along with the ID card and the relevant full-size candy bar.

The DTV proved to be incredibly popular among trick-or-treaters; during its four hours of operation in 2022, it issued 269 unique Treat Licenses (and the same number of corresponding full-size candy bars).

Full walkthrough:

The Crew

The DTV was a very ambitious halloween costume, and it would not have been able to come together successfully without the help of a number of dedicated friends and coworkers. Caitlin and I set up the IT systems behind the DTV, and Kenneth built out the graphics assets, employee ID cards, and treat forms, but many many hours of costume assembly, setup, and operation were made into light work by the excellent crew who showed up to help out.

Action shot of the crew at the end of the DTV crew at the end of their shift. Not everyone who helped with the construction of the costume is shown in this photo, as a few had to leave early!

How It Works

The DTV costume was primarily a custom IT infrastructure project, with some web development, arts and crafts, and graphic design thrown in for good measure.

Ticketing System

Trick-or-treaters arriving at the DTV are served on a first-come-first-served basis. In order to evoke the linoleum-floored-purgatory vibes of the DMV, as well as for the practical purpose of keeping order among the massive blob of children, we knew that we would need to implement an automated ticketing system.

The DTV’s ticketing system is built by Caitlin in Django, with dedicated web pages for creating tickets, as well as consuming tickets from each available service window. Tickets are created by the employees at the RFC counter using the Create Ticket view, at which point they are added to a ticket database. Employees at a DTV service desk window can mark tickets as completed and ask for a new ticket number to be assigned to their window using the Window view. When new tickets are assigned to a window, they are displayed in the Status view, and announced via the text to speech API on the web browser of the machine driving the waiting area television display. Current wait time was estimated by looking at the time elapsed since the oldest still-incomplete ticket was created.

Overall, the ticketing system worked extremely well for the duration of the DTV’s operation. Wait times were estimated remarkably accurately (we topped out at a 23 minute wait time), no tickets were lost by the system, and window assignments were clear and never in conflict. We did encounter some issues with trick-or-treaters losing their ticket numbers, not going to their window when called, and then waiting infinitely while the service window assigned to them sat empty and eventually moved on to a new ticket. That said, these instances were rare and most trick-or-treaters who were assigned a ticket got processed in a timely manner.

ID Card Creation

IT infrastructure for the DTV costume was based on a Django web server running on a laptop at the primary service desk, which was connected to a LAN network being broadcast by a wifi router. Each DTV employee could use their laptop or mobile device to connect to the wireless network and access an employee portal for creating / editing ID cards, printing ID cards, creating or consuming tickets, and viewing live system statistics.

ID cards were created using a web form connected to a python script on the server computer. ID card information filled out in the webform would be sent to the python script in order to automatically generate an image of the ID card with text positioned in the correct locations with the correct format, as well as ID images and watermarks on the card.

Once a DTV employee created an ID card, they would click the “Print ID” button on their ID card interface to send a print job from the server computer to the ID card printer located at the primary service desk.

ID Card Printing

ID card printers can be quite expensive, but when sourcing equipment for the costume I found out that many old-generation printers were being sold off as surplus as schools, security offices, and government agencies were switching over to new models of printers. Venerable workhourses like the Zebra P-series were being offered for as low as 1/10 of their original list price, allowing me to snag a Zebra P330i single-sided ID card printer for under $250 (I found a deal, but normal prices are usually under $400 for devices in good condition). The printer was missing a critical component (cleaning cartridge), but with some 3D printed plastic parts (and later a used part sourced from eBay), we were in business.

While bringing up the printer, I was continually plagued by issues with cards printing some or all of their colors with a nasty offset. Looking at the card from left to right, it seemed like there would be a sudden vertical bar and everything to the right of the bar would be a smear of black or other mushed-up colors. Fortunately, this turned out to just be an issue with the color sensor having drifted over time, and running a ribbon sensor calibration with the stock driver was able to get things working consistently.

Each ID card is printed on a standard CR80 PVC card blank using a CMYKO (Cyan Magenta Yellow blacK Overlay) dye-sublimation ribbon. These ribbons are super cool (and very expensive), as they include a long chain of stitched-together color panels which are run across a thermal print head one at a time in order to print the various color layers onto the card. With genuine ink ribbons and the cheapest CR80 card blanks I could find on Amazon, we were averaging around $0.50 in materials per ID card. Expensive, but not bad considering that a full-size candy bar would be around $0.80.

Set Design

In order to capture the aforementioned “linoleum-floored purgatory” vibe of the DMV, we knew we were going to need to incorporate cubicles and a stuffy waiting area into the driveway of my parents’ house. My brother designed a half-cubicle / service counter to be constructed out of thin 1×2 planks and cubicle fabric, and we scrounged around the backyard for any lawn furniture we could find in order to create enough seating for the waiting area.

The primary service counter was constructed out of four identical wood-framed cloth panels framed with 1×2’s (we couldn’t find any non-crappy ones at home depot for a good price, so I ended up ripping down some nice 2×4’s with a table saw). These 1×2 frame pieces were cut to length and joined using pocket screws, and some convincingly cubicle-y fabric was stretched over each frame and stapled down. M6 threaded inserts were installed on each frame piece in order to join them together in a strong but reversible manner (we needed to disassembly the desk to transport it to my parents’ house, and I didn’t want to drive screws in and out of soft wood multiple times). There were some brief issues with getting brackets from Home Depot that would fit our M6 fasteners, but a sketchy hole-embiggening rig made out of a trigger clamp and my drill press made quick work of that. The plastic-lined countertop at the top of the service desk was built from some cut-down melamine shelf material, and iron-on edge banding was used around the edges to complete the appearance. LED lights were mounted to the underside of the counter to provide lighting behind the desk (for service counter employees) and along the front of the desk (to illuminate signage). A power strip was installed under the counter to allow IT equipment at the primary service desk to be powered conveniently.

Signage on set was constructed from coroplast with vinyl lettering cut on my plotter. Many friend-hours were dedicated to carefully lining up and applying lettering with transfer tape.

Posted by jmcnelly, 0 comments
Thoughts on Running a Farmers’ Market Stand

Thoughts on Running a Farmers’ Market Stand

I’ve always enjoyed cooking, especially Asian food (lots of influence from my mom’s side of the family in Wuhan) and slow-smoked barbecue (idk it’s tasty). One day in the summer of 2021, Caitlin (my Significant Other), Kenneth (my brother), and I stumbled into a strange cocktail of boredom and hubris and decided to start a farmers’ market stand specializing in hot food of the Asian-American fusion variety.

Chapter 1: Haha What If We Ran a Farmers’ Market Stand

In truth, we thought of the name first, Baobeque, and thought it was a fun enough name that it was worth thinking up a menu for a farmers’ market stand with that name, you know, as a joke. And cooking test recipes for it, you know, as a joke. And filing for the Fictitious Business Name. And registering for a resellers’ certificate and building a budget and starting a sales tax account with the CDTFA and getting a federal EIN and shopping around at commissary kitchens and writing a business plan and applying to farmers’ markets. For the joke. Haha so funny what if we actually ran a farmers’ market stand that would be so crazy we’re all engineers we have like no time.

An early food prototype: Char-Siu Pork Belly Burnt Ends on homemade bao.

Chapter 2: Why Won’t Anyone Let Us Run a Farmers’ Market Stand

On the outside, Farmers’ Market food stands look like a great idea for a business. They serve simple items, have low capital costs, and absolutely print money. For the cost of a tent and some minimal fees paid to the farmers’ market, you can have access to a vast number of potential customers who are willing to pay relatively high prices for unique and interesting food. So why aren’t there more of them?

It turns out that Farmers’ Markets are not just a collection of stands competing with each other on one street. The whole Farmers’ Market is carefully curated, competing with other Farmers’ markets in the area to attract the most customers, retain the best vendors, and secure the best venue. Farmers’ Markets are run by market managers who are in charge of admitting vendors to the market, collecting fees for the markets’ parent organization (usually one organization will run a number of different markets spread out throughout a large area across different days of the week, so that vendors and market staff can work multiple days a week). Because space in each farmers’ market is limited, market managers have to pick and choose which vendors are allowed a spot. In order to keep vendors happy (by avoiding too much competition in each product catrgory), and in order to provide market customers with a variety of choices, market managers usually limit hot food stands to one per specific food category (e.g. there can only be one hamburger stand). If the market is especially large, or there is extra demand for a certain category of food (e.g. artisan bread is super popular), market managers may allow a larger number of similar food vendors. If two vendors overlap but not entirely, market managers may artificially restrict the menus of the two vendors in order to resolve the conflict by reducing competition (e.g. if there’s a noodle vendor that also serves dumplings, they may not be allowed to sell dumplings if entering a market with a pre-established dumpling vendor).

All of this is to say, Farmers’ Markets aren’t just a collection of people who showed up with tents. Each vendor in the market is hand-picked to cater to the most likely tastes of the local clientelle, while providing mutual benefits and minimally destructive competition to other vendors in the market. Kind of like some kind of artificially constructed coral reef, if the corals are vendors and the fish are people who get up at the crack of dawn on a Sunday morning looking to purchase expensive produce from a tent outside a Starbucks.

Because of the large number of prospective vendors that want to join a farmers’ market, and the intense selection criteria created by market managers, many applications to join farmers’ markets are denied, and many more are placed on years-long waitlists to stand by in case another vendor drops out. After a number of fruitless applications, Baobeque seemed like it wasn’t going to get into any farmers’ market anytime soon. But, we were convinced that our concept was unique and provided an angle that wasn’t present in our local market, so we pressed on and began to (politely) badger the local market managers about our vendor application whenever we visited their market. After discussing our concept with them and staying engaged in for a few months, we managed to warm them up to the possibility of adding our tent concept to the market, and eventually they asked us for samples of our food (one of the final steps in the application process)! By some miracle, the market managers liked our food, and our application was green-lit and forwarded to upper management for final approval.

The sample box we provided to market managers. At this point the concept relied on a weird hybrid lunch / breakfast model, where we would serve breakfast like country fried potatoes and eggs until the meat was done smoking, at which point we would switch over to Asian/American fusion. Super weird and there turned out to not be enough time or equipment to pull off the mid-market menu switch. Seems like the food was all tasty enough, though!

Chapter 3: Oh No, We’re Running a Farmers’ Market Stand

Crap crap crap crap quick we gotta get everything ready!

With an approved application, we jumped into the process of acquiring equipment, figuring out branding, building our menu, booking time in a commissary kitchen, and iterating / practicing our recipes. We purchased a used cargo trailer for transporting equipment,

As a dry run for our first farmers’ market, we catered a college student event for free (they paid for the ingredients, and we cooked everything and served it), which was hugely helpful for pointing out many flaws in our process; our prep/setup/everything time was way too slow, our menu was too big, and our recipes weren’t scaling consistently. Fortunately, college students like free food, and didn’t complain–but we knew we would need to step things up before setting up shop at a farmers’ market with real paying customers.

Problems identified during dry run:

  • Low efficiency
    • We spent probably 20 hours preparing, catering, and cleaning for an event where we served ~70 people. Definitely not scalable, but a lot of time was wasted in figuring out how equipment worked, loading equipment into separate cars (instead of a single trailer), and generally being extremely slow about everything.
    • Our roles in the tent weren’t well rehearsed, and we kept tripping over each other and wasting a lot of time being blocked by each others’ tasks.
    • We were missing some key equipment for improving our efficiency. For instance, we were julienning onions by hand (badly), when we could be saving a bunch of time by using an inexpensive manual machine to do the same task.
  • Unscalable recipes
    • One of the main pain points of the catering event was homemade bao buns, which we were making from scratch and steaming ourselves. These buns took a tremendous amount of time to hand-craft for us (as culinary noobs), and worse, were easy to over-steam and had very little durability for hot-holding. If one of our bao buns was overcooked or hot-held for too long, it would end up looking like a wet version of Emperor Palpatine’s face, and would stick to every available surface inside the steamer. Not good.
    • We had a stir-fried eggplant dish that was 1) extremely slow to cook and 2) not that good. We needed to find a better way to cater to vegetarians.
  • Dumb mistakes
    • We made some small mistakes that added up to become large issues. Most of these were related to missing items that we all assumed someone else had remembered to pack for the event. For instance, we forgot to bring honey with us to add to the char-siu pork belly burnt ends glaze, which meant we weren’t glazing the pork belly burnt ends in a delicious sugar crust, but rather frying them in some kind of pink pork oil/water mixture. Still tasty, but not nearly as good as what we had prototyped.

Happy takeaways from dry run:

  • Our food was edible
    • People seemed to like what we were serving, and thought it was very unique (in a good way).
  • Operations had vast potential for efficiency improvements
    • Most of our issues were related to a few small bottlenecks, and a lot of our production capacity was being wasted. This was great news! If we could eliminate some of these bottlenecks and streamline other parts of our operations, it was obvious that we could greatly improve our overall eficiency.
  • This could work
    • Running a farmers’ market hot food stand is going to be a LOT of work.
    • Cooking for a large number of people on a tight schedule is fun, but in a stressful / kinda terrifying way.

Chapter 4: The Real Deal

Baobeque’s first farmers’ market appearance was in early October of 2021.

Core memories from The First Market:

  • We lucked out and happened to debut during the stormiest market of the year. It started dumping rain around an hour after the market opened, and not the light drizzle kind–the raining-horizontally kind.
  • As total noobs, we figured everyone weighs down their tent with sandbags at the market, since that seems like a tenty thing to do. It turns out that sandbags are heavy and usually not needed at all, so nobody had sandbags on their tent except for us. Due to the aforementioned wind situation, we watched from inside our tent as other tents were blown over our heads and down the street during the market. I distinctly remember seeing an Indian food tent being blown about 20ft above the street with a propane tank still attached. There wasn’t much food selling happening at this point as everyone was focused on holding things down, trying to keep stuff dry, and helping people dodge flying tents / pick up the mangled pieces.
  • Someone placed a cash tip into our open container of green onions, which was unfortunately located near the pickup window. Oops.
  • Our total take from the first market was around $600. Impressive for a super rainy day, but not nearly enough to break even. Still, a great start!
  • Some very kind friends stopped by to help us clean up after the market. Their help loading up our trailer in the pouring rain felt like a saving grace after a long day of prep / setup / cooking and getting soaked.

Sometime in our first few markets, a local student named Derek came and asked to film a food review. We were happy to say yes, and his well-produced video is still probably the best-documented video snippet we have of the customer experience. Of course, we were still getting our food ironed out, and a lot of the food presented in the video wasn’t yet our best work, but we were very happy to get a shoutout on the internet!

It was clear that we were bringing something unique to the farmers’ market, and customers seemed to really enjoy the dishes we were making. After our initial market debut, we continued to improve our operations and menu. Some improvements that we made:

  • Added a stir-fried Tomato-Egg dish as a vegetarian option. Probably our personal favorite dish but never got very popular among customers, for some reason.
  • Wrote full checklists and written recipes for ingredient shopping, prep, setup, and teardown.
  • Bought a $700 dough sheeter from Italy for improving our consistency and efficiency in preparing our custom green onion pancakes.
  • Played around with some specials, including smoked beef back ribs.
  • Cut out little blocks from 2×4’s and added some adhesive-backed sandpaper to make levelling blocks for our tables (the street was quite sloped where our tent was set up, and everything kept sliding to the back of the tent).
  • Worked out a really efficient system for writing down orders (written shorthand), calling orders within the tent (verbal shorthand / keywords for acknowledging with a callback), and staging orders for minimum wait times (FIFO with early warnings for any potentially blocking shortages).
  • Caitlin got really good at estimating wait times from the backlog, and usually was able to provide every customer with a wait time estimate that was accurate within a few minutes. She would write the time that the order was taken at the top of every new ticket, and this would be used for estimating current wait times. If an order was taking longer than the estimated time, everyone in the tent would know about it, and an apology could be made to the waiting customer (usually with a free drink or something similar).
  • Kenneth became a bao assembling machine. Most weekends he would assemble 300+ bao for customer orders.

As we gained a following, and as the market began to get busier (due to the return from COVID and adding new vendors), we saw our sales steadily increase until we were in the range of $1400 to $1700 per market. This was enough to break even with ingredients, rent for the commissary kitchen, market fees, and salary (Caitlin and I were working for free). Seeing the same customers come back weekend after weekend was very rewarding, and assauged my fears that we wouldn’t be able to build a steady business.

Chapter 5: Can we make this a Real Business™?

Business was good, but running a farmers’ market stand on top of having full-time engineering jobs was beginning to take a toll. In addition to working 45+ hour weeks at our full-time jobs, we were working an additional 20-ish hours each every weekend to run the stand. The types of work were quite different, which could be refreshing, but the volume of work was getting to be exhausting.

The business was breaking even, but was not in a sustainable place. From the capital side, our numbers were barely working, since we were only operating one farmers’ market, so all of our fixed costs (commissary rent, equipment cost, business fees, etc) were only being amortized across a single day per week of business operation. From the labor side, our business had no redundancy and relied on all three of its employees working at 100% capacity at all times, since any single person calling out sick for even just a few hours of work on a weekend could shut down the whole operation. We were faced with a decision: ride the burnout train into the ground, or put in one more big huff of effort to try professionalizing and expanding the business to a point where it could survive without continued unsustainable effort from our side. As optimists, we chose the second path, and set about making a Real Business™.

For Baobeque to survive without our own continued effort, we realized that it would need to become a self-sustaining business with its own employees and management. We were already doing things above board (paying all relevant permits and sales tax, great documentation for our processes, etc), which was a great starting point. In order to hire Real Employees™ for our Real Business™, we needed to write up an employment contract and employee handbook, figure out a payroll system, pay for employee insurance (in case of injury on the job), and collect (withhold) income tax from employee wages. This turned out to be substantial effort, but with the help of some of the readily available digital tools for small businesses (Square is a lifesaver), the process was completed within a few weeks. So, we put up a “hiring” sign, set the hourly wage as high as we could possibly afford ($18/hr), and waited for someone to ask us about it!

Within a few weeks, we lucked out and were contacted by someone who was the become our first Real Employee™. He had a great attitude and were quick to learn the ropes. Our original intention was to have them come to the market and learn the process for a while, and then have Kenneth take some weekends off. However, hiring our employee corresponded with an increase in sales, and any slack that was left was taken up by new processes we had to introduce to be compliant with labor laws (e.g. minimizing overtime work, mandatory bathroom and meal breaks, etc). We hadn’t had to stick to these processes previously since the only people working in the booth before weren’t paid employees. Adding these provisions increased the cost of doing business, but were obviously necessary. We hadn’t realized how much we’d been burning the candle from both ends just to make things work! And at the end of the day, if a job needs to not allow bathroom breaks to be financially viable, that job is either vastly under-valued or probably isn’t worth doing in the first place.

In order to pay for our higher costs that resulted from converting to a Real Business™, we raised our prices to the highest level that we thought would be fair to our customers (we gave our regulars some discounts during the cost increase period to soften the blow). Due to a number of factors, our revenue increased slightly and reached a more-or-less sustainable threshold. We were cash-flow positive as a Real Business™, but only by a hair. And, we didn’t have enough revenue to pay supervisors or owners more than the base employee wages, which would make promotions difficult.

Some things influencing our profits during the Real Business™ transition:

  • (+ revenue ) We raised our prices. For instance, a 3-bao meal with a salad went from its original price of ~$10 when we first opened up to a final price of $18! We tried to keep some “deep value” items on our menu with large portions and low costs to keep hungry customers satisfied (we sold jam-packed containers of slow-smoked pulled pork fried rice for just $12, usually enough to feed two people).
  • (- revenue) A really tasty dim-sum tent opened next to our booth in the market, which reduced demand for our product slightly by helping fill out the Asian food niche (but also resulted in some excellent food trades where we got to go home with some delicious shu mai and har gow).
  • (- profit) Pork prices went way up, something like 30%.
  • (+ revenue) Farmers’ market foot traffic increased as summer approached.
  • (+revenue) We introduced a new vegetarian dish to replace our less-popular tomato egg. We began serving hot sesame noodles, a spin on the Wuhanese dish Re Gan Mian (热干面) but with slightly different ingredients. This dish was easy to make in volume and had great profit margins.

Having completed our Real Business™ transition, with two employees (Kenneth converted to a full time employee during the transition), two co-owners, and a fully insured and above-board business, we had a toehold on a sustainable business plan, but residual burnout was creeping back in. Caitlin and I wanted some time on the weekends back, and Kenneth was about to start a new full-time job. At work, I was getting promoted to a management position on top of my existing engineering responsibilities, and I knew that I would need to find a way to not do 20 hours of farmers’ market work every weekend (along with additional hours of miscellaneous tasks outside of work hours during the week) in order to maintain my sanity and put my best food forward at work. We would need to find a way for the business to operate without us involved in day-to-day operations if it was going to be sustainable long term.

Chapter 6: The Impossible Chicken Egg Problem

To make the business run truly hands-off, we would need to hire someone who could be an experienced supervisor, and train them to train more people. To pay for an experienced supervisor, we would need to join more farmers’ markets to increase our revenue, better amortize our operating costs, and increase our economies of scale. But, since we already had full time jobs and were operating at 100% capacity, we had no bandwidth to join additional markets, or even really start a hiring search for a supervisor or new employees in earnest. If we wanted to expand the business to a sustainable and scalable point, we would need to invest a substantial amount more resources, into the business in the short term both in capital and in our own time.

Caitlin and I are both very passionate about our jobs (we’re engineering nerds and getting paid to build stuff with technology is actually the best), and neither of us was down to leave our engineering career to work on the farmers’ market business. We spent some brief time searching for a buyer, but didn’t find any initial takers and weren’t willing to run the business indefinitely while searching for someone to hand it off to. Our employee expressed some interest in acquiring the business, and we were excited about the prospect of selling it to him (at a very good price), but ultimately he wasn’t able to secure the funding and support he would need to run it sustainably. Ultimately, we made the decision to close the business as gracefully as possible while taking care of our employees, friends, and customers as best we could.

Baobeque’s last day of operation was on June 12th, 2022. We notified our customers in the weeks leading up to our closure, and many of our regulars came by to place one last order (or many last orders). We also printed up recipe cards for our most popular dishes, and handed them out to anyone who wanted them, so that anyone who had grown to love the taste of our food could try replicating it themselves.

While closing the business, we gifted our employees a generous severance package, and began selling off our major pieces of equipment piece by piece. Many of the friends we had made at the farmers’ market and the commissary kitchen were more than happy to buy our used equipment, and we were happy to provide them great prices as a token of our friendship. On June 19th, 2021, the Baobeque crew enjoyed a wonderful Sunday morning of sleeping in for the first time in a long time.

Posted by jmcnelly, 0 comments
Halloween 2021: The TSA (Treat Security Administration)

Halloween 2021: The TSA (Treat Security Administration)

For Halloween of 2021, we decided to bring the horrors of modern air travel to unsuspecting trick-or-treaters in our neighborhood. Thus, the “Treat Security Administration” was born.

The TSA

The Treat Security Administration is tasked with inspecting all treat and costume items being brought or worn onto the premises of any nationally recognized TDF (Treat Distribution Facility). For the safety of all trick or treaters, arbitrary items such as excessive amounts of candy, pointy hats (sometimes), certain kinds of chocolate, and that one kid’s squirty blood face mask are subjected to additional screening and inevitable delays.

The TSA crew at Los Altos’s premier TDF served trick or treaters compassionately and efficiently on October 31st 2021 (the year’s busiest treat distribution day)! Thanks to their diligent treat inspections and trick-or-treater harrassment, not a single treat-related attack or incident was reported on site that night.

The Setup

Any good airport security line needs a good, loud, beepy metal detector. Ideally the kind with bright LED lights that change color when an item of interest passes through. My brother did an excellent job crafting a metal detector frame out of 2×4 framing lumber, and used bent coroplast sheeting to fill in the gaps and add a finished appearance. A healthy coat of metallic silver / gray spray paint completed the effect.

For the beeping and flashing sound effects, I threw together an electronics system based on an Arduino Nano, an audio amplifier module, and individually-addressable LED strip, and some speakers. When a hidden button was pressed, the Arduino would blast a pulsed square wave through the speakers and change the LED strip color from green to red, recreating the iconic “BEEBEEBEEBEEBEEBEEP” sound effect that is a fixture of The Other TSA’s many locations.

Some basic register manipulation was required to get the PWM frequencies just right on the Arduino side of things, but other than that the code and electronics were pretty uninteresting. The whole blob of electronics is powered from a LiPo battery via a DC-DC converter, and was laid out on a fiberglass backplane mounted in a waterproof box.

All of the electronics jammed into a waterproof box with a fiberglass backplane.
Somehow the best picture I have of the whole metal detector put together.

The Crew

The best darn crew (and cow, and passenger) a TDF could ask for.

My brother acquired some blue uniform shirts and some very cheap black ties, then custom made everyone little TSA ID badges. Latex gloves and some bus bins from our farmers’ market stand completed the ensemble.

We had enough people to run a check in desk, treat inspection, and the metal detector with multiple shifts. Roles were as follows:

  • Check-in Desk
    • Ask trick-or-treaters for ID and boarding pass (they have neither; act surprised about this, but in a bored way). Ask them if they’re trick-or-treating for business or for pleasure. Ask them how long they will be trick-or-treating for. Squint at them suspiciously. Examine an imaginary ID card with a little UV flashlight. Tell the blob of waiting kids to please remain behind the white line. Send a trick-or-treater to the inspection area, and call NEXT in an assertive yet unenthusiastic manner.
  • Treat Inspection Area
    • Make kids put their treat sack into a gray bus bin. Ask for X flavor of treats to be placed in the bin separately, if desired. Sneakily plant suspicious items into the treat sack, like a roll of scotch tape or some safety scissors, so you can pretend to find them later. Tell kids not to take off their shoes. Slide the bus bin along the table next to the metal detector and inspect its contents. Tell kids not to take off their shoes. Inspect any items kids remove while being harrassed by the metal detector operator. Tell kids not to take off their shoes.
  • Metal Detector
    • Stand near the treat inspectors holding the metal detector trigger button (attached to the metal detector with a long cable) behind your back. Trigger the metal detector when every Nth kid walks through, and declare the issue to be with an arbitrary part of their costume. Trigger the metal detector consistently if that part of the costume passes through it again. Wait until the kid takes off that part of their costume and passes it through the inspection area, then let them pass through the detector without triggering (or trigger it again, and say sorry, it must actually be a different item–this was especially fun with older trick-or-treaters).

The Event

Running a TSA checkpoint for trick-or-treaters yielded a record ratio of trick-or-treater engagement and costume participant enjoyment to costume setup effort. Parents thoroughly enjoyed the joke, children were initially confused but completely auto-piloted through the situation with little need for guidance or additional explanation (most of them had been through airport security lines many times before), and laughs were had all around.

I found that if I triggered the metal detector while a kid walked through, and declared it was being triggered by some specific item on their costume (say, a hat), most kids would immediately comply by taking off the hat, putting it in an inspection bin, and walking through again. A few kids were initially skeptical of the setup and called out the metal detector as being “fake”, but if I triggered the metal detector again when they walked back through it on their way to try again, they were instantly 100% convinced it was totally real, and something in their hat was totally triggering this crazy hat detector to beep at them. Some kids would even take off the specific offending clothing item and wave it through the detector individually, and I would dutifully trigger the detector in sync with their test.

One of the most entertaining strategies of the night was telling one kid in line that X costume item was triggering the detector, but telling the kid immediately behind them in line (dressed identically) that X costume item was totally fine and it was definitely Y item that was triggering the detector. We had a number of witches, wizards, and draculas trying to figure out why their friend’s plastic hat/cape/wand was setting off the detector but theirs was not.

It was a continual chore to stop kids from taking off their shoes before going through the security line. Airport reflexes were deeply ingrained, even though many kids hadn’t been on a plane for the duration of the COVID-19 pandemic.

Project Files

Source Code

Posted by jmcnelly, 0 comments
Arduino Radar Speed Sign

Arduino Radar Speed Sign

For Halloween 2020, I decided to build a replica of a radar speed sign using an Arduino and an HB100 doppler radar module. This writeup is gonna be a bit fuzzy, since as usual, I decided to document the project a tasteful 8+ months after it was complete. Have fun reading my semi-coherent image and schematic dump!

The completed sign. It currently resides on the wall of my lab, and has been converted from battery power to a DC power supply for use as a static decoration.

How the Radar Do

The project uses an HB100 doppler radar module and a pre-amplifier circuit in order to convert movement of objects in the HB100’s field of view into a square wave that gets fed into the Arduino Nano. Radar makes everything sound fancy, but in this case it’s no more complicated than what you would find in one of those supermarket automatic doors that triggers when some leaves blow by. The HB100 transmits a 10.525GHz carrier signal, which is reflected off of a moving target (in the case of this project, a person walking across a room at close range). The return signal from the moving target is doppler-shifted, and is thus a higher (or lower) frequency than the carrier, depending on whether the target is moving towards or away from the transmitter. By mixing the transmitted 10.525GHz signal with the reflected signal, the HB100 produces a signal that is the difference of the two frequencies. Fortunately, for objects moving at non-relativistic speeds, this difference frequency is usually very chewable for even the dumbest of microcontrollers, as it’s usually in the range of a few Hertz.

Diagram of the guts of an HB100 radar module. The outgoing signal is broadcast from the Tx Antenna, and is mixed with the reflected signal coming into the Rx antenna. The difference frequency that results is piped out the IF pin to an external pre-amp circuit.

In order to get the difference frequency into a format that can be processed by a microcontroller, the signal passes through a two-stage preamp circuit which amplifies it from a lil squiggle into a rail-to-rail square wave. The pre-amp circuit isn’t that interesting, and is ripped straight from the datasheet. There are some capacitors in parallel with the feedback path in order to generate some poles that roll off the frequency response around 72Hz, stopping the pre-amp circuit from amplifying high-frequency noise that is beyond the range of interest. Also note the chunky (4.7uF) AC coupling caps between stages. These coupling caps are yuge because they need to have a low impedance at the frequencies of interest (<100Hz). If we look at the 12k resistor used for the IF load, and assume that the HB100 IF circuit has a characteristic impedance in the range of 12kOhms, we can see that a 4.7uF capacitor provides an impedance lower than the characteristic impedance all the way down to around 2.8Hz. Neat!

IF Amplifier schematic, as suggested by the HB100 datasheet. Redrawn by yours truly because blue. Also for labels to make things a lil clearer.
I guess I was looking at the HB100 output before the preamp or something lol. Vpp is only like 8mV. Needs amplification!
Breadboarding the preamp circuit.

Once the preamp circuit was working, it was pretty simple to stick the output straight onto one of the Arduino Nano’s digital inputs. Input interrupts were used to time the pulses and estimate the frequency of the signal, which can be converted into velocity using the doppler radar equation.

Cardboard Testbed(TM).

Bigass 7 Segment Display

From the beginning, the real pizazz for this costume was always going to be the giant LED 7-segment display. I’d been wanting to make one for a long time, for no particular reason other than whee LEDs shiny, and more LEDs = more shiny. There have been plenty of 7-segment display implementations with all kinds of hardware, from the WS2812B chips controlling segments with individual addressing to cool multiplexing schemes. However, my favorite approach has always been the tried and true SPI shift register configuration. Using two SPI shift registers (the good ol’ 74HC595), each digit is controlled by a single shift register, with a single segment responding to a single bit output from each shift register. In the past, I’ve used the 8th bit output to control a decimal point, but that wasn’t necessary for this particular project.

In order to make things easy and reasonably professional-looking, I designed a custom modular PCB containing 8 high-power amber LEDs. These hexagonal PCBs could interlock to form a 7-segment display digit, and contained the necessary current-limiting resistors, and switching transistors for turning the digit on and off. Solder pads at the interlocking edges of each PCB were used to share +12V and GND to the entire digit from any single powered segment. Additional solder pads on the edge of each segment connect to the gate of the switching MOSFETs, allowing a low-current enable signal from the shift register to control the segment of high-power LEDs. I should have added a series resistor to this gate network to protect the MOSFETs from ESD…in my late-night haste to assemble the costume, I managed to zap through the oxide layer on several MOSFETs with ESD, killing them. That caused a good amount of debugging headache! If I were to sell these segments or something, I would probably change the drive MOSFET to an NPN BJT with a base resistor for added robustness.

These boards are neat! Look at how they interlock with solder pads to share power and retain their shape!
I placed a lot of LEDs.

Putting Things Together!

Links

Github Repository

Here’s a list of some of the parts that I used, in case people are looking! These are Amazon affiliate links (gotta make some of them Bezos Bucks).

Posted by jmcnelly, 15 comments
Idiot Bird

Idiot Bird

This bird is so dumb that it laid an egg on one (1) stick. We built it a tupperware out of wood, so watch it have kids now I guess.

Posted by jmcnelly, 7 comments
Self Checkout Stand Halloween Costume

Self Checkout Stand Halloween Costume

Testing out the costume with my lovely brother.

Why did you make this cursed rectangle?

It’s a pretty iconic vignette of 21st century living: you’re checking out of the grocery store, and the cashier lines are long. You glance down the row of checkout stands, and the unoccupied self-checkout kiosk beckons from across the store, willing you to try it out just one more time. You have second thoughts, but are quickly entranced by the circa 2003 3D animations and a strip of paper that billows from that secondary receipt printer whose sole purpose is to print expired coupons for discount plumbing services.

You scan your first item, and then your second item. All seems well, but then the dance begins.

Beep.

Place item in the bagging area.

You gently place your dozen eggs in on the bagging tray.

Unexpected item in the bagging area. Please remove the item before continuing.

You remove the eggs.

Please place item in the bagging area.

Hesitantly, you place the eggs in the bagging tray.

Unexpected item in the bagging area. Please remove the item before continuing.

Two minutes and thirty seconds later, you notice the coupon hunter who was behind you in line at the cashier’s stand leaving the store with her two dozen gallons of milk that she got paid $5.23 to take home.

Unexpected item in the bagging area. Please remove the item before continuing.

Someone is trying to help you now. It looks like they maybe they work here.

Please remove the item before continuing.

You’re in the parking lot now. You have no eggs. They were terribly sorry, but there was simply nothing they could do. Helpfully, your car is filled with milk and you have five copies of the same coupon to AJ’s Plumbing n’ Animal Control Inc, valid till last February.

Ok, that wasn’t helpful at all. Fine. HOW did you make this cursed rectangle?

Oh, sure! Here’s the parts list:

  • 1x Epson TM-T88V USB Thermal Receipt Printer (used)
  • 1x Raspberry Pi 3B+
  • 1x 7in Touchscreen + 3D printed case
  • 1x USB Barcode Scanner
  • 1x Anker Soundcore Bluetooth Speaker
  • 1x 3-level LED Stack Light
  • 1x 80W DC-DC Converter (12V 3A)
  • 1x 15W DC-DC Converter (5V 3A)
  • 1x Automotive Fuse + Fuse Holder (this was actually a REALLY good idea, because of the next thing)
  • 1x 4S 4000mAh Lipo Battery
  • 1 sheet of Plexiglass from Home Depot
  • Some one-way mirror window film (also from Home Depot)
  • Buncha 3D printed parts*
  • Buncha Coroplast + 3/16in Aluminum Pop Rivets*

*Buncha refers to the metric Buncha (not to be confused with the standard Bumcha which was deprecated in 1993)

Look! Pictures!

Self-checkout stand with the crew (friends inside the boxes lit up their faces for the photo: normally the reflective coating on the plastic windows would hide the box operators from view).

We are weird nerds or something and we want to know more! Tell us!

Ok!

First, the simple mechanical and electrical stuff.

The entire machine runs on a 3S 4000mAh battery from some quadcopter builds I did a while back. This battery feeds into a fuse (important, I debated putting this in at all and it totally saved the whole costume from catching fire when a circuit board came unglued and shorted out the main power distribution board), and then into a power distribution board and a 40W DC-DC converter. The DC-DC converter is used to power a 12V rail that runs the stack lights, the receipt printer, and a smaller 5V DC-DC converter that runs the Raspberry Pi and USB peripherals. The stack lights are switched using a low-side drive circuit I put together using some 2N7000 small-signal MOSFETs. I had to buy an extra power supply brick for the receipt printer just so that I could cut the plug off of it, since the fine folks at Epson like their strange proprietary DC jack shapes.

The Raspberry Pi is interfaced with the 7in touchscreen over HDMI and USB, and the Anker Soundcore speaker is powered by its internal battery, and is connected to the Raspberry Pi using an aux cord. Interestingly (annoyingly), the speaker is “smart” and will stop listening to the signal on the aux cord and shut down if no sound is being transmitted. When a sound byte is sent to the speaker after some silence, it takes some time to “wake up” and can often clip the first half-second or so of the sound byte. This is very annoying if the speaker is being used for sound effects or voice lines! I managed to get around this issue by continuously playing a looping track of very, very quiet white noise from the Raspberry Pi, just loudly enough that the speaker would always stay “awake”.

The costume consists of two boxes shaped from Coroplast: a “checkout stand” block and a “bagging area” block. The bagging area is a simple box with an LED illuminated “Self Checkout” sign on top, and some plastic bags with corresponding plastic bag hangers. Above the plastic bag hangers, there is a plexiglass window with one-way mirror tint allowing the wearer to see outside the costume. The checkout stand has the meat of the system inside it, with the Raspberry Pi, electronics, touchscreen, receipt printer, barcode scanner, speaker, and stack light attached to its inside, front, and top. There are two one-way mirror plexiglass panels on the self-checkout stand, allowing the wearer to see out the costume and the USB barcode scanner to read items that are swiped over it.

The checkout stand can be interacted with from the touchscreen or by scanning barcodes on the scanner. Additional controls are available to the wearer of the costume or a nearby operator via a wireless USB keyboard. Keys on the keyboard are bound to various voice lines and actions, allowing scans to be faked and costume actions / voice lines to be commanded.

Now for the software!

The system is hacked together around a Raspberry Pi, since I figured that was the easiest way to run a complex multithreaded state machine that would also deal with USB devices and audio files. Everything is written in Python, with different threads that take care of flashing the lights, running the USB scanner and printer, drawing the GUI on the screen, and running the checkout stand’s internal state machine that allows users to checkout and print their receipt.

The GUI is made in Pygame, allowing easy capture of user touchscreen events, playing of sound clips, and drawing of on-screen text and buttons. The blissful part of this project was making every part of the GUI aggressively terrible, just like the real thing. I swear that once when I was in Safeway, I had to have an attendant enter their passcode to unjam the uncooperative kiosk I was using, and the kiosk cheerfully stated every number of their passcode out loud, just like it was a quantity of produce or a price. I happily included this helpful feature, among others, in my own rendition of the self checkout nightmare.

The sound files for the text-to-speech were painstakingly recorded and clipped from an online text-to-speech website that I found which had a voice that was pretty similar to what I had heard in grocery stores. I typed out every necessary number and digit combination, as well as the primary voice lines (“unexpected item in bagging area”), recorded them on my browser, then spent hours cutting them down to size using Audacity. With a bit of tweaking, they turned out all right (or at least, as terrible as the real thing)!

There is a random number generator buried in the state machine, and every additional item that a user scans in to their cart carries a small chance of entering the terrible “unexpected item in bagging area” loop. This feature really seemed to be most enjoyed by the parents we encountered on Halloween night. There were some other easter eggs that we enjoyed using to startle and delight various children throughout the night as well…

And here’s the rest of it! Was a very fun costume to build and play around with on Halloween with friends. 12/10 would recommend. All of the code is fully open source, and if anyone else would ever like to build a similar abomination, I would be more than happy to assist with design files and advice.

Github repo with code, etc.

Posted by jmcnelly, 0 comments

PIC Beeper

After learning about the PIC12F752 in a mechatronics class, I was tempted to use the cheap microcontroller to play music. The device has 1024 Bytes of program memory, but only 64 Bytes of flash, making storing a song in data memory very difficult. Instead, I hacked together a code generation program in Python that would read MIDI files and output the notes as a C program, which could reside entirely in program memory.

Even while storing notes in program memory, each PIC could only hold around 40 notes. I took this as an opportunity to create a chainable series of boards, each of which could only play a set portion of the song. Each board has input pins for power and the master reset pin on the microcontroller, and has output pins for the same functions. Powering one board in the stack provides power to all of the boards, and the first board in the stack boots up and asserts a LOW on its master reset output, thus disabling the subsequent boards. Once the first board is done playing, it asserts a HI on master reset, allowing the next board in the chain to play. When the next board is done, it asserts a HI on its master reset output, and the chain continues to play.

Early prototypes of the PIC beeper board were made on a CNC in my dorm room using 1-sided FR4 copper-clad boards.

An original prototype milled out of single-sided copper clad FR4.

I later moved to commercially produced PCBs for the final product (2-sided boards). In order to reduce the form factor of the board, I switched to a QFN package for the 12F752 and added a custom POGO programming header to interface with the PiCKit programmer. At some point in this process I also realized that the CR2032 battery didn’t have enough current to power some of the louder / lower resistance beepers I wanted to use, so I switched to a design with two AA batteries powering all of the beepers in a stack.

Closeup of the new board with its compact programming header.
A prototype board being programmed, with a Genuine Bodge (TM) visible on the left.

I purchased the final boards as a small panel with v-scoring, and used a solder paste stencil and my Controleo3 reflow oven for assembly. I used water wash solder paste, and covered the buzzers with Kapton tape to protect them during the water wash / ultrasonic cleaning process.

Once the boards were fully assembled, I fired up my code generator and programmed them in sequence with their corresponding portions of the song.

The assembled chain of beepers worked as intended! Some of the notes are a little bit scratchy or weirdly loud, but I think that’s attributed to them being close to the resonant frequency of the beeper or the PCB. The notes are synthesized by varying the period of a 50% duty cycle square wave, so there are lots of higher frequency harmonics, but it works in a pinch!

Posted by jmcnelly, 0 comments
Birdcam

Birdcam

Live stream

I decided to build a bird feeder with a live-streaming camera for my significant other’s birthday. It seems to work pretty well! The system is based on a Raspberry Pi Zero W running the Motion firmware, with an image mask and motion trigger set to activate when birds land on the feeder. Every night, a shell script runs the imagemagick utility to convert all images with the same minute time stamp into fun little combined gifs. This project is a work in progress–automatic image tweeting and imgur uploads should be coming soon! In the meantime, if anyone needs an absolutely massive number of tiny bird gifs, I’m happy to share!

Parts List

Code

Posted by jmcnelly, 0 comments