Archives: Control

Improving motor constant calibration in moteus

moteus is able to for many motors automatically determine all the relevant parameters that are necessary for control. That includes phase resistance, phase inductance, torque constant and pole count. The calibration routines have worked pretty well for a wide variety of motors and all the currently available moteus controllers, but when working to expand the supported envelope recently I undertook an effort to make that support even broader, specifically to improve accuracy when measuring resistance and torque constant, and to reduce outliers when measuring inductance.

Current mode commutation calibration in moteus

Way back in 2019, I documented the approach moteus has used for encoder commutation calibration ever since. In principle, it commands a fixed voltage that is swept through a range of electrical angles. Assuming the voltage is large enough, this will drag the rotor around with it similar to if the motor was a stepper motor. While that is happening, the commutation encoder reading is recorded over time, so that a mapping can be made between commutation encoder and the electrical angle of the motor. When combined with the old dead time compensation technique, it resulted in relatively sinusoidal current waveforms and thus smooth motion of the rotor and a smooth mapping.

Rethinking dead time compensation in moteus

Way back in 2021, I wrote up a post detailing a method for improving the linearity of the relationship between applied voltage and current for moteus, particularly during the calibration phase. At the time, this did solve a real problem – during calibration, moteus applied a fixed voltage to the phase terminals, swept the electrical angle of that voltage, and hoped that the mechanical angle as sensed with the on-axis sense magnet matched well. However, as a result of some new work, I’ve found that the premise behind that approach was flawed and it needs some re-thinking. This describes what I found, and what’s being done to resolve it going forward.

Moaar power!

Exciting news! All the existing moteus controllers in the world now have an upgraded default maximum power and upgraded rated maximum power as of release 2025-03-27! Depending upon the input voltage and PWM rate, sometimes nearly twice the amount. First, check out the comparison table, then the rationale:

Old default max / rated New default & rated
moteus-r4 340W / 450W 900W <= 30V, 400W >= 38V
moteus-c1 75W / 100W 250W <= 28V, 150W >= 41V
moteus-n1 340W / 1200W 2kW <= 36V, 1kW >= 44V

Background, why a power limit?

moteus brushless motor controllers drive 3 phase PMSM motors, accepting a DC input voltage, and outputting current to each of the 3 phases of the motor. It does so using MOSFET based switching, which alternately connects each phase to either ground, or the DC positive input. As that switching progresses, charge is either drawn, or replenished into, the onboard bulk capacitors.

hoverbot

I made a thing!

With that video out of the way, here is a bit more of a write-up!

Motivation

The hoverbot is a simple 2 wheel balancing robot. I built it to demonstrate how the moteus-c1 can be used to drive hoverboard motors and to demonstrate the capabilities of the pi3hat for high rate control and effective attitude reference calculation. It is powered by a single Bosch 18V cordless drill battery and controlled through an identical websocket based interface as the quad A1, primarily operated by a phone with a paired bluetooth joystick.

Optimizing moteus command rate

Probably one of the most frequently asked questions in the mjbots Discord is “how fast can I send new commands to moteus”, or “how fast can I read the status from moteus”. That may be because you want to perform torque based control in your application and require high bandwidth, or just because you have a high torque to inertia ratio system that reacts on very short time-scales. No matter the reason, the principles that control the maximum rate you can send updates are the same.

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.

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:

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.

moteus with velocity=NaN

When commanding a moteus controller, many of the registers defined in the reference documentation give explicit semantics when the value is passed as either a floating point NaN value or the “maximally negative integer” for integer encodings. Those that do not specify a meaning for NaN are “undefined” and anything can happen. For the most part, this isn’t a problem, but in one specific case users were repeatedly caught off guard.

Three common registers often set in position mode, (also accessible by the unlabeled first three arguments to “d pos”), are 0x020 “target position”, 0x021 “target velocity”, and 0x025 “maximum torque”. Target position has a defined meaning when set to NaN: the controller assumes that the target position is the current target position, or the sampled position if the controller is not yet in position mode. Maximum torque also has a defined meaning when set to NaN: it then uses the maximum torque as defined by the maximum phase current limit. However, target velocity had no such definition, and in practice when used, resulted in the controller becoming mostly non-functional.