← Back to Kevin's newslettersPublished: 2024 August 16

Note: GMail misclassified my last newsletter as spam for many readers. ¯\_(ツ)_/¯ If you missed it, you can read it and all past issues at https://kevinlynagh.com/newsletter/.

Upcoming travel

Let me know if you want to grab a coffee in any of these places!

Robotic inventory management

A friend of mine has developed a robotic system for accurately dispensing exact quantities of small, loose parts (nuts, bolts, screws, etc.). He recently asked for my advice on how to set up an online shop: In particular, he wants online orders to automatically trigger his system (send CAN bus messages to print labeled bags, drop them onto conveyor belts, dispense parts, etc.) so that all he has to do is hand over the bags to the delivery service.

While this is quite a well-trodden problem space, I’m chagrined that there aren’t any solutions I feel great about.

Shopify seems like an obvious choice, but my initial few hours of exploration surfaced several impedance mismatches:

On the other hand, it’s not clear to me how to build this system without having to tackle a bunch of incidental complexity. Even assuming we use Shopify (or another service — open to suggestions) as a frontend for payments, collecting shipping addresses, etc., that still leaves the inventory management and robotic fulfillment system.

Conceptually the system design is straightforward:

From a modeling perspective I’m confident I can use something like Rust’s Algebraic Data Types to make nice lil’ state machines for the business domain. However, there’s tons of complexity around incidental, boring stuff:

All of these are solved problems in the large, when you’re on EC2 and have an army of developers to write serialization/deserialization plumbing, implement data migrations, and operate your Kafka clusters or whatever.

But how can this sort of system be built in the small? What’s the best solution for a one-person operation selling (at most) a few hundred orders of maybe a few hundred components a day? That’s just megabytes of data, and (in theory) a single computer should be more than sufficient.

But in practice, what are the options? Duct-taping Shopify together with Google Sheets / Airtable / Retool?

I’m curious about how y'all would solve the more general systems/information management problem here.

Like a moth to a flame, I’m tempted to try hand-rolling some kind of Rust framework built on top of durable queues with web UI and schema migration. But before I do, I’m curious to hear about what y'all might try. Open-source frameworks? Commercial apps? Abandonware from the 90’s? I’m all ears!

I find LLMs useful

My friends seem divided into two groups: Those extremely excited about LLMs and using them daily, and those who’re skeptical and/or who’ve bounced off ‘em. I spent most of 2023 in the latter group, but after seeing enough specific examples of people solving their problems with LLMs I kept trying to use 'em and have now had enough successes that I’m firmly in the “yeah, these are great” category.

I shared a few of my discussions with GPT-4 back in February, and this time I want to shout out the Cursor IDE. It’s a fork of VS Code that has a few specific UX iterations that make it easier to interface with LLMs:

Being able to say, e.g., “Use only types and methods in @stm32f103c8” is extremely helpful for generating good output with the Rust Embassy framework, as it relies on chip-specific code generated at build-time from macros and build.rs scripts.

I find LLMs shine when writing Rust, as:

Most of the benefit I’ve gotten from LLMs hasn’t been skill-enhancement but motivational — they help me emotionally overcome the dread/boredom of fighting with the Nth UI library of my career or writing out Arc::new(Mutex::new(...)) for the thousandth time. In situations where previously I would’ve just not coded anything at all, now I’m more inclined to try coaching an LLM for 5 minutes, which sometimes yields cool results.

For example, I was streaming a voltage signal from an embedded platform to my computer via USB, where I was just printing the numbers to stdout. I realized it’d be nice to have a live oscilloscope-type view, but it wasn’t something I wanted to sink an hour into. I copy/pasted my print-USB-to-stdout to a new file, then asked Claude (via Cursor) to convert the code into a a graphical app displaying a line chart using the egui Rust framework.

It generated a page of code, but that failed to compile because the egui folks had factored their line chart out into a separate crate. So I indexed that crate’s documentation and said “Please refactor to use the new egui_plot crate as documented @here”, Claude fixed the errors, and I had a running plot up in about 5 minutes.

I noticed the plot wasn’t updating as fast as the stdout streaming had been, and realized that the version Claude generated only polled for new data on every frame (60 Hz) rather than at the full rate allowed by USB (1000 Hz). I said:

Extract the USB reading into a separate thread so that we always read the USB as fast as possible, regardless of how often the app update function is called.

I’ll spare you the diff, but Claude did pretty much what I asked. Here’s a snippet of its response:

Here’s a brief explanation of the changes:

  1. We’ve introduced Arc<Mutex<>> to safely share the samples between threads.
  2. A new usb_reading_thread function has been created to continuously read from the USB device.
  3. The main function now spawns this thread before starting the GUI.
  4. The ADCApp struct now only contains the shared samples.
  5. The update method of ADCApp no longer handles USB reading; it just displays the data.

These changes ensure that USB reading occurs continuously in a separate thread, while the GUI updates independently at its own rate.

Again, not a skill issue — all of this makes sense to me and is pretty much how I would’ve done it. I didn’t have the energy to eat this low-level programming garbage, but I had the energy to supervise an LLM which turned it around in literally 10 seconds.

Nicholas Carlini has a ton more examples.

Health/exercise follow-ups

After the last newsletter, one reader recommended SiPhoX Health, a $165/quarter bloodwork-by-mail service for measuring biomarkers like ApoB, Vitamin D, HDL/LDL/total cholesterol. Sounds like it may be cheaper (and definitely more convenient) than dropping into a Labcorp for a blood draw.

A few other folks wrote in to add on the “saving for later” theme, recommending:

Yes, all good ideas, highly recommended!

As for my fitness routine::

Exercising five times a week is the most frequent routine I’ve ever done, and so far it feels great — underscoring that, at least for me, not exercising is what makes me tired.

Casual statistical modeling + learning NumPy

I’ve never formally studied statistics, so at a friend’s recommendation I’ve been working through McElreath’s Statistical Rethinking with his 2023 online lectures. (Don’t skip the latter — McElreath has a great sense of humor.)

The book and lectures do a great job walking through examples of building casual graphs to precisely define your model of interactions between variables and justify why you do or do not “control” for some of those factors. There are both fun examples (“does Waffle House cause divorce?”) and ones relevant to topics in the social/pop-science discourse (“do people get happier as they get older?”).

The overall approach taught in the book is to:

This appeals to me as a broadly useful, general approach — rather than shop around for some closed-form “test” that has a bunch of assumptions baked into it, I can just write some code and throw compute at my problem.

I’ve also been skimming Pearl’s Causal Inference in Statistics, which prompted me to have a go at generating Simpson’s Paradox using Z3.

While going through Statistical Rethinking, I’ve been using this Python/Numpyro code translation rather than the book’s R. Although I spent a year writing R in my first job out of college and haven’t found a better exploratory data visualization tool than ggplot2, I figured that a casual data scientist like myself would be better served staying within the more popular NumPy / Pandas ecosystem.

For Python broadly:

For learning NumPy:

I haven’t found a plotting library that I like. Plotly feels OK, but the recommended “Plotly Express” API doesn’t make it easy to, e.g., combine points and lines on the same chart — it’s doable, but you’ve got to break out into a sort of mutable and verbose API. I tried Altair for 5 minutes, but quickly ran into rendering issues because it was trying to dynamically load JavaScript from the web after I’d already installed the Python package (no thanks!) I’ll probably try PlotNine, a Python ggplot clone, next, but I’m open to any suggestions for a Python library which can make, e.g., a scatterplot with a fit curve and shaded area indicating a compatibility interval. E.g., this figure from the book:

A scatterplot with fit curve and shaded area

Haunted stm32f103

I’m helping a friend write firmware for an stm32f103 (the famous “blue pill” microprocessor). The requirements are pretty straightforward:

I gave it a shot using the Rust Embassy framework, and it all works swimmingly…except that the MCU freezes and locks out the debugger within 10–60 seconds (indeterminate). Not hard fault, mind you, but all of the CPU registers end up pointing to garbage like 0x0 or 0x2100_0000.

I asked my much more experienced (literally programs embedded guidance control for rockets) friend for help. He was able to reproduce the issue, but we’re both still stumped as to the root cause:

A single register write before the WFE instruction seems to fix it. Four NOPs do not. Feels like this must be some weird bus mux contention issue involving processor sleep…but…it’s pretty wild.

You feeling lucky? Check out this repo for more details and code that reproduces the issue — all it requires is an stm32f103 (blue pill, nucleo board, etc.) and a few minutes.

Misc. stuff