Link
On this page

Motion control

BLDC motors Stepper motors

The motion control logic in the SimpleFOClibrary is implemented in the motor.move() function. The motion control loop is responsible for calculating the target torque (current or voltage) to be applied to the motor in order to achieve the desired motion. The desired torque is then passed to the torque control loop (motor.loopFOC() function) which is responsible for calculating the necessary voltages or currents to be applied to the motor windings in order to achieve the desired torque.

The SimpleFOClibrary supports several motion control modes, which can be set by changing the controller parameter of the motor:

All the motion control modes are completely transparent regardless if you decide to use BLDC or Stepper motors.

Motion control modes overview

Mode Variable Type Position sensor Required Description motor.target Units
Torque torque Closed-Loop Yes Direct torque/current control Amps or Volts
(depending on torque control mode)
Velocity velocity Closed-Loop Yes Speed regulation Radians per second
Angle angle Closed-Loop Yes Position control with standard cascade Radians
Angle
(No Cascade)
angle_nocascade Closed-Loop Yes Position control without cascade Radians
Velocity Open-Loop velocity_open_loop Open-Loop No Speed control without feedback Radians per second
Angle Open-Loop angle_open_loop Open-Loop No Position control without feedback Radians
Custom control custom User defined Depends on implementation User defined User defined

Torque and Motion control compatibility

The motion control mode is independent of the torque control mode, so you can use any of the torque control modes with any of the motion control modes. For example you can use the voltage mode to control the motor position, or FOC current mode to control the motor velocity. You can also update the motion control mode in real-time. See the torque control docs for more information.

Units warning

The units in the library are following standard motion control conventions. Ampers, Volts, Radians and Radians per second are used throughout the library. If you want to use different units, you will need to convert them accordingly.

See the units docs

Things to consider when choosing the motion control mode

Feature Closed-Loop Open-Loop
Efficiency HIGH: Only uses the current necessary to maintain state. LOW: Draws maximum current/voltage all the time.
Accuracy HIGH: Real-time correction of disturbances and load changes. LOW: Assumes the motor follows the target; prone to posision loss under load.
Heat COOLER: Motor stays cool when idle or under light load. HOT: Motor runs hot even when stationary or spinning freely.
Safety HIGH: Can detect stalls and limit velocity/current dynamically. LOW: No stall detection; can “runaway” or vibrate if overloaded.
Hardware REQUIRES a Position Sensor (Encoder, Magnetic, etc.). MINIMAL: No sensor required.
MCU performance HIGHER: More computational load due to feedback processing. LOW: Simpler calculations; less CPU usage; suitable for low-end MCUs.
  Go to Closed-loop control docs Go to Open-loop control docs

Quick frequency consideration

By default the motion control loop is running at the same frequency \(f_{MC}\) as the torque control loop \(f_{TC}\), which is usually around 1-10 kHz. However, in some cases you might want to run the motion control loop at a lower frequency than the torque control loop, for example if you have a very high pole pair motor and you want to reduce the noise in the velocity or position measurements. Or if you only run the motor at very low speeds you do not need such a high frequency for the motion control loop.

You can decrease the motion control frequency \(f_{MC}\) by setting the motion_downsampling parameter of the motor, which will run the motion control loop at a lower frequency than the torque control loop. For example, if you set motion_downsampling to 10, the motion control loop will run at 100 Hz while the torque control loop will run at 1 kHz.

// set motion control loop to run 10 times slower than the torque control loop
motor.motion_downsampling = 10;

Or in other words, the motion control loop will run at a frequency of \(f_{MC} = \frac{f_{TC}}{\texttt{motion_downsampling}}\).
Or more practically motor.move() function will be called every motion_downsampling number of motor.loopFOC() calls.

  • If you are not sure what is the frequency of the torque control loop, you can check it by reading motor.loopfoc_time_us variable, which represents the time between two motor.loopFOC() calls in microseconds. The frequency of the torque control loop is then calculated as \(f_{TC} = \frac{1}{\texttt{motor.loopfoc_time_us} \cdot 10^{-6}}\).
  • You can also check the frequency of the motion control loop by reading motor.move_time_us variable, which represents the time between two motor.move() calls in microseconds. The frequency of the motion control loop is then calculated as \(f_{MC} = \frac{1}{\texttt{motor.move_time_us} \cdot 10^{-6}}\).

To go a step further check out the guide in our docs
Real-time loops with timers

Closed-Loop control

There are three Closed-Loop control types implemented in the SimpleFOClibrary:

  • Torque - MotionControlType::torque
  • Velocity - MotionControlType::velocity
  • Angle/Positon - two types:
    • Cascade controlled: MotionControlType::angle
    • Non-cascade controlled: MotionControlType::angle_nocascade

BLDC motors Stepper motors

All of these control modes require a position sensor to be used, as they rely on the feedback from the sensor to calculate the necessary voltage or current to be applied to the motor in order to achieve the desired motion.

And they can be set by changing motor’s controller parameter.

// set motion control loop to be used
// MotionControlType::torque
// MotionControlType::velocity
// MotionControlType::angle
// MotionControlType::angle_nocascade
motor.controller = MotionControlType::angle;

Go to Closed-loop control docs

Open-Loop control

Additionally you can run the motor in the open-loop, without position sensor feedback, as well:

  • velocity open-loop control - MotionControlType::velocity_openloop
  • position open-loop control - MotionControlType::angle_openloop
Index search also uses open-loop position control, but has some additional parameters, see index search


BLDC motors Stepper motors

These control modes do NOT require a position sensor, these control modes estimate the motor position and velocity based. Better said they assume that the motor can follow the target velocity or position without any load or disturbance, which is not always the case.

And they too can be enabled by setting motor’s controller parameter.

// MotionControlType::velocity_openloop    - velocity open-loop control
// MotionControlType::angle_openloop       - position open-loop control
motor.controller = MotionControlType::angle_openloop;

Go to Open-loop control docs

Custom control mode

BLDC motors Stepper motors

The SimpleFOClibrary also gives you the possibility to implement your own custom control loop. This is an experimental feature and we are not yet 100% happy with the implementation, but we wanted to give you the possibility to try it out and give us feedback. The custom control mode allows you to implement any control loop you want, and link it to the library. This way you can use the library’s functions for reading sensors, controlling the motor and so on, while implementing your own control strategy.


// MotionControlType::custom - user defined control loop
motor.controller = MotionControlType::custom;

// link your custom control function that will be called in the main control loop  motor.move() funciton.
motor.linkCustomMotionControl(&myCustomControlFunction);

Go to custom control documentation

Digging deeper

For more information about the source code implementation of the motion control strategies check the library source code documentation.