Hierophect’s Circuitpython 2021

I’ve been working on Circuitpython for about a year and a half now, contributing to the module code that helps users access chip features. 2020 was tough, but this community has been a refuge against the worst parts of the pandemic, and I feel extremely lucky to have gotten to learn and work on so many different things despite other parts of life being put on hold.

Here’s some of the stuff that happened this year:

  • I spent the early part of 2020 working on support for the STM32 H7 and i.MX chips, and the later half on modules for the ESP32-S2.
  • Some of the stuff I had hoped for got added, like deep sleep/low power features.
  • Other stuff didn’t quite make the cut, like merging in Micropython and adding C module support (hopefully we’ll still get to that eventually).
  • My personal goal to contribute a community library for the Dynamixel servo motor went well!
  • My personal goal to add DMA support did not (I got hopelessly tied up in low level message corruption).
  • I’d hoped to start a meetup in Boston for Circuitpython. For sad and obvious reasons this could not happen. But the number of interested people was encouraging, and I think it’d be worth it to try again in the future.

I think we did a good job of expanding the platform with some new and highly capable chips – the STM32 H7 with raw power, the i.MX with crazy speed for the price, and the ESP32-S2 with WiFi.

But I think one challenge we faced was providing examples of how to actually apply this capability – this was easier with the ESP32-S2, which quickly inspires all kinds of internet-connected builds, but harder on the i.MX and STM32, which are best suited to more complicated projects that are hard to fit in a Learn guide.

So what would I like to see this year?

  • I’d like to see our more powerful chips given new example projects and documentation – big ram-consuming display projects on the H7, fast signal handling on the i.MX, and passed-over features like AudioIO on the F405.
  • I’d especially love to see some introductory robotics support:
    • STM32 has a machine learning module called CubeAI, which can be used for on-chip machine learning and computer vision. This, or any other ML tool, would be super cool to implement.
    • A ROS (Robot Operating System) messaging interface would open up Circuitpython microcontrollers to more advanced robotics teams, and could help beginners get started learning about popular robotics platforms.
    • Camera modules on the ESP32-S2 and STM32 chips would open up all kinds of neat projects.
    • I’d like to see more advanced servo libraries and display code aimed at robotics use.
  • I’d like to see more UI tools – Circuitpython already has some good tools for this, but there’s a lot of potential for new DisplayIO widgets and Touch libraries that could power more complex projects.
  • And a final, weirder idea – I’ve been wondering if we should try exposing some of the underlying code we’ve created for Circuitpython for use in C projects. I see the potential for a C API that that mirrors what’s used in Circuitpython, so you can jump into native embedded projects without having to learn a whole new codebase like Arduino. There are some big challenges with this, particularly when it comes to exception handling. But the appeal of being able to switch between chips with C projects as easily as we do in Circuitpython is super appealing to me. I’m hoping to work on my proof of concept more this year.

Outside of these broader dev ideas, I’ll also be plugging away at my various Circuitpython PCB projects, which I think are best summed up by this old quote from Bell Labs back in the 80s:

“The first 90 percent of the code accounts for the first 90 percent of the development time. The remaining 10 percent of the code accounts for the other 90 percent of the development time.”

Whether it’s projects or a pandemic, here’s to a year of wrapping things up.

Hierophect’s Circuitpython 2020

As we hit the new year, the call has gone out to the greater Circuitpython community to contribute their thoughts, hopes, and projects for 2020. I’m excited to share some of the things I’ve been thinking about for the project.  

I was brought on late last summer by Adafruit Industries to build and maintain the STM32 port for Circuitpython, working on the API code beneath the python interpreter that allows users to command the peripherals that power each Circuitpython development board. It’s been a blast working with the team and learning more about the project, as well as inspiring and humbling to witness all the progress that’s been made over this past fall. 

But while I’ve spend plenty of time mucking around in the deep wizardry of the STM32 HAL, I’ve never properly been on the user end of Python. The limited experience I do have actually developing with Circuitpython has been pretty exciting; being able to tweak a calibration value or change an algorithm and see those results instantly rather than after 5 minutes of compilation and re-programming is a mind-blowing experience for an embedded C developer. But my python coding skill itself leaves something to be desired, something I’m forced to sheepishly admit on Github issues that straddle the line between Python and my C code. 

Thus, one of my favorite people to talk to in my local network is Don Blair, a developer for an open source agricultural tech project who uses Circuitpython full-time for his work. What excites me so much about Don’s projects is the potential for Circuitpython to be a force for good in the world, not just as a teaching tool, but through the actual tangible projects it is used in. I felt a 2020 post wouldn’t be complete without a perspective like this, completely from the user side, and with the end goal of making the world a better place through code. So in preparation for this post, I sat down with him and we did our best to combine our ideas from both sides of the Circuitpython project, from the code.py file down to the bare-metal C and register-driven peripherals that make it all work. Here are some of the things we talked about. 

Scientists, Activists, Programmers

Lucian: I think it’s an exciting idea for Circuitpython to be used by people who aren’t necessarily beginners to tech, but are simply beginners in hardware. Even for a seasoned programmer, switching to a microcontroller project from another field is a rightfully intimidating process – there’s a huge volume of material to learn and new skills you need to acquire if you simply jump into the raw C. Arduino made this process easier, but Circuitpython makes it accessible on a whole new level. I’ve found myself recommending Circuitpython to data scientists, environmental activists, and machine learning specialists alike who want or need a hardware component in their projects but can’t simply become embedded engineers on the fly. Python is a language that many of them already know – a 2018 study of 23,859 data professionals found it to be the most popular by far, with 83% of respondents using it regularly – and Circuitpython gives them the means to use their existing background with a real-world interface, reading sensors, controlling robots, and controlling remote systems. 

Like I said before, I’m excited by how these projects spread good past the education phase. I think teaching people new skills is an intrinsic good on its own, but the prospect of Circuitpython helping scientists to diagnose our oceans and farmers to better understand their crop cycles seems like a whole new level of impact to me. In 2020 I hope we can do more to recognize and encourage this kind of Circuitpython use, and I hope to help add new features that better support these kinds of projects. 

Don:  I’ve been working with environmental scientists and researchers on monitoring projects for several years now, and I’ve learned from many of them how important environmental monitoring has become in land stewardship, wildlife conservation, and in assessing — and figuring out how best to mitigate — the impacts of climate change.  And what I keep hearing from these practitioners is that they’re stuck using proprietary, difficult-to-operate, expensive monitoring hardware — often stuff that was designed in the early 90s, and encrypts its data (which could easily be a simple CSV file) so that using the instrument is only possible with an expensive software license — where the software typically only runs on a now-outdated version of Windows.  

Researchers and farmers who have been exposed to the world of inexpensive, open source hobby electronics — with its wide range of easily-interfaced devices, connectivity options, and flexible data formats — are amazed by the capabilities they see.  But as Lucian says, even the relatively accessible Arduino platform can be intimidating to novices, with the consequence that adoption and development of open source hardware in environmental monitoring applications seems slower than it ought to be. That’s why the *truly* beginner-friendly approach taken by CircuitPython recently has been such an exciting development for me:  there is finally a platform that I can unhesitatingly recommend to farmers, hydrologists, agronomists, and resource managers. 

Among programming languages, Python is particularly popular, and particularly easy to understand; and the hardware is often set up so that no special IDE is required — the code can be accessed and modified on the device as if it were a USB stick.  This represents a huge leap in accessibility and usability for these communities. A detailed, high resolution picture of environmental dynamics is going to become more and more important in the next few years — we need to make deploying monitoring devices as frictionless and easy for practitioners as possible.  I think CircuitPython really has the potential to make this possible, and to become the ‘beginner-friendly’ standard in farming and in scientific research.

A Sleep/Suspend Interface:

Lucian: I’ve worked on a number of low power projects in the last year that need to go months or even years without having the batteries replaced. The current version of Circuitpython doesn’t have much support for this kind of power efficiency – you need to assemble your own external power-off system, which makes for a bigger form factor and requires the device to be hard rebooted. This year I’d like to explore a suspend or Wait-For-Interrupt system that can smoothly enter and wake from sleep mode, so that Circuitpython devices can enter the Suspend state offered by most microcontrollers that sustains the device memory on only a few nA of power. 

This is an essential feature not just for common hobby projects like alarm clocks, battery powered robots, or open-source mobile devices, but also for environmental sensing applications. Many data gathering devices must be left in the field for years at a time and only wake for a few minutes at a time every hour, day, or week. It’s a feature I think would be a practical addition for both sensor/device oriented beginners, and also the academic applications I’m excited about in data science. 

Don:  Because CircuitPython makes sensor measurements and datalogging so straightforward, I’ve been eager to deploy battery-powered field loggers using CircuitPython firmware.  But one immediately runs up against the lack of any ‘low power sleep’ functionality on the CircuitPython hardware. My current method for getting around this when deploying CircuitPython hardware in the field is to use an Adafruit TPL5100 Power Timer breakout, which acts as an external power switch, turning the entire datalogging microcontroller circuit off between logging sessions, and waking up at intervals that are set with a resistor value.  

This method works fine, as far as it goes — but it adds cost, and its range of functionality is quite restricted compared to what would be possible if the micro itself was capable of low-power sleep:  waking on interrupt in response to an external signal (sensor reading, radio signal, or RTC); storing running parameters in memory rather than e.g. needing to write to flash or SD card; etc. It would be really useful if farmers and researchers who wanted to quickly and easily deploy dataloggers or remote radio nodes in the field could instead simply call a low-power sleep function in CircuitPython.

Dynamically Loaded C

Lucian: when discussing this post, I had a moment with Don where we remarked on how crazy it would be if native C code could be loaded dynamically into a Circuitpython program just by dragging them into the drive. Imagine my excitement when reading the other Circuitpython 2020 posts and learning via Deshipu that Micropython has just recently done this. Circuitpython benefits from a clean shared-bindings API that provides familiar access to basic chip functions across any supported development board. But one downside of this is there isn’t really a conceptual home for modules that are board-specific or so early in development that they haven’t nailed down their API. One way to handle this is to make it easier to add new modules, a process which I’m interested in providing more documentation for. But I think board specific modules could be an opportunity to expose chip specific features and enable developers to distribute new modules for testing that could later be turned into official additions. 

I’d expect this to also be relevant to the use of Circuitpython in scientific applications. I’d love to see the door opened to unique modules like a machine learning or motor driver stack on chips like the i.MX RT, or enabling researchers to use a custom C library for a DSP project that they can’t justify adding to the main API but want to expose to novice researchers for use in environmental sensors. Without more experience, I can’t say with confidence what would and wouldn’t be possible with a system like this, but I’d love to at least explore the concept this year. 

Supercharging SPI

Lucian: one less broadly applicable thing I’d like to explore this year is batching data to SPI and other communication methods via Direct Memory Access (DMA), which is relevant to a number of my personal imaging and sensor projects. I think a more advanced native C layer for buffering the inputs and outputs of the BusIO modules would be neat – a setup where python code is used to initialize and diagram a communication system, but not necessarily to run it realtime to save speed. My hope would be to allow things like faster DSP, data storage and DisplayIO outputs, without compromising the beginner focus of the API. 

Projects for this year

Lucian: I have a lot of projects I’d like to do, which in conjunction with the above is probably stupidly ambitious. In all likelihood I’ll start a number of things and only keep up with my favorites, as per usual… but here’s my shortlist.

– Adding half-duplex UART and creating a library for the Dynamixel, my favorite kind of servo motor, which uses a shared addressable bus and has some great features like continuous rotation mode, torque detection, auto shutoff, etc. The bonus, of course, will be putting it in a robot. 

– Porting my old SPUDwrite project to Circuitpython and open-sourcing it, using the E-paper, keyboard and SD card code. I’d also love to work on some new SPUDs (Single Purpose User Devices). A lightweight, hackable SPUDphone comes to mind…

– Finish the featherwing for my generic breakout board tester. 

– Start a Circuitpython meetup here in Boston at Artisan’s Asylum! Hopefully more news on this soon. 

Don:  I’m planning on continuing to support the CircuitPython projects that we’ve deployed in Portugal (soil moisture monitoring via a LoRa — WiFi gateway, pics here), Nebraska (soil moisture via cellular modem, pics here), Maine (sea level rise — pics here), and on Martha’s Vineyard (tide monitoring, pics here) while continuing to develop more applications for research at sea. 

In particular, I’m hoping to further develop and refine the CircuitPython-based satellite modem system that we tested out on the R/V Neil Armstrong (a research vessel based at Woods Hole — pics here) a few months ago, with hopes of using it as the core electronics for a ‘drifter buoy’ system that would temperature of currents off the Northeastern US coast. 

We’re also working on the analog front-end for an impedance spectroscopy system that we’re planning on driving with CircuitPython to make it easier for laboratory researchers to get things up and running.  In general, CircuitPython is becoming our go-to for making scientific research instrumentation as accessible and easy to understand and modify as possible — we’re really passionate about getting the word out about it, and showing people what’s possible now!

Lastly

I’d like to express appreciation for everyone who’s written Circuitpython 2020 posts so far, they’ve been really inspiring to read! Many of the topics people have brought up, such as package management and automated testing, have been covered so well I didn’t bother to include them here, but I’m super excited to see where they go and help wherever I can. I hope everyone achieves their goals this year, no matter how ambitious – here’s to an awesome 2020 for Python on hardware. 

Dynamixel Servos

Makers who have begun to outgrow introductory robotics and have started to research more powerful systems may be familiar with the Dynamixel series of servo motors. The Dynamixel has a number of advantages over the common RC Servos that are typically used in RC airplanes and beginner-level robotics projects. In general, they add functionality and flexibility at the cost of added complexity and a slight loss of cost efficiency, making them ideal for robotics projects that are beginning to outgrow the hobby stage.

Pros:

  • Lightweight for their torque: just half the weight of a metal geared RC servo of the same weight (great for robot arms that have to lift their own weight).
  • Single  Bus: all the motors in the system can be attached to the same network bus, with each motor only responding to instructions marked with its specific address. No more rats nest of cables!
  • Programmable: Dynamixels contain an internal memory you can modify to change their speed, range of angles, and address. They can also return data about their operation to be used by their controller system
  • Mistake-proof: temperature and over-voltage protection is built in and will automatically shut down the motor when overstressed, rather than shredding their own gearing like an RC servo.
  • Wide Operating Rotation: 300˚ or higher, compared to the maximum 180˚ of virtually every RC servo.
  • Continuous Rotation Mode: most dynamixels can disengage their gearing on command and rotate freely, though they lose their servo functions when doing so.
  • Scalable: the cheapest dynamixel (the AX-12) costs $45 and has 212 oz-in of torque, but more expensive models can go all the way to 1,400 oz-in and use the same network and instruction set, making it easy to upgrade cheap prototypes into much more powerful systems.

Cons:

  • Cost/Torque Disadvantage: the $45 AX-12 has 212 oz-in of torque, compared to 277.6 oz·in on a $18 LewanSoul LD-20MG metal-geared RC servo.
  • Increased Complexity: the cost of all those extra features. Because they are programmable and use a UART network instead of PWM, Dynamixel motors require specialized controllers and custom libraries to run, making projects that use them significantly more complex.

A Direct Comparison:

To provide a specific comparison to reference, here’s a direct comparison of the similarly priced Dynamixel AX-12 and the FEETECH FT5121M and FEETECH FT5335M from Pololu:

Stat AX-12 FT5121M  FT5335M
Voltage  12V  7.4V  7.4V
Torque  212 oz·in  285 oz·in  550 oz·in
Speed  0.169 sec/60°  0.12 sec/60˚  0.18 sec/60˚
Weight  55g  60g  180g
Size  32 x 50 x 40 mm  40.5 × 20.5 × 37.5 mm  62.8 × 32.5 × 55.9 mm
Rotation  300° or Continuous Turn  180˚  180˚
Price  $44.90 $49.95  $39.95

As can be seen, the stats between the AX-12 and FT5121M are pretty close, so you don’t pay much of a premium for the extra features on the AX-12. With larger motors, you can also note the tradeoff between power and weight – note how the FT5335M’s higher torque comes at the cost of being almost twice as heavy, making it less practical for something like a robotic arm despite its power.

Getting Started:

What you’ll need:

[link] AX-12
[link] Arbotix-M Microcontroller
[link] 5V FTDI Cable *UartSBee also works but it’s more expensive
[link] 12 V power supply *also available on Amazon
[link] 2.1/5.5mm Jack to 2.5/5.5mm Plug Adapter *optional, depending on power supply
[link]  Power hub 1 (6 way, no capacitor) *optional
[link] Power hub 2 (4 way with capacitor) *optional

I’m not going to do a full tutorial of how to do the initial setup of the Arbotix-M unit, since Trossen Robotics already has a really good one here:

Initial Setup Tutorial

However, there are still some things to keep an extra close eye on! Here are some recap notes on potential issues:

  • This tutorial requires Arduino 1.6 or higher. I found that all the example code works fine in Arduino 1.8, the latest version as of this post.
  • While the Arbotix-M is programmed with Arduino, it does not have the USB port that most Arduinos have, and must be programmed through an FTDI cable! I missed this the first time I set up the platform and it delayed my project by a week. Don’t make the same mistake I did.
  • You can extend the Dynamixel communication bus using one of the two extension units above. They can also take in extra power so you don’t overdraw your power supply when you’ve got a lot of motors, and one has an extra capacitor to buffer the power line.
  • Both the Arbotix-M and the communication bus extenders both have power jacks that are 2.5×5.5mm, like an Arduino. However, most 12V power supplies, including the ones on their website are 2.1×5.5mm and will not fit. You need a 2.1 to 2.5 converter, also listed in the above parts list. Double check!
  • Don’t miss the Setting Dynamixel IDs part 2 of the  at the bottom, which gets you set up with the Dynamanager Java application. You need to do this to use more than 1 servo on your network bus, otherwise they’ll all respond at once!

Example:

Once you’re set up with a network of servos with different addresses, and have tested each motor with AXSimpleTest to make sure they work, here’s a quick Arduino sketch to let you test it out:

//import ax12 library to send DYNAMIXEL commands
#include <ax12.h>
int addr = 0;
int location = 0;

void setup()
{
 Serial.begin(9600);
}
 
void loop()
{
 while (Serial.available() > 0) 
 {
 
  //look for valid integers for brightness and store to storage variables
  addr = Serial.parseInt();
  location = Serial.parseInt();
  
  Serial.print("Motor: ");
  Serial.print(addr,DEC);
  Serial.print(" Location: ");
  Serial.println(location,DEC);
 
  //look for the newline in the serial stream:
  if (Serial.read() == '\n') {
   //constrain values to fall within viable angle range
   location = constrain(location, 0, 1024); //limit 1024 for ax12s, 4095 for mx64
 
   Serial.println("#############");
   Serial.println("Comm Established with address " + String(addr));
   SetPosition(addr,location); //set the position of servo at address
   delay(1000); //wait for servo to move
 
   int temp = ax12GetRegister(addr,AX_PRESENT_TEMPERATURE,1);
   Serial.println("current temperature");
   Serial.println(temp);
   int pos = GetPosition(addr);
   Serial.println("current position");
   Serial.println(pos);
   Serial.println("current error");
   Serial.println(ax12GetLastError());
  
  }
 }
}

To use it, type in the address of the motor you want to move, followed by a number from 0 to 1024 representing the angle you want. Make sure your serial monitor appends a newline on send, and hit enter – that specific motor in the network should move. For instance, typing 2,512 should move motor #2 to about the halfway point of its total rotation at 150˚.

If each motor in your system works, you should be all set to start implementing them into more complex projects.