Painbox part 3: a bunch of updates

Since I last wrote about my Painbox project (part 1, part 2), progress has been very lumpy. Here’s a bunch of short updates on various aspects of the project.

The grill

grill body uncappedgrill body bottom uncappedgrill body bottom cappedfinished grillReplacing the clunky “copper tubes through a 2×4″ test grill was high on my list of priorities, so I tackled that first. I considered a number of different options, but settled on making a custom one-piece grill out of a 1/2″ HDPE cutting board. Essentially, it’s like a two-sided PCB, except instead of copper traces and plated vias, I milled width-wise grooves into the top and length-wise grooves into the bottom with through-and-through holes connecting the two sides. The result is a sort of channel that snakes across the top, through to the bottom, over the neighboring groove, then back to the top. To make it capable of moving water, I capped the grooves with pieces of 0.025” aluminum sheet, also cut out on the Shapeoko 2. The first and last hole of each path are threaded to accept a hose barb.

Other than the capping and sealing process, which was awkward and imprecise, the whole thing turned out really good. If I was going to do it again, I would use a piece of virgin HDPE instead of a cutting board so it would have a better surface finish. I’d also probably go with thicker stock, since that would improve durability and flatness while increasing the margin for error during machining.

Temperature sensors and reservoir design

In the last post, I talked about my success with immersing the sensors directly in the water. To try and make that more permanent, I drilled a small hole in the top of my reservoir caps, threaded a thermistor through the hole, and then tried to seal the whole thing up with some silicone glue stuff I had lying around.

This did not work.

Problem 1 – the water in the reservoirs does not really reach the thermistor, since they are not hanging down that low, and the water is not that high. Result: bad readings.

Problem 2 – the silicone stuff is glue, not epoxy or sealant. While it appears to solidify into a rubbery plug, it turns out it really doesn’t like to cure solid when it’s in a big blob, and over time gravity will let it goop down and into the moving water, where it will ultimately foul your pump. I had to disassemble and clean out one of my aquarium pumps four times before I realized there was probably a loose blob trapped elsewhere in the system. Turned out it was hanging on to the fins inside the water block and would occasionally throw a clot or two after an hour of continuous running. After cleaning that out, problem solved.

Problem 3 – trying to keep things simple, the connection style is just a long wire pair soldered to the thermistor. When manipulating the reservoir cap, that long wire wants to twist up unless it’s disconnected from the microcontroller, and even once it’s disconnected, it flops all over the place while you’ve got a wrench on it, making it pretty unwieldy.

A related problem is that my reservoirs just don’t work that well. I’d previously decided to make them small so that there’d be less water volume in the system, but somehow at the same time I ended up with reservoirs that made it hard to fill or drain the whole system. Water just didn’t want to disseminate into the system when added to the tiny reservoir.

Combined with the temp sensor issues, this lead me to change my reservoir design. Instead of a 3-way corner elbow, I’m using a 4-way tee as the base and adding appropriate threaded connectors and hose barbs. The inlet and outlet will be oriented such that the water will flow downward from the inlet to the outlet. Across from the inlet, I’ve added a dedicated port for the thermistor, which will still be connected to a threaded cap. However, this time I’m going to try to drill individual holes for each of the thermistor’s leads and use a minimum amount of actual sealant to make it waterproof. Since the sensor will now be level with the inlet, I can just fill the reservoir until the inlet is covered and know the sensor will also be immersed. With the legs exposed on the outside, I’ll solder a tiny connector board on that allows for easy disconnection. The final branch of the 4-way tee will be the fill port, which will just have a plain cap in it. I might add a bleed valve of sorts to the top of the fill cap if I find the system needs help shedding bubbles.

TEC controller board

Latest version of the TEC controller

Latest version of the TEC controller

During earlier testing, I didn’t use any sort of closed-loop control scheme, which lead to, well, uncontrolled temperatures. To implement closed-loop control in this system, you need a sensor, a TEC controller, and the logic to control it. For the sensor, I’m using the aforementioned thermistors. The logic part is easy, and comes in the form of an Arduino PID library.

The TEC controller, though, is where things get difficult. Coming from an Arduino, PWM is easy, but TEC efficiency is greatly reduced when controlled in this fashion. To get analog control of TEC current, I designed a PWM-to-constant-current converter board. The basic principle of operation is to use an op-amp, MOSFET, and power resistor to form a feedback-controlled current sink. Then, rather than using a potentiometer to set target current, I’m using the PWM output of an Arduino plugged into an RC lowpass filter. The filter converts the PWM into an analog voltage, which is converted into the target current by the op-amp feedback network.

Simple enough scheme, but unfortunately I still had to go through a few revisions.

tec_v2_sch  tec_v2_layout

In rev 1, I made a small order of magnitude math error and incorrectly sized my power resistor, thus dissipating about 10x my desired wattage in the resistor. (It’s hard to appreciate what it means when these things are rated as “fire proof” until your IR thermometer reads 300 degrees C.)

tec_v2_sch  tec_v3_layout

After correcting that math, it turned out that I had my feedback dividers set in the wrong direction – I actually need to step the input voltage down, not the feedback voltage – so I spun another version of the board. This worked much better, but to my dismay I couldn’t get both the hot and cold channels to reach as much of a temperature difference as I wanted. After some head scratching, I determined that my power supply wasn’t beefy enough to drive two 10A loads at once and must be sagging, so I Amazon’d up a much bigger one. When I plugged that in and let it rip, things looked good until my tragically undersized +12V trace heated up to red-hot and blew like a fuse. In retrospect, of course that trace was too small… but I think I had been telling myself I would solder-fill it or something to increase carrying capacity.

tec_v4_sch tec_v4_layout

So we’re on to rev 3. This version solves all the problems I’ve come across so far: better connector strategy, better layout for the analog components around the opamp (fewer vias), smaller outline, and of course the fattest power traces I could pull off. I milled it out, riveted the vias, flooded the power traces with solder, and stuffed it full of components. I’m feeling pretty good about this one, but I won’t be able to test it until I get all my plumbing straightened out again.

Mounting brackets

Waterblock, TEC, heatsink mounting bracket

Waterblock, TEC, heatsink mounting bracket

I’m also tired of using zip ties to mount everything to my project board, so I started on the process of making permanent mounting brackets for the important parts.

The first thing up is the hot-side waterblock, TEC, and heatsink. The design is very simple – just a sort of pocket that holds all the parts in a stack and a retainer that slips over the top. There are holes in the corners to bolt it down. This was the first time I’ve ever tried milling such a thick piece of plastic, and I found it be a bit challenging due to the debris evacuation aspects. I used a 1/8″ upcut endmill, which worked fine for the main cavity, but in the continuous, thin, deep cut of the outline, chips accumulated, remelted, and ultimately bogged down the mill. I was able to rescue this part with some cowboy maneuvers, but overall the result wasn’t too great. I’ll be remaking this for sure with better tooling and/or process. I’ll make a similar version that mates with the giant CPU chiller I’m using on the cold side, too.

What’s next

As soon as I have brackets for remounting the main components, I’m going to start on a new project board and try to mount everything closer to what I’ll want it to look like in the final enclosure. Then I’ll transfer all the control electronics to a more permanent breakout board, and start to design the final enclosure. Still lots to do, but definitely inching along!

Minimum Viable Operational Overhead

Operational overhead is all the costs you incur just to keep your app running, totally separate from initial and ongoing development. This is all the behind-the-scenes work necessary to support ongoing operation: updating special models (“categories”, “countries”, etc.), auditing capacity consumption, re-running failed scheduled tasks, granting access or privileges, etc. It’s uninspired busywork that we can’t seem to escape. It ends up relegated to your on-call rotation and is generally a drag and a distraction from future development.

Nobody likes operational overhead, yet rarely do engineers budget time into their project plans to build features that help reduce it from the beginning. Why not? Most often the refrain is “Sounds great, but we don’t have the time to build that.” But make no mistake, these same engineers will spend vastly more time maintaining the systems they build than building them in the first place! When the time comes for you to take some operational action, the work you’ve done in advance to minimize overhead determines whether it’s a just quick series of clicks or a nightmarish slog through the application database console. If it’s the latter, then you are setting the team up for lengthy interruptions and costly outages.

Operational overhead is another kind of tech debt, where you are paying for “quick” development now with operational work later. I’d argue that allowing operational overhead is right up there with avoiding unit tests: it seems fast, but is actually slow. Worse, operational overhead is an enormous morale drain.

Minimum Viable Operational Overhead

Minimum Viable Operational Overhead, then, is the philosophy of building systems that require the lowest amount of operational overhead possible while still working. The “minimum viable” part is in there to remind us that customers must come first, and in practice any useful system will have operational overhead. But when you prioritize reducing operational overhead, your customer is your future self. Making sure to budget for this kind of work will help you produce higher-quality systems and allow you to move more quickly in the future.

The actual techniques you should use to reduce operational overhead are too various and situational to list, but I have two favorites that always seem to be applicable. The first is to automate everything. You should try to minimize the number of operational tasks that require (or encourage) the least bit of creativity or analysis during execution. If it requires you to think about how the pieces fit together, then the context switch will be worse and you run a greater risk of making a mistake along the way. Even if it seems simple, write a simple script that does the task and document the arguments extremely well. Make sure the usage is described in your runbook and it’s copy-pasteable. Better, just build the copy-pasteable part into the app — it can be easier to just handle the special case than it is to document it. The more brainless you can make your operational interruptions, the better.

A common trap to fall into here is to think “eh, this is a one-off, I’ll automate this the next time it comes up.” Don’t do this. It’s hard to tell at the outset how many times you might have to redo an operational task. The best case is that the next time it only takes you 5 seconds, but the worst case is that you’ve rigorously done a one-off. Script it this time.

The second key technique is to make a UI. I can hear the grumbling already, but honestly, it’s not that difficult to attach a trivial web UI to the service or to add a few views to an existing application. When you do this well, it pays off in spades. It is incredibly powerful to be able to click a link or fill out a short web form to complete an operational task, especially the kind that involve hairy curl requests or manipulating complex database records. This also tends to make operational tasks almost self-documenting, because you have a place to write a document that lives right alongside the code itself. And since it’s an actual code artifact integrated right in with the existing internal API, it’s much easier to keep it up to date and functioning. (Write tests for your admin UIs!)

But the best part is that you will find that these internal-facing admin UIs grow like weeds, accumulating more and more command / control / monitoring features over time. It’s often not the first button that’s the big win — it’s that by taking the time to create a trivial web UI now, you are dramatically lowering the activation energy for future efforts that just need a place to put one more button. Eventually you’ll have a whole control panel full of them.

Thanks to Dmitri, Jack, and Sarkhan for reading and editing this post!

Custom Bench for Shapeoko 2 (+ Upgrades)

complete-bench

I bought a Shapeoko 2 about six months ago. One of the things the mistakes I made on day one was the lack of a permanent, high-quality bench for it to live on. Not thinking ahead, I built my SO2 on top of a knock-down bench I built for doing “dirty” tasks – it’s just a sheet of 3/4″ particle board on top of two sawhorses. Permanently attaching a CNC machine to a floppy surface turns out not to be the best call, and I’d rather have the dirty bench available for assembly projects anyways.

So it was time to build a permanent bench. Here are the key features I decided on:

  • Sturdy. No sagging surface or rickety legs. I want this thing to be able to survive the rigors of daily use and future moves.
  • Mobile. It’s got to be on wheels so I can push it up against a wall when I need to.
  • Extra storage below. I’ve accumulated a few boxes of SO2 stuff that are best stored with the machine.
  • Convenient hookups. Should have on-board power strip and integrated cord. Also, let’s add in a permanent vacuum line so we can put a debris collector on the toolhead.
  • At least moderately attractive.
  • Cheap.
extrusion_cart_frame_render

Concept render of aluminum extrusion version.

While I first considered building a bench out of aluminum extrusion, after spending a few hours planning and pricing, it wasn’t going to work out. It would be too expensive and not that sturdy. It also didn’t help that the materials would have to be special ordered and couldn’t easily be cut with the tools I have on hand.

Ultimately, I settled on regular dimensional lumber for the project. I don’t usually consider 2×4 benches to be terribly attractive, but by squaring them off to 3″ x 1-1/4″ with my table saw, I ended up with a much more acceptable-looking piece of wood. Also, instead of butted-and-bolted joints, I decided to try out some table saw joinery techniques and opted for a half-lap approach. The best part of dimensional lumber is that 2x4s cost less than $3 / 10′ and are available at the local hardware store.

cart_frame

Frame all glued up and put on wheels.

The design itself is very simple. The four corner posts are made of 4x4s resawn down to 3″x3″. All the horizontal beams are resawn 2x4s. Both the posts and beams have half-laps cut in their ends using my table saw’s crosscut sled and a dado stack. (The corner posts are half-lapped from two sides.) I added some midspan supports to make the top and shelf even sturdier; those are connected with glue and pocket screws. The rest is all just wood glue.

torsion-box

Inside of the torsion box before the skin was glued on.

The bottom shelf is a piece of 1/2″ MDF, but the top of the bench is more exotic. It’s a 24″x48x4″ torsion box made from 1/2″ MDF, including the skins. Inside, there’s a grid of ribs on 6″ centers. The ribs fit together with half-lap joints as well, which I cut on my table saw’s crosscut sled with an improvised indexing jig to get reliable spacing. All together, this work top is probably the single sturdiest thing I’ve ever built, and it is not absurdly heavy. It’s exactly what I want to serve as the basis for my CNC. The torsion box is attached to the frame with a few brackets and screws. Put together, the cart has a very solid feel to it. Finally, there’s a set of locking casters on the bottom of the corner posts to make it mobile.

assembled-cart

Fully assembled glamour shot

compartment-open-2

compartment-closed

After I had the cart rolling around, it was time to transplant my Shapeoko 2. This part had me a bit worried, since the existing parts had been wired together in place and didn’t have much slack. I ended up taking advantage of a little extra space underneath the torsion box by making a “hidden” compartment to stash the spindle and motor power supplies. I attached a power strip to the frame and ran the cable out through a hole in the bottom, then made a hole in the torsion box surface for cables from the control panel to reach inside. This turned out to be a huge pain, since I had to go through one of the vertical ribs to get inside of the frame. If I ever do something like this again, I’m definitely going to plan in advance and make the holes before gluing the skins.

In all, I ended up routing the motor supply, spindle supply, and e-stop hookup down through the box, into the frame, and into the secret compartment. This really cleans up all the stuff that used to hang around next to the control panel and makes it easier for me to slide the Shapeoko2 itself as far to the edge of the work surface as possible. (This is important because I am planning to eventually extend the machine to 1000mm in the x-axis, and that just about fills the entire width of the surface.)

drag-chain-detail-rearloc-line-frontThe final touch was the debris collection system. I saw a forum post about using Loc-Line to make a nice debris collector that hangs out near the toolhead and decided this was the approach for me. The only part I didn’t like was how the collector moved with the toolhead. This configuration makes it hard to position the collector nozzle close to the work piece without eventually crashing into it. Instead, I decided to mount the Loc-Line in a fixed configuration that didn’t move in the Z-axis. To do this, I whipped up a mounting plate that bolts onto the back of the X-carriage and provides a hole pattern to mount the Loc-Line adapter. It also provides a vertical slot mount the X drag chain horizontally. The other end of the drag chain connects to a vertical “mast” with another long slot; the whole thing bolts to the “accessory rail” I added behind the X Makerslide. This worked great, especially if you ignore the ungainly stack of spacers and washers I needed to make the bend of the drag chain work out.

vacuum-hookupThe PVC pipe tee on the X-carriage connects to a piece of corrugated hose, which connects to a tall piece of pipe bracketed to the side of the cart. That goes all the way down to the foot of the cart and to an adapter that my shop-vac’s hose can plug right into. It works great! The only thing I would change would be to use larger diameter PVC pipe – the shop vac sounds like it’s struggling a bit due to the constriction of the current setup.

Pain box part 2: When in doubt, add watts

In my last post, I introduced my painbox project and talked about the prototype I’d assembled so far. The basic functionality was there, but the performance was subpar. The device itself was also a giant mess, making it hard to iterate on. Time to make some improvements.

New parts

I decided to try to improve performance by upgrading the underperforming components. The most important performance aspect is the “cold” side temperature – you’ll recall from the last post that it never really got that cold at all. There are two reasons for the poor performance: the TEC wasn’t pumping much heat, and the passive heatsink on the hot side of the TEC couldn’t bring it close enough to ambient. Luckily, both of these problems were easily solved with a little money. I found a much higher wattage TEC and a CPU cooling heatpipe/heatsink/fan combo to go with it. Specifically, the heatsink has a dissipation rating that matches that of the TEC, which should hopefully allow ideal performance.

heatsink

Cleaning up the project board

In the process of switching out the TEC and heatsink, I decided to redo all the plumbing and component organization as well. First off, I wanted to install smaller reservoirs to drop the volume, thinking this would improve time to target temperature. I swapped out the old reservoirs made with PVC straight tees for pre-threaded PVC corner tees. I’d estimate this drops the volume of water in the reservoir by about 50%, and it uses fewer pieces and less space to boot.

Next, I drilled holes to mount the “hot” heat exchanger to the project board. Nothing too fancy here, just four holes and some zip ties to keep the water block, TEC, and heatsink in place. At the same time, I mounted the “cold” TEC and the new giant heatsink to the project board with some long #4-40 screws.

Finally, I redid all the plumbing. The vinyl tubing I’d used is much stiffer than expected, making tight bends and precise part positioning difficult. To replace it, I used pieces of 3/8″ copper tubing bent with my tube bender and joined to other parts with short lengths of vinyl tubing as couplers. The result is much, much cleaner and more compact. I also moved the pumps to be directly in line with the inputs to the radiator.

Here’s how it looks after all the work:

painbox_clean

The plumbing is very neat, though the wiring is still a giant mess. I’m going to have to implement a good strategy there soon.

Performance

I could hardly wait to try it out again after hooking up that giant heatsink. I repeated my earlier setup of thermistors taped down to radiator pipes with pipe insulation, then turned it on and monitored results. Here’s what I got:

Power was switched off at 20 minutes, though monitoring continued to as a way to gauge how quickly temps went back to equilibrium.

Much better! We can now see that the cold side actually does get cold: down to about 16C after 10 minutes. I let it run for a while and then gave the radiator a touch. I found that the hot side still felt a tad too hot, making it impossible to really judge if it was “working”. So then I turned it on again and watched the temperature readout until it was at a desirable hot temp, and quickly gave it another try. It definitely felt hotter than it actually was! It’s very encouraging that the effect can be felt when the temps are in the right spot, even if that’s only briefly. Without closed loop temp control, the temps will never be where they’re supposed to be, so that’s definitely the next item on my todo list.

Temperature sensors

Another issue is temperature sensor accuracy. Right now, I’m relying on spherical thermistors pressed against cylindrical copper pipes and held in place with adhesive pipe insulation. Contact between the sensor and the pipe is really negligible, meaning that the temperature I’m sensing is the temperature of the air pocket between the pipe and the insulation. That air pocket is being heated/cooled by air-to-pipe conduction only. In practice, this means the temperature I’m reading back is not the same as the pipe’s surface temperature, and therefore does not reflect what a user would feel. Not good!

I did a quick test of immersing one of the thermistors in the water of the cold loop. In that case, the reading basically agreed with the one taken from the radiator surface using my non-contact thermometer. Interestingly, this means that the pipe surface temperature is basically equal to the water temperature, and I should be able to measure that temp by just putting the sensor in the water. I’m going to figure out a way to permanently install the sensors through the walls of the reservoirs.

Building a Dune “Pain Box” with the Thermal Grill Illusion

I’m a big fan of the Dune series, so when this post about the Thermal Grill Illusion popped up in my feed reader, I was immediately hooked. For those of you who are not acquainted with the Dune franchise, the “pain box” – which is never actually named in the series – is a device which causes an excruciating burning sensation without actually producing any injury.

Why is this a cool thing to have in the real world? Well, first, it’s an homage to the series, and I imagine other fans will get a kick out of it. Second, I find the idea of having a source of injury-free pain intriguing from a willpower standpoint – how long can you intentionally experience discomfort, even if you know it’s causing you no damage? Lastly, constructing it requires a mixture of electronics, mechanical engineering, and presentation, which puts it squarely in the middle of all my interest categories.

Overall design

What I’m going for is an enclosed box with a hand-sized (4″ x 8″ x 3″) opening. The bottom of the opening will be the illusion surface – what I’m referring to as the “radiator”. The box should be as small as possible for portability and overall presentation. It will have to be plugged in from a power consumption standpoint. It needs to be able to produce a hot temperature of ~41 degrees C and a cold temperature of around 18 degrees C, and I’d prefer not to use large reservoirs as the heat source. (See portability requirement.) Also, this device has potentially weird safety aspects, so it needs to be designed such that it’s hard for it to actually hurt someone. This means temperature feedback and some way to remove danger or alert the user. And lastly, I’d like to be able to make it on my Shapeoko 2 CNC machine, which limits the size of any single component to about 12″ x 12″.

Given that I’m going for compactness and simplicity, the most obvious source for both heating and cooling is a device called a thermo-electric cooler, sometimes called a Peltier. The basic concept is that it’s a solid state heat pump, where heat is pumped from the cold side to the hot side. The colder you make the hot side, the colder the cold side will get. Flip the direction of the current, and the device reverses the flow of heat.

How exactly the heat from these devices will be transferred to a user’s hand is still up in the air. Generally speaking, achieving the desired temperatures and making sure they get to the user is really the core challenge of the whole device. The rest is just tidiness and presentation.

Version 1 (Failed)

Immediately after I decided to use TECs for my hot/cold source, I bought a 5-pack of them from Amazon. (I was surprised by how cheap they were, but it turns out that might not have been a good thing. More on that later.) The next question is how to distribute the hot and cold. I’ve got a fair amount of experience making printed circuit boards on my CNC, and I know that lots of people make PCB heater boards (commonly seen on 3D printers, for instance). If a PCB could transmit heat, why not cold as well?

I designed a very simple PCB that is really just two large, interleaved copper pours connected to a space for a TEC and heatsink. The idea was that heat or cold would flow through the copper, since it’s highly conductive. It’s also a crazy simple and compact design, so I was pretty excited to produce it. Here it is, all assembled:

radiator_pcb

Turned out great! Except it completely failed to transmit heat. In fact, while the pours basically stayed at ambient, the back side of the board right under the TECs got really hot or really cold! It would seem that the thickness of copper on a standard PCB blank is way too thin to be a good conductor. Oh well, into the bin and onto the next alternative.

(Side note: the PCB heaters I alluded to earlier are not radiators of heat per se. The current being pumped through the traces on the board is what actually creates the heat in the first place.)

Version 2 (work in progress)

The new design I’m working on now swaps the PCB radiator for one made of copper tubing. Small diameter copper tubing is very affordable, easily cut and bent, and highly heat-conductive. To actually deliver heat/cold to the array of tubes that will make up the radiator, I’m using two closed-loop water heater/chiller systems.

For each loop, the basic design is a TEC strapped to a water block, with the loop looking like water block -> radiator -> simple reservoir -> aquarium pump. The TEC on each loop is configured to either heat or cool the water, which in turn heats or cools the copper tubes. Here’s my bench test of this setup:

2015-02-05 21.25.01-2

Note that my radiator is currently a proof of concept made from 3/8″ copper tube sections bridged together with 5/16″ ID vinyl tubing. I’d hoped that this tubing technique would replace the need for expensive copper plumbing fittings, but unfortunately the tubing kinks at a much larger radius than i’d like to have for good spacing. I also bought a cheap tube bending tool with the hopes that I could use that to make what I need, but discovered that the tube bender also had an overlarge bend radius! For now, I’m going to leave it alone and brainstorm alternatives.

While early qualitative testing was promising, it’s certainly not producing the level of discomfort I’m hoping for. (Ha.) Two major problems here: the hot side actually eventually gets too hot, and the cold side never quite gets cold enough. To help quantify this poor performance, I wired up a pair of thermistors and an Arduino Pro Mini to serve as a temperature logger. Here’s what the data from that logging session looks like:

image

Good news: the hot side gets hot. That is the end of the good news. Bad news: it takes over an hour for the hot side to reach its apparent max temp of 42.4 degrees C. Worse news: the cold side does awful. It gets a teensy bit cold during the first few minutes, but then eventually actually starts to increase the temp over ambient in the long run!

I think this poor performance reflects a handful of problems:

  • The hot loop just doesn’t have the pumping ability to move heat fast enough. The cold side of the TEC gets pretty cold, and that’s probably because the water in the hot loop makes up a pretty decent heat sink, even without an outlet for all that heat.
  • The cold loop doesn’t have powerful enough heatsinking on the hot side of the TEC to overcome the self-heating effect. This explains the slight drop and then long-term rise in temperature. It is also entirely possible the cold loop TEC has burned out due to overheating.
  • There is probably too much water in each loop. Between the lengths of tubing and the fairly oversized reservoirs, this is adding more mass that has to be heated or cooled, slowing down the desired temp changes.
  • The TECs I bought are under-rated for what needs to be done. I’ve been reading accounts of folks who turn on their TECs and immediately see frost on the cold side, and I’ve never come close to seeing that.

Overall, despite flaws, this design seems like it has promise. The next steps are:

  • Experiment with a more expensive / higher rated TEC unit to see if the performance is better. We’re only talking like $12 each here, so not a deal breaker.
  • Replace the janky heatsink/fan combo on the cold loop with something professionally designed to remove a lot of heat.
  • Experiment with running two TECs and waterblocks both in serial and in parallel to see if it improves the time-to-target-temperature and max delta-T
  • Prototype a feedback controller to allow each loop to hold a target temperature
  • Experiment with techniques to make a denser radiator grid

Epic Workbench Part 1

A few months back, we moved out of our apartment and into a rental house. Among the many great things about the new place was the two-car garage. With only one car, what’s a suddenly space-rich maker to do? Set up a workbench, of course.

Initially, I was planning to design a bench out of plywood that would tab-and-slot-and-screw together. I got as far as initial sketches in OpenSCAD before I decided it was just going to be too much work to design the bench I’d want to have. My search for alternatives took me here, which looked awesome, but was far too expensive. Luckily, that page lead me here, which introduced me to the world of galvanized steel fence posts.

Finally, the sweet spot: a linear construction material that’s strong, rugged, locally available, and best of all, cheap! Even the fittings (1, 2) are very affordable. (Unlike, say, galvanized steel threaded pipe, which can beggar you in a single hardware store trip.)

I settled on 1 3/8″ fence posts as my material of choice then got to designing. Feature-wise, I’m looking for a large worktop, with ample storage above and below, and lots of vertical space for pegboard, which will end up being tool storage. Add to that a securely-anchored bench vise, permanent power strips, and some bright lighting, and you’ve got my perfect “mostly electronics, sometimes random mechanical” workspace.

My usual process with 3D design projects these days is to buy samples of the components I’ll be using so that I can take measurements and make reasonable estimations for how things will turn out. In this case, I bought a single 10-foot length of pipe, one tee fitting, and one elbow fitting.

While I was at the hardware store, I bought some metal-cutting reciprocating saw blades so that I could actually cut the pipe I’d bought. I’d really rather have used a tube cutter, but the one I already own is 1/2″ too small, and a pack of blades is about 1/3 the cost of an appropriately-sized tube cutter from Amazon. I was pleasantly surprised by how quickly those blades chopped up the pipe: perhaps 45 seconds per cut, a totally reasonable amount of time for the number of cuts I had to make.

Over the next week or so I spent my daily commute time designing the workbench in OpenSCAD. Here’s a render of what I came up with:

workbench_render

Notable features:

  • Everything is laid out around unbroken vertical tubes that run up the back, making up the legs and the rear supports of the top shelf. I figured this would lead to the strongest overall design.
  • The fittings are necessarily taller than the pipes themselves, and since there are so few of them (at different heights, even!) it’s necessary to make a custom spacer/clamp component in order to make a level worktop. No worries, though, as I can easily just CNC all the spacers and clamps I need. Also, once I have the spacer/clamp thing nailed down, I can easily use copies of that part to make mounting brackets for all the pegboards.
  • I found this great calculator called The Sagulator that helps you compute how much a surface of varying thickness will bow given how it’s supported, etc. This was really helpful in estimating eventual performance and influencing part placement.
  • All the tee fittings have very convenient screw holes stamped into them for securing the “cross” part to the pipe. I’m planning to put screws in all of these to make the frame sturdier and easier to re-assemble if I ever have to take it apart. (For example, to move to a new house.)
  • The worktop and shelves will still be CNC-cut, but mostly just because I want some rounded corners and “eyeballed” cuts stress me out. (What are the chances I would be able to maneuver a 7’x2.5′ piece of plywood on a bandsaw, anyways?) One major advantage of this approach is that I’ll be able to drill very precise pilot holes for all the spacer/clamp assemblies, making it much easier to assemble when all the parts are cut out.
  • I’d like to make use of adjustable feet so that I can precisely level the whole workbench, but I haven’t yet figured out how to adapt commercially-available leveling feet to the ends of my pipes. I think I’ll end up CNCing some inserts that I can pound in and then thread in the leveling feet.

As of now, I think the design is basically finalized. I bought all the pipe and fittings I need and I’m ready to start fabricating. Stay tuned for updates on actual progress!

Creating animated GIFs from OpenSCAD

animated

I do almost all my physical designs in OpenSCAD, and sometimes I want to post an image of my models. Since these are 3D models we’re talking about, a static image is kinda insufficient, but an animated GIF can do the job nicely.

OpenSCAD has an animation feature which allows you to create models that can mutate relative to time. While it’s primitive, it lets you slap a time-based rotate around your top-level object to get a nice 360 spin view. Then, when you select Animate from the View menu, the display will animate.

To go from the animated view in OpenSCAD to an animated GIF, check the “Dump Images” checkbox in the animation controls. This will cause each frame to be written out to a PNG file in the same directory as the .scad file. I like to check the box and then wait for the animation to repeat a little more than once to be sure that all the images have been dumped.

Once all the images are on disk, converting them into an animated GIF is surprisingly simple if you have ImageMagick’s convert utility. Here’s the command I use to convert a bunch of frames into an animated GIF:

convert 'frame*.png' -set delay 1x24 animated.gif
view raw gistfile1.sh hosted with ❤ by GitHub

The only real gotcha here is the “-set delay” option, which has a cryptic syntax: NxM means “N units of 1 second divided by M”. Thus, “1×24” means 1/24 of a second. I’ve had the most success setting the frame delay this way, but there are probably other ways to do it.

Designing a capacitive touch wheel in OpenSCAD and EAGLE

I’m a big fan of DIY capacitive touch sensors. Without any custom parts or special fabrication techniques (beyond regular PCB creation), you can create really impressive interfaces. I first used this on the Question Block Lamp (Getting ready to ship! Order yours now!), and ever since I’ve been looking for great places to apply the technique.

Recently, I decided that one of my projects would really benefit from the addition of a capacitive touch wheel. I didn’t want to re-invent the wheel, so to speak, so I started Googling for designs.

The design

The page for the Arduino CapSense library sent me looking for the Quantum Scrollwheel sensor datasheet, which contains a handy schematic for a scroll wheel. wheel_schematic So how’s this thing supposed to work? The wheel is composed of three separate, identical electrodes that are tessellated together to form a ring. Each electrode is interleaved with its neighbors such that as you move away from the center of one electrode, the current electrode exposes less and less surface area while the next one exposes more and more. This means that if you measure the capacitance values of all three electrodes in succession, you should see approximately complimentary values on two of them, and an “untouched” value on the third. This should be sufficient information to figure out the orientation of the touch.

Ok, so how do we draw this?

The schematic for this wheel design is straight-forward enough, but this is far from an easy shape to draw. As I highlighted in a previous post, EAGLE really isn’t going to help you draw something like this, so you need to turn to another program to do it and then import the results. My tool of choice is OpenSCAD, so I got to work on a script to generate this shape.

Since all the electrodes are identical, we really only have to draw one and then rotate some copies around to complete the tessellation. Only, this shape is a bit unique – the curved triangular sections don’t lend themselves to being described with simple OpenSCAD primitives.

The first approach I considered was to think of each curved triangle is as a regular 2D triangle, only rendered incrementally along an arc. Polar coordinates would make this especially easy to describe. While this feels like it would be an elegant way to express these sections, OpenSCAD isn’t friendly to this approach. You can define arbitrary polygons, but you can’t add points to a polygon with any sort of native loop. In the past, when I had no other choice, I’ve written a Ruby script to generate the point list manually and then pasted them into my OpenSCAD script. This is clunky and involved, so I try to avoid it if at all possible.

However, I came up with another way to express this shape that is more amenable to being generated directly in OpenSCAD. It’s a technique I found on the OpenSCAD mailing list that the creator referred to as “chain hull”. A chain hull of a list of primitives is the union of the convex hulls of neighboring pairs of said primitives. Did you follow that? This page has a good visual example of the operation in action. I think chain hulling is a brilliant use of the primitive functions available in OpenSCAD and allows for complex shapes to be described very concisely.

To build our curved triangle sections with a chain hull, I laid out an arc of very thin squares ranging from the minimum width to the maximum width in a linear fashion. The chain hull magic takes each pair of squares, hulls them, and then unions all the results. Here’s the code that generates the shape:

module curved_triangle(r, pitch, separation, gap) {
assign(num_steps = 36)
assign(top_d = pitch - 2 * separation)
assign(bottom_d = triangle_tip_width)
assign(delta = top_d - bottom_d)
assign(d_incr = delta / (num_steps-1))
assign(b_incr=116/(num_steps - 1))
render()
for (i=[0:(num_steps-2)]) {
hull() {
rotate([0, 0, b_incr * i])
translate([r, 0, 0])
square(size=[top_d - d_incr * i, 0.01], center=true);
rotate([0, 0, b_incr * (i+1)])
translate([r, 0, 0])
square(size=[top_d - d_incr * (i+1), 0.01], center=true);
echo("blah", top_d - d_incr * (i+1));
}
}
}

And here’s a view of the intermediate shapes and the resulting chain hull:

hull_illustration

The base shapes, and the chain hull that gets drawn around them.

With a module built to create these curved triangles, the rest of the script is glue code to put the triangles in the right places. I wrote one module to generate the concentric/alternating triangles for an entire electrode, and then another module to generate the whole scroll wheel by rotating three electrodes into their proper positions. The final result comes out looking pretty good:

scroll_wheel

One gotcha I figured out in the course of this project is that EAGLE really doesn’t like to have zero-width lines, even if they’re just describing the outline of a polygon. To account for this, I drew the wheel sections a tiny bit smaller to account for the line width I’d use in EAGLE. This is not unlike accounting for the kerf on a laser cutter, so if you’ve done that before you’ll be familiar.

Getting it into EAGLE

The next step is getting it out of OpenSCAD and into EAGLE. I wrote about using OpenSCAD shapes as board outlines in another post, but this case is a little different. Board outlines can just be simple wires, but polygons need to be closed shapes. The DXFs that come out of OpenSCAD are just collections of segments. I needed a way to convert these segment lists into ordered lists of points that they could be entered with the POLYGON command. So, of course, I wrote a Ruby script to do it.

The operation for converting a set of segments into a ordered list of points is pretty easy. The trick is to think of the list of segments as edges in a graph, and then the objective becomes traversing the graph and outputting a list of connected components. To do this, first I read all the segments into memory, then put them into a map indexed by their start point. Then I pick an arbitrary segment, write its two points to a list, and then use the second point to do a map lookup for the next segment that matches it. This process then repeats with the second point of each segment until we’re back to the start point. This process nets a list of lists of points, each list being a closed polygon. Once all the segments appear in a polygon, we’re done, and from there it’s easy to generate a set of EAGLE commands and write them into a .scr file.

Before I run this generated script from the EAGLE command prompt, I do one hand editing pass to name the polygons so that they are connected to the proper signals in the schematic. With that done, I set the my desired line width to match what I used in the OpenSCAD script, and then load the polygons into EAGLE by running the command “script poly” where poly is the name of the .scr file created in the last step.

When EAGLE renders the polygons, they’ll start out empty with dotted borders. To get them filled in, you need to route connections to them and then run the RATSNEST command. If you’re planning to use the autorouter, a good practice at this point is to use the restrict and keepout layers to defend these polygons. If you cover the electrodes with a polygon in tRestrict or bRestrict layer (depending on whether your electrode is on the top or bottom), then the autorouter will leave it alone when routing other traces. Just make sure to hand-route a connection point through the protective layer, and then the autorouter will be able to take it from there. (tRestrict/bRestrict are just hints to the autorouter and will not trigger design rule warnings. Pretty handy!)

touch_wheel_on_board

The whole bottom of the board, featuring the the scroll wheel!

Next steps

I just ordered a batch of boards using the scroll wheel described in this post, so when they arrive, I will populate one and get to work on creating a library for easily reading out a position. Stay tuned for a future post!

Simple constant current LED driver

Here’s a simple circuit for driving LEDs at constant current. I like this one because it can be built with a variety of different components based on what you have on hand. I built my version with two 2N2222A transistors and a sense resistor from my resistor kit.

constant_current_driver

How does it work?

A small current on the CONTROL line causes the DRIVE transistor to switch on and sink through the SENSE resistor. The FEEDBACK transistor only operates when the voltage at the SENSE resistor is greater than its VBE, or turn-on voltage. When it turns on, it draws some current away from the base of the DRIVE transistor, reducing its gain and causing it to drop more voltage. This negative feedback will cause the whole system to equilibrate such that the SENSE resistor is seeing exactly the FEEDBACK transistor’s VBE. 

Why is this better than a ballast resistor?

You can drive a variety of LEDs with different forward voltages without worrying about changing any of the components (provided that you are comfortable using the same current). The DRIVE transistor will just drop more or less volts as necessary.

Also, if you’re trying to drive some high-current LEDs, you’re more likely to have common transistors that can handle the power dissipation than you are to have high wattage resistors. This makes prototyping and experimentation easier.

Finally, depending on your LEDs and your power supply, you could end up using fewer components by driving multiple LEDs in a string, rather than driving each LED separately.

Sizing components and calculating current and power

LEDs: You can use as many LEDs as you’d like provided that their combined forward voltage is less than the supply voltage minus VBE.

Power supply: Your input voltage needs to be at least the sum of the forward voltages of your LED string plus the minimum drop across the DRIVE transistor plus the VBE of your FEEDBACK transistor. Otherwise there won’t be enough voltage to turn on the LEDs.

Transistors: Anything NPN (or N-channel, if you’re using MOSFETs) you have handy has the potential to work. The most important thing to think about is how much voltage you’re expecting it to drop for you and what that means for power dissipation. This transistor will be acting in its linear region, so any voltage it doesn’t pass on from collector to emitter will turn into heat! For instance, let’s use an example of a 12V power supply and two white LEDs with a 3.2V forward voltage. The drive transistor will have to drop 12 V – (2 * 3.2 V + 0.6 V) = 5 V. If your target current is, say, 200 mA, then the transistor will be dissipating 5 V * 0.2 A = 1 watt of power. For some transistors this is no problem, but for others that’s a death sentence. Read your datasheet!

Sense resistor: This resistor sets the amount of current you want to pass through the LEDs. You can compute its value by taking the VBE of your FEEDBACK transistor and dividing by desired current. For instance, if you’re using a 2n2222A transistor with a VBE of 0.6 V, and you want to sink 200 mA of current, you would need a 3 ohm resistor. Power dissipation is straight forward, since you know the voltage and the current. Using our existing example, a 3 ohm sense resistor would see 0.6 V * 0.2 A = 0.12 watts. That’s small enough that you can use 1/4 watt resistors from a part kit with little worry.

Over-driving LEDs for brightness

Most of the time when I’m driving an LED, I do it with a simple ballast resistor, and that’s all there is to it. Lately, however, I’ve been working on a few LED matrix projects, and while it’s certainly possible to use the same simple resistor approach, this leads to a very dim display. (Since any given LED’s duty cycle is 1/N max, they appear much dimmer than they normally would.) 

The good news is that there’s a straightforward solution to this problem. LEDs have a rated forward current, but they also have a rated peak current, specified at a given pulse width and duty cycle. For instance, these red LEDs are rated for 30mA forward current and 185mA peak in 0.1 ms pulses at 10% duty cycle. Why is this stat useful? As long as you stick to the pulse width and duty cycle parameters, you can intermittently drive an LED at an excess current and get a brighter light without burning it out. 

There is a risk in using this setup, though. If for some reason your PWM signal were to lock up in the “high” state, then the pulse width limitations would be exceeded and you’ll probably fry the LED in an instant. This means you need to be especially cautious during development – crashing your microcontroller at the wrong time can be costly!

While the theory of this is straight-forward, I wanted to test how it actually looks in practice before I integrated it into my design. If it was only moderately brighter, I didn’t want to spend the energy (and money) on adding an array of transistors to my board.

breadboard_setup

My test setup.

I decided to throw together a test setup that would allow me to compare brightness of an LED at its full-on steady current, one PWM’d with a ballast resistor to keep it at its steady current, and one at peak current and PWM’d. This sets up a comparison between the maximum brightness, the brightness of the same LED in a naively driven matrix, and finally the same LED over-driven.

The LEDs I’m using here are surface mount in a 1206 package. Saying that they are very small is an understatement. They are by no means breadboard compatible, so the first step was creating a simple breakout board.

I used a piece of pre-drilled perfboard with a solid copper pour on one side to make the breakout. I marked off a few columns of 6 holes each so that it would span the IC gutter on a breadboard, then cut the piece out with a pair of aircraft snips. Next, I used a utility knife and a straightedge to score the copper and separate the columns from each other, and then did one horizontal stroke to make a grid of 1×3 hole pads.

breakout_board_detail

Detail of the LED breakout board

Next, I soldered two rows of 0.1″ header to the top and bottom of the board for mating with the breadboard. Then, I hand-soldered 6 LEDs, 3 red and 3 green, onto the board. (Judicious use of continuity tester and solder sucker not optional.) Finally, I used a file to chop one corner as an orientation indicator and then cleaned up the rough edges.

To prove that everything was working, I started out by connecting the steady current resistor and probed all the LEDs. Everything lit up fine. With the baseline established, the next step was to set up the PWM signal. According to this page, the Arduino’s built-in analogWrite() PWM runs at about 500Hz, which is too slow for the target pulse width. Since I didn’t need crazy precision or performance here, I decided to quickly write up an Arduino sketch that toggled the output pin manually and used delayMicros() to set the interval. The sketch turned out to be pretty simple:

[gist https://gist.github.com/bryanduxbury/7729613]

To verify that this was giving the output I expected, I hooked up the output pin to my handy DSO Nano. On the first try I ended up with a 996 Hz frequency and good pulse width. The error in the frequency is probably due to the fact that there’s overhead to toggling pins and calling delayMicros(). I suspect I could dial it into precisely 1000 Hz by guess and test on the delay durations, but it’s not that important at this point. In the real production scenario, I’ll be using a hardware timer and it’ll be worth getting it exactly right.

Connecting the PWM output to the second LED was straight forward, though I did add a NPN transistor in between the output pin and the LED so that it could drive all the PWM inputs without any worries about current draw.

The over-driven LED was the most complicated to set up. I plugged the peak current number into an LED resistor calculator, and it told me I needed a 12 ohm, 2 watt resistor. Yikes! I certainly don’t have anything like that on hand. Rather than putting a whole ton of resistors in parallel, I wired up a simple constant current LED driver circuit using some common transistors and resistors. I’ll leave the discussion of that driver circuit for another time, but the cool thing about it is that it allows the transistors to do all the heavy wattage dissipation while the resistors see a tiny load. 

With everything wired up, I powered it on to assess the results:

Closeup of the final brightness test. Hooray for DSLR cameras!

Closeup of the final brightness test. Hooray for DSLR cameras!

I would say that the PWM-only LED is substantially dimmer, and the overdriven LED is almost but not quite as bright as the steady-on LED. This turned out to be exactly the sort of obvious difference I was looking for. It seems well worth adding the additional circuitry to get a much brighter display.