This is my blog. I write articles here. Click into an article to see its images.

'Tenet' project start

12 Jul 2022

categories: small-computers
tags: rpi

I’ve had an idea kicking around for a while, to make a raspberry-pi-based netbook. Two years ago I was playing around with thermal receipt printers for another project idea and I was also starting to learn stenography. I got the idea to build a netbook for stenography. Some kind of steno netbook. I’ve taken to calling it tenet.

I regained interest in the idea when I saw the ShaRPiKeebo on CrowdSupply. This powerful little device has a fantastic screen. I got to see one up close recently when a friend showed me her new Playdate console. I’m not particularly keen on the keyboard the ShaRPiKeebo comes with, but it’s so close to my use case that I bought a couple of the PCBs and backed the project. In the meantime, I also picked up some of the screens on breakout boards from Adafruit!

So, what’s the use-case, what’s the pitch? I want this computer to be small, portable, solar-rechargeable, and daylight-readable. It’s for writing and light programming away from a desk, possibly even off the grid. It could be used in a pinch for sysadmin/on-call tasks, or some kind of terminal-based email or chat, but its main use case is for writing. Am I a writer? Do I know what writers want? Why am I asking myself so many questions instead of building small computers?

Image: a bunch of computer parts, loosely arranged. Read below images for more descriptions

Ok, what about components?

Image: A Keyboardio Atreus keyboard. 44 keys arranged in a split-monoblock, columnar orthogonal layout.

The keyboard I’m starting with is the Keyboardio Atreus. It is small, thin, light, and a little more ergonomic than other 40% boards. I say “starting with” because it has a couple of shortcomings for this project: it won’t work for a full steno machine because it would need one extra column on the right side, and for more weight and space savings I should use a board with Choc switches and keycaps. But the Keyboardio Atreus is more than up to the task of being the board for the prototype computer.

Image: A 2.7-inch 400x240 SHARP Memory Display, on an Adafruit breakout board. Shown here with a Raspberry Pi 4 for scale.

The other part tied for first place in user interaction is the screen. These Adafruit SHARP Memory Displays are 2.7" on the diagonal, and have 400x240 pixels. The display is monochrome, with no back- or front-lighting. They communicate with the Pi over I2C, so some custom software will be necessary to use them as a monitor.

Image: A 3-cell lithium ion polymer battery, connected to a circuit board that’s hooked up to a small solar panel.

Powering it all is a 3.7V battery from Adafruit. I’m not sure it’ll suffice for the printer but we’ll get to that shortly. I’ve got this hooked up to a circuit that accepts DC power from a solar panel or USB-C power. I have no idea how long the thing will last on a single charge. I guess once I get it running we’ll find out.

Image: Two thermal receipt printers, one in a blocky enclosure and the other cut apart, to become longer but less thick.

The icing on top will be a thermal receipt printer. I hope that this could operate in a few modes. The first is standard, to tell the computer to print a file, and have it come out the top. The second would be to have the terminal print its buffer line-by-line as it scrolls above the top of the screen. This second use case is challenging to achieve, but fulfills the destiny of this modern-day typewriter.

Image: An alternate view of the receipt printers, showing how the long thin one uses part of its original enclosure.

I’m not sure yet which shape of printer will be best for the computer as a whole. Honestly it will probably have to come with its own supplemental power supply too, because these need 6-9V to print reliably. Lots of experimenting with shapes to do. Which brings me to the next component: the enclosure.

Image: All of the above parts, stacked as densely as possible.

My first idea for an enclosure was a kind of backwards laptop: when closed the printer and screen would lie flat, above the Raspberry Pi and battery cells.

Image: The same as above, but now a hand is holding the screen and long/thin printer angled up 80 degrees from horizontal

Upon extending the hinge, the printer and screen come up. It was my first idea about what this should look like. I was hoping to evoke something of a spiral-bound memo pad that flips open in a similar way.

Image: The above parts, this time using the bulkier printer, arranged in a cube-like shape with the screen forming an angled face at the front.

Once I had all the parts together on the table (notably the bulky battery cell), I found another arrangement that’s a little less complicated, as it has no moving parts and does not require redesigning the printer’s enclosure. Is it sufficient for the computer? Is it better? Nobody knows the answer.

As I write this, my ShaRPiKeebo PCBs are on their way here from France. I have a few ideas on how to experiment with the Adafruit boards to make those displays work, and I have some CAD work to do to get these parts to stick together more permanently.

Yours in Unnecessary Small Computers,

Canary v1

22 Jun 2022

categories: small-computers
tags: 3dp circuit-python i2c rp2040 stemma

Recently my partner bought an LCD resin 3D printer. That was kind of the last straw for a risk that has been growing in the last few months. I already had a filament 3D printer (so far just for PLA, but who knows!), and several weeks ago I hooked up a kegerator with a carbonation system. Oh, and all of these share the same airspace as my office.

The risk we’re concerned about is a buildup of VOCs, carbon dioxide and carbon monoxide. To mitigate this, I wanted to build a device that can sense these things, display their levels on a readout, and potentially make a loud noise if they go over a certain threshold.

Are there consumer devices that also do this? possibly. Are there even fancy filter fans that can show you what’s in the air on your smartphone? also yes. But this sounded simple enough to prototype that I could spend a little extra money on the parts and then have fun putting them together. (Also, I couldn’t find a consumer-grade device that would measure carbon dioxide, so I wanted to start there).

The main board I chose for this is the Adafruit Trinkey QT2040 (guide). I didn’t have a lot of criteria to match. I mostly wanted it to be easy to get running, and use I2C for the connections. Trinkey is easier than easy. Anything Adafruit makes that works with their Circuit Python libraries is very approachable, code-wise. And this board is based on the RP2040 chip, which is more than powerful enough to run the code I need.

It also happens that Adafruit maintains a hardware spec called “Stemma QT” that transmits I2C signals over premade JST PH wires (youtube intro). Trinkey has Stemma QT (hence “QT2040”), and a lot of the sensor breakout boards that Adafruit makes also use Stemma QT.

An Adafruit Trinkey RP2040 QT

The star of the show is the CO2 sensor: that’s an Adafruit SCD-41 (guide) photoacoustic “true” CO2 sensor. It measures temperature, relative humidity, and CO2 (in parts-per-million). It transmits all of this over I2C, using Stemma, once every few seconds.

An Adafruit SCD-41 sensor package

For an interface, I’m using a monochrome 0.96" I2C OLED Display (guide) with 128 x 64 pixels. Later I may switch to something like a SHARP Memory display, for low-power use.

A monochrome 0.96

I had a Pi-Fan laying around from a past project, and figured the sensor wouldn’t do much good without a continuous supply of new air.

A DC brushless “pi-fan”

Finally, I 3d-printed a frame for all these parts to screw (or hot-glue) onto. The first attempt is always a little kludgy, but I really like it! Without further ado, here’s my first take of a CO2 sensor:

The full CO2 sensor device, powered off

The full CO2 sensor device, powered on

The code and 3d-printing files are available at

Final Bill of Materials:

Next time I come back to this, maybe I’ll add a speaker and “hush” button, or CO and VOC sensors, or a battery for portable use!

Starting in on Dactyl

25 May 2022

categories: keebs
tags: 3dp dactyl ergodox glove80

Since December 2020 I’ve been using an Ergodox EZ as my main keyboard, both for work and games. I have my own QMK firmware flashed on it, and I’m nothing but pleased with it.

[image] My Ergodox EZ

Seasons change though, and in January 2021 I found myself backing the Glove80 Kickstarter. I’ve been curious about a curved (“manuform”) keyboard, and this one looked really slick.

[image] a Glove80 in Colemak layout

Up to that point I’d put together keyboard kits with PCBs, and hadn’t yet 3d-printed any enclosures or plates. I kept seeing peoples' cool creations on reddit though, and eventually I started down that path myself.

Today I’m writing this on my first 3d-printed, handwired keyboard! It’s the “Dactyl Manuform Open”, available from source code here.

[image] my new Dactyl Manuform handwired keyboard

For my first attempt I didn’t want to change anything from the stock model, but I did frankenstein it with some parts from a similar build, here. I had noticed in my first print of the Dactyl Manuform that the legs wanted to adjust themselves a little too much.

I was stymied temporarily by my available tools at the time: I only had an FDM printer, which didn’t have the right resolution for some of the smaller parts. My partner recently got an LCD resin printer though, so I’ve completed the Dactyl Manuform build.

[image] the guts of a handwired 3d-printed keyboard

Handwiring was fun! A little frustrating. My only loose connections were in some crimps in rectangular cable connectors (my build eschewed the standard 3.5mm cable between the halves, because one fewer microcontroller is 50% easier to debug). I ended up cutting out the cable connector and replacing it with soldered wire connection: it’s not as if I’m going to use either of the halves by themselves.

I’ve come up with my own firmware for it (cribbed from qmk’s). It’s technically Via-compatible, but I don’t know yet how to set the vendor/product/keymap to make the tool show an accurate representation of the layout and key mappings. A work in progress, perhaps.

Last night, after typing on it for an afternoon, I started hacking around in the source code, to see if I could get one with the key layout I’ve grown accustomed to with the Ergodox. I was able to generate something that seems like it’ll fit my needs better, and then I took another look at one of the Dactyl Manuform’s ancestors: the Dactyl Keyboard.

[image] Adereth’s Dactyl Keyboard

With the exception of the inner row, this matches the key layout of the Ergodox. I like the 6-key thumb cluster. I’m not sure how comfortable the shape will be, but aesthetically I think it’s a great board. As I write this, my FDM printer is making a bottom shell, and my partner’s resin printer is making a top shell (in two parts).

[image] three parts of a keyboard frame: two top shell halves printed in resin, and a bottom shell printed in PLA filament

As with my first attempt at Dactyl Manuform, I haven’t tweaked any of the source code. That may come later, if I really find the shape or lack of an inner column uncomfortable. Next up: wiring this half, playing with it, and iterating!

[image] an Adereth Dactyl Keyboard, coming soon to a desk near me

Lunchtop & Cyberdeck

23 Sep 2021

categories: keebs
tags: lunchtop

I’ve been collecting parts in earnest for two new projects. The basic idea is a portable, hackable, ruggedized workstation. The first iteration of this idea came to me from my partner, who is a Homestuck fan. That one is Lunchtop, and will be built into a red plastic lunchbox from the 70s. The other idea came from, and built into a Pelican case.

These projects interest me partly because I like thinking about the ubiquitous format (“laptop”) being turned on its head and reimagined. And it interests me partly because I get to build two new mechanical keyboards. This post will focus on the latter challenge.


The task is to design and fabricate two keyboards for these computers. The parameters:

  • Lunchtop can fit 8u tall and 11u wide, based on the lunchbox dimensions
  • Cyberdeck can fit 13u wide and 7u tall, based on the dimensions of the Pelican hardcase I’ve selected
  • both must have switch plates that fasten to underlying case structure with screws
  • both may have points on the underside of the switch plate for the pcb to fasten to
  • both should only use a single ProMicro-style microcontroller
  • both should allow for hotswapping the switches, so I can iterate on the switchplate design

I was glad to find a hotswap pcb in a good size for the Cyberdeck (5x12). So far I have not found a good hotswap option for 11u or 10u wide, so I have a few options:

  1. I could cobble multiple non-hotswap PCBs together (Gherkin 3x10 and Yasui 4x10, for instance). This ditches the “single ProMicro” and “hotswap” design parameters.
  2. I could cobble multiple non-hotswap PCBs together, and use mill-max inserts to make them hotswap. This also ditches “single ProMicro”.
  3. I could cobble multiple non-hotswap PCBs together and cut a bunch of traces, soldering new wires on to re-grid them. This would allow for “single ProMicro” but it’s more damaging than I’d like.
  4. I could follow this guide for a 3d-printable hotswap “PCB”. This would meet the design parameters but will take a little more time than options 2 or 3.


The tipping point came when I started reading this very detailed guide to hand- wiring one’s own keyboard. So I’m headed down the road of the printed hotswap “pcb”.

  1. the hotswap guide requires npm and OpenSCAD. I started by making sure nvm was installed, and picked the latest version of npm. I installed OpenSCAD. I should maybe note that everything I do on the terminal is in WSL, and everything in a GUI application is in Windows. And any time I need to build and flash QMK firmware…I do it on a Mac.
  2. I made a layout over at I downloaded the layout JSON and ran it through the hotswap guide’s npm script. [note about exact file IO]
  3. I opened the generated scad files in OpenSCAD. I’m much more familiar with FreeCAD lately, but I’ve had experience with many CAD programs, so a new one can’t be all that foreign, right?

[transmission cuts off here]


26 Aug 2021

categories: keebs steno
tags: ergodox georgi daisy mb44 fruitbar

I’d like to take a moment to rebase where I’m at with steno (and keyboards), and provide a little context. At the time of publishing this, the blog website has just gone live, and all prior articles from my steno journal have been imported and reformatted.

First things first: I have not done much practice with steno in 2021. I have done quite a bit of practice building mechanical (qwerty) keyboards though. I’ve also headed off into the weeds with some raspberry-Pi-based projects that I can’t talk about yet.

A brief inventory of my keyboards:

  • I use an Ergodox EZ every day at work. I keep it in qwerty mode, but in the past I’ve tinkered with putting steno in its firmware.
  • I have a Georgi that’s all souped up with symbol and media layers, as well as a dictionary of nav commands.
  • I’ve experimented with split boards smaller than the Ergodox (Kailh Choco, pinky3, and Sofle). I really wanted something in a smaller profile, and with rotary encoders. I had a lot of fun building them but in the end the thumb positions actually started causing my first RSI! I also found that I have grown used to the huge number of keys available on the Ergodox.
  • I’ve made some forays into the land of 40%, with Daisy, JD40 MkII, and TG4X. This experiment has stalled, as I’m currently waiting on a group buy for the MB-44.
  • I’ve thought long and hard about a 4-row 50% keyboard, and then in my research found that others are currently making them so I don’t have to. As of this writing I eagerly await the group buy for the Fruitbar. I expect that once I have a more office-centric job I’ll take the Ergodox there, and at home I’ll use this longboi keyboard.

As far as my steno work goes…it’s been a while since I’ve touched it. I still would love to get back to it, moreso now even due to my new RSI.
Perhaps I’ll write a proper breakdown of how that machine works for me, and why I built the firmware and dictionaries the way I did.

alphanumeric & 3d printing

25 Jul 2021

categories: Lander Module
tags: HT16K33

Recent efforts have gone into getting the 14-segment alphanumeric display working. I first tried it with d2r2’s translation of the Adafruit library into Golang, but that proved a little frustrating. I then pivoted to’s experiment, and that worked much better. I do have to wrap it in some logic for a few reasons:

  • out of the box, it panics in certain situations related to the decimal
  • I will need a single interface that ends up controlling multiple ht16k33 devices (as in a 6- or 8-digit display)
  • I will likely need to implement scrolling text
  • I may or may not need the interface to control a whole line of nearby displays (as in the case where there are two 6-digit timers, but sometimes they work together to scroll a long string) But I got the test (ht16k33Test) to work! Here are some next steps I’m tracking:


  1. incorporate a segmented display into the console, and the modeTest. Have the display print different things in different modes.
  2. try using periph/conn/gpio instead of warthog618/gpiod
  3. begin playing with the I2C multiplexer board
  4. begin playing with the oled screen
  5. order a 24-bar graph (also based on ht16k33), and play with that
  6. begin playing with the analog joystick
  7. flash the Butterstick with normal-ass keys and write a listener specifically for those keys


  1. experiment with the textured Prusa print plate?
  2. Measure the keyboard cutout, 3dp a cover with known rectangle cutouts and screw-holes.
  3. Print a switchplate for the butterstick
  4. Make cuts for other panels, determine how to screw panels on


  1. Go to the first build crew meeting
  2. establish communication with someone who can help with the power circuit
  3. re-establish who is writing the narrative

As of the last meeting (7/22 with Dr Professor), we had a sketch of the final layout of touchpoints (see notes/layout_1.png). It did not include the bar-graph module though…

~ ~ later that day ~ ~

First print of a panel was a huge success! I did the thermal printer. I made the cuts to the vent port, and now the TI-99/4A is ruined! (for any other purpose).

The spacing of the vents is such that I think I’ll need to use #3 screws. It also happens that that’s the size that should fasten the printer to the plate! So far I’d been imagining using my stock of #8 screws, but it’ll be good to have options.

Case in point: I’m printing test plates now for the keyboard backer and keyboard switchplate, and the first test uses #8 for both, but I can already tell that no. 3 might be more fitting to fasten the switchplate to the eventual front plate.

Did some more thinking about the 24-bar graph idea. I think I’ll pick up a few to play with, but I don’t think there’s room for them on the console.

RPi4 setup, The Game-Stack

4 Jul 2021

categories: Lander Module
tags: golang

To dev on the RPi 4 I have to first update it:

sudo apt update
df -h # to check disk has enough free space
sudo apt full-upgrade
sudo apt clean

The game stack (tm) requires some careful thinking. I almost want to thread the quit signal all the way down, from main to the game server, to the modal game, to each mode. Because (a) the modalGame Run() can’t block on the mode’s Run(), and (b) we’ll want to wait while a mode finishes Close() before we Setup() the next mode.

So, a Run() needs to return a signal, and be non-blocking. And the selector switch needs to provide a signal for its value changes. And the modalGame’s Run() needs to listen to three signals:

  • quits from above
  • changes from selector
  • dones from below

Something like this:

func (mg *modalGame) Run(quit chan bool) (chan bool, error) {
  done := make(chan bool)

  go func() {
    run := true
    for run{
      select {
        case <-quit:
          run = false
        case <-selector.ValueChange():
          // start new mode
        case <-mg.currentModeExited:
          // clean up


The overall structure is proofed here:

Question: do I need games to return a channel for error-forwarding?
Answer: Probably not:

  1. nobody is going to read the logs of this thing (ooh! that gives me an idea though: there should be a button in test mode that prints the logs?! Or will that waste paper?). So it’s reasonable for the game to just log the error and exit 1 or whatever
  2. what would the listener do about it? tell the game to quit? the game should be the one to make that distinction itself

Question: when a mode in the modal game exits organically, what should happen?
Answer: What this means is that someone has completed the mode. They’ve done all the sequences, and gotten a report card. However it happens, the console should be rendered inoperable until the User Switch is reset. In program terms, I think it’s ok for the current modalTest to exit out.

      listen to changes to the mode selector switch

In the actual program, the testing, launch and landing games will not end of their own accord, but keep listening for a rising edge of the user switch. This behavior allows the user to “reset” their experience, if necessary. (Though perhaps they’d have to hit a kill switch to get the sequence to stop in the first place).

      listen to changes to the mode selector switch
        listen to changes to the user switch
        listen to changes to the user switch

Question: do we even need the games' Run() to return an exit code? I wonder what kind of runtime (pun intended) error would be catastrophic in that way.
Answer: let’s wait and see, after I do the next level of tests

End of day progress report:
Work continues apace! The modeTest runs, but it has at least one bug :P

  1. I should have an “off mode” handy.

  2. I should try out stubGame.

  3. if I leave testingGame, the listener for the selector stops? All I got was

    go run src/cmd/modeTest/main.go
    game server starting
    selector value changed to 1
    selector value changed to 2

    …and that’s it! no more input made any changes. I had to kill the main process and one subprocess to get the gpio back.

First step: more logging.
Well, second step. First step: try to sleep.

state machine

3 Jul 2021

categories: Lander Module

A few things are clear today:

  • I should dev on the RPi 4, so I can remote SSH in with VS Code
  • The next software hurdle to cross is the modal architecture. To that end I’ve worked up an interface and implementation that uses a guitar pickup switch as a SP5T instead of its normal operation (three digital outs, five positions: 100, 110, 010, 011, 001)
  • This modal idea is about to get a little hairier. I’m coalescing ideas about different sets of components, that get read at different times. The program essentially has to go through a state machine. Perhaps I should build the state machine as a first-class entity. The first step is probably to graph it out.
  • During development of this machine, I should keep a close eye on how reliable the experience is. Are there intermittent errors with pin lines unable to open or close? etc. If it becomes unreliable, I need to start keeping a reliable version printed and ready to install in the chassis. I don’t mean to use this policy to encourage breaking things, but rather to mitigate against what I know has been my pattern with software as a whole…

Oh gosh, I just realized a SP4T won’t work to do both power and data, unless I do some fancy diodes and voltage step-downs. No, let’s keep it simple and use two admin keyswitches. For the admin touchpoints, I wonder if I can fit them all (2 keyswitches and a USB…and an HDMI?) in the expansion slot. Or if I should just make them regular slide switches behind a screwed-on panel. Hmmmm, no, that’s too much touching, and what if the panel loses threads and falls off? For that HDMI question, I wonder if RPi can connect to phone hotspot and I can ssh in through that? New ticket!

So, next step is to mock this up using the guitar pickup switch as the “mode”, and assume power switch is on. Then, set up at least two different mode games, that each use the same toggle and LEDs, but with different behavior (e.g. test mode flashes an led while the toggle is held, but the landing mode latches the led).

transcribed to Go, looks promising

30 Jun 2021

categories: Lander Module

I have successfully transcribed my simple python script to a slightly-less-simple go program. No, I don’t know why I call python files “scripts” and go files “programs”. I’ve been using the library. It seems to do what we need. I didn’t immediately understand the WithFallingEdge option, but edge detection is easy enough to implement, and I bet if I tried again to figure it out I could.

It’s time to try the next hurdle, and this time to start in Go. I have a Quad Alphanumeric display backpack here, and it’s supposed to work over I2C. So let’s get it soldered and breadboarded!

first done 3d print, first done code!

29 Jun 2021

categories: Lander Module

First tests are promising! I have completed a 3d-printed bracket mount for the digital joystick. I have also completed a short program that reads a single mom-off-mom toggle and latches an LED every time it goes up or down. I wrote it in Python, but my hopes are high that I can transcribe it to Go next. Some resources I should look into for that effort:

  • I have also ordered the 3rd round of parts from Adafruit and Digikey, and finished intake processing for the 2nd round. Upcoming experiments are:
  • write to a 14-segment timer/countdown display (using mission-start time, and also event-start time)
  • write to an OLED display, perhaps by putting a ship graphic overlaid on a landing zone graphic.
  • super extra credit: use an OLED display like an attitude gauge!
  • write a “main alarm” sequence, with buzzer When the 3rd batch of stuff comes in, I’ll be able to
  • play with I2C I/Os
  • vet some more toggle switches I should not purchase any bulk switches or buttons until after the second production meeting with Deeps, on 8 Jul.

oof, getting this first script done feels good. Hurdle over!

More thoughts, this time about upcoming 3d-prints:

  • should print a couple more joystick brackets
  • should print several more switch guards
  • should test hole size for m2 and m3 screws (for mounting PCBs on)

LED driving, I2C chains, pull-up and -down resistors

27 Jun 2021

categories: Lander Module
tags: gpio i2c

I’ve been getting up to speed on LED driving and button/switch driving, so that I can prototype a Raspberry Pi with code that reads a switch, and turns on and off an LED. A couple of thoughts here:

The RPi 0W has 26 available GPIO pins. This feels like a lot, but if I pair one or two LEDs with each toggle switch, I’ll run out quickly.

Next I found this AW9523 breakout, which controls 16 I/O over I2C. If I give up 2 ports on the main board itself for I2C, and I can chain 4 of these expanders together, that gives me a total of 88 I/O ports!

The printer code I’ve been working with so far in Tissubots takes the serial pins away too (Tx/Rx are GPIO 14 and 15), so we’re looking at about 86 pins.

what about our 14-segment digit displays? those run on I2C as well! first, know that they can be chained up to 8 in a row, so I only need one bus to drive all the segment displays on the whole console.

Can I run a second I2C bus on the pi? This instructable seems to think I can run 5 additional busses beyond the builtin one, if I modify the /boot/config.txt.

Where does that leave us? Out of the 26 available GPIO pins, maybe:

2 for tx/rx to printer
2 for I2C: 4 I/O expanders (64 pins)
2 for add'l I2C: all segmented displays (up to 8 4-digit backpacks)
2 for add'l I2C: 4 I/O expanders (64 pins)
2 for add'l I2C: 4 I/O expanders (64 pins)
2 for add'l I2C: 4 I/O expanders (64 pins)
2 for add'l I2C: 4 I/O expanders (64 pins)
12 remaining pins on RPi
64 * 5 + 12 = 332! :flushed:

ok so it’s time to order some of those expanders I guess.
I won’t use all those pins, obviously. In fact, I will probably set up one chain for just LEDs (using its nifty constant-current feature), and one chain just for buttons/switches/joysticks (using pull-up or -down resistors). I still have 3 (supposed) available I2C buses! maybe if I use a buzzer that requires its own breakout? or I could add in a little OLED display (4-wire SPI).

A “pull-down” resistor goes between digital pin and ground. Then put the button between voltage and the digital pin. The resistor pulls the pin down unless the button is pressed (connecting voltage).

A “pull-up” resistor is like “pull-down”, but swap the ground and supply nodes. All else being equal, it seems to me it would save power if we use pull-down. How to select the resistance: resistor should be “1/10 less than the input impedance of the digital pin” (does this mean 90% of the input impedance?) (or 10kOhm if you can’t be bothered).

RPi has onboard pull-up and pull-down resistors, but if we put all the buttons and switches on expanders we’ll need to use resistors in connection to the expander.

It would be especially cool if each panel on the console ended in its expander. That way it would be very quick to swap out a dud panel. Just need a board near the RPi that has all the JSTs for the different expanders. Maybe…huh, maybe even a Hat for it! Can I make my own RPi hat?

toggle switch guard print #1

18 Jun 2021

categories: Lander Module
tags: 3dp fdm

I printed out the “space shuttle toggle switch guard”. In plating I selected the single guard then did “Add Part” to expand it to a row of 5. Then, in print settings I made sure to go into Expert > Infill and set “Solid infill threshold area” to 16mm^2. This ensures there’s a solid infill for the upright portions of the guard, extending just below the joint with the side plates. Overall, quality was pretty low, probably due to all the jumping around, and bridging. For the next attempt, I may want to re-model the holes for the switches, since the switches I bought are nowhere near fitting the holes as-is. I might also want to try a build in a different orientation? or with different infill options (was it really necessary to use solid, or to use infill at all?) Anyway, good first attempt!

Oh, for the second iteration I could avoid the 12-hour time by just printing squares with holes in, and inset the squares to the guard I have! CA glue will be a key part of the build anyway.

In other news, first Digi-Key order arrived and it is great! Lots of buttons to push and the joysticks live up to their name (especially the ball-top one).

For the next round of orders I want to try to get a large square button or two, for a “main alarm” function. These can be pricey, but with only 1 on the board I think it’s worth it. I also want to try out some “standard round” toggle switches, because I can print out the cover to make it look more spacey.

Project start, core principles

17 Jun 2021

categories: Lander Module

A couple weeks ago Dr Professor asked me if I want to build a thing for Caravan Rally (happening this October). So far we’ve been talking about a “lander module” experience. Here are some parameters:

  1. it should be fun, engaging and diverting
  2. it should involve 2-3 people working together
  3. it should last about 5 minutes
  4. it should entail the operators landing a spacecraft
  5. it should be able to answer the question “how well did the operators land the spacecraft?”

Immediately my mind jumped to Moon Lander, and to the Apollo 11 VR experience. Drawing from those, and from this awesome Kerbal controllerf1, I’m building a game/toy/gadget that fits the above parameters.

I’m tracking parts and tickets in an Airtable.

Project is due in mid-September.

I will have regular meetings with Dr Professor to provide progress reports.


The main piece of this is a console that can fit in someone’s lap, have a bunch of knobs and switches and gauges on it, and be an operable computer for landing a spaceship.

The LM is meant to be operated by one person in a Caravan vehicle.


I’ve purchased a TI-99/4A to provide the “chassis” for this console.

I am experimenting with various buttons and switches that light up. I intend to build these into panels which can be screwed to the chassis, and plugged into a pcb. The pcb will connect the panels to power, and to a central controller like a Raspberry Pi or Arduino.

If I design any PCBs, their cad files will be stored in [a private] repository.

The whole thing will be powered by battery that may potentially be charged by USB and/or cigarette lighter.

Here are some ideas for devices that the console could use:

  • sliders, buttons, and switches. Momentary vs toggle.
  • a joystick, e.g. for precise control of maneuvering thrusters
  • dial or linear gauges. Not sure yet how to achieve this except perhaps a decal’d voltage meter. Perhaps a stepper motor and small screw.
  • 7-segment LCD indicators, e.g. for a mission timer
  • OLED or e-ink screen, e.g. for precise graphics
  • thermal receipt printer, e.g. for printing event summary, and/or scenario parameters
  • extra-special credit: real-looking attitude indicators
  • speakers, for playing sound effects of explosions etc.
  • buzzers, for when an alarm goes off.

More flighty ideas include:

  • the computer networks to a “GM” computer that allows a second human to control the sequence parameters
  • the computer networks to a small switch computer in each other car, to indicate caravan readiness
  • the computer has an audio output (cable, bluetooth, fm transmitter) for making the ship sounds be more…immersive
  • an on-board accelerometer and/or microphone, to implement an interaction like “if this gauge goes dead, try tapping on it”


The sequence code is another key part of this deliverable. It should fulfill the primary parameters, and if possible fulfill these secondary parameters:

  • the sequence should develop iteratively, so that I can always deliver a serviceable experience.
  • the layers of the application should stay separate, so that I may reuse them in future projects (that may or may not involve spaceships).

All source code will be stored in [a private] repository.


Another piece of this is a section of the Flight Manual dedicated to operation of the Lander Module (LM). This document will be read and interpreted by others in the Caravan vehicle.

The whole Flight Manual document will include more elements than I provide from this project.


Here’s where the fun starts. In order to keep it simple and deliver an MVP, I feel I should focus on core competencies:

  1. Main sequence. Player must push buttons in correct order to transition through multiple stages of landing.
  2. Controls include momentary and toggle inputs
  3. Indicators include a mission timer (counting up), event timer (counting down), and various LEDs
  4. Stages are: Atmospheric Entry, Main Drag (Parachute), Maneuvering, Touchdown

For each stage, the controls and indicators do slightly different things. For instance:

  • During Atmo the controls change the ship’s attitude, and the indicators show attitude, heat levels, and altitude. Final action to change stage is to eject the heat shield in a specific heat/altitude window.
  • During Main Drag, the controls are really just to deploy parachutes, and the indications are altitude, vertical speed, and ground speed. Stage exit is to cut the parachutes in a specific altitude/speed window.
  • During Maneuvering, controls are to align the ship with the landing zone, and make sure you don’t crash. Indicators are speeds, and some kind of “pointed-in-the-right-direction”-ness. Stage-exit action is to deploy landing gear when you’re in position and have 0 ground speed.
  • During Touchdown, controls are to burn the landing thruster. Indicators are speeds, and whether or not you went to space today.

That’s probably as simple as I’m willing to make it. If and when that’s done, I can implement new layers to it. For instance:

  • Parametric stages: These variables affect how the controls operate, but probably shouldn’t make the experience harder, just different. After all, the operators of this will likely get one “real” shot with it, so we can’t expect them to try many times, growing and learning.
    • Maybe the landing zone has really low/high gravity.
    • Maybe it has a heavy/light atmosphere.
    • The fuel or RCS mass starts at different levels?
  • Alarms: when the alarm goes off, it will blink various LEDs around the console. Based on which LEDs they are, there’s a different resolution pattern to perform (as detailed clearly in the Appendix of the LM Flight Manual).
    • the Heat Shield won’t separate, gotta blow the backup clamps
    • chutes won’t open, gotta deploy the backups
    • landing gear won’t deploy, cut throttle and blow airbags
  • Glitches:
    • maybe a DRO wonks out and starts showing garbage.
    • Maybe the whole console goes dead until you “power cycle” it.
  • New Sequences:
    • There’s an opportunity for a single “Launch” sequence at the beginning of the Rally. Maybe we could use this console for that too.
    • Maybe there’s a Training sequence for people to play with in the car before they have to do the real thing.
    • Maybe there’s a choice of landing zone.
  • More complex stages:
    • the Drag stage splits into two, for fast chutes and slow chutes
  • More complex inputs and outputs:
    • the Touchdown stage gets a screen and a joystick, and a “Moon Lander”-esque feel.

Questions for Design Team:

  • should we implement a Training Mode that lets them practice landing, say, on the Moon?
  • will we encourage teams to write their own margin notes in the Flight Manual?!


25 Nov 2020

categories: steno
tags: qmk plover

I just realized: using alt to mouse-select multiple cursors in VS Code does not trigger the OSL to fall back. Is that a task I do with the dictionary instead? No, dictionary can’t help there. HMM!
Perhaps a key on the symbol layer that does a TO(BASE). yup, that works!
I’ve also printed out some cheat-sheets, and now I guess nothing is stopping me from developing some muscle memory…

I’ve started a tiny bit of coding with steno. It’s alive! Starting to think about building my own “single stroke commands” dictionary, but because it’s so many different chords, thinking of building a generator that takes an input of all the chords for each modifier (plus a few others for nav/cursor control), and then it prints out all the hundreds of permutations! Some things I’m learning about dictionary entries as I do this:

  • a / is present to delineate strokes

  • a - is present to delineate left-hand vs right-hand, but only

    1. if there are no left-hand keys in the chord
    2. if writing it down without a - would show ambiguity (HRPB is either HR-PB “license”, or H-RPB “hit-and-run”)
    3. if there is no ambiguity? (e.g. *ET/K-L “ethical”)
    4. only if there’s also no *.

    Does Learn Plover! have anything to say on this subject?

    When defining dictionary definitions by hand, you should be sure to include the hyphen when appropriate

    I think I can handle that. Why not always generate a - until I see it break?

One final note, someone’s blog recommended keeping the dictionary handy, that being able to quickly add or edit definitions was really helpful. I wonder if I could set up a single key in my layer or a brief in a dictionary to run that Plover function?


24 Nov 2020

categories: steno
tags: ergodox georgi

Made a cheat-sheet for the single-stroke commands dictionary tonight. Did my first cut, paste and undo! The shapes are a little goofy but I think they’ll suffice for my needs. Might even allow me to free up some keys on the firmware layer (no need for arrows, letters, or functions).
I did order an Ergodox. The clutter argument was very compelling. It’ll take 4 weeks to get here, so in the meantime I’ll keep practicing on Georgi.
I’m excited to put together a firmware for Ergodox that does everything I need–and with LED control!


23 Nov 2020

categories: keebs steno
tags: qmk butterstick georgi ergodox

A few things I noticed in practice tonight

  • tapping the OSL key doesn’t let me alt-tab with impunity, but holding it does.

  • my custom nav layer doesn’t support select-all, cut, copy, paste, undo, or redo. I wonder again if I should record the number of times I use a feature in a day, and put those at the front and center.
    oh, also ctrl-backspace (or alt-bsp and cmd-bsp on mac).
    Even if I put my most common commands on the first nav layer, I still need either

    1. (hw, current status) a qwerty keyboard standing by.
      pro: I have it (it’s free)
      con: slow to switch from typing to commanding
      con: BIG desk clutter
      con: need the qwerty keyboard for typing while learning steno
    2. (hw) a macropad (e.g. Butterstick) standing by.
      pro: I have it (it’s free)
      con: slow to switch from typing to commanding
      con: smol desk clutter
      con: need the qwerty keyboard for typing while learning steno
    3. (fw) three or more layers on the georgi.
      pro: I have it (it’s free)
      pro: everything is at my fingertips (it’s quick to switch)
      pro: no clutter!
      con: patience and time to tweak and learn the layers
      con: need the qwerty keyboard for typing while learning steno
    4. (hw) A BIGGER georgi, with more keys to hand (see: Gergo. I think maybe Gergoplex isn’t enough columns).
      pro: it’s a kit I can build myself (another round of custom switches, this time maybe kailh silver?)
      pro: everything is at my fingertips (quick to switch)
      pro: no clutter!
      pro: less need to layer the commands (quicker than switching)
      pro: do not need a qwerty kicking around while I learn steno
      con: hard to program it to be steno sometimes and command sometimes?
      con: I’d need to build my own enclosure for it.
    5. (hw) white tiger option: get an ergodox already (~$350).
      pro: it’s a kit I can configure myself (it does hotswap)
      pro: everything is at my fingertips
      pro: no clutter!
      pro: less need to layer the commands
      pro: do not need a qwerty kicking around while I learn steno
      con: hard to program it to be steno sometimes and command sometimes?
      con: expensive
    6. (sw) learn and develop the Single Stroke commands dictionary in Plover.
      pro: I have it (it’s free)
      pro: VERY easy to reconfigure a broken brief on the fly
      con: need the qwerty keyboard for typing while learning steno
      con: patience and time to tweak and learn the briefs

Options 4 and 5 (Gergo and Ergodox) are similar enough that I can runoff them: With Gergo, I have to design and build the enclosure, and buy keycaps and switches. With Ergodox, I just have to spend ~$280 marginally (and maybe make or buy steno-friendly keycaps). With Gergo, I get to make it look however I want, with Ergodox, no such personalization.

+ personalized  - cost
- kit work      - not personalized

Actually, now that I think about it, the Gergo wouldn’t be a full size qwerty, so I’d be training (1) steno, (2) columnar qwerty, and (3) gergo commands and shortcuts for qwerty. Ergodox loses on customization, but “costs” less in terms of money-work, and wins on me not doing that (3) training.

I’d also point out that the “do not need the qwerty keyboard for typing while learning steno” is not worth nothing.

In the end it’s really down to an ideological choice: do I want to do this retraining of my brain and fingers through software, firmware, or hardware? And even if I do it through software, do I want the greater hardware anyway to speed things along, declutter the process, and/or be more ergonomic for me? (For the record I have yet to experience any RSI…)

I will sleep on it.


22 Nov 2020

categories: steno
tags: qmk butterstick georgi

Last night / this morning I read a lot about how QMK works with layers. Then I worked up keymaps for both the Butterstick and the Georgi!
The first milestone is complete: I can successfully alt-tab any number of times!

Next milestones:

  • make the nav layer key (and fn layer key) momentary-layers (like OSL, but that didn’t seem to work immediately).

    OSL(layer) - momentarily activates layer until the next key is pressed. See One Shot Keys for details and additional functionality.

    // One-shot layer - 256 layer max
    #define OSL(layer) (QK_ONE_SHOT_LAYER | ((layer)&0xFF))

    Defined in quantum/quantum_keycodes.h and used in the action_for_keycode function of quantum/keymap_common.c.

            // OSL(action_layer) - One-shot action_layer
            action_layer = keycode & 0xFF;
            action.code  = ACTION_LAYER_ONESHOT(action_layer);
        case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:;
            // OSM(mod) - One-shot mod
            mod         = mod_config(keycode & 0xFF);
            action.code = ACTION_MODS_ONESHOT(mod);

    which leads to

    #define ACTION_LAYER_TAP(layer, key) ACTION(ACT_LAYER_TAP, (layer) << 8 | (key))
    num action_kind_id { ACT_LAYER_TAP = 0b1010 /* Layer 0-15 */ }
    #define ACTION(kind, param) ((kind) << 12 | (param))

    Of course all this code is just a bunch of bit shifting!
    Let’s try OSL() one more time, just in case…
    Yeah, it’s probably because I had #define NO_ACTION_ONESHOT in my config.h, huh?
    Nope, OSL still isn’t working on the georgi. Switching to Butterstick to see if it’s a steno mode thing.
    Yes, OSL works on the butterstick. Also, implementing oneshot_layer_changed_user in keymap.c makes it print to the QMK toolbox (I wasn’t seeing those prints from Georgi).
    Switching back to Georgi for one more shot, then I’ll compromise with TG and hope I don’t get in a bad layer state.

    I got it! I had to delete the #define NO_ACTION_ONESHOT, and go into (beware there’s one for the keyboard and one for the keymap!) and set NO_TAPPING = no! Now I can use OSL to shift layers.

  • maybe write a custom function like TH(kc1, kc2), where if you tap it sends kc1, and if you hold it sends kc2. For inspiration:

    LT(layer, kc) - momentarily activates layer when held, and sends kc when tapped. Only supports layers 0-15.

    // L-ayer, T-ap - 256 keycode max, 16 layer max
    #define LT(layer, kc) (QK_LAYER_TAP | (((layer)&0xF) << 8) | ((kc)&0xFF))
    // M-od, T-ap - 256 keycode max
    #define MT(mod, kc) (QK_MOD_TAP | (((mod)&0x1F) << 8) | ((kc)&0xFF))

    Since stubbing this out and then playing with my layers quite a bit above, I realized I had an extra blank key next to the media keys, so I no longer need to double up TH(KC_VOLD, KC_MUTE), but maybe it’d be a fun experiment sometime anyway. Another day. Today my nav and media layers work great and I should take some time to practice them (and to practice steno lol).


20 Nov 2020

categories: steno
tags: plover wsl qmk

I adopted a nav/command dictionary that I found on the internet.

I have by now also read the section in Learn Plover! about dictionaries, so I feel well-equipped to start tabbing my way around.
The only real trouble is (on a Windows machine) I keep this repo checked-out to a directory in WSL2, which is not (easily) accessible from Windows, where I’ve installed Plover. Whoops.

Ok, I realized (again) that this will not solve all my nav use cases. I still need a way to alt-tab that either lets me hold alt while hitting tab any number of times (and sending those inputs individually, so I can see results), or I need a brief for “hit alt-tab twice in a row” etc, up to like 4 or 5 (the max number of windows I’d want to be open in a space anyway). Gonna try setting some of my own nav briefs for this.

<experiments with Alt_L(Tab Tab Tab) ensue>

I think this particular behavior is not something I can achieve with steno. Perhaps it is time to back up and take another look at the QMK symbol layer bound to my bottom left pinky key. Another night.


19 Nov 2020

categories: steno
tags: plover georgi qmk

Today I updated my qmk_firmware repo [now deleted] to match what Jane has on their side. I tried a PR, but that got really mucky with a changed file and a changed submodule, so I backed out, saved patches of my commits, and completely remade my fork. It turns out the changed file also hit my new fork (wtf?), but the patches applied just fine.

Last night I read about dictionaries, and how Learn Plover! teaches the shift/ctrl/alt/super keys. It’s interesting, and I’m ready to start tinkering with my own dictionary for nav & control. I also tried using the Georgi’s pre-baked Symbol layer, but had some trouble with the alt-tab behavior I expect [see previous post].
It’s worth re-flashing with the updated qmk from germ/qmk_firmware, and if that doesn’t work I can still try my own symbol map and if THAT doesn’t work perhaps I can fall back to using a steno dictionary entries to define “alt-tab once”, “alt-tab twice” etc.


17 Nov 2020

categories: steno

Maybe I’ll be satisfied looking at the progress.json activity page to see how consistently I’m practicing. It’s no heatcalendar, but it’ll do.

In other news, I’ve got a cheat sheet of punctuation and whitespacing (the book didn’t mention, but it’s T*AB for a tab character). Next item todo is to figure out how people manage modifier keys and navigation keys.
The real crux is this use case: hold down ctrl (or cmd). Press tab any number of times. Also hold shift. Press tab some more times. Let go of shift… let go of ctrl (cmd).

plover v4.0.0

15 Nov 2020

categories: steno
tags: plover

Upgraded to Plover v4.0.0. When they say “back up your plover.cfg” that file is in C:\Users\<username>\AppData\Local\plover\plover\. Wondering if there’s a way to stay accountable for daily activity without bloating this journal file.


14 Nov 2020

categories: steno
tags: plover

journaling with steno now! ok back to qwerty. that took a few minutes, but I’m having fun learning about the control mechanisms (to insert a space or not, to capitalize or not), as well as punctuation and positioning chords. I’d like to try to find a testimonial about Plover’s “space placement” option (before or after chord output). I feel like that option may (a) have a medium-to-large impact on the workflow for coding vs prose, and (b) be really hard to retrain later.


13 Nov 2020

categories: steno
tags: georgi

Got a little practice in. I realized I’m not yet ready to fully drop the progress-tracking. My reasoning is that I’m doing this from at least 2 different computers still, and Typey Type doesn’t have user accounts, so if I want to track progress there I should copy the file down after every session.
Thankfully I was able to quickly build a CLI tool that will help me merge two JSON files into one, summing the values along the way. That should help in the task of saving the progress JSON at least.

I also remembered that because Georgi only has the two rows for my fingers instead of a steno machine’s standard 3, the third thumb button (on both sides) is my number bar modifier.
I wonder again how I might use the extra two pinky keys on the left side too, since I probably won’t need–wait…i’m not so terrible at georgi qwerty! [that last phrase only took several minutes to puzzle out, and even then i didn’t know all the punctuation keys]. Anyway, even while I’m doing steno I’ll want a way to hit arbitrary shortcuts. That’ll be interesting.


12 Nov 2020

categories: steno

Started the spilliams/steno repository! I hope in the end it’ll contain useful tidbits I picked up along the journey, as well as any custom dictionaries I develop.

Some historical background on the journey so far is below. Going forward, I don’t want this journal to be just a list of wpm counts and times (though I’ll certainly include some for milestone tracking). The last few times I dusted off the steno machine I ended up putting a lot of effort into time- and wpm-tracking, so much that it became Not Very Fun Any More.

Less of that from now on, focussing on the fun parts instead!


20 Feb 2020

categories: steno
tags: georgi

1 day of practice in February. 13wpm on Georgi.


16 Dec 2019

categories: steno
tags: georgi

1 day of practice in December. Still hovering around 10 wpm on Georgi (using Typey Type). I started punctuation though!


25 Nov 2019

categories: steno

4 days of practice in October. 1 in November.


6 Oct 2019

categories: steno
tags: soft/hruf georgi

That stint in August lasted 5 days. Seeing a pattern…
It’s ok though. I’m having fun with this when I have fun. Any practical effects will be a nice bonus, but not worth beating myself up about if I don’t achieve.

In August I got up to about 16 wpm on Typey Type with the SOFT/HRUF.
Now I’m using the Georgi, around 13 wpm on Typey Type.


25 Aug 2019

categories: steno
tags: soft/hruf

That stint in May lasted 4 days. Back at it now. 10 wpm on Typey Type with the SOFT/HRUF.


12 May 2019

categories: steno

I took baseline typing speed tests at with my 2015 macbook air and WASD v2 keyboards: 73 and 76 wpm, respectively.
I also started learning the SOFT/HRUF machine, with an initial count of 8 wpm on Typey Type.