On this page
Estimated Current Control Setup
⏱️ ~30-60 minutes
This guide shows how to use estimated current control (model-based current) when you don’t have current sensors. It lets you command torque in Amps by estimating current from motor parameters.
Read more about when to use estimated current control
Prerequisites
Before starting, make sure you already have:
- Working sensor and driver setup - Sensor setup guide and Driver setup guide
- Closed-loop FOC working in voltage torque mode - Closed-loop voltage control guide
Motor parameters
Estimated current control relies on accurate motor parameters to estimate current. In order of importance, you should know or measure:
- Phase resistance (Required) - How to measure
- KV rating (Optional but Recommended) - How to measure
- Inductance (Optional and not critical for basic use, but improves high-speed performance)
Phase resistance and KV rating are the most important parameters for basic estimated current control. They are often specified in the datasheet or can be measured with simple tests. Inductance is less critical for basic use but can improve performance at higher speeds by compensating for back-EMF. If not available, it can be omited for basic use, but consider adding it later for better performance.
Read more about estimated current control parameters
If you have current sensing already set up, you can use it to measure the motor parameters directly - See here for automatic motor characterisation guide
Step 1: Set motor parameters
The motor parameters are set as properties of the motor object and can be provided either in the constructor
BLDC motors Stepper motors Hybrid Stepper motors
// In constructor
// BLDCMotor motor = BLDCMotor(pole_pairs, phase_resistance [Ohm], KV_rating[rpm/V], Lq[H], Ld[H]);
BLDCMotor motor = BLDCMotor(11, 0.4f);// only R
// or
BLDCMotor motor = BLDCMotor(11, 0.4f, 120.0f); // R and KV
// or
BLDCMotor motor = BLDCMotor(11, 0.4f, 120.0f, 0.001f); // R, KV, and inductance
or by modifying the properties directly. For example:
motor.phase_resistance = 0.4f; // Ohms
motor.KV_rating = 120.0f; // rpm/V (or KV from datasheet)
motor.axis_inductance.q = 0.001f; // Henries (optional)
Step 2: Enable estimated current mode
Switch torque control from voltage to estimated current:
motor.controller = MotionControlType::torque;
motor.torque_controller = TorqueControlType::estimated_current;
// Set safe limits
motor.updateCurrentLimit(1.0); // Amps
motor.target = 0.0; // Amps (torque command)
The example of the full code is shown below. You can also copy your working closed-loop code and just change the torque controller type to get started with estimated current control.
BLDC motors Stepper motors Hybrid Stepper motors
#include <SimpleFOC.h>
#define POLE_PAIRS TODO
#define PHASE_RESISTANCE TODO
#define KV_RATING TODO
#define INDUCTANCE_Q NOT_SET // optional - can be left as NOT_SET for basic use
BLDCMotor motor = BLDCMotor(POLE_PAIRS, PHASE_RESISTANCE, KV_RATING, INDUCTANCE_Q);
// TODO instance driver
BLDCDriverXPWM driver = BLDCDriverXPWM();
// TODO instance sensor
Sensor sensor = Sensor();
Commander command = Commander(Serial);
void doMotor(char* cmd) { command.motor(&motor, cmd); }
void setup() {
Serial.begin(115200);
SimpleFOCDebug::enable(&Serial);
encoder.init();
encoder.enableInterrupts(doA, doB);
motor.linkSensor(&encoder);
driver.voltage_power_supply = TODO; // set voltage [V]
driver.init();
motor.linkDriver(&driver);
// Estimated current control
motor.controller = MotionControlType::torque;
motor.torque_controller = TorqueControlType::estimated_current;
motor.updateCurrentLimit(1.0); // A
motor.target = 0.0; // A - zero torque command to start
if(!motor.init()) { Serial.println("Motor init failed"); return; }
if(!motor.initFOC()) { Serial.println("FOC init failed"); return; }
command.add('M', doMotor, "Motor");
_delay(1000);
}
void loop() {
motor.loopFOC();
motor.move();
command.run();
}
Validate torque response
- Open Serial Monitor (115200)
- Type
M0- motor should feel free to move (almost as disconnected) - Type
M0.5- Motor should accelerate and reach the max velocity smoothly - If stopped by hand, motor should resist with a force proportional to the current command (0.5 Amps in this case)
- Type
M0.8- you should feel stronger torque - Type
M-0.8- motor should reverse the force against your hand with the same strength - Type
M0again - motor should feel free to move again - Release motor and type
M1.0- motor should accelerate to the same speed as before (approximately)
- The higher the current the higher the acceleration, but the speed should be consistent regardless of load
- When motor is at max speed type
M0- motor should decelerate smoothly to a stop
⚠️ Troubleshooting: Motor Parameters Not Tuned Correctly
If any of these steps fail, this probably means that some of the motor parameters is wrong. In that case the best way to proceed is to do a step by step validation of each one of the parameters.
See this guide for how to validate and tune motor parameters.
Quick Troubleshooting
The best way to troubleshoot is to test each motor parameter systematically. Here are the key diagnostics:
Motor doesn’t move or moves very slowly?
- Phase resistance is probably too low
- Increase
motor.phase_resistance - See phase resistance testing guide
Motor and driver get hot at low currents?
- Phase resistance is probably too high
- Decrease
motor.phase_resistance
Motor feels strange when idle (target = 0)?
- KV rating is probably incorrect
- Motor should feel like it’s disconnected when
motor.target = 0 - Increase KV if motor resists rotation; decrease if it spins freely on its own
- See KV rating testing guide
Motor is unstable or jerky at high speeds?
- Add or increase inductance:
motor.axis_inductance.q = 0.001 - See inductance testing guide
For detailed diagnostics of each parameter, see the full motor parameter testing guide.
Still having issues?
Browse throught the SimpleFOC community forum, there might already be a solution for your specific hardware or issue. Also don’t hesitate to ask for help there!
Step 3: Velocity control and tuning
Now that you have torque control working, you can switch to other motion control types like velocity or position. The estimated current controller will still be used under the hood to achieve the commanded velocity or position with the correct torque. For example, to switch to velocity control:
motor.controller = MotionControlType::velocity;
or using the command interface:
MC1
Now to a quick test:
M0- motor should be static and hold positionM6.28- motor should accelerate and reach approximately 1 rotation per second (6.28 rad/s)M-6.28- motor should reverse and reach -1 rotation per secondM0- motor should decelerate smoothly to a stop
Troubleshooting
Motor oscilates and vibrates at low speeds?
- This usually means that the velocity PID needs to be tuned. See the velocity control tuning guide for how to do that.
- If you want to move quickly without tuning, you can also try lowering the velocity PID P and I gains to reduce oscillations.
- Read the gains, type
MVPandMVIto the terminal to see the current values - Try lowering them gradually until the oscilations stop
- Read the gains, type
Motor doesn’t reach the target velocity?
- Current limit is probably too low.
- Increase it with
motor.updateCurrentLimit(3.0); - Using comand interface:
MCL3.0
- Increase it with
- Voltage limit too low (if changed but the user)
- Increase
motor.voltage_limitto 50-60% of your supply voltage - Using command interface: ex.
MLU5.0to set themotor.voltage_limitto 5V
- Increase
- Power supply too low
- Try to increase the supply voltage or use a more powerful supply
Motor and driver heat up at low speeds?
- This usually means that the phase resistance is too low, causing high current draw at low speeds
- Increase
motor.phase_resistanceto reduce current and heat, but be careful not to set it too high or the motor won’t move well - See phase resistance testing guide
Motor feels weak?
- This usually means that the phase resistance is too high, limiting current and torque
- Decrease
motor.phase_resistanceto allow more current and torque, but be careful not to set it too low or the motor and driver may overheat - See phase resistance testing guide
- Decrease
- It can also be the current limit is set too low, or the supply voltage is insufficient
- Increase
motor.current_limit - Using command interface:
MCL3.0for setting it to 3 Amps
- Increase
Step 4: Position control and tuning
Now you can also switch to angle control:
motor.controller = MotionControlType::angle;
or using the command interface:
MC2
Then you can test it by sending angle commands in radians:
M3.14- motor should rotate to half a rotation (180 degrees)M6.28- motor should rotate to one full rotation (360 degrees)M0- motor should rotate back to the starting position (0 degrees)
Troubleshooting
Motor oscilates and vibrates at low speeds?
- This usually means that the angle PID needs to be tuned. See the angle control tuning guide for how to do that.
- If you want to move quickly without tuning, you can also try lowering the angle PID P and I gains to reduce oscillations.
- Read the P gain (typically the only one to set) with
MAPcommand, and lower it gradually until the oscilations stop
- Read the P gain (typically the only one to set) with
Still having issues?
Browse throught the SimpleFOC community forum, there might already be a solution for your specific hardware or issue. Also don’t hesitate to ask for help there!
What’s Next?
You now have a fully functional model-based FOC control system! Depending on your needs:
For Robotics/Automation
- See Motion Control docs
- Implement feedback loops in your application code
For Precision Applications
- Tune PID parameters for your motor
- Use angle mode for position control
- See PID tuning guide
For Learning
- Explore the SimpleFOC library examples
- Read about FOC theory and source code
- For debugging, monitoring, and communication docs, see Communication and Debugging sections