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.
.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
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
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();
}
}
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
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?
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…