Bike Lights

display panel
Photo
(click for a larger view)
Description

This project demonstrates multi-jack, multi-board patching.

It builds upon the blinky bike light project from the Adafruit Arduino tutorial.

We have an Arduino, a breadboard, 5 LEDs, a switch, and a small handful of resistors. From those, we get a set of lights that turn on, off, blink, and blink in sequence.

The version of code we'll use is here.

Please note: this is Limor's code. She wrote it, I didn't.

I understand the code and could write something comparable, but wanted to build this project on simple code that already existed, did something interesting, and was well-documented. Limor did a great job on all those counts.

We're only going to make minor changes to the circuit and the code. Believe it or not, the basic connections are complex and interesting enough to keep us busy for a while.

Here's the circuit on a breadboard.

It's roughly the same as the one shown here. The only major difference is that the current limiting resistors connect to ground, like the previous project, rather than to the Arduino pins. That doesn't change the circuit's overall behavior though. It just means that the low end of an LED will be about 1.7v below the supply voltage, rather than the high end being about 1.7v above ground.

And here's the patch on the shield.

For reference, brown is 5v, solid blue is ground, and solid green is the switch sensor. The inked lines supply power to the LEDs, running red, yellow, green, blue, purple through header pins 4-8.

Wire it all up, plug a cable between the shield and the breadboard, load the code into your Arduino, and check out the Adafruit project make sure everything does what it should.

The patch shield exists to scratch the same general itch that has plagued other people: how to connect an Arduino to a circuit on a breadboard. There are other good and interesting solutions out there, like the boarduino, but my personal itch was slightly more specific.

As a general rule, I don't want all 28 pins of an Adruino in my breadboard. I usually want ground, two or three digital pins, and maybe an analog input or two.

So the core function of the patch shield is pin isolation: it lets you pull out the pins you want and ignore the rest. It also lets you arrange the pins you've selected however you want them on the breadboard.

We've already used the basic idea of pin isolation without giving it an official name. The patch template is a tool that makes it easier to isolate and arrange pins.

Pin isolation plays into another general design trick though: modularity.

Pretty much any system complex enough to be interesting is too complex to contemplate as a whole. We manage the complexity by drawing boundaries around some of the more tightly connected parts, giving those boundaries names, and agreeing to be just a bit vague when we use those names in the future.

Case in point: every electrical component has some amount of resistance, inductance, and capacitance. A precison wire-wound resistor is in fact a small coil of wire, exactly the same as an inductor. The wires are separated by insulation, which allows a dielectric potential to form, exactly the same as in any capacitor. We just agree to ignore the device's inductance and capacitance when we call it 'a resistor'. As long as we stick to applications where those (admittedly low) values don't cause too much trouble, we can live with being technically wrong while still being 90% right.

We call these wrong-but-useful boundaries abstractions, and they're the best tool we have for managing complexity.

When we use abstractions to reduce a large number of interacting parts to a smaller number of interacting parts, we engage in modularity. A good module tends to have a specific purpose, a clear boundary that separates it from all the other modules in the system, and a well-defined interface that allows it to talk with other modules.

To put it more simply, a good module defines three things:

  1. Stuff that comes in
  2. Stuff that goes out
  3. Stuff that connects the two

You can break modules down into sub-modules, and those three categories of stuff make an awfully tempting place to start.

You always need the 'in' and 'out' parts, otherwise you get a module that's content to sit quietly and contemplate its navel. That's very zen, but not terribly interesting to watch.

You can, however, create modules that focus on one of those three duties, and make the other two as simple as possible. Computer programmers have known about the three kinds of specialized modules for a long time, and have given them names:

The Model specializes in making interesting connections between the inputs and outputs. This is where most of the fun (and pain) happens.

The View specializes in converting outputs that are easy for the Model to generate into something more interesting to watch.

The Control specializes in taking interesting stuff from the world and creating signals that are easy for the Model to process.

Arduinos -- and microcontrollers in general -- are really good at handling the Model part of a design. The circuits we connect to an Arduino tend to be sensors that collect information to be processed (Controls), or end-effectors that convert digital signals into interesting real-world effects (Views).

So with all that in mind, let's look at our bike light circuit again:

The Arduino handles the Model.

The LEDs form a View.

The switch is a Control.

The wiring connects the module interfaces. Technically, the 'output' of the switch Control is at the left end of the green wire: the node where the switch meets the pull-down resistor. That node still goes high and low when you press and release the switch, whether the green wire is connected or not.

The jumper defines a connection between the output of the Control and a specific input for the Model. Move the wire, and you get a new mapping between the Model and the Control.

Now that we've defined our modules, we can consider the patches for them separately.

The Control wants power and ground, and produces one output signal.

We can also move the whole Control patch over to jack 2, so the circuit can live on its own breadboard.

The View takes five input signals and wants a single ground connection.

This patch daisy-chains the View's ground connection off of the Control's. That's probably okay for this application, but if you had a sensitive Control circuit, a noisy View (PWM'd LEDs, for instance) could generate enough ground-bounce to poison the input.

In such a case, you'd want to patch the ground connections separately to keep the noisy digital output ground and the quiet input ground as far apart as possible.

Here's how the whole patch looks on the shield.

And here are the breadboards.

This new layout is functionally identical to the previous one, but gives us openings to do all sorts of interesting things.

Whenever you're building or changing a complex system: do the View first.

The View is easier to debug than any other part of the system. You know what to expect and can tell if it's working just by looking at it (or listening to it, or whatever). Once you know the View is good, you can use it to check various configurations of your Model. Once you know the Model is good, you can build Controls to trigger changes from one configuration to another.

If you try it the other way, and build the whole system first, you have no idea where to start looking when something fails. You can waste time checking voltages when you really have a software bug, or you can waste time checking your code when the real problem is a miswired component.

In the spirit of following my own advice, my first modification to the circuit is to duplicate the View in a slightly more permanent form.

The circuit is identical to the one in the breadboard, and the layout isn't critical. As long as the correct leg of the chip socket connects to the correct pin of the correct LED, you're good.

Actually, I built a few of them.

Now, we could test the new modules simply by plugging them into the existing header and making sure they blink the same way as the original, but it's more fun to daisy-chain the signals across to another header and run two Views in parallel. That way we can be sure each new version works exactly the same way as one we know to be good.

Of course, to do that, we need to move the Control patch.

The power and ground lines cross since the pins for the new header are in a different orientation. This layout is pin-compatible with the circuit already on the breadboard though.

It would be easy to swap the lines and modify the circuit, but it's good to get in the habit of resisting that temptation. If a change isn't absolutely necessary to the current objective, don't make it.. yet.

We can (and will) rewire the Control circuit later, but it's easier to change the View in one step and the Control in another than it is to try and do both at once. Often as not, when you split your attention between circuits, you forget something.

Here's the new patch on the shield.

And here are a couple of View boards side by side.

There's one more simple trick we can play with the output.

So far we've been using the following pin mapping:

Arduino 8 9 10 11 12 GND
View 1 2 3 4 8 5

The pattern is important, but the order isn't. We can reverse the order of the LED pins:

Arduino 8 9 10 11 12 GND
View 8 4 3 2 1 5

And make the board 'wave' in the opposite direction.

The real fun, though, comes from daisy-chaining the old mapping off the new one.

Now we have two ports that receive exactly the same signals, and are connected to identical boards, but make the boards blink symmetrically.

Once again, here's the patch on the shield.

(As an aside, this one's complex enough to show why breaking the patch into smaller pieces can be useful)

And here are some shots of the boards in action.

We've done a lot of fiddling around, and have gotten some interesting results, without changing the basic circuitry or a single line of the code.