Yet another in the series on building a new leg for the quad A1:
A motor driver like moteus switches power to the phases of a brushless motor using a set of 6 (or possibly more), MOSFETs. The typical topology involves 3 high side N channel MOSFETs and 3 low side N channel MOSFETs arranged in 3 half bridges like this:
Since the gates of these FETs need to be driven with potentially high voltages, and you never want the high side and low side to be on at the same time, typically a gate driver is used. For the moteus r4.5 and earlier controllers, the DRV8323 driver from Texas Instruments is what performs this function. This driver lets you configure the drive current for each of the gates for both operations, charging up the gate and discharging it. For high power drive systems, charging up or discharging the gate too fast can result in undesired transients like accidentally switching the other FET on due to capacitive coupling, or inductive ringing as the current starts moving through the FET instead of the body diode. If the gate charges too slowly, then the FET spends much of its time not fully on, which increases power dissipation in the FETs.
For the purposes of this write-up, this means that the FETs do not turn on or off instantly, and the turn-on time can differ from the turn-off time.
One of the lowest levels of control in moteus accepts a set of desired voltages on each of the 3 phases, and then selects a PWM duty cycle for the 3 phases which attempts to achieve those voltages. For most control purposes this mapping isn’t too critical, as usually it is driven by an outer current loop, which selects these values to try and achieve a desired phase current. Thus any non-linearities are mostly washed out, just reducing the control performance a bit. The times it is most important is during motor calibration when a fixed voltage waveform is applied for spinning the motor, and when the phase resistance and inductance of the motor are estimated.
To date, that function has used a relatively simple model that treats the 3 phases independently. For each phase, the voltage is mapped to a PWM using a piecewise linear approximation with two segments. This works reasonably well on the r4.5, and gets the resistance and inductive measurements into a usable territory.
As a consequence of the global semiconductor apocalypse, I’m working on a new version of the moteus controller that uses a gate driver which it was possible to purchase with less than a year lead time. Unfortunately, it is more sensitive to failure induced by ringing than the DRV8323 was. Because of the abbreviated design timeframe, I left the power stage of the r4.5 alone when making this switch, and it had a fair amount of ringing when using the drive currents it is configured with by default. So, for the new board, it needs to be run with much slower gate drive waveforms than the r4.5 board could achieve.
Using the lower current results in a very distorted mapping between PWM and voltage on the phase terminals, such that calibration wouldn’t complete and measuring the phase resistance was not practical. You can get an idea of the problem by looking at the plot below of phase current during the motor calibration phase. The driving voltage is a sine wave, and the current is supposed to be a sine wave also. Because of the additional distortion, low voltage commands result in nearly no actual current production and there is a large undesired waveform when the three phases are active, but at different levels.
Thankfully current control mostly worked, although it likely suffered from degraded performance at small currents. Despite that, not being able to calibrate is a big deal, so I had to take another look at this control step to make it able to handle the larger non-linearity.
Quantifying the problem
I didn’t necessarily want to try and model the gate drive at a more detailed level to understand this, to tackled the quantification problem by brute force. I wrote a simple tool which commanded a fixed PWM on the A phase, and then did a 2D sweep over the B and C phases in a region where my power supply could provide sufficient current without undue heating. The plots of the B, and C currents as 3D surfaces are shown below (the A current can be found from those two currents).
I think numerically inverted that mapping, to determine the necessary B and C pwm values to achieve a given B and C phase current.
The C phase plot looked the same just mirrored. Notably, this has two distinct regions. There is a region which extends to infinity where the command B is related to the desired B 1 to 1 with a fixed offset. However, that region only seems to exist beyond a line that is related to the C command. On the other side of that line, the fixed offset is no longer required. I did a rough curve fit to this, which looks like:
In the above plot, the sampled data is now faded out, and the simple surface fit is fully saturated. It works plenty well, and is controlled by 2 parameters as before (since the dividing line between the two regimes seems to not be something that is likely to need to be configured).
I reworked the mapping to always operate in terms of a B and C phase that are larger than the A phase, then shift things back to the correct phase and balance afterwards. That way this correction surface could be applied as is.
This new technique gives much better low-voltage performance, especially when more than one phase is active and when larger amounts of compensation are required. Here’s a plot showing the current waveform during a sinusoidal calibration sweep.
With the r4.5 board, you can see the low voltage performance improve a fair amount. With the newer r4.8 board and its higher required compensation, the improvement is dramatic.
I’m excited to announce the release of moteus r4.8!
Due to the ongoing semiconductor apocalypse, this minor release uses some alternate components which were easier to source. It remains compatible with the r4.5 and r4.3 both electrically, mechanically, and with firmware.
A secondary win is that external primary encoders are now supported, via an unpopulated connector pad on the backside of the board. I’ll write up more about that in a later post.
Good luck building!
What happens if you accidentally write to address 0x00000000 on an STM32 microcontroller? Answer: usually almost nothing, because most linker scripts by default map a bank of flash there, and you can’t write to flash normally. The flash controller does notice and sets an error flag, but most applications aren’t exactly checking the flash peripheral’s error flags on a regular basis.
However, if you use the HAL to try and perform a flash operation, it doesn’t bother checking the error flags *before* trying to perform an operation. It just tries, and reports any errors it observes at the end. So, if you have an application that occasionally makes a spurious write to the zero address, and also performs flash operations, it will manifest as spurious failures of the flash operations.
How might one go about discovering which part of a large application is accidentally writing to address 0? The debug hardware on the STM32 is unable to use a watchpoint for peripheral addresses, like the flash controller’s error status. What I ended up doing was using the SYSCFG_MEMRMP register to make address zero be an alternate mapping of SRAM after the application has started. After which, you can set a data watchpoint on address 0 to get a break exactly when the spurious write occurs.
For me, that puts the ISR table there, but that isn’t a problem because I only needed to do this temporarily to use a watchpoint.
In the spirit of my last post on the topic, here is another video-only update on a new leg design for the quad A1:
The moteus controller, communicates exclusively over CAN-FD for command, telemetry, and diagnostics. It will accept either standard or extended frames, and until now, the ID format in terms of bits looked like the following:
33333222222221111111100000000 43210765432107654321076543210 XXXXXXXXXXXXXQSSSSSSSDDDDDDDD
- X: Don’t care
- Q: 1 for query, 0 for no query
- S: source ID
- D: destination ID
If the lower 8 bits matched the configured ID, all the X bits would be completely ignored and moteus would accept the CAN message as if it were destined for itself. This may not be super desirable, as it consumes nearly all of the available CAN-FD addressing space.
Starting with firmware version 2021-08-20, moteus now uses the following ID format:
33333222222221111111100000000 43210765432107654321076543210 PPPPPPPPPPPPPQSSSSSSSDDDDDDDD
Where P is a 13 bit “CAN prefix” that can be configured and defaults to 0. moteus will only accept CAN frames where this prefix matches the configured value*, and all frames it sends will have the prefix set as configured. This allows you to reclaim large sections of the CAN ID space for other devices in the event that moteus controllers share a bus.
[*] Footnote: The bootloader will require that the CAN prefix be set correctly, but WILL NOT set the prefix on the messages it sends. The existing moteus client side tools will function, but other devices on the bus may be confused.
I and the quad A1 had a great time at the FAB16 festival in Somerville this past weekend. The robot got to do a lot of running around, it and I got to meet a lot of new people, and two bands showed up!
Here’s a video of the quad A1 and Spot hanging out trying tricks:
And here’s another one of a “dance off” (kinda) with the School of Honk band. Note that although both robots collapsed at the end of this video, the quad A1 got back up and kept dancing. (Spot wasn’t broken, they just didn’t want to right it when close-ish to people). Thanks to Kathleen and Josh from BD for inviting me into their area and for being such good sports!
At the very end of the day I managed to drive the quad A1 into a sewer grate… here’s the robot carnage that resulted:
Fortunately, only 3D printed parts were broken, so it will be an easy repair.
The title says it all! Check out the quad A1 and friends there!
I’m going to try something new for this effort, and instead of making a bunch of blog posts culminating in a video, I’m going to make a bunch of intermediate progress videos. They may, but may not, culminate in an overview blog post. Here’s the first!