moteus-c1

I’m excited to announce the newest addition to the moteus line of BLDC controllers, the moteus-c1! The moteus-c1 is a smaller, lower power, lower cost version of the moteus-r4 and moteus-n1, but still packs a big punch.

The top of the line performance metrics for the entire moteus lineup now look like:

moteus-c1moteus-r4moteus-n1
Input Voltage10-51V10-44V10-54V
Peak Phase Current20A100A100A
Continuous Phase Current5A / 14A11A / 22A9A / 18A
Dimensions38mm x 38mm46mm x 53mm46mm x 46 mm
I/OAUX1 D and E are present as through hole pads.

AUX2 is identical to moteus-n1
AUX1: SPI, Hall, ADC

AUX2: I2C and UART
3.3V only
AUX1 and AUX2 support SPI, UART, Quadrature, Hall, and I2C.

5.5V and 3.3V provided on each connector.

I2C pullups are configurable on each connector.
RS422NoneNoneBuilt-in transceiver for RS422 based encoders
CAN fault tolerance58V12V58V
Price$69$79$149

The upshot is that for low current motors where RS422 is not required, it is nearly as capable as the moteus-n1 for less than half the price!

Compatibility

The moteus-c1 is fully electrically and software compatible with the moteus-r4 and moteus-n1. It uses the same connectors for power, CAN, and AUX2 and it has the same through hole layout for power and phase terminals as the moteus-n1. While the moteus-c1 requires firmware version 2024-04-30 or newer, the same firmware image can be used across the entire moteus line and all functionality that is available based on the connectors present are available on all controllers.

Accessories

The controller itself isn’t the only thing available at a price that is an exceptional value. The moteus-c1 developer kit has been updated to use the mjcanfd-usb-1x and entirely 3D printed brackets. One omission from this lower cost kit is the stm32 programmer, which is still available separately. This gets the overall price of the moteus-c1 developer kit down to the almost crazy point of $149, which around the same as a single moteus-n1!

As with the moteus-r4 and moteus-n1, we also stock a heat spreader for the moteus-c1 for applications where you want to push the thermal envelope. This heat spreader now comes with thermal tape rather than paste, which should make installations less messy.

Intro Video

Finally, here is a short introduction video. The observant viewer will notice many not yet announced demonstrations and projects! Those should get written up in the following months as time permits.

External daisy chain boards and new PH3 cable lengths

It continues to be the spring of new products at mjbots (see the mjcanfd-usb-1x from earlier), and today I have some basics that are newly added to the store to make building machines just a bit simpler.

First are two tiny boards to make daisy chaining power and CAN-FD connections easier for boards that don’t have built-in daisy chain connectors like the moteus-n1. First is a junction board for PH3 cables:

And the second is a similar junction board for XT30 cables:

Finally, we now have our JST PH3 jumper cables in a wider variety of lengths. You can now get them in any of:

That’s it for today, but it isn’t it for our new spring products. Some of the most exciting are yet to come!

mjcanfd-usb-1x

While it may not be technically spring outside, it is spring for product announcements here at mjbots, and I’m excited to announce the next evolution of CAN-FD adapter hardware we’re offering, the mjcanfd-usb-1x:

The major changes from the fdcanusb:

  • USB-C instead of USB micro
  • Smaller form factor – 30x18mm
  • PH3 CAN-FD connector instead of DB9
  • Less expensive, only $39

This makes the mjcanfd-usb-1x better suited for in-application deployments and just all around better as a development tool. It can be mounted down more easily, uses the same connector and pinout as moteus, and is compatible with our existing PH3 cables.

Don’t worry, the fdcanusb will still be sold for the forseeable future, for applications where you need a DB9 connector, or to replace existing fdcanusbs. Also, the developer kits for the moteus-r4, moteus-n1, and qdd100 will continue to ship with the fdcanusb for the time being, although they will switch over to the newer mjcanfd-usb-1x at some point in the not too distant future.

moteus + Arduino

The moteus line of brushless motor controllers currently require a CAN-FD host to send commands in order to actually execute a motion profile. moteus has long provided a python library that can be used on desktop operating systems to send commands and parse responses, and recently added a C++ one as well. Next up, and described in this post, is a library for Arduino which provides the ability to command and monitor brushless motors using moteus motor controllers.

I’m impatient! How do I use it?

Just open the Arduino library manager and search for “moteus” and install. Then you can open one of the examples and modify it. ”WaitComplete” is a good one to get started with.

What is supported?

The library now supports many Arduino compatible boards and CAN-FD expansions that use the MCP2517FD or MCP2518FD CAN controllers. Anything that the acan2517FD library supports is fair game. It has been observed to work with:

There are two pieces of configuration that are board and controller specific that must be specified when setting up the library. First, the pin assignments and SPI peripheral must be passed to the ACAN2517FD constructor. That can be derived from the pins you used to connect the CAN-FD controller.

Second, you need to match the CAN-FD base clock rate that the board uses. The CANBed FD uses a 20MHz clock, which is what is set in the example. The Mikroe MCP2517FD Click defaults to a 40MHz clock, but can be configured by jumper. In any case, you need to pass the clock rate that your board in to the ACAN2517FDSettings object.

Caveats

The biggest caveat is that some operations with moteus still require a desktop computer with a standalone CAN-FD adapter, notably calibration and interactive modification of configuration. That means while Arduino can be used once a system is commissioned, you will need at least one desktop compatible adapter to perform provisioning operations. The fdcanusb from mjbots (included in each devkit) is a hassle free way to get that.

The Mikroe MCP2517FD CLICK and possibly other boards do not have onboard termination. A CAN-FD bus is specified to require a 120 ohm terminating resistor between CANL and CANH at each end of the linear bus. Most short busses will operate with only one end terminated, and as the fdcanusb has a built in terminator, with that often nothing else is required. However, with an Arduino shield or adapter that does not have an integrated terminator, an external one is required. You can crimp a 120 ohm resistor into a JST PH3 connector, or get a pre-built PH3 CAN-FD terminator from mjbots.

With some smaller Arduino platforms, notably the Arduino Uno or Longan Labs CANBed FD, the combination of the ACAN2517FD library and the moteus library can consume a significant fraction of the flash and RAM available. For simple applications this isn’t a problem, but if you want to execute something more complex, you may be better served using a more capable Arduino compatible processor, like a Teensy 3/4 or a Nano Sense 33.

Video

See it in action here!

recapturing position and velocity with moteus

Recently I covered a new feature for the moteus brushless controller that improved robustness for velocity control when external torques exceed the maximum allowable control torque. In this post, I’ll cover a feature that can be used for a similar situation in position control, “recapturing position and velocity”.

In some applications, while in position mode, it can make sense to limit the maximum torque during specific periods so that external torques are able to overpower the controller. The most obvious case would be if the maximum torque is set to 0, or the kp and kd scale are set to 0 temporarily. A problem then arises when resuming control, as the “control position” will be wherever it last was, despite the fact that the actual motor have have been dragged by the external torque some distance away. When the torque limit is released, a large transient can develop as the controller tries to instantaneously get back to the old control position.

Previously, the only suitable workaround was to stop the motor driver entirely by issuing a “stop” command, then re-starting control by sending a new position mode command. This works, but causes a moderate delay before control can be re-established, as moteus executes a self calibration procedure of several milliseconds before resuming control.

As of firmware release 2024-01-06, there is now a new command, “recapture position and velocity”, which can be used in these circumstances. It forces the control position and control velocity to match the measured values without exiting position mode. It can be sent using all the normal methods, i.e. through the diagnostic protocol with tview, or the register protocol with raw CAN frames, the python library or C++ library. A typical operation might look like:

initially start control by sending position mode command

after some time, set maximum torque to 0 to let the motor free-wheel

an external torque drags the motor far from its initial position

send the "recapture position and velocity" command

immediately after send a position mode command with nonzero max torque

Assuming that a velocity limit is in place, the following plot shows what the control position and actual position would look like with no mitigations in place, and with using the new recapture command.

For reference, the different means of commanding this look like:

  • Diagnostic channel: d recapture
  • Python: await c.set_recapture_position_velocity()
  • C++: c.SetRecapturePositionVelocity()

BIG price improvement for moteus-r4

I’m excited to announce a big price drop for the moteus-r4.11 controller for both single units and in volume!

QuantityOldNew
1-10$104$79
10-99$99$75
100-499$94$71

We’ve been scaling up production, which enables these reductions of about 25% across the board. moteus-r4 is now by far the most cost effective motor driver with integrated encoder in its class. Here’s a quick comparison with similar products:

ODRIVE S1Tinymover R5.2moteus-r4.11
Voltage12-50.5V12-38V10-44V
Continuous phase current40ANot specified22A
Peak current80A40A100A
Dimensions66mm x 50mm40mm x 36mm53mm x 46mm
Open sourceProprietary FW and HWGPL FW, Proprietary HWApache 2.0 FW and HW
Price$149$108$79

I personally am looking forward to all the new projects that these lower prices enable! Check it out below or join the mjbots Discord to chat and get some ideas for how you can use a moteus-r4.

max_velocity_slip with moteus

The moteus brushless motor controller supports several concepts of operation from within its primary “position” mode, including a velocity mode. As documented in the reference, you can run in that scenario using commands equivalent to the diagnostic mode command:

d pos nan V nan

Where V is the desired velocity. However, as with most control operations, there are a number of edge cases that can be useful to handle. When operating purely in velocity mode, the normal PID constants can be interpreted slightly differently:

  • servo.pid_position.kd – this is effectively the proportional constant in velocity control
  • servo.pid_position.kp – this is effectively the integrative constant in velocity control
  • servo.max_position_slip – this is the “anti-windup” term for the integral term

If an external torque is applied that exceeds the maximum torque that the system is capable of generating for an extended period of time, then undesired transients can emerge. In that case, the actual velocity can diverge arbitrarily from the commanded velocity. For instance, if a drag force were applied that exceeded the maximum commanded torque, the system could stop. If that external force is released, then there is a large discrepancy between the actual and commanded velocity, which results in a non-ideal transient response that may overshoot or oscillate.

The normal mechanism to enforce a slew rate for the commanded velocity in moteus is to use the trajectory velocity limit, either through configuration with servo.accel_limit, or by specifying a per-command acceleration limit. That limits the rate of change in velocity command, but does nothing in the case where an external force causes the controller to diverge.

As of release 2024-01-06, moteus now supports a new configuration option to help resolve this:

servo.max_velocity_slip

Like servo.max_position_slip, this limits the amount that the control velocity can diverge from the measured velocity. If set appropriately, it will result in a motor using the configured acceleration limit if an external torque is released, rather than attempting to instantaneously restore the commanded velocity. Selecting the value for this configuration does require some care. It must be significantly larger than the expected noise in velocity measurements, yet small enough to result in an effective clamping during expected transients.

The following plot shows an instance where an external torque causes the actual velocity to temporarily drop to 0. The left plots demonstrate what will happen if servo.max_velocity_slip is “NaN”, i.e. disabled, and the right plots show what will happen if it is set to 2 Hz. As can be seen, limiting the delta between the control and actual velocity can result in decreased overshoot or otherwise undesired transients when external torques are released.

This video gives a quick demonstration of the with and without as well.

Default bandwidths for moteus

moteus has long had both automatically tuned current control bandwidth and a built-in low-pass filter for encoder readings. During calibration, these are usually set with moteus_tool‘s --cal-bw-hz option, which specifies the current loop (interchangeably called the torque loop) bandwidth. TLDR is that these heuristics have changed as of pypi 0.3.64, hopefully with only improved behavior. Read on if you want to understand more or if you need to resolve problems with something that changed for the worse.

Overview

The encoder bandwidth selected, modulo some heuristics, was usually twice that of the current loop. This was a quick and dirty heuristic which worked alright for a long time, but didn’t have much of a basis behind it. While cleaning up calibration for gimbal-style motors, I decided to take another pass at this as well.

The two filters, current and encoder, serve different but inter-related purposes. The encoder filter, maybe obviously filters readings from the primary position sensor. Movement that is higher bandwidth than the filter will be not observable by moteus. Thus, if the platform is capable of movement at bandwidths higher than the filter, the control loop will be operating on incorrect data and will usually become unstable. However, as the bandwidth is increased, inherent noise from the encoder will result in the controller producing audible noise as it attempts to correct for the “noise” in the measurement in position and velocity.

The current loop similarly controls how quickly the controller can change the torque it is commanding. It is similar to the encoder filter in that higher cutoff values (i.e. larger bandwidth) results in higher performance but more audible noise. This should typically be around the same as the encoder filter, as most of the changes in the desired torque will come from encoder readings. However, the commanded torque (or position/velocity) can also change at potentially high rates in response to application demands, and thus there may be a need for it to be higher than the encoder filter.

Diagnosing inappropriate bandwidth

If the bandwidth is too low for either filter, performance and stability will degrade. For either filter, oscillation or vibration may result. Commanded movements may overshoot their intended target, especially at relatively high accelerations. Commanded torque will not track accurately.

If the bandwidth is too high for either filter, the primary downside is audible noise. If the limits within moteus_tool are circumvented, the filters themselves may become unstable, resulting in erroneous operation.

A special case of problems with a too-high encoder bandwidth occurs with encoders of extremely low resolution. The most common case here are using hall effects as the output position sensor. In this case, too high of a bandwidth will result in poor velocity sensing, and thus poor velocity and position control. In those applications, the range of usable encoder bandwidths may be very small for velocity or position control (although for torque control going higher is always fine).

Updated behavior

To better balance these factors, as of pypi 0.3.64, moteus_tool --calibrate is changing things in a few ways:

1. The biggest, is that it will now default to set the encoder bandwidth to be equal to the torque bandwidth rather than be equal to twice it. For most users, the only result of this is that motors will have less audible noise during operation. In some cases, the lower encoder bandwidth may result in instability or oscillation, but given that the torque bandwidth was already that low, this is unlikely.

2. Another change is with respect to high inductance motors. The most common types of high inductance motors are gimbal motors and hoverboard motors. Previously, a different heuristic would artificially limit the torque bandwidth to a low value. This has since been deemed unnecessary, so now these motors will calibrate with a larger torque bandwidth by default. For gimbal motors, that means they may become usable even without resorting to servo.voltage_mode_control (which bypasses the torque loop entirely).

3. Yet another change relates to hoverboard motors. There had been a heuristic to attempt to limit encoder bandwidth on all high-inductance motors. That inappropriately caught gimbal motors. Now this limit is only applied if hall effect sensors are used to measure output position, which is the only time it would be useful.

4. Finally, no bandwidths are allowed to be greater than 1/30th of the control update rate. With the default 30kHz control rate, that permits bandwidth up to 1kHz for both torque and encoder. At the lowest currently supported rate of 15kHz, that falls to 500Hz.

New Project: Juggling Robot

I’ve been looking for a new motor control project to tackle that is both interesting, and a bit more unique than another Ascento clone. Looking around, I was surprised at the current paucity of robots capable of more advanced juggling feats. There are quite a few that can manage 3 balls, and nearly none I’ve found that can manage more, with the exception of Nathan Peterson’s inclined ball roller. I figure that I have access to lots of factory second moteus controllers, which are capable of quite demanding control applications, so I should be able to put something together.

This is what I’ve got so far:

This is a single 6 DoF Stewart platform controlled by 6 moteus r4.11s with mj5208s acting as the servos. A pi3hat and power_dist are nestled inside a 3d printed hexagon. M4 push rods with tie rod ends connect the servo horns to the upper platform, which has an indent to “catch” the ball. At this point, all I’ve done is some simple open loop toss behaviors without any fine tuning or aiming. It can reliably catch and toss some 50g micro juggling balls up to around 30cm, and can throw (but not catch) up to around 80cm.

My intention is to first get this to be able to throw and catch at higher throws, then do some basic 1 hand patterns with 2 or maybe 3 balls. Once I get that working, then I’ll add in a second platform to make the second hand and see what I can pull off. I’ve got an rpi global shutter camera with the intent to do visual tracking of the balls if necessary, but we’ll see how accurate I can get the tosses just open loop first.

The hackaday project page with an overview is here.

moteus_tool –restore-config

For the moteus brushless controller, the moteus_tool utility has long had a --dump-config command line action which will cause the entire contents of the configuration to be written to standard output.

–dump-config format

This configuration looks like this:

servo.pid_position.kp 4
servo.pid_position.kd 0.1

moteus_tool has also had a --write-config option, which is something of a misnomer, as it actually just sends any commands one at a time from a file to the controller. Notably, it requires that the file to contain actual valid diagnostic mode commands.

–write-config format

Thus, if you wanted to restore the above two configuration options, and then save those values to persistent storage, the file contents would need to be:

conf set servo.pid_position.kp 4
conf set servo.pid_position.kd 0.1
conf write

As of pypi version 0.3.62, the moteus_tool --restore-config action will now accept the --dump-config format directly and also send the conf write at the conclusion. This means that --restore-config can now be used directly with the output of --dump-config. Yay!