The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Author: Ed

  • EMC2 HAL Pin Names: Logitech Dual Action Gamepad

    Here are the pin names for a Logitech Dual Action USB (wired) gamepad, according to EMC2 2.3.4. You’ll need these to wire it up as a control pendant for your EMC2 CNC milling machine…

    Front View
    Front View

    From /proc/bus/input/devices we find:

    I: Bus=0003 Vendor=046d Product=c216 Version=0110
    N: Name="Logitech Logitech Dual Action"
    P: Phys=usb-0000:00:1d.1-2/input0
    S: Sysfs=/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0/input/input2
    U: Uniq=
    H: Handlers=event2 js0
    B: EV=1b
    B: KEY=fff 0 0 0 0 0 0 0 0 0
    B: ABS=30027
    B: MSC=10
    

    That tells us to use:

    halrun
    loadusr -W hal_input -KRA Dual
    loadusr halmeter
    

    There’s no need for -KRAL because it has no programmable LEDs.

    Prefix all these with input.0. to get the complete name.

    Hat Left-Right abs-hat0x-counts
    abs-hat0x-position
    Hat Up-Down abs-hat0y-counts
    abs-hat0y-position
    Hat Push none
    Left Knob Left-Right abs-x-counts
    abs-x-position
    Left Knob Up-Down abs-y-counts
    abs-y-position
    Left Knob Push btn-base5
    Right Knob Left-Right abs-z-counts
    abs-z-position
    Right Knob Up-Down abs-rz-counts
    abs-rz-position
    Right Knob Push btn-base6
    Button 1 btn-trigger
    Button 2 btn-thumb
    Button 3 btn-thumb2
    Button 4 btn-top
    Button 5 btn-top2
    Button 6 btn-pinkie
    Button 7 btn-base
    Button 8 btn-base2
    Button 9 btn-base3
    Button 10 btn-base4
    Mode button swap Hat & Left Knob
    lights red LED

    All of the buttons have -not output pins.

    The Knob position values run from -1.0 to +1.0 (float) and rest (almost) at 0.0 when centered. Their counts (s32) run from 0 to 255 and rest at 127 when centered.

    The Hat button position values are only -1.0 and +1.0, centered at 0.0. The counts are only -1 and +1, with 0 when un-pushed. Although they take on only integer values, the position values are floats.

    Both Knobs and the Hat have -Y position values at the top and +Y values at the bottom, exactly backwards from what you want. Expect to reverse the Y axis sign when you write the HAL code.

    The -X position values are to the left, where you want them.

    Although there’s a tactile click when pushing the Hat straight down, there is no corresponding button output. I don’t know if this is an oversight in the HAL interface or if there’s no actual switch in there.

    The Mode button swaps the Hat and Left Knob functions. With the red LED on, both the Hat and Knob axes produce only -1 and +1 position and counts values.

    A guide to figuring this stuff out is there, with useful pointers elsewhere on the main doc page.

    Tomorrow: turning it into an EMC2 pendant.

  • Spectral Characteristics: The Graph

    In the process of pulling together a talk for the Trinity Robotics contest, I rediscovered my spreadsheet of spectral response data. It’s been compiled over the years from myriad sources (utterly without attribution), suffers from gaps & interpolations, and undoubtedly emits a fairly high bogon flux density.

    To wit: trust nothing!

    Spectral Response
    Spectral Response

    Horizontal scale has UV on the left and IR on the right.

    Vertical scale is linear, roughly corresponding to power in or out at a particular wavelength. It should, of course, be logarithmic, but that’s in the nature of fine tuning, as no source data has that much resolution.

    Things to note:

    • Human eyes are tuned to see chlorophyll and not much else. That must’a been important at one time or another…
    • The nice bumps on the left are visible LEDS: violet blue green orange yellow red. The IR LED over on the right stands alone.
    • There’s no overlap between human vision and IR LED emission, but you can still see a dim red glow if you stick it right up against your eye.
    • Don’t do that with a UV LED, though.
    • White LEDs are just blue LEDs with fancy phosphors. That’s why the spectrum looks like a blue LED with a bump in the yellow-orange neighborhood. They’re not well-balanced at all.
    • High-pressure sodium lights kill IR sensors stone cold dead. Look at that peak, perfectly aligned with the photodiode response. If you could see in IR, you’d go blind. That’s what made the Trinity contest so challenging for so many years; they recently switched to fluorescent lighting and the complaints dropped dramatically.
    • Those emission spikes are why camera color correction doesn’t work well: if there’s no energy in a region, you can’t crank the gain up enough to make a difference.
    • An 87C Wratten filter is great for excluding visible light, but the overlap with that HP-Na spike tells you it won’t do jack with that sort of lighting.
    • Fluorescent tubes produce intense spikes at 436 and 546, corresponding to mercury emission lines. Their phosphor emissions extend far into the IR, too, but the data I have doesn’t include that region.
    • Ditto for metal halide bulbs.

    To produce the graph, apply this bash script to the CSV file…

    
    #!/bin/sh
    export GDFONTPATH="/usr/share/fonts/TTF/"
    gnuplot << EOF
    #set term x11
    set term png font "arialbd.ttf" 24 size 1200,800
    set output "Spectral Response.png"
    set title "Spectral Response"
    #set key 28,-0.75 Left reverse samplen 2 noautotitles
    #set key right noautotitles
    unset key
    unset mouse
    set bmargin 4
    set grid xtics ytics
    set xlabel "Wavelength - nm"
    set format x "%3.0f"
    #set xrange [0:9]
    #set xtics 0,10
    #set mxtics 4
    set ytics nomirror autofreq
    set ylabel "Relative Response"
    #set format y "%3.0f"
    set yrange [0:1.1]
    #set y2label "Panel Power - mW"
    #set format y2 "%3.0f"
    #set y2range [0:800]
    #set y2tics 200
    set datafile separator ","
    set label 1 "Eye" at 550,1.05 font "arialbd,14" center
    set label 2 "White" at 480,1.05 font "arialbd,14" center
    set label 3 "IR" at 940,1.05 font "arialbd,14" center
    set label 4 "87C Filter" at 1050,0.85 font "arialbd,14" center
    set label 5 "Photodiode" at 825,1.05 font "arialbd,14" center
    set label 6 "Tungsten" at 1050,1.00 font "arialbd,14" center
    set label 7 "Fluor" at 410,0.42 font "arialbd,14" right
    set label 8 "Halide" at 680,0.41 font "arialbd,14" left
    set label 9 "HP-Na" at 805,0.60 font "arialbd,14" right
    set label 10 "Violet" at 410,1.05 font "arialbd,14" center
    set label 11 "Red" at 635,1.05 font "arialbd,14" center
    plot    "Spectral Response Curves.csv" \
     using 1:2 with lines lt -1  lw 3 title "Eye", \
     "Spectral Response Curves.csv" \
     using 1:3 with lines lt 1 lw 2 lc rgb "light-blue" title "White" , \
     "Spectral Response Curves.csv" \
     using 1:4 with lines lt 1 lw 2 lc rgb "dark-violet" title "Violet" , \
     "Spectral Response Curves.csv" \
     using 1:5 with lines lt 1 lw 2 lc rgb "blue" title "Blue" , \
     "Spectral Response Curves.csv" \
     using 1:6 with lines lt 1 lw 2 lc rgb "green" title "Green" , \
     "Spectral Response Curves.csv" \
     using 1:7 with lines lt 1 lw 2 lc rgb "gold" title "Yellow" , \
     "Spectral Response Curves.csv" \
     using 1:8 with lines lt 1 lw 2 lc rgb "orange" title "Orange" , \
     "Spectral Response Curves.csv" \
     using 1:9 with lines lt 1 lw 2 lc rgb "red" title "Red", \
     "Spectral Response Curves.csv" \
     using 1:10 with lines lt 1 lw 2 lc rgb "magenta" title "IR" , \
     "Spectral Response Curves.csv" \
     using 1:11 with lines lt 1 lw 2 lc rgb "dark-red" title "Photodiode" , \
     "Spectral Response Curves.csv" \
     using 1:12 with lines lt 1 lw 2 lc rgb "dark-gray" title "87C Filter" , \
     "Spectral Response Curves.csv" \
     using 1:13 with lines lt 1 lw 2 lc rgb "dark-yellow" title "Tungsten" , \
     "Spectral Response Curves.csv" \
     using 1:14 with lines lt 1 lw 2 lc rgb "orange-red" title "HP-Na" , \
     "Spectral Response Curves.csv" \
     using 1:15 with lines lt 1 lw 2 lc rgb "brown" title "Halide" , \
     "Spectral Response Curves.csv" \
     using 1:18 with lines lt 1 lw 2 lc rgb "midnight-blue" title "Fluorescent"
    EOF
    
    

    And the data in CSV format because WordPress doesn’t allow spreadsheets…

    
    #"Wavelength","Eyeball","White LED","Violet LED","Blue LED","Green LED","Yellow LED","Orange LED","Red LED","IR LED","Photodiode","IR Filter","Incandescent","Sodium","Metal Halide","Daylight Flour","Moon Fluor","Fluorescent"
    300,,,,,,,,,,,,,,,,,
    310,,,,,,,,,,,,,,,,,
    320,,,,,,,,,,,,,,,,,
    340,,,,,,,,,,,,,,,,,
    350,,,,,,,,,,,,,,,,,
    360,,,,,,,,,,,,,,,,,
    370,,,0.02,,,,,,,,,,,,,,
    380,,,0.11,,,,,,,,,,,0.06,0.04,0.03,0.03
    385,,,,,,,,,,,,,,0.06,0.05,0.04,0.03
    390,,,0.33,,,,,,,,,,,0.07,0.06,0.05,0.04
    395,,,,,,,,,,,,,,0.08,0.07,0.06,0.05
    400,,,0.90,,,,,,,0.05,,0.09,,0.09,0.09,0.07,0.06
    405,,,,,,,,,,,,,,0.10,0.40,0.37,0.39
    410,,,1.00,,,,,,,,,,,0.10,0.13,0.10,0.09
    415,,,,,,,,,,,,,,0.15,0.13,0.10,0.09
    420,0.05,0.02,0.33,0.02,,,,,,0.12,,0.12,,0.26,0.15,0.11,0.10
    425,,,,,,,,,,,,,,0.16,0.16,0.13,0.11
    430,,0.05,0.11,0.11,,,,,,,,,,0.13,0.18,0.14,0.12
    435,,,,,,,,,,,,,,0.13,1.00,1.00,1.00
    440,0.16,0.08,0.05,0.92,,,,,,0.19,,0.15,,0.11,0.21,0.17,0.14
    445,,,,,,,,,,,,,,0.11,0.22,0.18,0.15
    450,,0.30,,1.00,,,,,,,,,,0.13,0.24,0.19,0.16
    455,,,,,,,,,,,,,,0.15,0.26,0.20,0.17
    460,0.25,0.65,,0.77,,,,,,0.25,,0.19,,0.18,0.26,0.21,0.17
    465,,,,,,,,,,,,,,0.15,0.26,0.21,0.18
    470,,0.90,,0.22,,,,,,,,,,0.15,0.26,0.21,0.18
    475,,,,,,,,,,,,,,0.17,0.27,0.22,0.18
    480,0.36,1.00,,0.11,,,,,,0.32,,0.22,0.02,0.20,0.27,0.22,0.18
    485,,,,,,,,,,,,,,0.16,0.27,0.22,0.18
    490,,0.80,,0.03,,,,,,,,,,0.20,0.27,0.22,0.18
    495,,,,,,,,,,,,,,0.17,0.27,0.22,0.18
    500,0.50,0.32,,,,,,,,0.39,,0.25,0.10,0.18,0.26,0.21,0.18
    505,,,,,,,,,,,,,,0.23,0.25,0.21,0.17
    510,,,,,,,,,,,,,,0.22,0.25,0.20,0.17
    515,,,,,,,,,,,,,,0.22,0.24,0.20,0.17
    520,0.70,0.30,,,,,,,,0.44,,,0.02,0.18,0.24,0.20,0.18
    525,,,,,,,,,,,,,,0.20,0.24,0.20,0.19
    530,,,,,,,,,,,,,,0.22,0.24,0.20,0.21
    535,,,,,,,,,,,,,,1.00,0.24,0.21,0.24
    540,1.00,0.48,,,0.08,,,,,0.49,,,0.02,0.45,0.26,0.23,0.27
    545,,,,,,,,,,,,,,0.27,0.70,0.67,0.78
    550,1.00,0.55,,,0.45,,,,,0.52,,,0.05,0.18,0.29,0.27,0.36
    555,,,,,,,,,,,,,,0.20,0.30,0.30,0.40
    560,1.00,0.55,,,0.95,0.13,,,,0.54,,,0.10,0.18,0.32,0.32,0.45
    565,0.91,,,,1.00,0.34,,,,0.55,,,0.30,0.24,0.33,0.35,0.49
    570,0.83,,,,0.85,0.55,,,,0.57,,,0.43,0.24,0.34,0.37,0.52
    575,,,,,,,,,,,,,,0.26,0.39,0.44,0.59
    580,0.65,,,,0.37,0.96,0.08,,,0.59,,,0.33,0.24,0.42,0.46,0.61
    585,0.61,,,,0.31,1.00,0.19,,,0.60,,,0.40,0.23,0.34,0.39,0.52
    590,0.58,,,,0.24,0.94,0.30,,,0.62,,,0.15,0.24,0.32,0.38,0.51
    595,,,,,,,,,,,,,,0.29,0.30,0.37,0.48
    600,0.50,0.40,,,0.11,0.60,0.80,0.13,,0.64,,0.51,0.46,0.37,0.28,0.34,0.44
    605,,,,,,,,,,,,,,0.30,0.26,0.31,0.41
    608,0.46,,,,,0.56,1.00,0.29,,,,,0.33,,,,
    610,0.45,,,,,0.55,0.97,0.33,,,,,0.32,0.37,0.24,0.29,0.36
    615,,,,,,,,,,,,,,0.33,0.21,0.27,0.33
    620,0.40,0.32,,,,0.20,0.80,0.60,,,,,0.32,0.26,0.19,0.24,0.29
    625,,,,,,,,,,,,,,0.33,0.17,0.21,0.25
    630,0.30,0.28,,,,,0.52,0.95,,,,,0.20,0.25,0.15,0.18,0.22
    634,0.26,,,,,,0.43,1.00,,,,,0.19,,,,
    635,,,,,,,,,,,,,,0.27,0.13,0.16,0.19
    640,0.20,0.25,,,,,0.30,0.90,,,,,0.17,0.27,0.11,0.14,0.16
    645,,,,,,,,,,,,,,0.26,0.10,0.12,0.14
    650,0.15,,,,,,0.20,0.60,,,,,0.16,0.25,0.09,0.10,0.12
    655,,,,,,,,,,,,,,0.31,0.08,0.09,0.10
    660,0.10,,,,,,0.10,0.43,,,,,0.14,0.27,0.07,0.08,0.09
    665,,,,,,,,,,,,,,0.29,0.06,0.07,0.07
    670,0.08,,,,,,,0.30,,,,,0.13,0.24,0.05,0.06,0.06
    675,,,,,,,,,,,,,,0.28,0.05,0.05,0.05
    680,0.05,,,,,,,0.20,,,,,0.11,0.25,0.04,0.05,0.05
    685,,,,,,,,,,,,,,0.37,0.04,0.04,0.04
    690,0.03,,,,,,,0.10,,,,,0.10,0.26,0.03,0.04,0.04
    695,,,,,,,,,,,,,,0.24,0.03,0.03,0.03
    700,,0.24,,,,,,,,0.84,,0.81,0.09,0.26,0.03,0.03,0.03
    705,,,,,,,,,,,,,,0.21,0.02,0.03,0.02
    710,,,,,,,,,,,,,,0.16,0.02,0.02,0.02
    715,,,,,,,,,,,,,,0.15,0.02,0.02,0.02
    720,,0.20,,,,,,,,0.87,,0.84,0.08,0.14,0.02,0.02,0.02
    740,,0.10,,,,,,,,0.90,,0.87,0.06,,,,
    760,,0.08,,,,,,,,0.93,,0.89,0.05,,,,
    770,,,,,,,,,,0.94,,0.90,0.11,,,,
    780,,0.04,,,,,,,,0.96,,0.92,0.05,,,,
    800,,0.02,,,,,,,,0.99,0.03,0.95,0.06,,,,
    810,,,,,,,,,,1.00,0.08,0.96,0.07,,,,
    820,,,,,,,,,,1.00,0.16,0.97,1.00,,,,
    840,,,,,,,,,,1.00,0.38,0.97,0.07,,,,
    860,,,,,,,,,,0.96,0.58,0.98,0.06,,,,
    880,,,,,,,,,,0.91,0.73,0.99,0.05,,,,
    900,,,,,,,,,0.15,0.87,0.81,1.00,,,,,
    910,,,,,,,,,0.37,,,,,,,,
    920,,,,,,,,,0.67,,,,,,,,
    930,,,,,,,,,0.96,,,,,,,,
    935,,,,,,,,,1.00,,,,,,,,
    940,,,,,,,,,0.97,,,,,,,,
    950,,,,,,,,,0.73,,,,,,,,
    960,,,,,,,,,0.45,,,,,,,,
    970,,,,,,,,,0.26,,,,,,,,
    980,,,,,,,,,0.16,,,,,,,,
    1000,,,,,,,,,0.10,0.43,0.89,0.98,,,,,
    1020,,,,,,,,,,0.36,0.90,0.97,,,,,
    1040,,,,,,,,,,0.29,0.91,0.96,,,,,
    1060,,,,,,,,,,0.22,0.91,0.94,,,,,
    1080,,,,,,,,,,0.15,0.92,0.93,,,,,
    1100,,,,,,,,,,0.08,0.93,0.92,,,,,
    
    
  • Chipmunk

    I accidentally-on-purpose spilled some sunflower seeds when I refilled the bird feeder, just to see who was awake. Surprisingly, the seeds remained untouched for about two days, then this fellow appeared… and cleaned them up in a matter of minutes.

    Spring is on its way, despite the recent storms!

    Chipmunk with sunflower seeds
    Chipmunk with sunflower seeds

    Taken with the Sony DSC-H5 zoomed in all the way (12x) through the 1.7x tele-adapter. It’s not a great combination, but it’s better than no picture at all. This is a crop of about the middle half of the image, with a touch of unsharp mask, then scaled down 2:1 for improved webbishness. After all that, it’s a wonder you don’t mistake the critter for a moose…

  • Dell Inspiron 8100: VGA Kernel Options

    Just installed CrunchBang Linux on the old Dell Inspiron 8100 (1 GHz 512 MB Pentium III laptop) to get some experience with OpenBox and maybe make the thing usable with the Arduino IDE on my electronics workbench.

    As with most distros, it features a totally useless boot progress thermometer splash screen that hides all the interesting details. Carving the splash quiet options off the kernel line in /boot/grub/menu.lst gets back to the usual torrent of text info, which I find comforting. But the default screen is 80×25, which means things scroll by at a pretty good clip…

    Adding vga=ask to the kernel line lets you dump what the BIOS thinks will work. This includes:

    • 0x345 or 0x346 = 1600x1200x16
    • 0x315 = 800x600x32
    • 0x31A = 1280x1024x16

    Plus a whole bunch of other modes that don’t matter much these days. Anyone for 40×25 text mode?

    I wanted 1600×1200, but both of the listed options caused a garbled display: double-spaced raster lines and eventual overlapping wrapped text. There’s probably a BIOS bug in there somewhere.

    Choosing the 80×60 modes produced truly ugly squashed text.

    After some poking around, 0x31A produced a usable display that, to my wondering eyes, appears to be 1600×1200. The kernel expects the decimal equivalent of that value: vga=794.

    It’s plenty dense enough for all the boot text…

  • Beveling Some Edges

    Clock case test fit
    Clock case test fit

    The case for the Totally Featureless Clock is exactly what you’d expect: a solid black acrylic block with a Lexan Graylite faceplate. All you see are digits… no buttons, no knobs. Just the time, all the time.

    I’d hoped to just epoxy the faceplate on and be done with it, but the edges really didn’t look right. A bit of rummaging turned up a Dremel 125 “High Speed Cutter” that looked to be exactly the right hammer for the job.

    Dremel conical cutter in drill chuck
    Dremel conical cutter in drill chuck

    The Sherline CNC mill just doesn’t have the reach for a foot-long cut, so I clamped the case to the manual mill and grabbed the cutter in an ordinary drill chuck. This is absurd, but ya gotta run with what ya got…

    According to the Dremel specs, the cutter should run at 20-30 k RPM, but, trust me on this, the mill doesn’t go that fast. I set it for 2000 RPM, the fastest it’s run in years, and hoped for the best.

    The runout was breathtaking.

    I aligned the case against against a parallel in one of the T-slots, which got it surprisingly close.  A trial cut showed it was off by a bit, but two slight realignments (loosen clamps, slide gently, reclamp) and trial cuts put it spot on. That worked fine for three sides.

    The cutter is about 6.3 mm dia and just over 9 mm long, so the cutting edge is inclined at almost exactly 1:3. That means a horizontal misalignment of 10 mils causes a vertical misalignment of 30 mils. Conversely, you can measure the vertical error and then tweak the horizontal to make the answer come out right.

    Tweaking the alignment
    Tweaking the alignment

    The fourth side was off enough to make the final joint to the first side pretty ugly. I measured the vertical offset at about 80 mils, set the front magnetic block as a pivot and stuck a 25-mil feeler gauge between the rear block and the case. Remove the feeler, loosen the clamps, rotate the case, reclamp, and the cut was just about perfect. Certainly within my tolerances for such a thing… you can’t see it unless you’re looking for it.

    The bottom picture shows the final bevel, hot off the mill table, minus the protective plastic wrap and plus a bunch of dust and adhesive smudges from the wrap. The end plate gives the vertical line down the right side and a slight discontinuity where it’s a few mils shy of the side. There’s a hairline around the whole case where the faceplate joins the black acrylic; I used transparent epoxy and a light weight to clamp the faceplate down, so the joint is uniformly thin all around.

    A few passes on a sanding block ought to get rid of the tool marks and spiff the bevel up just fine all around.

    I love happy endings.

    Final corner bevel
    Final corner bevel
  • X10 Controller: End of Life

    X10 Controller Circuit Board
    X10 Controller Circuit Board

    After 30-some-odd years, the X10 controller we’ve been using to turn off all the lights at bedtime finally stopped working. For the last few months it had been occasionally jamming ON, even when nobody pushed any keys, and the only way to reset it was pulling the plug.

    The big silver can on the white cable is an ultrasonic mic, so perhaps the circuitry around that was getting cranky: the ultrasonic cleaner in the bathroom (which we use for eyeglasses) would reliably jam it. I think the controller was responding to the third harmonic of the 40-ish kHz cleaner power, delivered through the power line.

    As you’d expect, all the electrolytic caps were shot; ESR for the big one was “open”, the smaller ones around 5 Ω. The capacitance values were entirely within spec, of course. I replaced all three.

    X10 Controller keyboard
    X10 Controller keyboard

    While I had the hood up, I cleaned the switch contacts, even though that probably had nothing to do with the problem. Back in the day, they used actual metal deformable domes, stuck under an adhesive layer that did a fine job of keeping the crud and dust out.

    Put everything back together, fired it up, and it misbehaved the same way. I’d say we got our money’s worth out of it, though.

    A replacement is on the order of $15 from the usual eBay suppliers, so it’s not the end of the world.

    The new one probably doesn’t have the ultrasonic receiver, so it shouldn’t respond to the ultrasonic cleaner with the same enthusiasm.

  • Braille Signage

    I passed a few minutes in the high school lobby (while waiting for the Fencing team to return from a competition) trying to decipher the Braille signs. I’ve always had my doubts about the utility of these things, but I suppose if you’re going to have signs, they may as well have tactile lettering, too.

    Anyhow, what little I knew about Braille (six dots, um, 64 symbols, um, tapers off after that) didn’t extend to actually knowing any of the letters, but how hard could a substitution cipher be? I figured out most of the letters in Stairway quickly, but some were obviously missing. Perhaps Braille includes symbols for common digraphs?

    Stairway
    Stairway

    The Library across the lobby provided more letters, with obvious mismatches that showed I wasn’t anywhere near as clever as I thought (a distressingly common situation these days). Perhaps the two leading dots indicate “Here be there text”?

    Library
    Library

    Then I found the Ticket Booth, which strongly suggested digraph symbols.

    Ticket Booth
    Ticket Booth

    Upon returning home, I did the obvious search and eventually wound up at the Library of Congress Instruction Manual for Braille Transcribing: a short introduction to a very complex subject. Poring through Appendix B provided all the correspondences I needed:

    • The basic alphabet is sorta-kinda decimal
    • Yup, digraphs have their own encoding
    • The two leading dots are a sticky uppercase shift marker
    • Fortunately, I didn’t encounter real contractions
    • There’s an 8-dot variant coming into play

    Some years ago we took an introductory course in American Sign Language when one of my not-quite-a-nephew (son of a cousin, whatever that is) went deaf. Without anyone for day-to-day practice we never achieved fluency, but that was a window into another world, too. We still pass a few basic signs to each other across a noisy room …

    Photography note: photograph signs from far enough off-axis that the flash hotspot on the surface is out of the image. If you must get a rectangular sign out of it, apply a perspective transformation to the image.