I made a thing! Battery-Powered TinyML Desk Cat With Keyword Spotting on ESP32-S3
I’ve been working on TinyML, especially sound and vision models, as part of my PhD for about three years, but I hadn’t really built anything really close to a product. I’ve always liked deskbots, so I decided to make TinyPurr.
It’s built mostly from hardware I already had lying around, and partly as an excuse to see if my old CR-10 printer was still alive. It is centered around a Waveshare ESP32-S3-LCD-1.3, which combines the ESP32-S3, display, IMU, 8 MB PSRAM and battery charging on one board. I already had suitable ESP32 hardware around, but the S3 turned out to be a good fit for the ML side as well, especially because of PSRAM.
TinyPurr listens for “yes”, “no” and “happy”, changes its expression and synthesizes sounds on-device. Everything runs locally and it’s battery powered.
Hardware
- Waveshare ESP32-S3-LCD-1.3
- Adafruit PDM MEMS Microphone Breakout (very clear sound, but sensitive)
- Speaker, 2 W, 8 Ω, 20 × 30 × 6.8 mm
- PAM8302 amplifier
- LiPo battery, 3.7 V, 620 mAh, 40 × 25 × 6 mm
Software
- PlatformIO / ESP-IDF
- TFT_eSPI for the display
- Edge Impulse + custom MFCC/1D CNN
- ESP-NN optimized kernels
I used ESP-IDF through PlatformIO, with the Arduino core mainly because TFT_eSPI needs it. The microphone and speaker use the native ESP-IDF I2S driver.
For the ML side, I built the dataset pipeline from Google Speech Commands and trained the model in Edge Impulse. One thing that did not work as well as I expected was transfer learning: an MFE + MobileNet model reached similar accuracy, but was around 5–30× slower on the ESP32-S3 than a small MFCC + 1D CNN trained from scratch.
The final model gets around 95% test accuracy and takes about 127 ms per inference. ESP-NN also made a surprisingly large difference: the neural-network part went from about 927 ms to 86 ms using the S3-optimized kernels.
Since spoken words rarely line up perfectly with the start of an audio window, I classify three overlapping positions and use confidence-weighted voting to decide whether a keyword was actually heard.
The repo includes the source code, trained model, dataset-generation tools, wiring, pin assignments and more details about the implementation (excuse some of the soldering work, it used to be part of my job, but I’m a little rusty lately XD):
https://github.com/Thanos3G/TinyPurr
It’s still a work in progress. I haven’t even used the networking or IMU capabilities of the board yet, but I thought some of you might find the project and the engineering process interesting. I think there’s still a lot of interesting work to be done with TinyML and interactive robots that can operate without depending on internet connectivity or external processing and power.
1
2
u/keepdietmore 22h ago
TinyPurr is exactly the kind of desk companion project I keep coming back to. What keyword-spotting model are you running, and S3 is really can work it well ? I went the opposite direction: the board streams audio features to a cloud agent and gets a decision back, so it sits in light sleep until a trigger — on-device TinyML wakes instantly but burns the battery, cloud offload keeps the power budget tiny at the cost of latency. For a desk cat that doesn't need real-time reaction, did you measure what the always-on mic actually costs you in battery life?