Various users have been trying to use lower-cost Raspberry Pi CAN-FD adapters for the moteus controller for some time (like this one from Seeed), but have had problems getting communication to work. I buckled down and went to debug the problem, discovering that the root of the issue was that the linux kernel socketcan subsystem calculates very sub-optimal CAN timings for the 5Mbps bitrate that moteus uses. This results in the adapters being unable to receive frames sent at the actual 5Mbps rate, but instead only slightly slower.
The solution is to manually specify the bus timings when configuring the socketcan link. This makes the MCP2518FD boards work, and also PEAK-CAN-FD USB adapters (and probably every other socketcan CAN-FD adapter) work as well. You can find the timings linked in the moteus reference documentation: https://github.com/mjbots/moteus/blob/main/docs/reference.md#bit-timings
General socketcan improvements
As a result of all this debugging, I made some general improvements to socketcan support in all the client side moteus tools.
I released moteus and moteus_pi3hat 0.2.0 to pypi. These provide socketcan interfaces for python, transparently using them if no fdcanusb or pi3hat peripherals are found.
Thanks for everyone on discord’s patience as we worked through these compatibility issues!
Over the Thanksgiving day holiday, I knew I had a bunch of harnesses to build. Rather than being a good corporate steward and actually building them, I instead built a machine to automate the first of the 3 time consuming parts of the harness construction: wire cutting and stripping.
This was just thrown together from two cosmetically damaged moteus devkits, a Raspberry Pi 3 an old development version of a pi3hat, a hand wire stripper, two synthetic rubber bands, an off the shelf 24V supply, and a bunch of 3d printed parts.
Why?
Simple automated wire management at the DIY level is not new. It’s been done many, many, many times before. YouTube has decided that every day I need to see someone else’s take on the problem. Look down in the resources at the bottom for my collection of alternate solutions.
What differentiates this version is (1) I built it most from junk parts I had around, (2) since it uses brushless motors it can be both very fast and very precise. Here’s a clip of it executing a few cycles where it strips 3mm from the front end, pre-cuts 3mm from the other end, then cuts the wire to a total length of 5cm. The overall cycle time for all operations is around 1s per wire for the 30cm wires I needed right now.
By replacing the guides and doing some tuning, it should be capable of managing wire between 30 AWG and 18 AWG, although to date I’ve only tested it on 26 AWG.
It did take a bit longer than the weekend — I printed a second revision of everything early the following week, then waited for a panel mount switch to make the power supply look more professional.
Video
Here’s the overview video, with some more shots of it in operation.
https://www.youtube.com/watch?v=mNCjpKPapnc – a fancy touch screen display, stripping, and dual drive so that it can strip both sides, although I’m not quite sure why the inner wire feed needs to be actuated
https://www.youtube.com/watch?v=v0rXccYcr9o – this one also pre-cuts both sides and strips neither, but uses an unnecessarily complex mechanism where the wire is diverted either into a V blade or a flat blade
https://www.youtube.com/watch?v=a-kJznYpbV0 – the cutting action is sooooo slow, especially since it does a pre-strip cut on both sides, but bonus points for being made nearly entirely from aluminum
https://www.youtube.com/watch?v=WVnbbqSEDU0 – high production values and a full build and design walkthrough from element14. Double bonus for 3d printing and machining, although it sounds like from some forum posts that it wasn’t too reliable and also has a super slow cutting action.
https://www.youtube.com/watch?v=OKB_-fYj-IU – One of the nicest looking builds, complete with mood lighting and lots of machined parts, strips one side and pre-cuts the other
https://www.youtube.com/watch?v=mNCjpKPapnc – a fancy touch screen display, stripping, and dual drive so that it can strip both sides, although I’m not quite sure why the inner wire feed needs to be actuated
https://www.youtube.com/watch?v=v0rXccYcr9o – this one also pre-cuts both sides and strips neither, but uses an unnecessarily complex mechanism where the wire is diverted either into a V blade or a flat blade
https://www.youtube.com/watch?v=a-kJznYpbV0 – the cutting action is sooooo slow, especially since it does a pre-strip cut on both sides, but bonus points for being made nearly entirely from aluminum
https://www.youtube.com/watch?v=WVnbbqSEDU0 – high production values and a full build and design walkthrough from element14. Double bonus for 3d printing and machining, although it sounds like from some forum posts that it wasn’t too reliable and also has a super slow cutting action.
https://www.youtube.com/watch?v=OKB_-fYj-IU – One of the nicest looking builds, complete with mood lighting and lots of machined parts, strips one side and pre-cuts the other
https://www.youtube.com/watch?v=Jl6ZATZypAQ – Seems like this guy does a new, basically the same version, every year. This year’s has a touch screen, but otherwise seems to perform about the same.
I’m excited to announce new python bindings for communicating with moteus controllers! A simple example from the README:
import asyncio
import math
import moteus
async def main():
c = moteus.Controller()
print(await c.set_position(position=math.nan, query=True))
await asyncio.sleep(1.0)
asyncio.run(main())
This code will try to locate an fdcanusb on your host and use it to communicate with controller with ID 1. All of those details can be customized through code depending upon how you construct things. The library is pure python, although it doesn’t work on Windows currently because it relies on an asyncio aware pyserial wrapper that doesn’t work there.
At the same time, there is a parallel python library “moteus-pi3hat” which only has an armv7l package. This provides an identical API for working with the pi3hat on a Raspberry Pi. It lets you configure which controllers are attached to which bus (by default it assumes everything is on bus #1). After setting that up you can use an identical API to command and monitor the controllers.
To date, all of the development tools for the moteus brushless controller have been available exclusively for Linux based operating systems. I’ve been doing some behind the scenes work, and have gotten to the point where moteus_tool now runs natively on windows and can communicate with moteus controllers using a fdcanusb.
Check out the Windows installer for the latest release:
To make this work, I started from the excellent grailbio/bazel-toolchain, which provides LLVM toolchains for Linux based systems based on the official LLVM pre-compiled binaries. I forked that into mjbots/bazel-toolchain and added Windows support. It isn’t perfect, because the LLVM project only distributes Windows binaries in installer form, and it isn’t possible to extract binaries from them without specialized tooling. So, this version relies on a manually re-packed compressed archive of all the executables.
I also added support for building the libc++ standard library, and using that instead of the MSVC standard library. This let me get c++20 coroutines working with clang on Windows.
All put together, the porting was pretty painless after having a toolchain in place. Just a few #if’s here and there, and I had to write a custom Windows specific console stream, as stdio and stderr do not support asynchronous completion ports on Windows.
Meet the newest revision of the moteus controller!
Yes, it does look mostly the same as the r4.3 that has been getting a lot of use lately. This revision exists mostly to improve manufacturability, but I snuck in a minor design improvement while at it. Now, the maximum voltage input is rated up to 44V from the 34V of the r4.3! (Note though, that the pi3hat and power_dist still are limited to 34V). Otherwise the new controller is fully electrically, mechanically, and software compatible with the r4.3.
Previously, rules_mbed used the “crosstool_top” bazel mechanism for toolchain configuration. This allowed a single package to contribute a set of C++ toolchains which would be selected based on CPU and compiler. One of the downsides from the rules_mbed perspective, is that it made it difficult to make a build that included both mbed targets and host targets (or anything else non-mbed). rules_mbed worked around this by including a functioning clang host toolchain within it.
With the new toolchain resolution support, at the command line you specify to bazel what “platform” you want to be the final target. The updated rules_mbed specifies a “platform” for each of the STM32 processors that are supported. So for instance you could use:
It then uses that platform to find a toolchain with a compatible operating system and CPU, which for rules_mbed is the arm-gcc compiler for the correct chip.
Because of this, the command lines necessary to compile the moteus firmware and host side tools have changed. Rather than expose the raw bazel options, it now just uses a bazel config to abstract away whatever mechanisms are required. So, the two necessary new command lines are:
tools/bazel test --config=target //:target # build firmware tools/bazel test --config=host //:host # build host tools
Soon, we’ll use this capability to add some useful new features to the moteus tools, such as support for non-linux operating systems.
As part of some experimentation in native Windows tools for moteus, I’ve created a dirt simple rules_wix repository in github. It provides a minimal wrapper around the WiX Toolset for creating Window’s installers from within bazel. There’s nothing fancy there yet, but it can at least make an installer with a single executable in it!
The moteus controller has always supported multiple turns when counting positions. It has a one-revolution magnetic encoder built in, but after turn on, it keeps track of how many turns have occurred. However, if you’ve followed previous moteus tutorials, you have probably noticed a persistent caveat that for accurate control, the position of the output shaft needs to stay within a hundred revolutions of 0.0 or so. Now, I’ll describe why that was, and what I’ve done to remove the limitation, allowing unlimited rotations!
Background
The moteus controller uses a somewhat unique integrated position / velocity / torque control loop. This formulation gives a couple of advantages: First, there is no bandwidth loss due to having a cascaded position and velocity controller. Second, when driven by a higher level controller, it can seamlessly switch between position, velocity, and torque control, or any combination of them without having to manage mode transitions.
The command consists of the following values, all as 32 bit floating point values (optionally upscaled from integer values using the register protocol).
Desired Position
Desired Velocity
Feedforward Torque
kp scale
kd scale
Maximum Torque
The control loop measures two quantities as input, the “current position” and the “current velocity”. The position is measured as a 32 bit signed integer, where one revolution of the magnetic encoder equals 65536 counts. The velocity is numerically differentiated across the most recent 6.4ms of movement.
There are two internal state variables as well: One is the “target position”. This captures the most recent position command, and is advanced by the velocity command at the full control rate. The other is the integrative term of the PID controller. Both of these are stored as 32 bit floating point values.
The problem
This structure poses a few inherent limitations. One, being that as the control position is sent as a floating point value, the resolution available for positioning decreases as you get further from 0. That probably isn’t a big limitation, as there aren’t many applications where you want to have both absolute positions and also unlimited revolutions.
The bigger limitation is in the “target position” internal state variable. It needs to be updated to take into account the current velocity command at every control cycle, or 1/40000 of a second. For a commanded speed of 0.01 revolutions per second, this incremental update is only 2.5e-7 of a revolution. Given that 32 bit floating point values only have roughly 7 decimal digits of mantissa available to them, you don’t have to get far beyond 0 before an update that small doesn’t even change the value at all.
The command format also has an option, such that if the command position is set to a floating point NaN value, it will “capture” the current position. This can be used to command velocity-only control with an implicit integrative term, or when combined with a stop position to move to a target at a fixed velocity. However, since “capturing” stores the value as a floating point value, significant precision can be lost. This was only a problem at larger position values, but at the maximum position before wraparound, the available capture resolution was measured in multiple degrees.
The resolution
The resolution was relatively straightforward. Instead of storing the “target position” as a floating point value, it is now stored as a 64 bit integer measured in 1/(2**32) of a magnetic encoder revolution. This gives sufficient precision to represent velocities as small as 0.0001Hz (0.036 dps) uniformly at all positions, while still having more absolute range than the measured current position value. The final PID controller is then expressed relative to the target position. This lets it still operate in floating point coordinates, but with no worry about large artifacts due to a position offset.
The only other implementation hurdle was making it run fast enough. Largely that revolved around ensuring there was never a need to convert between 64 bit integers and floating point values, which is relatively slow on the STM32G4.
The result
With this fix in place, it is possible to operate the controller safely at high velocities for arbitrary periods of time. Even when the “current position” value wraps around from positive to negative! Also, low speed control works just as well at any position offset. When operating in those “continuous rotation” applications, the user should just be careful about if the “desired position” field of the command should be set. Largely, it should be left as NaN for when used in continuous rotation applications.
Here’s a video showing high speed wraparound and low speed at arbitrary offsets.
At the request of @nichols in discord, I’ve recently implemented a new control mode in the moteus controller, “stay within”. In this mode, as long as the controller is inside the currently commanded bounds, only a feedforward torque is commanded. When either of the optional lower or upper bound is violated, the normal PID controller is used to force the position back to the bound.
Here’s a quick video demo:
Note that this could have been roughly accomplished in a couple of ways by a higher level controller — either by monitoring the position and commanding zero kp/kd scales when inside the boundary, or just solely commanding feedforward torques based on position sensing. However, this approach lets the control run at the full 40kHz of the moteus controller, which results in much smoother operation at the boundary condition.