Summary
Working on hardware projects often has significant friction involved when compared to pure software. Brian Pugh enjoys tinkering with microcontrollers, but his "weekend projects" often took longer than a weekend to complete, so he created Belay. In this episode he explains how Belay simplifies the interactions involved in developing for MicroPython boards and how you can use it to speed up your own experimentation.
Announcements
- Hello and welcome to Podcast.__init__, the podcast about Python and the people who make it great!
- When you’re ready to launch your next app or want to try a project you hear about on the show, you’ll need somewhere to deploy it, so take a look at our friends over at Linode. With their managed Kubernetes platform it’s easy to get started with the next generation of deployment and scaling, powered by the battle tested Linode platform, including simple pricing, node balancers, 40Gbit networking, dedicated CPU and GPU instances, and worldwide data centers. And now you can launch a managed MySQL, Postgres, or Mongo database cluster in minutes to keep your critical data safe with automated backups and failover. Go to pythonpodcast.com/linode and get a $100 credit to try out a Kubernetes cluster of your own. And don’t forget to thank them for their continued support of this show!
- The biggest challenge with modern data systems is understanding what data you have, where it is located, and who is using it. Select Star’s data discovery platform solves that out of the box, with a fully automated catalog that includes lineage from where the data originated, all the way to which dashboards rely on it and who is viewing them every day. Just connect it to your dbt, Snowflake, Tableau, Looker, or whatever you’re using and Select Star will set everything up in just a few hours. Go to pythonpodcast.com/selectstar today to double the length of your free trial and get a swag package when you convert to a paid plan.
- Your host as usual is Tobias Macey and today I’m interviewing Brian Pugh about Belay, a python library that enables the rapid development of projects that interact with hardware via a micropython-compatible board.
Interview
- Introductions
- How did you get introduced to Python?
- Can you describe what Belay is and the story behind it?
- Who are the target users for Belay?
- What are some of the points of friction involved in developing for hardware projects?
- What are some of the features of Belay that make that a smoother process?
- What are some of the ways that simplifying the develop/debug cycles can improve the overall experience of developing for hardware platforms?
- What are some of the inherent limitations of constrained hardware that Belay is unable to paper over?
- Can you describe how Belay is implemented?
- What does the workflow look like when using Belay as compared to using MicroPython directly?
- What are some of the ways that you are using Belay in your own projects?
- What are the most interesting, innovative, or unexpected ways that you have seen Belay used?
- What are the most interesting, unexpected, or challenging lessons that you have learned while working on Belay?
- When is Belay the wrong choice?
- What do you have planned for the future of Belay?
Keep In Touch
Picks
- Tobias
Closing Announcements
- Thank you for listening! Don’t forget to check out our other shows. The Data Engineering Podcast covers the latest on modern data management. The Machine Learning Podcast helps you go from idea to production with machine learning.
- Visit the site to subscribe to the show, sign up for the mailing list, and read the show notes.
- If you’ve learned something or tried out a project from the show then tell us about it! Email hosts@podcastinit.com) with your story.
- To help other people find the show please leave a review on iTunes and tell your friends and co-workers
Links
- Belay
- Geomagical
- PIC Microcontroller
- AVR Microcontroller
- Matlab
- MicroPython
- CircuitPython
- Celery
- Potentiometer
- Raspberry Pi
- Raspberry Pi Pico
- ADC Converter
- Thonny
- Adafruit
- Pyboard
- Python Inspect Module
- Python Tokenize
- Magnetometer Project
- Lidar
The intro and outro music is from Requiem for a Fish The Freak Fandango Orchestra / CC BY-SA
Hello, and welcome to podcast dot in it, the podcast about Python and the people who make it great. When you're ready to launch your next app or want to try a project you hear about on the show, you'll need somewhere to deploy it. So check out our friends over at Linode. With their managed Kubernetes platform, it's easy to get started with the next generation of deployment and scaling powered by the battle tested Linode platform, including simple pricing, node balancers, 40 gigabit networking, and dedicated CPU and GPU instances. And now you can launch a managed MySQL, Postgres, or Mongo database cluster in minutes to keep your critical data safe with automated backups and failover.
Go to python podcast.com/linode today to get a $100 credit to try out their new database service, and don't forget to thank them for their continued support of this show. The biggest challenge with modern data systems is understanding what data you have, where it is located, and who is using it. Select STAR's Data Discovery Platform solves that out of the box with a fully automated catalog that includes lineage from where the data originated all the way to which dashboards rely on it and who is viewing them every day. Just connect it to your DBT, Snowflake, Tableau, Looker, or whatever you're using and select star will set everything up in just a few hours.
Go to python podcast.com/selectstar today to double the length of your free trial and get a swag package when you convert to a paid plan.
[00:01:32] Unknown:
Your host as usual is Tobias Macy, and today I'm interviewing Brian Pugh about Belay, a Python library that enables the rapid development of projects that interact with hardware via a MicroPython compatible board. So, Brian, can you start by introducing yourself?
[00:01:46] Unknown:
Hi. My name is Brian Pugh. I'm the lead deep learning scientist at a startup called Geomagical, where we develop the augmented photography application called Creative for IKEA. So go check that out if you wanna see the handy work of our team. But, independently, I developed this library belay so that I could get my weekend projects done actually done in a weekend.
[00:02:06] Unknown:
And do you remember how you first got introduced to Python?
[00:02:09] Unknown:
Yeah. So, originally, I began my programming journey in c so that I could program PIC and ABR microcontrollers. And then later on, I went to college for electrical engineering. And a lot of the classes, they all used MATLAB for assignments. So that was my first time really using an interpreted language. And then over internships and stuff like that, I began getting into deep learning where the de facto language is Python. It was similar enough to MATLAB that it was easy to transition over, and I haven't really looked back ever since.
[00:02:39] Unknown:
And so in terms of the BELAY project, you mentioned that it's something that you've built to help you actually get your weekend projects done in a weekend. I'm curious if you can just talk to some of the details about what it is that you've built there and some of the story behind how you decided that this was somewhere that you wanted to invest in because it was an area area that you were active enough that it was worth building a dedicated project? I guess just first in summary, Belay is a library that solves a problem. I want my computer to control some hardware.
[00:03:08] Unknown:
So with Belay, you can do something as simple as toggle an LED from your computer and just, like, make, like, 6 lines of code. And Belay achieves this by interacting with a MicroPython compatible board via its REPL, its read, evaluate, print interface. So it uses this to evaluate commands as well as to sync code between your computer and the device. So Belay really just blends the boundary between your computer application and the firmware running on device. It should be noted that Belay doesn't run on MicroPython. Belay is a library that runs on your host computer that is shuttling Python statements and expressions between your computer and microcontroller.
There's no explicit upload this firmware to your microcontroller step for the user to perform. It just works out of the box with MicroPython or CircuitPython. Source code is just transferred as needed. So once you have this Belay library imported, how it works is you decorate a Python function with the Belay task decorator, and what this decorator will do is send the function's source code over to the microcontroller project or a microcontroller board that's running MicroPython. So this function is being sent over to the device, and the function on the host on your computer is actually replaced with a remote executor. If you were to call that function on host as you would, like a normal function, it will actually send a command to execute it on device and return the results from the micropython interpreter.
So in some ways, it's sort of like Celery where functions are being executed on a remote machine. Just in our case, it's a microcontroller. And so I created this library because the conventional approach of computer hardware interactions was super cumbersome and tedious. Conventionally, if you want an application on your computer to interact with hardware, there are 3 large efforts. Number 1, you have to create the application itself. But I mean, like, you know, that should be the fun part. 2, you have to create the firmware for the microcontroller that is interacting with the hardware. And typically that's done almost independently of your actual application.
So now your project actually kind of has 2 projects within it. And then finally, you need to develop a communication protocol to shuttle data between your firmware running on your microcontroller and your application running on your computer. So for simple projects, if you're just reading something like a potentiometer, the communication protocol can be pretty simple. Your microcontroller can be reading those analog values in and can just be printing them out to the serial port, and then the computer can parse that byte stream without too much trouble. However, if your project gets more complicated and you want more inputs or more outputs, the communication protocol also has to become more complex.
Firmware might have to listen for and parse commands, and your application might need to deserialize more complex responses from your firmware. So command parsing, interpretation, and result parsing, they're all pretty generic across many projects. So I figured, why not make a library for it? So with Belay, you don't have to independently develop that firmware and you don't even have to think about the communication protocol because that's all handled for you. I wanted to spend less time developing firmware and protocols and more time working on the actual fun stuff, the projects themselves.
[00:06:13] Unknown:
So Belay was born. In terms of the kind of scope of projects that Belay is intended to use be be used for, you mentioned that it's working from the host computer to relay those commands to the microcontroller. And I know, too, that when you're writing things in MicroPython, oftentimes, also, you want to just build an isolated project that's going to run on a continuous loop on that microcontroller board or, you know, triggered by some of the interrupts like the I squared c port or something. So I'm curious if Belay is focused primarily on projects where that microcontroller is going to remain attached to the host computer, or is it something too where you would also use it for developing some of those self contained projects on that hardware board?
[00:06:56] Unknown:
So, originally, I developed BELAY with the intention that the microcontroller is gonna be continuously attached to the computer. And it doesn't have to be like your main desktop or something. It could be a more simple single board computer like a Raspberry Pi. And it originally stemmed from 1 of my Raspberry Pi projects. I needed to read a potentiometer. And the Raspberry Pi doesn't have a built in ADC converter. And with the silicon shortage and everything, an ADC converter that's compatible with the Raspberry Pi costs, like, $15 or whatever. And I was like, no. I'd rather just buy a bunch of Pi Picos that are, you know, much more generically useful. But then, of course, I then had to deal with this whole communication protocol, firmware development, and things like that.
And so, you know, that that led into developing this library because it was such a pain. But so, you know, for those projects, I intended the microcontroller to be constantly attached to the computer. However, as I've been using Belay for other projects, I found that it's useful for generic development even if the end product is not going to be attached to a computer. And that's because, you know, you have delay handling all these hardware interactions, but hardware interactions are typically only, you know, part of the whole software you're developing. There's a lot of other logic going around too. So if you can move a lot of that development over to your computer instead of running it on micro Python, You can use a lot better debugging tools that normal Python gives you, like PDP or whatever IDE you're using. So it can be used both for a full project and also just in the development of a project.
[00:08:26] Unknown:
As far as the, I guess, target audience for Belay, obviously, the primary audience is yourself. And as you decided to release it as an open source project, curious what were some of the, I guess, conceptual cleanup that you wanted to do to make it more broadly understandable and sort of who you had in mind for who you thought might come along and pick up BELAY and start using it for their own projects?
[00:08:50] Unknown:
This is not my first project that has had to communicate with a microcontroller. And whenever you're just working on a quick project, it's typically going to be hacky and dirty. And just whatever you can do to make it work, you make it work and then so you can move on. But I decided, I was like, you know, this is a reoccurring problem. I want to get it done right. I wanna get it done cleanly. I want it to be well documented. I wanted to solve it once so that I never have to worry about it again. That's whenever, you know, you start doing a little bit more software engineering rather than just hacking stuff together. So originally, I came up with an interface that I would like that I would like to develop with, and then I figured out how can I make this interface actually happen? And then, I flushed out the code to, you know, make it work that way. And then, you know, it's important that whenever you're designed that way, that it's also maintainable so that if other people are coming to the project and let's say there's a feature that they want that is not currently implemented, I don't want it to look too scary for them to try and come in and contribute a feature.
So I've been trying to keep it as simple as I can while still providing all the functionality we want.
[00:09:54] Unknown:
In terms of the typical, I guess, workflow of building a project for a microcontroller board, I'm wondering if you can talk to some of the common points of friction that you run into that slow you down and make your weekend projects span multiple weekends.
[00:10:12] Unknown:
Yeah. So embedded project development in general is, like, if you've never done it and then you move into it, it's really quite unpleasant compared to traditional software development that just runs on a normal computer. There's a bunch of issues, but I'd say some that I'd like to highlight that, you know, Blade does solve or at least, you know, is tangential. 1 of the first big problems is that you have to get your environment set up. Now if you're only using 1 microcontroller from 1 manufacturer, you know, this is a kind of a 1 and done, and it's not too big of an issue. But if you're, you know, switching around microcontrollers, switching around manufacturers, it becomes quite tedious because for each manufacturer, for each microcontroller, especially if you're programming in c, you'll have to download the microcontroller manufacturer's toolchain or IDE to, you know, compile and flash your code to your device.
And often these tools have a lot of unique quirks and features to those specific chips or manufacturers. Typically, you know, several years, like decades of technical dead that, you know, they're like, this is just the way it is. So it takes a lot of time to become familiar with all those features and tools and the way it's done in that framework. And so that slows down development a lot because, you know, even if you know c, you're in a whole other land now. So that's 1 issue with embedded development. Another 1, and this is probably the most critical 1, is the available debugging tools, especially for hobbyists. So, you know, hobbyists typically have really inexpensive boards, and they don't wanna buy expensive tools. You know, I wanna buy that $5 clone, like, off Amazon or eBay or whatever. And if you don't have the proper hardware or software support, even simple things like breakpoints can be very difficult or impossible to set up, So inspecting program state can become quite hard, and this frequently reduces the programmer to doing things like just print debugging, which is never efficient.
And so if you think print debugging is not efficient, the biggest issue is the long iteration cycles. So this is the time between and then the code being slowly transferred over to some serial port. And then the code being slowly transferred over some serial port. During that time, you get bored or distracted. You're browsing Reddit or whatever. And then sometimes by the time your code is actually running, you forget the changes that you've already made. So now you don't even remember what you're trying to debug. So for MicroPython development, if you're using an IDE like Phonny, this is less of an issue because whenever you save, it automatically syncs. So the delay is just a few seconds. If you try to develop MicroPython from the command line, it can quickly become tedious, though, because you have a single serial port communicating with your microcontroller.
And so you're using that serial port for both sending code over as well as the standard out, you know, that you're trying to get all your print debugging back from. So you had to be constantly switching back and forth, and, you know, that's just kind of annoying. CircuitPython does alleviate some of these issues by allowing you to directly edit code on device. CircuitPython mounts its file system as a USB drive to your computer so you can directly edit your Python scripts. But the resulting project isn't exactly Git friendly since you're editing all these files on another system. And then if your file system gets corrupted, then you're kinda just screwed. So in my opinion, it's not an excellent, experience either.
[00:13:25] Unknown:
So in terms of the pain points that you mentioned there, I'm curious how many of them you actually aimed to resolve with Belay and some of the ways that you went about kind of building nicer interfaces or more convenient iteration loops into your development workflow through this library?
[00:13:44] Unknown:
Right. So the primary goal was just to simplify the interactions between the computer and the micro controller. But, you know, while developing that, I inherently developed what what I think is a better experience to develop with, and that's, you know, defining these short terse functions that are doing the actual hardware interactions. There's typically not too much to debug with that in micro Python because a lot of libraries, like, you know, from Adafruit or whatever, they do a lot of the heavy lifting for you. And so you only have to have, like, 3 lines of code. There's not much to debug. And then that moves the rest of the logic that, like, you know, is your custom? What do I do with these inputs? What do I do with these outputs? It moves it back onto your computer instead of on the MicroPython interpreter.
So when it's on the computer, it's so much easier to debug because you can just set a breakpoint, and you can inspect the state. You can inspect the values. You have much better visualization tools. Like, if you wanted to plot a bunch of values, you have matplotlib available to you, that would certainly not be available on MicroPython.
[00:14:42] Unknown:
The other interesting element is discussing kind of what are the pieces of developing for hardware that are just inherent to the problem space. You're never going to solve it, and you decided not to even bother trying to address them in belay and maybe some of the ways that you modified your own kind of development workflow or the way that you structure your, maybe, function definitions or sort of code workflow to be able to make it more accommodating to the hardware constraints themselves?
[00:15:12] Unknown:
Right. So, you know, whenever you're developing in Belay, you naturally try and make your tasks, your functions that interact with the hardware as short as possible. And, you know, so not everyone does this, but it's actually gonna end up enforcing good practice because it abstracts away the hardware interactions So even So even though Belay is sort of like, if you don't use it in your final product, it encourages better code structure just just for the maintainability of your project.
[00:15:47] Unknown:
So in terms of the actual implementation of the Belay library, I'm wondering if you can talk to some of the, maybe, built in Python capabilities that you leaned on, some of the ways that you had to design around, some of the specifics of MicroPython and the constraints of the hardware that you're dealing with and maybe some of MicroPython's lack of inclusion of different standard library of modules?
[00:16:11] Unknown:
On the computer side, Belay is built on top of an interface called PyBoard from the MicroPython repository. I believe it was primarily developed by Damien George and Paul Sokolowski. And what this utility is, it's basically an adapter that makes it much easier for a Python program to interact with the micro Python REPL. Because if you ever use the micro Python REPL or any Python REPL in general, there's, like, a lot of characters on the screen. Like, you know, you might have the 3, you know, less or, yeah, greater than symbols at the beginning of the prompt to tell you to type in. And then, also, there might be elements that you don't even think of. Like, whenever you're typing characters into a REPL, it's echoing the characters back.
So what this package does is it sort of just abstracts all that away. It takes care of all the things. It knows how to send commands over. It knows how to get the byte stream back to you. So this was all based off of the work that they already did. And with that, you might think that the problem is already solved, and in many ways, it is, but Highborne adapter did make developing Belay significantly easier because it handled all of the low level communication logic. What BELAY brings to the table is it adds a ton of syntactic sugar to it, abstraction, and a few features that make the common use case or what I believe is the common use case to be much simpler. So if you were just to use this PyBoard module, this PyBoard, you know, script, whatever you wanna call it, there are several extra steps that you need to perform to get the similar functionality as Belay. So you can just think of this as you can send a string command over, and you get a byte stream back. So if you we want to send source code over of some function that you want to run on device, you have to first, you know, package it up into a string, send it over. If you want to improve the efficiency of the transfer, you should probably minify that Python code before you're sending it over. That's like doing things like removing unnecessary white space, comments, docstrings, stuff like that.
And then to actually invoke the function on device, now that all that source code is on device, you would need to parse together a Python expression calling that function with the arguments you want. So that can be a bit tedious, a bit error prone. Belay also handles that. We can get into that in a little bit. So you have this command that will execute the function on device, but now you wanna get the results back. So before you actually send it over that source code, you have to modify it a little bit because returning the value from the function isn't quite doing what we want. We actually want to serialize that result and send it over standard out so that our computer gets the result. So So you have to do a bit of serialization and printing the standard out. And then finally, your computer has to parse that serialized byte stream back into an appropriate Python data type, whether it be like a list, a 2 pull, an integer, whatever it might be, exactly what the developer would expect and hope to get back, you know, the useful representation. So these are the challenges that So So we do this with 1 or 2 methods. We have a classical sync method that will sync, you know, full files over to the micro Python file system, And it does a few smart things, like it'll check hashes of local files on the MicroPython system to make sure that if a file has changed, we can sync it over. If it hasn't changed, we don't need to waste the bandwidth sending over the same files.
But then the more useful 1 is decorating functions in your Python script with this task decorator. So in order to get the source code of the function we're decorating, we use the built in Python module inspect, which does a bunch of cool things, but it essentially allows us to get the source code of the function we're decorating. We had to come up with our own minification script. This uses another Python built in called tokenize, which is a Python well, it's a Python source code tokenizer. It basically breaks up, you know, this giant Python source code string into what each individual element means so we can sort of determine what parts are valuable, what parts are not. So we can strip out docstrings and comments. We can reduce the indentation level. Like, if you had 4 spaces for 1 indentation level, you can reduce that to 1. So typically, you can make your source code, like, 3 times times smaller just with naive minification.
So now you have that minified codes. You know, Belay sends it over. We record what that function name is. We know what the function name is on device so that whenever we're parsing our string command together, we have it. And then we actually do something that I feel like is relatively clever. We have to figure out how to serialize and deserialize these Python objects. And for all Python built ins, if you use the built in repr command for representation, this returns a string for, you know, an object. And if it's a Python built in, the return string contains exactly the information to recreate that object. So if you do repr of an integer, it'll return 5. And then in order to turn that string back into a Python object, you can use the built in literal eval from the AST library, the abstract syntax tree library, and that will perform a safe deserialization of that string. So you have an object. You can feed it to repr to produce a string, feed that string into ast. Literaleval, and that will produce the exact same object back. So we use that for serializing the parameters that we're sending to the micro Python device, and we're using it to deserialize and serialize the results being sent back.
And so in doing it that way, we're able to represent all the built in Python objects. I didn't know about this. Originally, I was using JSON serialization and deserialization because it seems like a pretty obvious solution. But the limitations of that, which I didn't like, was you couldn't represent Python sets because that's not valid JSON, and also you couldn't represent binary data because JSON doesn't support bytes. Soon after, I was like, oh, wait a minute. We can just use representation literal eval. So moved over to that and it became a lot cleaner and stuff like that. It is also good because not all libraries are available across all micro Python and circuit Python implementations. Like, for example, in that file syncing I was mentioning earlier, originally, we were hashing files using sha256 just because it was built into micropython, and it was easy, good enough. You're gonna get a unique fingerprint of a file. However, whenever I started making Belay CircuitPython compatible, it turns out CircuitPython doesn't have that, you know, cryptography library, that hashing library built in. So I had to figure out a new hashing function.
So after a bit of Googling, I discovered this well, I mean, I discovered it on Google, this, cool hashing function. I think it's called f n v 1 b or 1 a, something like that. It's an incredibly terse hashing function. It's like 3 lines of Python. So then I was able to bundle that in with Belay for file hashing instead of having to rely on circuit Python or MicroPython specific features. That was another, like, cool little, internal implementation detail. But yeah. So between all of this, you know, it it's a lot of syntactical sugar where taking the source code, remitifying it, sending it over. We're automatically parsing the commands for you. We're automatically serializing and deserializing the parameters and results, and we're sending that back to you so it's all done seamlessly.
So I guess at at a medium level, that's how Belay works. There are finer details here and there, but that's the general concept.
[00:23:23] Unknown:
As far as the, I guess, workflow of using Belay, you mentioned that it's largely, you know, add a decorator to a Python function. It will handle sending that back and forth to the micropython board. I'm curious what you are using as sort of the kind of triggering to as somebody's going through the development process, is it just, you know, I just need to run Python my file name, Or do you set up some sort of file watches with Belay where you can say, every time I save the file, just resync the state so that I don't have to, you know, do this manually. I can stay more in the flow of just writing something and then see what happens and just kind of managing that back and forth workflow of writing on your laptop or writing on your host computer and then being able to interact with that microcontroller.
[00:24:11] Unknown:
Right. So that automatic detection and stuff is what you're describing is available in circuit Python. Whenever you edit a file on circuit Python and you save it, it'll automatically reload the Python interpreter and re execute your file. But late doesn't have anything magic running in the background that's watching files or anything like that. It's just a conventional Python script. So if you have your main Python function, just run Python main dot py. It'll execute it. The 2 main features of getting code onto the board, you know, the sync call as well as these decorators. You know, the you can put the sync call at the top of your script to make sure that if you have any changes in the Python libraries that you wanna send over to your device, that those are automatically sent over. And then all of the task decorator functions, those are sent over every single time because those are only stored in the interpreter state. It's not like they get synced to the file system or anything like that. So workflow is basically a standard Python project. You're editing your script, you get to run it, and then that's all it is.
[00:25:09] Unknown:
Another interesting challenge whenever you're dealing with kind of resetting the state of the code on a device is having to reconstruct the prior operational state. So for instance, if you're trying to debug something and resolve an error and maybe you had to, you know, interact with a few toggles or, you know, it's dealing with some sensor inputs where it's only gonna trigger when it hits a particular temperature threshold or, you know, luminescence value if you're dealing with a light sensor. I'm wondering if you have any kind
[00:25:41] Unknown:
of practices or ways that you've approached that challenge of being able to kind of regenerate the state of the program at the time through the error so that you can, you know, make a change and then quickly get back to that point? So if we, like, make the assumption that the issue lies in your own code and not in some third party's code, yeah. So, Belay allows that to happen quite easily. So, you know, if you have an uncaught exception, if you run postmortem debugging on your code and only hardware interactions are in the delayed tasks, then the whole weird state that your hardware stuff generated, that should still be in your Python interpreter state on your computer. And so you can, of course, save that state to, like, a pickle file or whatever for future debugging so that whenever you're trying to debug what the actual issue is, you don't need to do all your hardware interactions again. You already have the important state in your interpreter and save to a file, so you can reproduce it over and over again. Without that, you would just look and be like, ah, well, something weird happened, and I have no idea if we can ever reproduce that again. By, you know, abstracting once again the hardware from the actual logic, it makes it much, much easier.
[00:26:47] Unknown:
Yeah. It's definitely very useful, and the point of being able to kind of pickle the operational state and use that as a test case for debugging is interesting. And I'm wondering from that what you have kind of started as your own practice of managing, kind of building up a test suite if you're iterating on a particular hardware device and, you know, doing a long running project and then building up a library of some of those saved error states and then building up a set of unit tests around that given project so that you can, you know, make changes and understand, like, am I introducing a regression that's bringing me back to this problem or some of those kind of testing and debugging over a longer period of time?
[00:27:27] Unknown:
Unit testing is a good point. Unit testing on embedded projects is always a bit difficult. You know, it's quite easy to add in unit test to the business logic, if you will, once it's isolated from your hardware because that just runs anywhere. It's not actually specific to the hardware it's running on. And this is actually a big struggle with Belay because the entire library is centered around interacting with hardware, interacting with hardware so that you don't have to worry about it. And so writing unit tests for Belay is very hard. For some of the stuff, it's quite easy, like minification and stuff that doesn't interact with the serial port with the boards and all that, but actual unit testing of the functions is difficult. You can't really just have a GitHub action that, you know, is like, oh, yeah. Just make sure you have a PyPico attached and run these commands, and it'll be fine.
So, actually, if anyone knows how to set up better CI for hardware projects, I'm I'm all ears. I would love to hear about that. And then, you know, pickling your current state so that triggers a bug is always great because you don't necessarily wanna use that exact pickle file in a unit test because that's kind of opaque. However, you can typically find out what was the exact edge case that caused this to trigger. And so then you can create that simplified unit test that triggers that exact use case, not only just to prove that you've solved it, but then also you don't make the same mistake in the future.
[00:28:50] Unknown:
In terms of some of the weekend projects that you're using Belay for, I'm wondering if you can share some of the types of projects and some of the ways that Belay has helped you with some of that development cycle and how it maybe changes the way that you think about the design of your programs because of the fact that you do have these faster and more seamless iteration cycles.
[00:29:10] Unknown:
Whenever I have an idea for a project, I'm much more likely to actually do the project now. Previously, I would be like, I really don't wanna deal with the serial port. I really don't wanna deal with all this new line parsing and, like, what happens if it disconnects and all these other edge cases. So now that I have this library that abstracts all that way, I'm much more likely to actually do projects. Belay is quite young. It's only about a month and a half old since I made it public. So I've only used it really for 2 projects so far. 1 is a personal project I haven't released yet, but it was simply just used to read a potentiometer from a pipe echo. That made it a lot simpler because, tangent, whenever you're uploading projects with Belay, you feel a lot more confident because no matter what, the firmware the quote unquote firmware, the code that's running on the device will always be up to date with the code that's running on your host. So previously, you'd be like, oh, I need to reflash the firmware that's running on the microcontroller and make sure that it's up to date because otherwise, I made these backwards incompatible changes in my core application. You really don't have to worry about any of that since the code is automatically updated every single time you run the program.
So you're much more likely to make changes, and then you don't have to be as mindful to make them backwards compatible because you know the code running on the microcontroller is always up to date. So 1 of them was just, you know, radio potentiometer. That's actually for a little project where I have this old school radio that I have a bunch of media player instances running all at the same time, and I have a tuning knob that changes the volume to all these different, quote, unquote, radio stations. So I have, like, a potentiometer hooked up to that running delay to send the analog values over to a Raspberry Pi that's playing a bunch of audio.
Another project that I released, maybe I think it was, like, 2 weeks ago, is a magnetometer or Gaussmeter command line project. So this is also on my GitHub. But, basically, it's a PIP installable package that has all the firmware bundled in with Belay, and it can hook up to a bunch of I2C magnetometer chips. A lot of them are available, like, on Adafruit. I used their drivers, And it just takes all of the magnetic field values, prints them to the command line, and also plots a nice graph in them and stuff like that. And that's because in an upcoming project, I'm using a bunch of magnets for stuff because, you know, magnets are always cool. And I needed to get some readings to make sure that my gaussmeter is typically, like, 1 to $500, while an I2C chip that does basically the same thing as, like, $10.
So I was like, hey. This is a great chance to use my library and then also get a really cheap tool. Yeah. And so it's very cool because with most microcontroller projects, typically in the setup phase, you're like, alright. Download this firmware. Download this toolchain. Compile it, flash it, make sure it's all up to date. There's a lot of steps. But with this, so long as your board is just running circuit Python, you just run the command and the firmware's automatically uploaded and everything's already figured out. So you could have some whole other project running on your device, and then you just run my magnetometer project.
And now different code is automatically running on it. So you don't even have to think about the hardware at all. It's all bundled together, and so I think that's a pretty cool use case of delay.
[00:32:27] Unknown:
And to that point of you don't have to care about what program was running on it before, that also brings up the interesting point of if you have multiple potential use cases for the same hardware device where maybe it has maybe it's something like 1 of the Adafruit circuit playgrounds or something where it has multiple different sensors and interfaces on it. And so depending on, you know, what you're doing is part of your general activity, you wanna run different programs on it. In the case of the standard of way of having to load the projects in, maybe it's cumbersome, and you say, I don't really wanna deal with that. But if you have something like belay where you just say, I just trigger this, and then it's doing the thing that I want it to do, that makes it a little easier to kind of make those boards multipurpose or just kind of, like, repurpose them from previous projects that you're working on. Wondering how maybe some of the ways that you've incorporated that into your kind of project flow, or maybe in the morning, you want to, you know, use it to measure the temperature of your coffee and make sure it's the right temperature. And then in the evening, you wanna use it to, I don't know, figure out what is the temperature outside to see if you need to throw out a sweatshirt before you go walk the dog or something.
[00:33:34] Unknown:
Definitely. I mean so, like, previous to using belay, I would, like, have, like, sticky notes or, like, some masking tape on each microcontroller for, like, what project is it for so that I don't mess up firmware or I don't, like, you know, erase something that, like, was sort of tedious to set up. But now on my desk, I just have a bunch of pipe echo boards just sitting around. It doesn't matter which 1 is which. I just pick up 1 and then run over to my other project, and it allows me to use it for those super ephemeral cases like, oh, I need a magnetometer. Well, I just picked up 1 from my desk, and now I'm just gonna go use it for that project. It lowers the barrier to entry so that you're much more comfortable doing these things, where previously, it just always seemed like a lot of work. And whenever it's a lot of work and it's meant for fun, then you just sort of don't feel like doing it anymore. So I think I've been able to do a lot more creative projects since then.
[00:34:22] Unknown:
In your conversations with, you know, friends, colleagues, people who have come across the project. I'm wondering what their sense has been as far as is it largely people who are already engaged with hardware development, and they say, oh, this made my life easier? Or are you also talking to people who are saying, oh, well, hardware development seems interesting, but maybe I'll actually give it a try because this part is simpler?
[00:34:46] Unknown:
So, invariably, a lot of my friends don't do a lot of hardware development, but I have posted to some of my friends for helping teach their kids programming because the conventional setup is still a bit cumbersome. This makes it a little bit easier. And then I think whenever you're teaching programming to children, if you can well, I mean, you know, children and adults, like, if you can make it more interactive, see physical actions happening based off of, you know, the ideas and the actions that you typed, I think that makes it a lot more enticing because writing something on a computer and making something on a computer happen, it's kinda cool, but like, you know, it doesn't really spark the creativity, but, you know, typing something on a computer and now a motor's turning, or now like, yo, a speaker's going off, that's a lot more exciting. So I think you can get, you know, people more engaged in programming.
[00:35:32] Unknown:
Recognizing that it's still a fairly young project, I'm wondering what are some of the most interesting or innovative or unexpected either ways that you've seen Belay itself used or projects that you've seen people use Belay to help kind of catalyze.
[00:35:46] Unknown:
Right. So, yeah, Belay is young, so I haven't really seen too many projects explicitly use it. I did see 1 user on GitHub use it for developing I'm assuming this is for school or something, developing a Sumo Bot. So I was, like, checking out their code a little bit, and they were primarily using it with a few different lidar sensors to make sure that the lidar sensors are producing exactly what they want so that their sumo bot would go in the correct direction and stuff. Because, you know, whenever you're programming for a microcontroller, you might just be sort of blindly making changes and then hoping it works out, but this expedites the process a lot more because they're able to get this stream of data easily from a lidar device without having to write a bunch of code that they would just throw away, you know, and plot it out on a computer and be like, yeah. My sensor is working. My code is working. So now I can, like, you know, figure out the logic of what do I wanna do whenever my LiDAR sensor is giving me these values.
I thought that was a pretty cool use case of it. Definitely on the end of delay is not gonna be in the final product, but it's being used as a helpful way of getting your project started. Oh, and actually, I was going through their read me a little bit as well. Another nice thing about Belay is that the setup environment is so simple that you feel much more free about making changes. You can come back to a project a month later and not have to worry about, I don't remember how to set up the tool chains. I don't remember how to set up all the environment variables. I don't remember how to set up all of these parameters. Well, it's all already taken care of, so you're more likely to interact with it and also collaborate with other people working on the same project. And so I thought I I really liked that.
[00:37:19] Unknown:
To the point of kind of managing the specifics of a given board, I know that some of that is handled by the kind of micropython aspect of it, but I'm wondering what are some of the elements that you've incorporated into Belay to be able to maybe auto detect, oh, this is a PyPico. Oh, this is an AdafruitGamma. You know, this is the baud rate. These are these are the serial parameters that I need. Just, like, curious how much of that you've incorporated into Belay as well.
[00:37:45] Unknown:
Right. So I think there's a fine balance between exposing everything to the user because, you know, people can get overwhelmed with choices. Like, why are you giving me a choice if there's only 1 good value for it? So with that, I don't wanna, for example, change a baud rate. There's a default baud rate in MicroPython and CircuitPython. You can, of course, change it, but most people might are gonna be drag and dropping their firmware onto their PyPico or whatever. And so there's gonna be 1 set baud rate. They could, of course, compile their own version, but then, like, you know, that's all of a sudden becoming more work, and I think that's more of the minority. 1 feature I did implement for, you know, these specific device identification stuff is detecting whether or not it's running MicroPython or CircuitPython, which is typically the biggest driver of what your upstream code on your computer will be running. In my Magneto project, I'm like, hey, all these libraries, they only work on circuit Python. I'm not about to rewrite them to be, you know, more generic to micropython.
So I will detect if you're running circuit Python, it'll run. If you're not running CircuitPython, I'm gonna raise an exception and be like, hey. You need to run CircuitPython. You're currently running my MicroPython. As for specific device identification, it gets a little bit hard. I wanted to do a bit of automatic device identification, but it seems like a lot of the identifiers aren't very well defined. So for example, a Pypico identifier running MicroPython is different than a pico running circuit Python. 1 might return, like, raspberry pi pico blah blah blah. The other 1 might just return rp 2040 for the microcontroller it's running. So I didn't quite feel like building up a whole dictionary of what mappings, all these different identifiers map to different boards, But maybe that might be something we do in the future if people actually need it. As far as device agnostic stuff, MicroPython, you know, everything is nothing is device agnostic. You have to be like gpi05, gpi06, whatever, but circuit Python attempts to abstract as much device specific stuff away as possible. So that's 1 thing I really do like that CircuitPython did. I like MicroPython and CircuitPython for different reasons, but CircuitPython attempted to make everything board agnostic, all the interfaces, so that you're not gonna have a bunch of if statements scattered throughout your code if you wanna support a bunch of different devices.
[00:40:02] Unknown:
As far as managing whether it's running MicroPython or CircuitPython, is that something where it's largely going to be kind of hard flashed into the board, or is that something else that Belay could potentially handle where you say, you know, this time I wanna run MicroPython, I'm going to automatically download and flash the MicroPython core before I load my program onto it, or, you know, this 1 should be circuit Python, handle that flash, or is that something that's sort of out of the bounds or something that Belay should be concerned with? Well, so that was the original reason why I wanted to actually identify the boards because sometimes I'm running micro Python on some boards, CircuitPython on others, and I'm like, it's kind of annoying to have to I'm getting so spoiled here. It's kind of annoying to have to then reflash the different versions of MicroPython to CircuitPython.
[00:40:45] Unknown:
The issue is is that, like, then we started getting into having detect, you know, these fake USB drives they're mounting to your system, and then we had to be also figuring out what's the correct URL to pull these firmwares from. And it started getting very device specific and stuff that might be very fragile and might have to change a lot. Like, you know, what if the URL changes or what if it mounts to a slightly different name? And then, like, you know, I don't wanna accidentally mess with someone's file system in a bad way. So I figured it was a lot of work that would end up being very fragile. While it would certainly be useful, I'm quite okay with, you know, dragging and dropping my firmware for now. But if anyone else feels strongly about that, maybe they can open up a GitHub issue on the Belay project.
[00:41:30] Unknown:
Absolutely. In your experience of building and using Belay for your own work and your own hardware projects, what are some of the most interesting or unexpected or challenging lessons that you learned in the process?
[00:41:41] Unknown:
Whenever using Belay, I guess, I didn't realize how flaky the USB connections are. So especially whenever you're connecting to a bunch of other electronics. Like, on my radio project, my pipe echo, I don't know, like, for some reason disconnects every, like, 10 hours or so just randomly. For my magnetometer project, I would notice that in my setup over there with a bunch of, like, magnets and stuff going around, maybe it's generating interference, but it would crash, like, every few minutes. And so that plus, you know, what someone else wanted on GitHub, they opened an issue, was can I recover from a crash? Because whenever you disconnect or the Pi Pico or whatever board you have temporarily loses power, it loses that whole interpreter's and so the way that we ended up solving that was to record all commands that you send send over so that whenever the pipe echo or whatever board comes back online, we can replay those commands to try and recreate that internal state.
So it's not always gonna perfectly recreate the internal state, but for most projects where you're just doing simple IO, you're turning on motors, you're turning on LEDs, you're reading in buttons, there's not a strong internal state. So you just need to get the driver code back over on the board and then automatically reconnect. So that saved a lot of headache in some of my projects because typically I'd have probably like an extra 150 lines of code to try and handle a flaky serial connection that's now been moved over into this library. I can delete that. That's typically how a lot of my libraries develop. I have a project I'm working on. I ended up developing a lot of code that's starting to get kind of complicated, kind of hard to test, move it over into a library where it's in a much better architectural state so I can test it and be confident in it, and then delete a whole bunch of code from my other projects so that it's more about, you know, the exact task I'm trying to accomplish rather than all of these auxiliary tasks that also need to be solved.
[00:43:34] Unknown:
For people who are interested in kind of embarking on their own hardware projects, what are the cases where Belay is the wrong choice or it's not going to solve the problems that they're running into?
[00:43:45] Unknown:
Belay is the right choice for rapid prototyping and for nonperformance heavy projects. Belay is the wrong choice if you need to squeeze out every last bit of your resources, whether that be your serial connection or the processing power on your microcontroller or memory usage, because it inherently runs on MicroPython, and MicroPython is inherently gonna be interpreted much slower than, you know, the native running code that's been programmed in c or maybe even Rust that's on the device. Like, it's gonna be 1 to 2 orders of magnitude slower. But for a lot of projects, you don't really care your 1 to 2 orders of magnitude slower. I mean, you know, the I think it goes running at, like, 133 megahertz, something like that. Don't know. It's over a 100 megahertz. While a lot of people's projects would work perfectly fine on, like, an 8 megahertz ancient AVR microcontroller from, like, 20 years ago. So for many things, I would trade off a lot of hard software development for easy, maintainable software development with still acceptable performance.
But, like, if you're trying to quickly interact with stuff actually, you know, even quickly interacting with stuff, if you're using the PIO on the Raspberry Pi Pico, you might still be in good shape. But, you know, if you're trying to squeeze out all that CPU power, if you are pushing your serial connection to the limit, like, if you need to transfer a bunch of binary data in between your computer and your microcontroller, Belay is probably not gonna cut it simply due to the naive serialization we're doing with that repr literal eval, you know, combo, it's probably going to be 3 times less efficient for sending binary data than you could if you had a custom bespoke protocol that you made for your specific project. So for those people, I would say, I believe not for you. It might be good for prototyping your initial idea, but then if you start getting bottlenecked, you'll probably have to move into your own custom, more complicated solutions.
[00:45:35] Unknown:
As you continue to use Belay and tinker with some of these projects, what are some of the things you have planned for the near to medium term?
[00:45:42] Unknown:
Near to medium term, I always wanted to build, like, a robot arm and stuff. And, like, you know, with those things, a lot of the processing is gonna be done on the computer. But I never wanted to do all of the protocol and firmware development. I always felt like that would just be, like, kinda difficult. But I always wanna build a robot arm. I've got my 3 d printer. It's all about just, like, you know, building up the courage to actually start that, and then also, you know, have it sit on your desk for, like, several months. So that might be 1 thing I have in in the near future.
[00:46:12] Unknown:
Are there any other aspects of the work that you're doing on Belay or your overall experiences or suggestions for building hardware projects or prototyping hardware projects that we didn't discuss yet that you'd like to cover before we close out the show?
[00:46:26] Unknown:
No. But, you know, if you like the library belay, just please also check out some of my other projects on GitHub. Some of them are hardware projects like this. Some of them are generic Python libraries for
[00:46:37] Unknown:
other tasks. Some of it's deep learning. There's a there's a little bit of everything on my GitHub repo. So, you know, check it out if you like stuff like this. Alright. Well, for anybody who wants to get in touch with you and follow along with the work that you're doing, I'll have you add your preferred contact information to the show notes. And with that, I'll move us into the picks. This week, I'm going to choose the Gunnar brand computer glasses. I had been using some of the kind of cheaper ones for a while, just some of the blue light blocking glasses since I spend all day on the computer. Recently decided to kind of level up into a nicer pair because my last couple of pairs broke. So the Gunnar ones have been great, comfortable, so definitely recommend those for somebody who spends a lot of time on front of screens. So with that, I'll pass it to you, Brian. Do you have any picks this week? No. That's it. That's it for me. Thank you so much for having me on the show. Alright. Well, thank you again for taking the time today to join me and for the work that you're doing on the Belay project. Definitely very interesting library. Great to see people investing in kind of reducing some of the points of friction involved in hardware projects because definitely seeing a lot of kind of renewed interest in building for more constrained devices. So appreciate the time and energy you've put into that, and I hope you enjoy the rest of your day. Alright. Thank you.
[00:47:47] Unknown:
Thank you for listening. Don't forget to check out our other shows, the Data Engineering Podcast, which covers the latest on modern data management, and the Machine Learning Podcast, which helps you go from idea to production with machine learning. Visit the site at pythonpodcast.com to subscribe to the show, sign up for the mailing list, and read the show notes. And if you learned something or tried out a project from the show, then tell us about it. Email hostspythonpodcast.com with your story. And to help other people find the show, please leave a review on Apple Podcasts and tell your friends and coworkers.
Introduction and Sponsor Messages
Interview with Brian Pugh Begins
Brian Pugh Introduces Himself
Brian's Journey into Python
Overview of the Belay Project
Scope and Use Cases of Belay
Target Audience and Project Cleanliness
Challenges in Embedded Project Development
Simplifying Development with Belay
Technical Implementation of Belay
Workflow and Usage of Belay
Unit Testing and Debugging in Embedded Projects
Brian's Personal Projects Using Belay
Belay's Impact on Hardware Development
Community Feedback and Use Cases
Device Identification and Compatibility
Managing Firmware and Device Specifics
Challenges and Lessons Learned
When Not to Use Belay
Future Plans and Projects
Closing Remarks and Contact Information
Picks of the Week
Outro and Additional Shows