Motor Speed Ceiling

That is a very interesting idea. I’ll give that a go!

It does feel like it could be a sensor related issue. As the speed increases beyond the limit where it stops getting faster it’s actually locking up which makes me think that the field orientation isn’t in sync with the motors actual orientation anymore.

Let me make a video of that.

Here’s a video of it in action. When I say “T” that’s the command for setting the voltage so T3 sets the target voltage to 3 volts.

I’ll work on getting sensor smoothing working and see if that helps, thanks for the tip!

Just to be sure, do you have this in your platformio.ini ?

lib_archive = false;

1 Like

I don’t believe that I do, what does that do?

Without this, the generic pwm driver will be used, which is using analogwrite.

1 Like

That is interesting, I was just reading the docs on the ESP32 and MCPWM…so without that line I won’t actually be using MCPWM?

I think so. If this is happening, the pwm frequency would be something like 500 hz.

1 Like

That would certainly limit speed. I added that line and the behavior was the same as before, is there any way to check what PWM driver is being used?

Where would I find this file? #include <encoders/smoothing/SmoothingSensor.h> I’m looking in github and in the forums, but I haven’t found it yet

Edit for any future person who stumbles across this, SmoothingSensor is here.

Hmm maybe it’s not required anymore since this was merged in v2.3.3

Smoothing sensor is not part of the main repo.
You need to add this library.

1 Like

Well this is exciting and potentially relevant:

.pio/libdeps/esp32-s3-devkitc-1/Simple FOC/src/current_sense/hardware_specific/esp32/esp32_mcpwm_mcu.cpp:9:2: error: #error SimpleFOC: ESP-IDF version 4 or lower detected. Please update to ESP-IDF 5.x and Arduino-esp32 3.0 (or higher)
 #error SimpleFOC: ESP-IDF version 4 or lower detected. Please update to ESP-IDF 5.x and Arduino-esp32 3.0 (or higher)
  ^~~~~
In file included from .pio/libdeps/esp32-s3-devkitc-1/Simple FOC/src/current_sense/hardware_specific/esp32/esp32_mcpwm_mcu.cpp:12:
.pio/libdeps/esp32-s3-devkitc-1/Simple FOC/src/current_sense/hardware_specific/esp32/../../../drivers/hardware_specific/esp32/esp32_driver_mcpwm.h:8:10: fatal error: driver/mcpwm_prelude.h: No such file or directory
 #include "driver/mcpwm_prelude.h"

I’ll get that fixed and lets see if it makes a difference. Maybe I’m getting kicked to analog write because my ESP-IDF version is too old

1 Like

Ok, so I got everything to update to the latest version by switching over to the Arduino IDE and unfortunately the behavior was exactly the same. I am certain that we’re using MCPWM because at compile we get a nice message making that clear :grinning:

Adding sensor smoothing does seem to help making me think that we’re on to something there. With sensor smoothing I’m able to bump the top speed up to 127 rad/sec which doesn’t seem like a huge improvement, but the motor also sounds better (smoother).

smooth.phase_correction = -_PI_6;

What does this do in smoothing? Is there any chance that I’m doing something silly there?

Here’s my whole sketch if anyone cares to see the whole thing:

/**
 * 
 * Find KV rating for motor with Hall sensors
 *
 * Motor KV rating is defiend as the increase of the motor velocity expressed in rotations per minute [rpm] per each 1 Volt int voltage control mode.
 * 
 * This example will set your motor in the torque control mode using voltage and set 1 volt to the motor. By reading the velocity it will calculat the motors KV rating.
 * - To make this esimation more credible you can try increasing the target voltage (or decrease in some cases) 
 * - The KV rating should be realatively static number - it should not change considerably with the increase in the voltage
 */
#include <SimpleFOC.h>
#include <SimpleFOCDrivers.h>
#include <encoders/smoothing/SmoothingSensor.h>


// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(1);
BLDCDriver3PWM driver = BLDCDriver3PWM(47, 45, 35);

// hall sensor instance
HallSensor sensor = HallSensor(4, 5, 6, 1);

// instantiate the smoothing sensor, providing the real sensor as a constructor argument
SmoothingSensor smooth = SmoothingSensor(sensor, motor);


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


// voltage set point variable
float target_voltage = 1;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_voltage, cmd); }
void calcKV(char* cmd) { 
  // calculate the KV
  Serial.println(motor.shaft_velocity/motor.target/_SQRT3*30.0f/_PI);
}

//Computes a moving window average of the motor shaft velocity
void computeMovingAverage(){
  static float sum = 0;
  static int count = 0;
  static unsigned long lastCall = micros();
  sum += motor.shaft_velocity;
  count++;
  if(count == 100){
    Serial.println(sum/100);
    sum = 0;
    count = 0;
  }
}

void setup() { 

  pinMode(18, OUTPUT);
  digitalWrite(18, LOW);
  
  // use monitoring with serial 
  Serial.begin(115200);
  // enable more verbose output for debugging
  // comment out if not needed
  SimpleFOCDebug::enable(&Serial);

  // initialize encoder sensor hardware
  sensor.init();
  sensor.enableInterrupts(doA, doB, doC); 


  // set SmoothingSensor phase correction for hall sensors
  smooth.phase_correction = -_PI_6;
  // link the SmoothingSensor to the motor
  motor.linkSensor(&smooth);

  // driver config
  // IMPORTANT!
  // make sure to set the correct power supply voltage [V]
  driver.voltage_power_supply = 28;
  driver.init();
  // link driver
  motor.linkDriver(&driver);

  // aligning voltage
  motor.voltage_sensor_align = 1;

  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  motor.voltage_limit = 0.58 * driver.voltage_power_supply;


  // set motion control loop to be used
  motor.controller = MotionControlType::torque;
  
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialize motor
  motor.init();
  // align sensor and start FOC
  motor.initFOC();

  // add target command T
  command.add('T', doTarget, "target voltage");
  command.add('K', calcKV, "calculate KV rating");


  Serial.println(F("Motor ready."));
  Serial.println(F("Set the target voltage : - commnad T"));
  Serial.println(F("Calculate the motor KV : - command K"));
  _delay(1000);
}

long loopCount = 0;
unsigned long startTime = micros();
void loop() {

  //Compute the number of loops every second
  loopCount++;
  if(micros() - startTime > 1000000){
    Serial.println(loopCount);
    loopCount = 0;
    startTime = micros();
  }

  // main FOC algorithm function
  // the faster you run this function the better
  // Arduino UNO loop  ~1kHz
  // Bluepill loop ~10kHz 
  motor.loopFOC();

  // Motion control function
  // velocity, position or voltage (defined in motor.controller)
  // this function can be run at much lower frequency than loopFOC() function
  // You can also use motor.move() and set the motor.target in the code
  motor.move(target_voltage);

  // user communication
  command.run();

  static int i = 0;
  if(i++ == 100){
    i = 0;
    computeMovingAverage();
  }
}

What should I expect to see when I look at INHA on the scope?

What I am seeing is a square wave with about a 50% duty cycle that doesn’t seem to change much when I change the value of the target voltage.

You should see something like this

50% duty is 0v as the modulation is centered.

1 Like

Can you check what is happening here ?
Ua/Ub/Uc are the voltages from 0 to your supply voltage.
dc_a/dc_b/dc_c are the duty cycles from 0 to 1.

1 Like

They’re moving around a bit, but I’m generally seeing things that look like:

Ua: 13.85 Ub: 13.14 Uc: 14.86
dc_a: 0.49 dc_b: 0.47 dc_c: 0.53

Do those seem like reasonable values?

but what was the target voltage ? is the amplitude not going higher ?
that’s like 6% phase to phase.

1 Like

I believe that was at 1 volt? Bumping the voltage target up to 8 volts I can get the numbers to expand a bit to something more like:

Ua: 6.25 Ub: 21.75 Uc: 12.62
dc_a: 0.22 dc_b: 0.78 dc_c: 0.45

How is this computed?

Great, I was going to ask if you now got this message…

This is very strange - normally 1PP motors spin very fast…

Incidentally, I saw your Maslow project in make a number of years ago, I think it was in Make magazine, and took note of it at the time. Super-cool project :heart_eyes:

Wow, yes, ESP32s are fast MCUs. This is a little too fast. There is no point in going faster than your PWM speed with the normal SimpleFOC code. Perhaps add a delay to the main loop like delayMicroseconds(100) to limit it to 10-20kHz. Perhaps hammering the PWM peripherals with new values faster than it can set them isn’t comfortable for it, in any case it has no benefit.

And you will probably want to downsample your move() loop, although it isn’t doing much in this mode. motor.motion_downsample = 5; (2kHz move loop on 10kHz PWM)

I’m not quite seeing what’s holding you back here… at 61kHz main loop speed and with 1PP motor I’d expect you to hit 1000s of RPMs…

These seem centered around 14V, which is expected, but only have about 2V difference - what was your set-point here?

1 Like

Looks reasonable to me…

1 Like

Another thought:

Could the BEMF generated already be high enough to limit the speed? Do you have values for the phase resistance and KV you could plug into the motor constructor to see if BEMF compensation is helpful?
Careful, the set-point in torque voltage mode is then a (estimated) current, start with low values like 0.1…