Jeff Epler's blog

9 July 2020, 17:55 UTC

Raspberry Pi Gross Hacks

Are you getting messages like "Leaving diversion of /boot/.... by rpikernelhack" and then the new/updated kernel won't install? Run this awful command as root:
dpkg-divert --list | grep rpikernelhack  | while read _ _ a _ _ _ _; do dpkg-divert --package rpikernelhack --no-rename --remove $a; done
and it _might_ fix your trouble.


29 June 2020, 1:19 UTC

Software I want: Self-hosted 3D-printing static site

I've been 3D printing for years, and when I started a site called Thingiverse was pretty good—it emphasized Free licenses such as Creative Commons, and on/near the front page you could discover some novel designs.

However, that site has suffered from a severe lack of love from Makerbot, in part due to not directly generating revenue; recently, it got a redesign that added ads (okay, fine; I'd love a paid model which took the ads off my uploaded designs, though) but also turned the front page into "here are a dozen or so "popular" designs, which seldom/never change". The search and tag experience got much worse, etc.

At the same time, the cost of hosting a static site is really low now—even free, if you don't mind depending on a Github or Gitlab to do the real work for you.

This makes me see an opportunity to write a neat piece of code: A general framework for a static site generator that is designed to host 3D printing files. Here's the basic view of what I would like to see:

  • The basic site framework will be generated with cookiecutter
  • framework will use a well established static site generator such as Jekyll or Sphinx
  • comes with CI that works on github; other-host support actively solicited
  • can show STLs using webgl and probably three.js
  • is supplemented by a build system that
    • knows about scad files, including generating many variant STLs from one scad
    • generates png previews from STLs
  • does its best at presenting good metadata in Open Graph format

Stuff that is out of initial scope:

  • Multiple "projects" per git repository
  • Fancy site styling
  • Other file formats besides scad/stl

Things that are probably outside of ultimate scope are:

  • Customizer
  • Directly reproducing "social" features such as "like" and "comments"
  • Invasive tracking, including invasive social sharing buttons

A couple of hours this weekend let me get a good solid 60% of the basics going (most everything but the 3d model viewer), but also showed that I need to understand Jekyll better before trying to create something substantial in it. The Liquid template language is (deliberately, I imagine) quite limited, and consequently my initial ideas about how to represent the various resources (scad, stl, png, jpeg; generated or not generated) didn't really fit with how templates worked. I don't know whether this means I'm better off switching to another generator such as Sphinx, or whether I should fight it out because (Python projects aside) Jekyll is a lot better known in general.

As much as I like this idea, where I think it falls down is: My main quibble with Thingiverse is around how poor discovery has become. But a one page static site for a 3D-printable model is bound to be even worse for discovery. What search terms would you use on a general purpose search engine to find them? Where do you go to discover some designs you didn't even know you were interested in? (I don't want to do a heap of keyword-bait on each page, I have no knowledge of SEO and anyway the very idea leaves a bitter taste in my mouth) However, if you build a community elsewhere (e.g., on Mastodon) then maybe discovery moves there; A link, a common hashtag, and boost/favorite what looks neat. Would it work? Probably not. And don't even ask about RSS.


16 June 2020, 14:04 UTC

Black Lives Matter

I don't have eloquent words on this subject. Go read others who do.


19 March 2020, 19:41 UTC


Hi! Looks like this blog has gotten a bit stale. A lot has happened in the last year or so, and a lot is happening right now.

Due to luck, privilege, and a high savings rate, Ingrid and I felt we were getting within a few years of early retirement. In my own mind, I thought I was content to continue to work in the job I had been in since 1999, all the way until early retirement sometime in the 2020s.

There were a lot of good things about this job—I worked with several of my closest friends, the specific tasks sometimes were really engaging, and it enabled us to live without a care for money.

In the spring had I decided I might leave, but only if I found a job that felt "special". I had a few interviews with one company in the 3D printing space but I was adamant that I was staying in Lincoln and in the end the other company decided they were seeking someone to work on-site in Boston.

However, day to day life at the company was changing. Two close friends moved away and became remoties; another left to start his own business. The company, having been sold by the founder a few years earlier, had a small round of layoffs and the CEO was replaced. On the dev side, I was allocated 50% to 3 different projects for an extended period of time. ha ha not joking, though I still only clocked 40 hours of work a week, in part due to reaching a point of not caring whether I got fired or laid off. Technical debt felt insurmountable.

In June, just after the CEO was replaced, I was already coincidentally going to Seattle and had made plans to meet Scott Shawcroft (@tannewt) for coffee. I had made some small contributions to the project he heads, CircuitPython, a year earlier. I told him a little about what I was experiencing, and then asked him how he liked contract programming. Before I knew it, I'd agreed I'd put in a propsal to Adafruit to do a paid project on CircuitPython. Working for Adafruit felt like the proverbial "special" job.

Later on, I learned that in January for #circuitpython2019, Scott had written

Community is one of the defining aspects of CircuitPython and Adafruit… As we grow bigger and bigger we need to continue to empower community members to help out at every level… Specifically, I want to find more people to:
  • Help create and review core C changes (aka more @danh) including:
    • Modifying the supervisor
    • Adding additional platform support
    • Supercharging the skeleton systems like audioio and displayio.

is that my exact job description or what? (well, it's pretty close)

He also mentioned that Kattni would be keynoting at PyOhio, and I made plans to attend that conference the next month. Every talk I sat in somehow sent me the same message: my current job was not working for me, and I needed to make a big change. Kattni, who had already supercharged me with her talk about the importance of community, encouraged me that I should ask Adafruit for what I wanted.

I only sort of listened, asking for and getting one or two more one-off projects. But, of course, *extra* work and extra money weren't what I was looking for. I also interviewed with a remote-first contract development software company who had a booth at PyOhio. They seemed to be mostly web oriented but interested in getting into embedded/IOT space. In the end they didn't make me an offer and I was less convinced it would be a fit for me anyhow.

Then finally in August I did ask Adafruit for what I wanted: half time work on all parts of CircuitPython. They said yes the next day. For a variety of reasons, though, I didn't switch jobs until November. (I would do _that_ differently next time! Getting PTO for my Japan vacation was not worth that much) Since then, I've been doing around 20 hours a week of hacking on CircuitPython, and I've started finding the interest to do other personal projects. I've built two 3d-printed and hand-soldered keyboards, including one I designed myself. (It's my daily driver and the only thing I regret is that it works so well sometimes I forget I'm using a keyboard I designed myself!) I laser cut some designs in acrylic that I couldn't have done any other way. And I finally made a complete etched glass edge-lit display (albeit a single digit).

On the other hand, I've moved into a time of more uncertainty. Our 2020 household budget didn't entail giving up anything, except that we wouldn't be making any more retirement investments. Of course, those investments are down some obscene percentage and will probably go lower before they start to increase. So full retirement moves an indefinite distance into the future, at least as long as I choose to work only part time. (even before this Ingrid joked that we would be able to retire after the next recovery. I guess she's right)

Other "this never happened in any other year" events in the last 12 months: I've had foot surgery, eye surgery, and an unexpected dental crown breakage. Ingrid had a health scare of her own (and, thanks to high deductable health care, this is basically all out of pocket). We experienced a typhoon in Japan. Now, with COVID-19, we've canceled multiple trips, and we're worried about friends and relatives and the general condition of society over the next weeks or months. Right this second, we are under a tornado watch, unusual for this early in the spring; and then temperatures are forecast to drop like a rock and things will freeze overnight, so global climate weirding continues unabated.

However, I've taken my best old-work friends with me to new chat systems, I've got new friends at Adafruit (who are being extremely supportive of all their staff and contract workers like me even while they've had to suspend physical operations) and a local makerspace. At the moment I feel like I have the mental space to deal with "stuff".

The first time I drafted this story was a few weeks ago, and I ended with a caution against thinking you're at the end of your story--it's what kept me in a job that wasn't right for me anymore. Right now doesn't feel like a moment you'd mistake for the end of a story, but all the same we need to remember not to see ourselves as stuck. We need to examine what is going on and make the right changes to move forward.

No huge promises to keep up the blogging. But if you're interested in seeing what I'm up to in software, stalk me on github or join the Adafruit discord. You can also find me posting designs on Thingiverse when I have 3D printing ideas. I dabbled in twitter for about 5 minutes again but haha no no way not twitter.


2 January 2020, 21:15 UTC

Six Years of Prius (2013) Fuel Efficiency

Year Miles MPG Gal
2014 7546.8 44.4 170
2015 7333.6 43.9 167
2016 9368.8 44.8 209
2017 9936.2 45.1 220
2018 8853.6 42.0 210
2019 7188.6 40.1 179

Our total distance traveled was lower again this year, as was the fuel economy. Once again, I'm disappointed with the overall fuel economy--It's the lowest number of miles, but the third from the lowest number of gallons consumed.


25 June 2019, 1:39 UTC

Future directions for SCORPION STARE: 2022 Grant Recipients

Distribution: General / non-confidential

It pleases Us to announce that the following experimental research programmes will each receive £10,000,000 guaranteed and inflation adjusted anually for three years:

Two-diode imaging (Dean, Salem, Chen)

Single-pixel cameras have been an area of research for two decades, and it has been understood for even longer how to use a reverse-biased LED to measure ambient light levels. Combining the two technologies with SCORPION STARE could potentially allow 'STARE devices to be miniaturized into millimeter-scale passive devices.

Deep Stare (Wu, Angelov, Soleymani)

Technology like Deep Convolutional Networks, AGAINs, and the like have made it possible to create plausible images from archetypes. Deep Stare, if its promise can be realized, will allow remote / non-line-of-sight deployment of STARE technology against enemies of the state. All that is required is an accurate image generating model, coupled with petascale iteration, to neutralize a threat based on a description. Imagine that you can simply input "a 25-year old caucasian male insurgent stands in front of a High street shop, waiting for the right moment to unleash the demonic threads even now coiling in his belly", and before he can act, he is turned into radioactive slag.

Stereo acoustic imaging (Toth, Ben-Amram, Toth)

It will happen to one woman out of four in her lifetime: that hoped-for pregnancy converted to tragedy when her gynecologist explains that the embryo is (the wrong kind of) nonhuman. Stereo acoustic imaging promises to allow easy, outpatient treatment for our most precious resource, fertile females.

Civilian Applications

We also wish to announce funding of the following programmes to create civilian applications for SCORPION STARE technology. Each programme will receive £100,000 in the first year, with possible increase to £500,000 per year based on progress. In exchange, the Crown is awarded 27% of eventual revenues, in purpetuity.

  • Chain-free "chainsaw"
  • Single-use heating pads
  • Assisted suicide VR Goggles
  • Insect Control Cameras
  • Artificial Tanning Beds

His Majesty would like to congratulate all surviving entrants for their inventive grant proposals.


6 June 2019, 12:19 UTC

Yet another Raspberry Pi Stratum 1 NTP server

There are lots of instructions for setting up a Stratum 1 NTP server on your Raspberry Pi. A lot. After much research, I found a simple configuration that uses a single ntp reference clock and does not involve gpsd, but uses both NMEA and PPS for the most accurate timekeeping possible. NMEA+PPS is a mode of NTP's "Generic NMEA GPS Receiver".

Here's what worked for me:

Start with a pi3 and raspbian stretch. Add a GPS with TTL-level PPS and 9600 baud NMEA outputs.

Hook up you GPS: GND and +3.3V or +5V (according to the specifiics of your GPS) to any matching pin, the GPS's TX output to the Pi's RX input on pin 10 of the header, and the GPS's PPS output to the Pi's pin 12. (You can hook up your GPS's RX input to the Pi's TX output on pin 8 if you like, but I don't think this is necessary)

Using raspi-config, disable the serial console and enable the serial port hardware.

Manually edit /boot/config.txt to add: dtoverlay=pps-gpio — If you have to (or prefer to) use a different pin for pps, you can apparently specify it as dtoverlay=pps-gpio,gpiopin=##, where ## is the internal numbering of the GPIO pins, not the number on the 40-pin header.

Manually edit /etc/modules and add a line that reads pps-gpio — According to some sources, this step is not necessary.

Install ntpd with apt-get.

Delete all the content in /etc/dhcp/dhclient-exit-hooks.d/ntp, leaving an empty file.

Remove the file /run/ntp.conf.dhcp if it exists.

Edit /etc/udev/rules.d/99-com.rules. On each of the two lines that ends , SYMLINK+="serial%c", append , SYMLINK+="gps%c"

Create /etc/udev/rules.d/99-ppsd.rules with the content SUBSYSTEM=="pps", GROUP="dialout", MODE="0660", SYMLINK+="gpspps%n"

In /etc/ntp.conf, add a stanza to access the GPS:

# gps clock via serial /dev/gps0 and /dev/gpspps0
server minpoll 3 maxpoll 3 mode 16 burst iburst prefer
fudge refid GPS time2 +.250 flag1 1
(leave the "pool" line(s) or other ntp server lines; if your pi doesn't have a battery-backed RTC, you need a way to get the correct time initially, before a GPS fix may be available!)

"time2" doesn't seem critical with this setup, because the PPS time is preferred over the serial reception time. "minpoll", "maxpoll", "burst" and "iburst" may be superstitious and unnecessary.

Reboot now and have a look at `ntpq -c peers`. You should see something like this:

     remote           refid      st t when poll reach   delay   offset  jitter
oGPS_NMEA(0)     .GPS.            0 l    1    8  377    0.000   -0.001   0.003
+ntp.u           .GPS.            1 u    2    8  377    1.104    0.013   0.064

"GPS_NMEA" is selected as peer and is using PPS (this is what "o" in the first column means). delay, offset, and jitter should all be extremely small (Here, .001 is 1 microsecond). "ntp.u" is my other local stratum-1 NTP server. The "+" indicates it's in good agreement with the local GPS. If you use pool, you will see multiple lines here; some may have "+" and some may have "-".

If something's not working, you will get, " " (blank), "-" or "x" next to GPS_NMEA. If it's got "*" then NMEA is working but PPS isn't. Now you get to do things like debug whether the PPS signal is working properly according to ppstest, whether NMEA messages are actually coming in at 9600 baud, etc. Or you can follow one of those other guides. :wink:

Here's how the local time to GPS offset has looked over the last 10 hours or so — I find it awesome that my computer appears to be synchronized to GPS to within ±5 microseconds almost all of the time:


3 June 2019, 1:17 UTC

Precision vs Accuracy: A Clock

I was inspired by this watch face design (I think that's the original version) and by the arrival of a "OCXO", a very reliable time keeping circuit, to finally make an electronic clock.

Accuracy: Between hardware and software tuning, the OCXO keeps time with an accuracy of possibly better than 100 microseconds per day (loses or gains well less than a half second per year) (Yes, I'm deliberately ignoring a lot about crystal aging here!)

Precision: The time displayed is to the nearest minute, and the touchscreen setting mechanism is (deliberately?) poor, making it hard to set the time closer than +- 2 minutes or so. Oh, and it takes a good fraction of a second to update the screen anytime it changes. (The best way to set it seems to be to wait until a few seconds before 6AM/6PM and plug it in, since it boots with that time showing)

The clock consists of: .. all in a 3d printed enclosure that's not quite the right size.

The dial as an animation (1 revolution = 12 hours)
Along the way, I added an even more accurate time source to a Raspberry PI (GPS with PPS) so that I could even measure the accuracy of the OCXO, and discovered I even have a GPS module which was negatively affected by the GPS rollover that occurred in April of this year (the second 1024-week rollover). This leads to a surprising sequence of clock arithmetic, and finally gpsd decides the GPS is returning a date sometime back in 1963.


20 April 2019, 15:11 UTC

Hello, Allo

20 April 2019, 14:54 UTC

Another Qidi Tech I update

9 March 2019, 1:33 UTC

The Drake-Howard Equation

23 February 2019, 16:52 UTC

Re: Ideas box submissions

All older entries
Website Copyright © 2004-2018 Jeff Epler