Mosbadge¶
2025-04-23
TL;DR¶
I repurposed my EECS 473 capstone project into a furry convention badge, and wrote an accompanying web app to control it. The Mosbadge connects to my phone via Bluetooth Low Energy (BLE), and has an e-paper screen that displays whatever I upload to it. I brought the badge to MCFC 2025, but it was not my focus and did not lead to transformative events. The engineering experience will lead to more adventurous badges in the future.
Backstory¶
Back in Fall 2024, I took a course in embedded systems, in which my team designed the Live Caption Badge. It would transcribe speech and print the captions on an epaper screen.
Now that I'm done with this course, I asked my teammates if I could keep one of the prototypes and they said yes. (I ended up soldering another.) What they did not know was that, I am a furry with plans.
So, after months of tinkering, Live Caption Badge is now just Regular Badge — I dub thee Mosbadge.
Capabilities¶
- I can upload an image from my phone via BLE, with optional text overlays, and Mosbadge will display it.
- I can preload images, slides, and animations via USB onto the flash storage. Once it boots up, I can select one on my phone for it to display.
- I can flip through a slide by pressing the buttons on top.
- I can play animations up to 2 frames per second.
Hardware¶
▲ The Mosbadge (banana for scale)
I claim no credit in the 3D printed case. It was 100% my teammate Kyle's work.
I can talk all about the PCB though, because it's 100% my work.
The MCU is an ESP32-S3 module. It controls the epaper via SPI. The whole thing is powered with an 18650 battery, LDO'd to 3.3V. Firmware and image data can be uploaded via USB. Despite the USB-C connector, it's just a simple D+/D-, and you can't charge the battery over it.
For a list of Easter eggs on the PCB, read the 473 post.
Firmware¶
The firmware is written in C++ using FreeRTOS and the Arduino interface on the PlatformIO framework. It spawns three tasks:
- UI event loop task
- BLE handler task
- Button handler task
The UI event loop handles events generated by the BLE and Button handlers.
There's a bunch of other more boring parts:
- Abstractions and parsers for image data and metadata
- E-paper driver
- Power management
I picked C++ because I wanted classes for abstraction, because if there's one thing I learned in 473, it's the importance of a good interface. The ESP32 was powerful enough that I didn't need to optimize every bit of code. I also craved the power of the STL and RAII, then extensively used vectors, strings, and unique_ptrs. Was it a good idea? I don't know.
I've already complained about the vendor epaper driver code in the 473 post, so I'm gonna skip it here.
The power management puts the device to sleep if Bluetooth is disconnected for over a minute, unless it's running an animation. With the antenna on, the thing draws ~100 mA, but when it's asleep it draws only 1.8 mA. A portion of it could be the power indicator LED. Didn't expect it to be this good.
BLE & image compression¶
The most interesting part is BLE. The particular line of ESP32's do not support Classic Bluetooth, so we don't have file transfer. Instead, we emulate UART over BLE. I chose NUS (Nordic UART Service), which is implemented in this library.
BLE has this concept called characteristics, which are just data fields you can read or write. Each one can contain a maximum of 512 bytes of data. What NUS does is nothing but continuously writing a characteristic to a remote device.
Now, as it turns out, data rate over NUS was terrible. A frame took 24 seconds to transmit, at which point it's just SSTV but worse. Since the screen is 800×480, and each pixel is a bit, that makes 48 kB per frame. The data rate is therefore 2 kB/s.
To remedy this fatal flaw, I applied gzip compression to all image data. (gzip instead of fancy image compression algorithms used to save time.) Simple images can be compressed to 5% the original size. The Mosfet badge (shown in §Hardware), when compressed, is 2.4 kB. Photos with noisy patterns, however, can be on the 80% side.
Anyway, compression makes the common case fast, so I call that a win.
Filesystem¶
To make common cases even faster, I looked for a way to preload images on the ESP32. In 473, we encoded our bitmap icons and fonts to hex numbers in a C file, but it's not feasible here.
The ESP32 has got a huge flash (we bought the kind with 16 MB), and it can be partitioned. So I made a firmware partition, and a filesystem partition. The filesystem is LittleFS, optimized for SPI flash. Support for directories allows me to decouple files — for example, instead of making a giant self-contained file for a slide deck, I could dedicate one file for the metadata, and one for each slide. For single images however, I just amalgamated the metadata and data. Was this a good idea? Again, I don't know.
The data on the FS was also compressed. To make life easier, I wrote a Python script to do all the metadata and compression.
Web app¶
The reason behind a web app was that I didn't have the time to learn to write an Android app, and I can't just walk around with one arm constantly holding my laptop. The app consists of two parts: image manipulation, and BLE. The former was done with the HTML Canvas, and is extremely boring.
One rant I have about the state of web JavaScript is the sheer amount of
maneuvers I have to do to get anything to work. The cropper widget I'm
using (croppie) only accepts URLs
as input which makes sense if you're dealing with images on a server,
which I'm not, and imagine my face when I learned you could do
URL.createObjectURL()
on an arbitrary file.
The BLE part was similarly convoluted, but thankfully there exists a library that implements NUS (at least the part that transmits) with the Web Bluetooth API. The API works on Chrome only, but that's good enough for me. JavaScript supports gzip natively, which was convenient.
You may try out the graphic part on the demo page, but I make no guarantees.
Source code¶
You may see all Mosbadge-specific work in my Codeberg repo. The PCB is not there; it's in the Live Caption Badge repo. Note that although the software is GPL, the PCB isn't technically open source right now. If anyone's interested I could copy it over to the Mosbadge repo.
MCFC¶
So, with everything ready to go, I packed it up for MCFC. It was not heavy, just clunky, since it's literally a board screwed to a big box.
It was not eye-catching, nor was it designed to be, since it does not emit light or have flashy colors. I had various memes preloaded on it for use in various occasions. The most commonly used one was:
Since this was my first con, I was cautious about everything. Because of that, and because the Average Furry™ is not an embedded systems nerd, the Mosbadge did not manage to strike up as many conversations as I expected. It might sound stupid but I made slides I can pull out in case anyone asks me technical questions. Nobody did, but I pulled it out anyway.
A girl was interested in it at the check-in room, and an artist at the artists alley noticed the animation. Someone at the College Furs panel told me that "people would buy these". But I remember my 373 (prerequisite of 473) professor's words, and his words were, if people say what you made is "great", that's because they can't come up with anything else that doesn't hurt your fragile engineer ego. And last time I checked, I had a fragile engineer ego.
And when I look at the Mosbadge, I don't see a viable product in it: data
transfer too slow, epaper too fragile, poor user interface, overall
unmanufacturable. I could get a team and open a workshop to make these by
hand paw, which is a more ethical form of economy anyway, but there
are just so many things that need work (or a complete overhaul) before
I have the confidence to slap on a price tag.
I did get this flattering comment though:
Future¶
The Mosbadge has done its job. Whether or not it will show up in future furcons is to be decided, because I'm almost certainly gonna work on more exciting and interactive badges.
In my normie life I work as an IA (teaching assistant type job), and on office hours I would wear it so that people recognize me, which gives a new life to the Mosbadge.
Does it play Bad Apple?¶
Yes.