Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
Category: Software
General-purpose computers doing something specific
Reassembling the mill provided an opportunity to move the Y axis Home switch from the rear of the axis to the front. The key discovery happened during the teardown: I can get the saddle off the Y axis dovetail by removing the gib, without sliding it off the front, which means a front switch can remain firmly glued in place.
A few random hunks of steel and a wire nut held the switch in position while the epoxy cured:
Mounting Y axis home switch
The switch actuator bottoms out with the saddle just touching the preload nut, so the saddle can’t dislodge the switch: the switch trips just before the saddle hits the nut, at which point all motion stops and the motor stalls.
Moving the switch means I can remove all the gimcrackery that poked the rear switch with the tooling plate in place; I was never happy with that setup. I also removed the small block that trapped the rear end of the Y leadscrew, under the assumption that, as I haven’t yet dropped anything on the leadscrew, I probably won’t. That adds about 1/4 inch to the maximum travel and allows the tooling plate to whack into the column.
The switch wire runs along the stepper cable, a tidy technique that hasn’t introduced any glitches into the shared Home signal from the X axis drivers:
Sherline mill – X and Y axis home switches
The Y axis now seeks the Home switch in the positive Y direction, so that stanza in Sherline.ini looks like this:
As part of our discussion around those Hall effect switches, I cautioned our Larval Engineer that she can’t use capacitors to “smooth out” mechanical switch bounce, even though all of her cronies and (most likely) her profs will advocate doing exactly that. The subject also came up at the local hackerspace when she showed off her project, so I should explain why capacitors don’t solve the problem.
Here’s some switch contact bounce:
Switch bounce – black panel-mount
Another push on the button, just to show how unpredictable the bounces can be:
Switch bounce – black panel-mount – 2
Note the horizontal scale: 10 ms/div. The smaller glitches appear only by courtesy of the scope’s glitch-catching mode; they’re down around a few microseconds.
Now, let’s add the canonical 100 nF “debounce” capacitor in parallel with the contacts and record another set of bounces:
Switch bounce – black panel-mount – 100 nF cap
Notice that the switch contacts bounce in a completely unpredictable manner.
The pullup resistor is a rather stiff 1 kΩ, so the RC time constant is τ = 1 kΩ × 100 nF = 100 μs, but that applies only to the rising edges of the waveform as the switch opens. You can, indeed, see a slight rounding of those corners: the voltage requires about 5τ = 500 μs to reach 99% of the final voltage.
The capacitor also forms an LC tank circuit with the usual parasitic wiring inductance, producing spikes that exceed the supply voltage: that’s the first half-cycle of the tank oscillation as the switch opens. The Q is fairly low due to the relatively high resistance, so the oscillations die out quickly. If this were feeding a microcontroller’s input pin, its input protection diodes would clamp the spikes to one diode drop above the supply voltage and below 0 V, but that’s an entirely different study.
It should be obvious that adding the cap hasn’t done diddly squat to debounce the switch transition.
Increasing the pullup resistor to the usual 10 kΩ will increase the time constant to τ = 1 ms, round off the leading edges a bit more, and further reduce the Q. It won’t debounce the longest transitions, which are on the order of 20 ms for this particular switch. You can’t increase the pullup too much, because you want enough current through it to ensure a valid logic level despite external noise (which is also an entirely different study); 100 kΩ may be as much as you can stand.
But that’s just for glitches due to the switch opening. The closed switch puts a dead short across the capacitor, so the cap provides no filtering as the switch closes: the microcontroller will see every single low-going bounce. The photos show only bounces during the open→closed switch transition, but the closed→open transition can be equally ugly: yes, switches bounce closed as they open.
That means the microcontroller will see glitches as the switch opens.
So let’s increase the capacitor enough that the voltage can’t rise beyond the logic threshold until the switch stops bouncing. Ignoring LC tank effects, the voltage rises as 1 – e-t/τ, so we need that value to be less than 0.25 (for a bit of margin) of the supply voltage after the longest possible bounce as the switch opens. Let’s assume the switch has a single closed (low) glitch after a long time being open (high), at which time the voltage must still be under the logic threshold to prevent a false input. The datasheets only give the maximum bounce duration, if they give any bounce time at all, so let’s assume the longest bounce will be 60 ms.
That says τ = -60 ms / ln(0.75) = 210 ms. Given a 10 kΩ pullup, that’s C = 210 ms / 10 Ω = 21 μF.
No problem, right? Let’s just put a 22 μF electrolytic cap across every switch and be done with it!
Well, except for the fact that most pushbutton switches can’t tolerate that much energy through their contacts. Assuming a 100 mΩ resistance and ignoring stray inductance, the initial current will be 5 V / 100 mΩ = 50 A with a time constant of τ = 22 μF × 100 mΩ = 2 μs. At the usual 5 V logic supply, the cap stores 22 μF × (5 V)2 = 550 μJ of energy, so we’re now burning the switch contacts with a 250 W pulse. Some switches have a maximum energy rating to deter exactly this design blunder, but you should not assume the lack of such a rating means the switch can handle anything you throw at it.
No problem, let’s just put a resistor in series with the switch to reduce the initial current.
I think you can see where this is going, though, so I’ll leave all that as an exercise for the student.
Moral of the story: you must do debouncing in software by filtering the raw switch input. The trick will be to get that code right, which isn’t nearly as simple as you might think. In fact, the first half-dozen techniques you come up with won’t work, so use a dependable library and test the results… which is an entirely different study, too.
If it’s any consolation, I didn’t know this stuff when I was a Larval Engineer, either. In fact, I didn’t learn much of it until after I made all the usual mistakes…
A vial in the bottom of Mad Phil’s EMI Go-Kit contained a handful of these doodads:
AMP 842448-2 HF PCB Filters
The label on the vial came from AMP with a handwritten 842448-2. Searching on the obvious terms eventually produced a Surface Mount EMI Filters catalog from Spectrum Control, with page 25 saying that it’s a 10 A DC ferrite pi filter with a 20 dB insertion loss over 100 MHz; evidently, SC bought AMP’s product line and is keeping it alive for all the Mil-Spec folks. Oddly, you can’t find that catalog using the site’s built-in search function with the part number.
Rather than keep an entire catalog of parts I’ll never have, I used pdftk to snip out and rename the page for later reference:
In the process of figuring out how to set up the isolated WiFi Internet link on the file server, I discovered that the /etc/rc.local file runs before the eth0 interface that connects to the outside world comes up. As a result, my DynDNS host address hadn’t been updated in quite some time.
Worse, trying to set up eth1 failed, apparently because there’s a bunch of other network infrastructure that doesn’t start until eth0 comes online. Part of that infrastructure involves iptables; the added rules simply vanished.
The solution seems to require writing an upstart script that waits for whatever events it needs, does what needs to be done, and then goes away. The whole upstart mechanism and its event list seems, um, lightly documented, as I discovered there, but the custom setup formerly in /etc/rc.local now lives in /etc/init/local.conf:
description "Stuff that used to be in /etc/rc.local"
author "Ed Nisley - KE4ZNU"
start on (local-filesystems and net-device-up IFACE=eth0)
stop on shutdown
script
logger Starting local init...
logger Updating dyndns
ddclient -force
logger Bringing up eth1
ifconfig eth1 192.168.3.1 netmask 255.255.255.0 up
logger Setting iptables
iptables -A FORWARD -i eth1 --destination 192.168.0.0/16 -j REJECT
iptables -A INPUT -i eth1 --destination 192.168.0.0/16 -j REJECT
iptables -A POSTROUTING -t nat -j MASQUERADE
logger Ending local init
end script
That code assumes the outbound network interface will be eth0, which won’t work on a system using a pure wireless connection on, say, wlan0 or anything more exotic. I haven’t a clue how to parameterize that selection. Most likely, one would write another upstart script that would emit a custom signal based on the usual suspect …
It also assumes the networking infrastructure triggered by eth0 lighting up has hauled itself to its feet and is ready to roll. That seems to be true, although I’ll admit the script is, at best, lightly tested.
With the eth1 NIC up and iptables rules added, I think this script will restart eth1 when it goes down, but it’s not clear where the requisite network-device-down event comes from (certainly not from any script in /etc/init/*conf):
description "Restart eth1 when it dies"
author "Ed Nisley - KE4ZNU"
start on net-device-down IFACE=eth1
stop on net-device-up IFACE=eth1
script
logger Restarting eth1...
ifconfig eth1 192.168.3.1 netmask 255.255.255.0 up
logger Ending eth1 setup
end script
But, eh, at least the isolated interface comes up and packets go where they should (and not where they shouldn’t). Early results are encouraging…
We provide a camping spot for touring bicyclists riding through the Hudson Valley and, as you’d expect, most of them arrive toting netbooks, tablets, and other net-enabled doodads. While I’m a nice guy and they’re uniformly nice folks, I’d rather not hand them the keys to our house network, so I recently set up a WiFi Internet-only access point that’s firewalled from the LAN.
The general idea:
Use a stock WiFi router to handle DHCP / DNS / WiFi for guests (192.168.2.x)
Add a second NIC to the file server as eth1 (192.168.3.1), connected to the router’s WAN port (192.168.3.2)
Forward packets between eth0 (house network 192.168.1.x) and eth1, except …
Use iptables to prevent router clients from seeing the house network
The NIC Just Worked: the drivers come along with the kernel. Because it’s not a general-purpose network interface from the server side, eth1 setup doesn’t require much effort:
ifconfig eth1 192.168.3.1 netmask 255.255.255.0
I discovered the hard way that trying to define the eth1 interface with Network Manager caused no end of heartache & confusion, not least of which is that having two NICs somehow activates Ubuntu’s internal firewalling & port forwarding. Suffice it to say, just set the NM’s GUI to Ignore the eth1 NIC and do what needs to be done manually.
With one NIC, Ubuntu runs iptables in “let it be” mode: everything’s allowed, nothing’s blocked, and all packets get forwarded. The tables are empty and the default ACCEPT policy passes everything.
Adding a rule to the FORWARD chain prevents the router from sending packets to the house network:
iptables -A FORWARD -i eth1 --destination 192.168.0.0/16 -j REJECT
That still allows a ping response from the file server’s eth0 NIC at 192.168.1.2 back to the WiFi clients, because packets addressed to the server pass through the INPUT chain. This rule squelches those packets:
iptables -A INPUT -i eth1 --destination 192.168.0.0/16 -j REJECT
Although packet forwarding is enabled by default, another rule turns on the NAT machinery required to shuttle packets between the 192.168.3.x network and the outside world:
iptables -A POSTROUTING -t nat -j MASQUERADE
While fiddling with iptables rules that involve packet state tracking (which these do, at least implicitly, I think), you must reset the packet state memories to ensure new packets aren’t regarded as part of an established connection. Install the conntrack utilities, then reset the state as needed:
sudo conntrack -F
And then it Just Worked.
Now, back in the day, you’d just put those configuration lines in /etc/rc.local and be done with it. Unfortunately, nowadays the upstart process kicks off rc.local well before the system is in a usable state: somewhat before eth0 is active, which means any automagic network-related activity falls flat on its face.
So an upstart configuration script is in order… more on that later.
Some useful, albeit occasionally befuddling references:
One could, of course, buy dedicated hardware to do all that and more, but it’s nothing you couldn’t accomplish with a bit more configuration on a stock Linux box. Heck, you could even serve an Upside-Down-Ternet to anyone who deserves it; the original has some other suggestions that made the big time.
A tip o’ the cycling helmet to Dragorn of Kismet for getting me started…
Begin by mounting the Canon SX230HS on the macro lens adapter, zooming to about the maximum, fiddling with a ruler to put the end at the closest focus point, and eventually get an overall view like this:
Ruler – macro mid-focus
The images below were batch cropped from similar views with ImageMagick:
for f in $(seq 17 22) ; do convert -crop '1500x1126+1900+1800' \
img_18${f}.jpg img_18${f}-crop.jpg ; done
Yes, I’ve taken a bit over 1800 images since getting that camera… the old DSC-F505V recently rolled over at 10K images.
Take a set of six identically exposed pictures starting with the focus at infinity (about 95 mm in real life):
macro far focus
And ending with the closest focus at about 1 meter for this zoom setting (and 80 mm in real life):
macro near focus
Then apply enfuse (from the Ubuntu repositories) with a handful of parameters suggested there that combine the sharpest parts of each image into a single image:
It’s not perfect, it needs a few more intermediate images, there’s fringing around high-contrast edges, and so forth and so on, but for a first pass it ain’t bad at all.
I bar-clamped the camera & macro adapter to the desk in order to eliminate all motion. My usual tripod mount for the macro setup isn’t all that stable and the microscope stand isn’t particularly rigid, either, so I must improve a bunch of mechanical structures. In principle, you can post-process the pictures to realign them, although the tolerances seem daunting enough to make mechanical fixturing look downright attractive by comparison.
Now, if it should turn out that the SX230HS supports the CHDK USB remote trigger, that’d be nice. Or maybe the right way to proceed involves converting the problem to A Simple Matter of Software by writing a CHDK script that tweaks the focus by multiples rather than increments.