After getting all the legs swapped out, I ran my existing software to validate that all the pieces worked together. Here’s a quick video showing basically what I’ve shown before, but with all new hardware:
Now that I have a bunch of the mk2 servos set and ready to go, a new leg design, a new power distribution board to power them, and a raspberry pi3 hat to communicate with them, I built a new quadruped! I’m calling this the mjbots quad A1, since basically everything is upgraded.
After I initially assembled the new legs onto the chassis, I realized I had the geometry slightly off and there was some interference through part of the shoulder rotation. I made up new printed parts and replaced everything in front of the camera. Thus, watch some high speed robot surgery:
The quad A1’s first job is to validate the new moteus controller in the quadrupedal configuration, after which I’ll use it as the primary development platform to get all my gait work done.
Now that the IMU is functioning, my next step is to use that to produce an attitude estimate. Here, I dusted off my unscented Kalman filter based estimator from long ago, and adapted it slightly to run on an STM32. As before, I used a UKF instead of the more traditional EKF not because of its superior filtering performance, but because of the flexibility it allows with the process and measurement functions. Unlike the EKF, the UKF is purely numerical, so no derivation of Jacobians is necessary. It turns out that even an STM32 has plenty of processing power to do this for things like a 7 state attitude filter.
One problem I encountered, was by default I have been building everything for the STM32 with the “-Os” optimization level. Unfortunately, with Eigen linear algebra routines, that is roughly 4x slower than “-O3”. Doubly unfortunate, just using
copts at the rule level or
--copts on the command line didn’t work. bazel doesn’t let you control the order of command line arguments very well, and the
-Os always ended up *after* any of the additional arguments I tried to use to override. To get it to work, I had to navigate some bazel toolchain mysteries in rules_mbed in order to allow build rules to specify if they optionally want the higher optimization instead of optimizing for size. I’m pretty sure this is not exactly what the
with_features mechanism in toolchain’s
feature rule is for, but it let me create a feature called
speedopt which turns on
-O3 and turns off
-Os. The final result is at rules_mbed/530fae6d8
To date, I’ve only done some very zeroth order performance optimization. I spent 15 minutes parameter tuning, making sure that the covariances updated to approximately the correct levels and I added a simple filter to reject accelerometer updates during dynamic motion. I did just enough runtime performance to get an update down to around 300us, which is just fine for a filter intended to run at 1kHz. More will remain as future work.
Here’s a plot from a quick sanity check, where I manually rolled the device in alternating directions, then pitched it in alternating directions. (When pitching, it was on a somewhat springy surface, thus the ringing).
The pitch and roll are plenty smooth, although they look to perhaps not returning exactly to their original position. At some point, I will do a more detailed qualification to dial in the performance.
After getting the power to work, the next step in bringing up the new quad’s raspberry pi interface board is getting the FDCAN ports to work. As described in my last roadmap, this board has multiple independent FDCAN buses. There are 2 STM32G4’s each with 2 FDCAN buses so that every leg gets a separate bus. There is a 5th auxiliary bus for any other peripherals driven from a third STM32G4. All 3 of the STM32G4’s communicate with the raspberry pi as SPI slaves.
Making this work was straightforward, if tedious. I designed a simple SPI based protocol that would allow transmission and receipt of FD-CAN frames at a high rate in a relatively efficient manner, then implemented that on the STM32s. On the raspberry pi side I initially used the linux kernel driver, but found that it didn’t give sufficient control over hold times during the transmission. Since the SPI slave is implemented in software, I needed to leave sufficient time after asserting the chip select and after transmitting the address bytes. The kernel driver gives no control over this at all, so I resorted to directly manipulating the BCM2837s peripheral registers and busy loop waiting in a real time thread.
After a decent supply of bugs were squashed, I got to a point where the host could send off 12 queries to all the servos with the four buses all being used simultaneously, then collating the responses back. I haven’t spent much time optimizing the cycle time, but the initial go around is at around 1.0ms for a query of all 12 devices which is about 1/3 of the 3.5ms I had in the previous single-bus RS485 version.
Here’s a scope trace of a full query cycle with 2 of the 4 CAN buses on the top, and the two chip selects on the bottom. Woohoo!
The next peripheral to get working on the quad’s raspberry pi interface board is the IMU. When operating, the IMU will primarily be used to determine attitude and angular pitch and roll rates. Secondarily, it will determine yaw rate, although there is no provision within the IMU to determine absolute yaw.
To accomplish this, the board has a BMI088 6 axis accelerometer and gyroscope attached via SPI to the auxiliary STM32G4 along with discrete connections for interrupts. This chip has 16 bit resolution for both sensors, decent claimed noise characteristics, and supposedly the ability to better reject high frequency vibrations as seen in robotic applications. I am currently running the gyroscope at 1kHz, and the accelerometer at 800Hz. The IMU is driven off the gyroscope, with the accelerometer sampled whenever the gyroscope has new data available.
My first step was just to read out the 6 axis values at full rate to measure the static performance characteristics. After doing that overnight, I got the following Allan Variance plot.
That gives the angular random walk at around 0.016 dps / sqrt(Hz) with a bias stability of around 6.5 deg/hr. The angular random walk is about what is specified in the datasheet, and the bias is not specified at all, but this seems really good for a MEMS sensor. In fact, it is good enough I could probably just barely gyrocompass, measuring the earth’s rotation, with a little patience. The accelerometer values are shown there too, and seem fine, but aren’t all that critical.
Next up is turning this data into an attitude and rate estimate.
The first thing I needed to get working on the new quad’s raspberry pi3 hat, was the input DC/DC power converter. One of the main functions of this board is to take the main DC bus voltage of around 20V, and provide the raspberry pi with 5V power.
In the previous iteration of this board, it was limited to an recommended maximum voltage of around 24V. As with all the components in my hardware revisions I aimed to support a higher input voltage. Here I switched parts to the Diodes AP64351 so that I could get to a recommended maximum voltage of 32V (the part’s absolute max is 40V).
Normally, bringing up power isn’t all that interesting. Either it works, or some pin is obviously connected incorrectly and it doesn’t. However here, I had different behavior. When first powering on the device, it kinda flickered the output to 5V or less maybe once every second or so. While probing with the multimeter, I found that when I probed the soft start selection pin all of a sudden it started to seemingly work! Assuming the probe’s input impedance must be enough to do something, I soldered on an SMD resistor in parallel with the soft start selection capacitor (after trying more capacitance) and got it to work a little bit, but it was still flaky, cutting out whenever the raspberry pi started to draw significant current during the boot process.
The second instance of the board exhibited similar symptoms, except there I managed to accidentally short the soft start selection pin to 18V, likely toasting it. However, surprisingly, that seemed to get the chip into a working state!
After much thought (and I should have noticed it in the picture above), I discovered I had managed to populate the incorrect part, the AP64350, not the AP64351. The x50 version is mostly pin compatible, but has a frequency selection pin where the x51 has a soft start selection pin.
Replacing that chip with the desired part got everything working as expected!
With the new FD-CAN based moteus controllers I need a way for the raspberry pi to communicate with them. Thus I’ve got a new adapter board in house that I’m bringing up:
This one has 5 independent FD-CAN channels, an IMU, a port for an nrf2401l RF transceiver as well as a buck converter to power the computer from the main battery bus.
The prototypes were largely constructed by MacroFab, although I did the Amass connectors and the STM32s because supply chain issues prevented me from getting those parts to MacroFab in time.
Next I’ll start bringing up the various pieces!
To get ready for the initial limited release of fdcanusbs, I needed to program a whole bunch of them. Further, I wanted to be able to scale up a few factors of two without being too annoyed with manual steps. Thus, enter my minimal programming fixure:
It isn’t much, just a raspberry pi 3b+, the official 7″ rpi touch screen, a STM32 programmer, a “fixtured” fdcanusb to drive the device under test, and a label maker. The touch screen is mostly there to display the results if anything goes awry, as in normal operation there is just one button to push. The final cycle time to program a fdcanusb and install it into the enclosure is around two minutes, which is good enough for now.
I’ve received my first production run of the fdcanusb CAN-FD USB adapters and they are up for sale at shop.mjbots.com!
While this is necessary for interacting with the moteus controller, it is also a fine general purpose CAN-FD adapter. At the moment, the USB interface is a platform independent line based serial one (Windows, Linux, MacOS). It doesn’t yet interoperate with SocketCAN on linux, but hopefully that will be resolved in the not too distant future.
To date with my machined parts, I’ve mostly left everything in an “as-machined” state. As I get ready to make some servos where I care at least a little about how they look, I decided to invest a little in surface finish options. I started using some Scotch-Brite, which gave passable results for some components, but it was hard to be consistent and the final results were always somewhat anisotropic.
Thus, a new vibratory tumbler!
This is designed for polishing ammunition cases, but works fine for any metal parts that aren’t too large. I’ve been able to fit entire back housings from the mk2 servo into it, although at that size the polishing isn’t super efficient.
The resulting parts look pretty decent for features that the media is able to reach, definitely better than my hand attempts: