Can´t reach high RPM with SimpleFOC

Hello everybody, i´m having problems to reach a higher velocitiy then 70rad/s everthing above have to much power consumtion. Currently im unsing closed loop velocity motion control.
My Setup:

  • Arduino Mega
  • DRV8302 Board
  • Motor 24V, 3000RPM, 300W
  • For sensoring i use the integrated Hall Sensors of the motor

If i set the velocity above for example 50 rad/s my motor is consuming 1,5Amps witch is way too much for that less speed.

Can you help me to improve my speed problem ?


You might have to use the lag compensation I have mentioned about here.
If you see the table, it help me get more speed with less consumption.
The smoothing should also slightly reduce the consumption but not increase the speed, but it’s experimental.

Hi Candas1,

thanks for replying. Sounds logic can you explain me how set the inductance parameter ?

You should search in the documentation.
I myself have set only the inductance, not the other parameters.

This worked very well for the power consumtion and increased my speed by 30 rad/s. For my application i need a desired speed of 1400 RPM maybe a little more. Is there something else i can do for increasing speed ?

I am not sure what commutation you use now, but Space Vector PWM should get you more speed.
And you need to be careful with the limits you have set not to saturate the waveform.

This section of the documentation should cover those aspect.

I´m using Space Vector PWM. If this helps you here are my Code.

#include <SimpleFOC.h>

#define   INH_A 6
#define   INH_B 9
#define   INH_C 11
#define   INL_A 7
#define   INL_B 10
#define   INL_C 12
#define   EN_GATE 8
#define   M_PWM 3 
#define   M_OC 4
#define   OC_ADJ 5

#define MOVE 13

#define   _MON_TARGET 0b1000000  // monitor target value
#define   _MON_VOLT_Q 0b0100000  // monitor voltage q value
#define   _MON_VOLT_D 0b0010000  // monitor voltage d value
#define   _MON_CURR_Q 0b0001000  // monitor current q value - if measured
#define   _MON_CURR_D 0b0000100  // monitor current d value - if measured
#define   _MON_VEL    0b0000010  // monitor velocity value
#define   _MON_ANGLE  0b0000001  // monitor angle value

// motor instance
BLDCMotor motor = BLDCMotor(4,0.4,300,0.01);

// driver instance

// InlineCurrentSensor constructor
//  - shunt_resistor  - shunt resistor value
//  - gain  - current-sense op-amp gain
//  - phA   - A phase adc pin
//  - phB   - B phase adc pin
//  - phC   - C phase adc pin (optional)
InlineCurrentSense current_sense  = InlineCurrentSense(0.05, 12.22, A0, A1, A2);

// Hall sensor instance
// HallSensor(int hallA, int hallB , int cpr, int index)
//  - hallA, hallB, hallC    - HallSensor A, B and C pins
//  - pp                     - pole pairs
HallSensor sensor = HallSensor(21, 20, 19, 4);

// Interrupt routine intialisation
// channel A and B callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

// commander interface
Commander command = Commander(Serial);
void onMotor(char* cmd){ command.motor(&motor, cmd); }
void onMotion(char* cmd){ command.motion(&motor,cmd); }

void setup() {
  // monitoring port

  //motor.KV_rating = 300; // rpm/volt - default not set

  //Monitroing commands
    //display variables
    motor.monitor_variables = _MON_TARGET | _MON_VEL | _MON_ANGLE | _MON_VOLT_Q; 
    // downsampling
    motor.monitor_downsample = 10; // default 10

  // check if you need internal pullups
  sensor.pullup = Pullup::USE_INTERN;
  // maximal expected velocity
  //sensor.velocity_max = 1000; // 1000rad/s by default ~10,000 rpm
  // initialise encoder hardware

  sensor.min_elapsed_time = 0.0001; // 100us by default
  // interrupt initialization
  // enable hall sensor hardware interrupts
  sensor.enableInterrupts(doA, doB, doC);
  // hardware interrupt enable
  // sensor.enableInterrupts(doA, doB, doC);

   // DRV8302 specific code
  // M_OC  - enable over-current protection
  // M_PWM  - enable 6pwm mode (can be left open)
  // OD_ADJ - set the maximum over-current limit possible
  // Better option would be to use voltage divisor to set exact value

   // configure driver
  driver.voltage_power_supply = 24;
  // link current sense and driver
    // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  motor.controller = MotionControlType::velocity;

  // voltage torque control mode
  //motor.torque_controller = TorqueControlType::voltage;

  // controller configuration based on the control type 
  // default P=0.5 I = 10 D =0
  motor.PID_velocity.P = 0.01;
  motor.PID_velocity.I = 0.1;
  motor.PID_velocity.D = 0;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 2000;
  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.05;
  // setting the limits
  //  maximal velocity of the position control
  motor.velocity_limit = 500; // rad/s - default 20

  // angle loop controller
  //motor.P_angle.P = 20;
   // since the phase resistance is provided we set the current limit not voltage
  // default 0.2
  motor.current_limit = 20; // Amps
  // angle loop velocity limit
  //motor.velocity_limit = 1000;

  // power supply voltage
  //motor.voltage_power_supply = 12;
  // default voltage_power_supply
  //motor.voltage_limit = 24;
  // use monitoring with serial for motor init
  // monitoring port
  // comment out if not needed

  // initialize motor

  // init current sense
  // link motor and current sense
  // align encoder and start FOC

  // set the initial target value = 10;
  // define the motor id
  command.add('M',onMotor, "my motor motion");
  command.add('T',onMotion,"motion control");

void loop() {
  // iterative setting FOC phase voltage
  digitalWrite(MOVE, HIGH);  
  digitalWrite(MOVE, LOW);  
  // iterative function setting the outer loop target
  // velocity, position or voltage
  // if target not set in parameter uses variable
  //Monitoring values
  // user communication;

Based on what I shared, the maximum target should be 24 X 0.58 = 13.92V in voltage/torque mode.
But I am not sure how it works when you provide the phase resistance/current limit

Now my RPM limit is at 110 rad/s after this my current goes up to 3amps without any load.
I cant imagine whats the problem.


You can try using the motor.motion_downsample to see if reducing the frequency of calls to move() helps any.

Other than this, I assume you will hit a hardware limit on the Arduino Mega. It’s only an 8 bit, 16MHz MCU. The faster you go, the more interrupts it has to process from the HallSensor, while still computing FOC updates and sending them to the driver…

With a faster MCU, you may go faster…

1 Like

thanks for helping me, i will try a faster MCU and let you know if it works.

Greetings Marcel

Hello together,
I have now successfully ported the code to the nRF52 (Arduino 33 BLE). With this MCU and Hall sensors, I can achieve 140 rad/s in the closed loop without any problems.
For another application, however, I should be able to achieve 300 rad/s. I guess my limiting factor is now the hall sensors.
But if I run the motor in open loop mode I should be able to reach higher speeds ?
However, it is very difficult to get the motor to turn at all in open loop. I can only achieve higher speeds if I increase the velocity and current step by step. Is there a better way to achieve higher speeds? In the open loop, the limit was 200 rad/s.

Many thanks in advance for your help.

Greetings Marcel

Hey marcel,

The BLE may not have been the best choice, unfortunately.

While we support the nRF52 chips, the Arduino layer is based on mbedOS, which is very slow. So the performance of these MCUs is not super in ArdiunoIDE. And on PlatformIO there are some kind of bugs, and the Arduino BLE boards aren’t working in PlatformIO atm.

To get better performance, both in open loop and closed loop, a really fast MCU like an ESP32, a Teensy or a STM32F4/G4 would be better.

Switching from Hall sensors to a SPI magnetic encoder or ABZ encoder could also help.

In open loop its normal that you can’t go from zero to max in one step, since the motor is “following the commutation” you have to get it rotating gently, and “take it with you” to go faster. If you jump too quickly, the motor’s inertia means it can’t follow the commutation properly, and once it misses some steps it can break down altogether.