On this page
Position open-loop control
This control loop allows you to move your motor to the desired angle in real time without using the position sensor. This mode is enabled by:
// set position motion control open-loop
motor.controller = MotionControlType::angle_openloop;
You can test this algorithm by running the examples in the examples/motion_control/open_loop_motor_control/ folder.
How it works?
Choose the motor type:
Choose the torque control type:
Voltage torque mode Current torque mode
This control algorithm is very simple. User sets the target angle it wants to achieve \(a_d\). The algorithm only subtracts the current angle \(a_c\) and the desired angle \(a_d\) to find the direction it needs to move and goes in that direction with the highest velocity possible motor.velocity_limit(max velocity \(v_{max}\)). To set this velocity it uses the same algorithm as for velocity open-loop control.
In each step of the control loop, the algorithm calculates the distance from the target angle \(a_d\) and the current angle \(a_c\). It then calculates the next angle \(a_{c}\) using the following formula:
\[a_c = a_c + \max(-v_{max}d t,~ \min(v_{max}d t,~ a_d - a))\]A different way to write the same formula is:
A bit more verbose way to write the same formula is:
\[a_c = a_c + \begin{cases} v_{max}d t, & \text{if } a_d - a_c > v_{max}d t \\ -v_{max}d t, & \text{if } a_d - a_c < -v_{max}d t \\ a_d - a_c, & \text{otherwise} \end{cases}\]Or in code
// calculate the distance from the target d_angle = target_angle - past_angle; // constrain the distance with maximal allowable displacement d_angle = constrain(d_angle, -velocity_limit*d_time, velocity_limit*d_time) // calculate the next angle next_angle = past_angle + d_angle;
The sample time \(dt\) of the algorithm is adaptively calculated upon every algorithm execution (motor.move() call) and it is equal to the time passed since the last execution of the algorithm (time between two motor.move() calls). This means that the algorithm is going to be very stable even if the motor.move() calls are not happening at a constant frequency. You can check sampling time of the algorithm by checking motor.move_time.us (representing the time between two motor.move() calls in microseconds) variable.
Units
The angles in the formula are in radians, the velocity limit is in radians per second and the time is in seconds. Make sure to use the correct units when setting the target angle and velocity limits.
Configuration and Limits
Open-loop position control uses the motor.target variable as the desired angle entry, while the motor.velocity_limit variable sets the maximum velocity to be used for the desired movemebnt. This mode also and uses torque limits based on your chosen torque control mode.
// setting target velocity
motor.target = 2; // [rad/s]
// maximal velocity of the position transition
motor.updateVelocityLimit(5); // [rad/s]
// if in voltage control mode, you can set voltage limit
motor.updateVoltageLimit(6); // [Volts]
// if in current control mode, you can set current limit instead of voltage limit
motor.updateCurrentLimit(0.5); // [Amps]
Efficiency Considerations
Open-loop motion is a simple but inefficient control strategy. However its efficiency and characteristics depend a lot on the torque control mode you choose to use.
Which torque mode should I use
| Torque Mode | Best For… | Requirements | Limits |
|---|---|---|---|
| Voltage Control | Beginners & Gimbal motors. Best for low-speed testing where you don’t know the motor parameters yet. | None | Voltage motor.voltage_limit |
| Estimated Current | Drone & High-KV motors. Much safer for low-resistance motors; provides back-EMF compensation. | Phase resistance (\(R\)) and KV rating (\(KV\)) | Current motor.current_limit |
| FOC Current | High Performance. Most efficient and robust mode; handles variable loads and speeds perfectly. | Current Sensing hardware. | Current motor.current_limit |
Read more about open-loop efficiency considerations Read more about torque control modes
Position open-loop control example
Here is one basic example of the position open-loop control with the complete configuration. This code uses estimated current mode for torque control. The program will set the target position of 0 RAD and maintain it, and the user can change the target position using serial terminal.
// Open loop motor control example
#include <SimpleFOC.h>
// BLDC motor & driver instance
// BLDCMotor(pole pairs, phase resistance, KV rating)
BLDCMotor motor = BLDCMotor(11, 7, 90.0);
BLDCDriver3PWM driver = BLDCDriver3PWM(9, 5, 6, 8);
// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&motor.target, cmd); }
void doCurrLimit(char* cmd) { command.scalar(&motor.current_limit, cmd); }
void doLimitVelocity(char* cmd) { command.scalar(&motor.velocity_limit, cmd); }
void setup() {
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.init();
// link the motor and the driver
motor.linkDriver(&driver);
// open loop control config
motor.controller = MotionControlType::angle_openloop;
// torque control mode
motor.torque_controller = TorqueControlType::estimated_current;
// limiting motor movements
motor.updateCurrentLimit(0.5); // [Amps]
motor.updateVelocityLimit(10); // [rad/s] cca 100rpm
// init motor hardware
motor.init();
motor.initFOC();
// add target command T
command.add('T', doTarget, "target angle");
command.add('L', doCurrLimit, "current limit");
command.add('V', doLimitVelocity, "velocity limit");
Serial.begin(115200);
Serial.println("Motor ready!");
Serial.println("Set target position [rad]");
_delay(1000);
}
void loop() {
// torque control loop
motor.loopFOC();
// open loop angle movements
motor.move();
// user communication
command.run();
}