Hi guys,
Some time ago @Candas1 has implemented sensorless flux observer compatible with SimpleFOC into the drivers repo.
Given that it’s such an awesome addition to SimpleFOC and I did not see many people use it so far, I just wanted to add a quick post here to encourage people to try to use it.
Especially since from recently @mcells provided the library with a simple tool to estimate motor parameters (inductance and resistance) which is crucial for the sensorless foc.
The code is very simple, as usual
#include <SimpleFOC.h>
#include <SimpleFOCDrivers.h>
#include "encoders/MXLEMMING_observer/MXLEMMINGObserverSensor.h"
// BLDC motor & driver instance
// sunnysky x4108s-17 380Kv motor
// BLDCMotor motor = BLDCMotor(11, 0.13, 380, 0.00003);
// My big BDUAV 6354-180KV motor
BLDCMotor motor = BLDCMotor(7, 0.045, 180, 0.00004);
// MXLEMMING observer sensor instance
MXLEMMINGObserverSensor sensor = MXLEMMINGObserverSensor(motor);
// SimpleFOC Drive Shiled
BLDCDriver3PWM driver = BLDCDriver3PWM(D5, D6, D10, D8);
// inline current sensor instance
// ACS712-30B
// - amp gain in 66mA/V
// but there is a voltage divider 3.3/5.0 volts
// - 4.7k and 10k -> (10/14.7) = 0.68
LowsideCurrentSense current_sense = LowsideCurrentSense(0.68*66.0f, A0, A2);
// commander communication instance
Commander command = Commander(Serial);
//void doMotion(char* cmd){ command.motion(&motor, cmd); }
void doMotor(char* cmd){ command.motor(&motor, cmd); }
void setup() {
// use monitoring with serial
Serial.begin(115200);
// enable more verbose output for debugging
// comment out if not needed
SimpleFOCDebug::enable(&Serial);
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 20;
driver.init();
// link driver
motor.linkDriver(&driver);
// link current sense and the driver
current_sense.linkDriver(&driver);
// set control loop type to be used
motor.controller = MotionControlType::torque;
motor.torque_controller = TorqueControlType::foc_current;
// comment out if not needed
motor.useMonitoring(Serial);
// current sense init and linking
current_sense.init();
current_sense.gain_b *= -1;
current_sense.skip_align = true;
motor.linkCurrentSense(¤t_sense);
// should not do the sensor alignement with the observer
// so these params need to be set
motor.sensor_direction= Direction::CW;
motor.zero_electric_angle = 0;
// initialise motor
motor.init();
// align encoder and start FOC
motor.initFOC();
// subscribe motor to the commander
command.add('M', doMotor, "motor");
// Run user commands to configure and the motor (find the full command list in docs.simplefoc.com)
Serial.println("Motor ready.");
// if you do not know your motor parameters uncomment the lines below
// and the program will output the motor parameters to the serial
// motor.characteriseMotor(1.0);
// return;
// run the FOC at a fixed frequency (optional)
HardwareTimer* timer = new HardwareTimer(TIM5);
timer->setOverflow(15000, HERTZ_FORMAT); // Set timer frequency to 10kHz
// add the loopFOC and move to the timer
timer->attachInterrupt([](){
motor.loopFOC();
motor.move();
});
timer->resume();
_delay(1000);
}
void loop() {
// user communication
command.run();
_delay(50);
}
Here are some cool videos (that are a bit scary too).
The motors are torque controlled and I’m setting the torque target value in amps. In both cases I’m using a nucleo g747re and the SimpleFOC Drive shield. The current sensing is inline, but I’m using low-side as it is much faster.
The motor parameters are measured using the motor.characteriseMotor(1.0);
method.
This is an awesome addition to SimpleFOC and I just wanned to thank the community it!