Hey,
I’ve been running some timings on SimpleFOC, and I wanted to share. @admins feel free to delete this if you feel it is spam.
I use an AS5048 sensor, and tested on ESP32 (240Mhz), Atmega328P (“Arduino Nano” - 16Mhz) and STM32F103 (“BluePill” 72 MHz).
The following were my results so far, I will post more as I run more tests:
BluePill - total fail - I discovered my chips were not original STM32F103 chips, but rather some kind of clone that did not work .
Atmega328P, I2C Sensor @ 100KHz I2C Bus speed ~ 450Hz FOC iteration speed
Atmega328P, I2C Sensor @ 400KHz I2C Bus speed ~ 650Hz FOC iteration speed
ESP32, I2C Sensor @ 400KHz I2C Bus speed ~ 850Hz FOC iteration speed
Ok, that’s surprising! ESP32 is crushingly more powerful than the Atmega, why is it not faster? I looked for the answer using a cheap logic analyser, see the timing diagrams attached below…
Basically, even at 400KHz bus speed the I2C communication takes a really long time. So while the ESP32 is 1000x faster at executing the FOC code, it still needs just as long to read the sensor values. SimpleFOC needs to read the sensor 2x per iteration (something to think about?) so the I2C sensor really limits the performance.
To confirm this I ran some more tests with the SPI version of the AS5048:
BluePill - didn’t bother
Atmega328P - could not get it to read the sensor. Still checking into why, since other people have made it work it seems… will report back once it is working.
ESP32, SPI Sensor @ 1MHz I2C Bus speed ~ 4350Hz FOC iteration speed
Now that’s more like it!
Here’s some timing diagrammes:
AtMega328P, I2C @ 100Khz
ATMega328P, I2C @ 400KHz
ESP32, I2C @400KHz
ESP32, SPI @ 1MHz
For explanation: In these scans, I used 3 digital pins, channel 1 I switched on just before the call to moveFOC() and off immediately afterwards. Channel 2 times the move() routine, and Channel 3 times the getAngle() function, the call to the sensor.
The code I was timing looked something like this (depending on platform):
#include "Arduino.h"
#include <SimpleFOC.h>
#include <Math.h>
#define TIMING_FOC_PIN 2
#define TIMING_MOVE_PIN 0
#define TIMING_SENSE_PIN 4
#define SPI_CS 5
MagneticSensorSPIConfig_s AS5048_SPI = {
.spi_mode = SPI_MODE1,
.clock_speed = 1000000,
.bit_resolution = 14,
.angle_register = 0x3FFF,
.data_start_bit = 13,
.command_rw_bit = 14,
.command_parity_bit = 15
};
MagneticSensorSPI sensor = MagneticSensorSPI(AS5048_SPI, SPI_CS);
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(25, 26, 27);
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("Initializing...");
pinMode(TIMING_FOC_PIN, OUTPUT);
pinMode(TIMING_MOVE_PIN, OUTPUT);
pinMode(TIMING_SENSE_PIN, OUTPUT);
digitalWrite(TIMING_FOC_PIN, 0);
digitalWrite(TIMING_MOVE_PIN, 0);
digitalWrite(TIMING_SENSE_PIN, 0);
pinMode(SPI_CS, OUTPUT);
digitalWrite(SPI_CS, 1);
sensor.init();
motor.linkSensor(&sensor);
driver.voltage_power_supply = 9;
driver.init();
motor.linkDriver(&driver);
motor.controller = ControlType::velocity;
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 20;
motor.PID_velocity.D = 0.001;
motor.PID_velocity.output_ramp = 1000;
motor.LPF_velocity.Tf = 0.01;
motor.voltage_limit = 8;
//motor.P_angle.P = 20;
motor.init();
motor.initFOC();
Serial.println("Init complete...");
}
// velocity set point variable
float target_velocity = 2.0;
void loop() {
// FOC algorithm function
digitalWrite(TIMING_FOC_PIN, 1);
motor.loopFOC();
digitalWrite(TIMING_FOC_PIN, 0);
digitalWrite(TIMING_MOVE_PIN, 1);
motor.move(target_velocity);
digitalWrite(TIMING_MOVE_PIN, 0);
}
Here some thoughts on what this means in terms of attainable speeds / smoothness: