More adventures in STM32G4 bringup

Last time I had an actually hard problem…, a mis-aligned stack which caused randomly misbehaving software.  This time, I had a more prosaic problem.  One that while not necessarily as interesting, was even more time consuming and frustrating.

The serial port wouldn’t work.  I had copied the module I used for DMA based receive and transmit from the STM32F4 and it just wasn’t working.  Nothing was written and nothing was received.  I carefully inspected the software many times.  I looked at the registers in the debugger and nothing seemed obviously amiss.  I read the datasheet to look for subtle differences in the theory of operation between the STM32F4 and STM32G4 but came up empty.

Eventually, I went completely out of the box and compiled one of the STM provided UART examples from STM32CubeMX.  That did work!  But how?  I once again carefully inspected its source and mine and saw no obvious differences.

Then, I took the ultimate slow path in debugging and binary searched, gradually transforming the STM provided example into my code half by half to figure out which transformation was the ultimate cause.  This did do the trick.  The final fix:

-  huart_.Init.WordLength = 8;
-  huart_.Init.StopBits = 1;
+  huart_.Init.WordLength = UART_WORDLENGTH_8B;
+  huart_.Init.StopBits = UART_STOPBITS_1;

That’s it.  In the old version, I passed in to the HAL the word size and number of stop bits as integers.  Somehow this actually worked, despite being documented as requiring the necessary #defines even in that version.

Notch another win up to: “it sure would be nice if there was less undefined behavior in C/C++”.

Adventures in bringing up the STM32G4

In my continued quest to bring up the STM32G4 for the moteus controller r4.1 and other efforts, I get to discover and learn about the million and one ways in which things don’t work on my path to find the one or two ways in which they can work.  I recently had an interesting enough problem that it is worth it to signal amplify google searches on the matter for the next unfortunate soul.

First, the symptom: snprintf of 32 bit floating point values gave seemingly random results.  The diagnostics and configuration functions of the moteus controller can in some modes render values into ASCII for human readable interactions.  In this particular instance, I was enumerating the full set of configurable values and saw that all of the floating point values read bogus values, like “0.00000”, “-0.00000”, “2.00001”, etc, no matter what actual value they were set to.  Integral types seemed to work fine, and the debugger showed that parsing floating values when setting the configurable values was working just fine.

I had a similar problem not too long ago, when a linker script mis-configuration resulted in an overlap between the RAM based interrupt vector table and the first few global variables resulted in state necessary for C library functions being corrupted during early boot.  Thus, I began investigating under that assumption.  However, the linker script definitely had enough room (I allocated 0x200, where the datasheet shows that the final entry is only 0x1c4).  Just to be sure it wasn’t some other global memory corruption issue, I stepped through the first 5,000 or so assembly instructions of an snprintf call, inspecting all RAM that was accessed and making sure that it wasn’t corrupted.  I did notice that my 32 bit floating point value had been promoted to a 64 bit value when passed to snprintf, but didn’t think any more of it at that point.

Despite all that debugging, I found nothing of interest and turned to my choice of last resort, googling for the original symptom.  Usually this doesn’t find much, because the set of root causes for any one particular failure is so vast and many problems are the result of simple misconfiguration.  However, in this case, I hit the jackpot after digging through an hour worth of junk results.

The problem ultimately was one of stack alignment.

When I ported mbed to the stm32g4, I created the initial linker script from the STM32F446 that I had been using, but made the interrupt table bigger so that I wouldn’t have to worry about it at all.  However, I managed to goof it up and ended up with the top of the stack aligned only to 4 bytes, not 8 bytes.  Since 32 bit floats are promoted to doubles when passed through a variadic function, this resulted in the double being not 8 byte aligned when passed on the stack.

Once the problem was identified, the fix was easy enough:

moteus servo mk2: Reducing weight

After having produced the first functional demonstration of the moteus servo mk2, my next step was to decrease the weight.  While I was at it, I made two other changes:

  • Axial connections: I switched to a design with entirely axial connectors, which removes the need for 4th axis machining when producing the parts.
  • Planet Input Bearing: I switched the planet input bearing to be inserted from the rotor side.  This way, the bearing is captured between the planet input and the rotor, rather than between the planet input and the gears.  That also improves the ability to assemble and disassemble the unit.

moteus_mk2_reduced_weight_2

Slimming down the housings drops around 100g from the total weight.  I may still try to take out some weight from the planet input and output, but they don’t weigh much to begin with so the potential gains there are small.

Next up I’ll manufacture and assemble this, then get it running.

 

moteus controller r4.1

Another step in my plan for the next revision of the moteus servo mk2, is an updated controller board.  As mentioned in my roadmap, I wanted to revise this board to make improvements in a number of domains:

  • Communications: Now instead of RS485, the primary communications interface is FD-CAN.  This supports data rates of up to 8 Mbit and packet lengths up to 64 bytes.  The header is nominally at the original CAN bit rate, but I have no need to be standards compliant and am running very short busses so I may run everything at the higher rate.
  • Connectors: Now there exist power connectors, in the form of XT30 right angle connectors and they are also daisy chainable like the data connectors.  Additionally, all the connectors exit from the bottom of the board to make routing easier in configurations like the full rotation leg.
  • Controller: This uses the relatively new STM32G4 controller series.  It is lower power than the STM32F4, supports FD-CAN, and also supports closely coupled memory, which may allow me to improve the speed of the primary control loop execution by 3 times.
  • Voltage range: This board now has 40V main FETS, with all other components at 50V rating or higher.  Thus it should be safe with inputs up to 8S (34V or so).
moteus_r41
moteus r4.1 rendering

It still maintains a number of the capabilities of the moteus r3.1 controller:

  • Integrated FOC encoder: An AS5048 encoder is mounted in the center of the back, which allows direct mounting above the rotor for FOC control.
  • Form factor: The entire board is 45x54mm, with M2.5 mounting holes.  It is smaller than a 60mm BLDC motor and much smaller than an 80mm one.
  • Integrated current sensing: It uses a DRV8323 to drive the FETS, which includes current sensing for closed loop current control.

My first attempt at this, “r4”, came back from fabrication in an nonredeemable state.  I used the digikey supplied footprint for the STM32G4 UQFN part, which looked mostly correct on the surface.  However, while the footprint was good, the pinout was for the TQFP variant!  This resulted in me shorting out several power pins to ground right next to the exposed pad in a way I couldn’t easily rework.

r4.1 seems to be in better shape so far.  It powers up, and I now have blinking lights!

dsc_1958
moteus r4.1 as built

Next up is actually porting the control software to the new controller and communications interface.

Update on Pocket NC v2-50 Threadmilling

After machining a fair number of parts with threads, I’ve tweaked my thread milling feeds and speeds to both go a little bit faster, give a more reasonable fit, and remove the last bit of niggling interference with the M2.5 recipe.

I’ll list the changes here, and have updated the original recipe

Old New
Chamfer Width 0.10mm 0.05mm
M3 Pitch Diameter Offset 0.538mm 0.568mm
M3 Stepovers 10 6
M3 Repeat Passes NO YES
M3 Lead To Center NO YES
M2.5 Pitch Diameter Offset 0.430mm 0.480mm
M2.5 Stock to Leave 0.0mm -0.02mm
M2.5 Stepovers 7 4
M2.5 Repeat Passes NO YES
M2.5 Lead To Center NO YES

Notably, the “Lead To Center” option found on the linking tab is what prevents the M2.5 threads from rubbing when inserting in later passes.  Thanks to Quincy Jones from Implemented Robotics for that tip over in the mjbots discord!

 

moteus servo mk2: Functional test

Now that I have at least one functioning version of each of the pieces made for the moteus servo mk2 (planet input, outer housing, front housing, and back housing), I integrated all of them together into a functional prototype.

dsc_1841
A bunch of pieces
dsc_1842
Front housing with stator, internal gear, and planet output installed
dsc_1844
Planet input, gears, and shafts installed
dsc_1855
All put together… a bit on the heavy side for now

And finally, spinning it up!

moteus servo mk2: Back housing

The back housing is the final piece of the moteus mk2 servo that I wanted to prototype.  (The planet output is identical to the mk1, so I could use extra stock I had of it for the prototypes).  It is large, and only mates directly to 4 other things, which makes it a little less complex than the front housing.

back_housing_exploded1.png

back_housing_exploded2.png

Design

I had initially designed the back housing to mate to the as-yet-unannounced new version of the moteus controller, the r4.x series.  Unfortunately, I don’t have any of those working yet, so I tweaked the design to temporarily fit a r3.1 controller, which looks like this:

back_housing_exploded_r31.png

It mates to the rotor bearing in the center, the outer housing around the perimeter, provides support, mounting and heatsinking to the controller, and provides a mounting interface for the controller cover.

The only design intent change I made in the mk2 version here was to decouple the outer housing interface axially from the rotor bearing interface.  In mk1, the back housing was a flat plate.  Now in mk2, it is a very shallow cone, to slightly reduce the axial length of the large diameter outer housing and eventually make it possible to reduce the weight more because of it.

Manufacturing

Like the front housing, this was challenging to produce on the Pocket NC.  It required even more steps than the front housing, since it had no final flat surface which also had threaded holes.  Thus I ended up using a manual machining stage, followed by 3 operations on the Pocket NC.

Manual machining

The manual machining merely took 4in round stock that was rough cut to 5/8″ and faced it to approximately 15mm, then drilled a center 1/2″ hole.

dsc_1846

Operation 1

For the first Pocket NC operation, I used a 3d printed bracket to clamp the stock down, and then the four M2.5 holes used to secure the back cover were drilled and threaded.  These will be used in the next operation.

dsc_1827

Operation 2

In operation 2, those holes were used to bolt the stock to another 3d printed fixture, which was then bolted to the same 3d printed assembly as used in operation 1 (and for the front housing).

dsc_1833

Operation 3

The final step of operation 2 drilled and threaded 4x M3 holes on the back surface purely for fixturing purposes.  They are used to bolt the in-progress work to yet another fixture, so that the rest of the back can be machined.

dsc_1836

Video

Here’s a video showing all the machining steps:

 

moteus servo mk2: Front housing

The front housing is the most complex machined piece in the moteus servo mk2, as it was in the mk1.  It is relatively large and mates with many other components with the associated tight tolerance surfaces.  For mk2, the front housing is even larger in diameter, but otherwise has the same basic features.

front_housing_exploded.png

Manufacturing

Building a prototype of this was a real challenge given the tools I have available to me now.  For mk1, I didn’t even try and just had Xometry build my prototypes, and was lucky enough that the first ones worked.  My only CNC currently is the Pocket NC v2-50, which is just barely big enough to deal with this part, and has no convenient workholding that can be used for the stock.  Also, it has a low material removal rate, such that starting from stock here would be prohibitively time consuming.

Manual preparation

My approach was similar to that of the outer housing, in that I prepared the materials on the Artisan’s Asylum manual machines, then did the remainder of the machining on the Pocket NC.

I started with 4″ diameter round stock cut to 1″ +0/0.125:

dsc_1790

Then, on the mill, I faced the parts to the correct 22mm height:

dsc_1744

Then I drilled a 5/8″ hole close to the center:

dsc_1745

At this point, I switched to the lathe and performed some roughing operations, removing some of the OD and ID to reduce the amount of cutting the Pocket NC needed to do.  These were done with some 3D printed spacers to help align the stock in the lathe’s 4 jaw chuck.

dsc_1767

dsc_1772

dsc_1780

CNC work

Now that the part was roughed out, I first mounted it to the Pocket NC using a machined aluminum plug bolted to a custom 3d printed plate.

dsc_1779

dsc_1785

My first attempt used a 3D printed plug, which just delaminated and failed, thus I re-drilled some more holes for this first prototype offset from the original 8.  This operation threaded the holes on the front side, which are used to secure the piece for the second operation.

In the second operation, a second custom 3d printed fixture is bolted to the newly drilled front holes, and then bolted to a plate that is mounted on the B axis.  This enables the Pocket NC to reach the full back side and around the perimeter.  The bracket needed to be slightly offset from the center of the B-plate, otherwise the mill couldn’t reach all the way around.

dsc_1788

Datron 4mm endmill

This was the first part for which I used a Datron 4mm endmill on the V2-50.  It is definitely a good tool, although it has its shortcomings.  The biggest win is that it can remove material at more than double the rate of anything else I’ve got.  Granted, this isn’t exactly fast, but it is fast for a Pocket NC and makes parts like this front housing even remotely feasible.  It also produces a nicer surface finish, and has less deflection so straight walls are straighter.  For simple geometries I used 47k rpm, 0.25mm optimal load and 4mm stepdown and then slowed those down when dealing with the more complex shapes.

There are some downsides though.  One, it uses a 4mm collet, which negates much of the value in having the convenient tool changing handle.  It takes a longish time to switch collets so I have to arrange toolpaths to do all the 4mm collet things together.  Second, it produces more chips than just about any other tool I’ve used on the Pocket NC.  So much so, that I had to schedule breaks every 45-60 minutes in the program just to clear out chips.  Otherwise the chip tray became too full to use effectively.  For some geometries, such as when clearing pockets, the chips are thrown onto the X ways and require even more frequent clearing, otherwise the mill can’t move to the full X extent as it squishes the chips against the front side of the enclosure.

Machining video

Here’s a video of the third one I made, which used finalized fixtures for all operations.

Fit test

And here’s one of the front housings with all the various things mated in place.

dsc_1835

dsc_1834-1

moteus servo mk2: Outer housing

The outer housing for the moteus servo mk2 is just a precision round tube with some mounting holes drilled peripherally.  Still, manufacturing it was slightly annoying, mostly because of my available machining resources.

outer_housing_cad.png

Manufacturing

I started off with round tube stock with some extra margin on the inside and outside:

dsc_1789

Then I went and used the manual lathe at Artisan’s Asylum to get the correct ID, OD and length:

dsc_1741dsc_1742

At this point, I loaded it into the Pocket NC with Sherline 4 jaw chuck, using a 3d printed bracket to align the assembly with the base of the chuck.

dsc_1761

Now, I could use the B axis as an indexer, and drill and countersink all the holes.