2025-03-27 9:53 PM - edited 2025-03-27 10:06 PM
Hello everyone,
I am working on shifting sensored FOC to sensorless FOC for a BLDC motor using STM32F103C8T6. I have successfully implemented all necessary transformations (Clark, Park, and Inverse Park), and the waveforms appear correct.
To estimate the rotor angle, I am using a Sliding Mode Observer (SMO). However, since the STM32F103 lacks an FPU, So function like atan2f() increase execution time. Instead, I implemented an alternate method for angle calculation. I am using position detected by hall sensor as reference, but output of my sensorless algorithm is having some differences from hall sensor signal.
This is output waveform
Here is the code I am using for angle calculation:
void SMOcalcalculation(int32_t Valpa, int32_t Vbeta, int32_t Ialpa, int32_t Ibeta){
// this is for approximated or predicted values of motor phase currents
// this is need to reconstant bemf :The error between the actual and estimated currents (error_alpa and error_beta) is used to compute the Sliding Mode Observer (SMO) error, which is crucial for estimating back-EMF.
//The estimated back-EMF is used for sensorless rotor position estimation in FOC (Field-Oriented Control).
Ialpa_hat += (Valpa - Rs *Ialpa_hat) >> 2;
Ibeta_hat += (Vbeta - Rs *Ibeta_hat) >> 2;
//Error Calculation
error_alpa = Ialpa - Ialpa_hat;
error_beta = Ibeta - Ibeta_hat;
// Apply Low-Pass Filter
error_alpha_filtered = LPF_ALPHA * error_alpha_filtered + (1 - LPF_ALPHA) * error_alpa;
error_beta_filtered = LPF_ALPHA * error_beta_filtered + (1 - LPF_ALPHA) * error_beta;
//Calculated bemf using Sliding Mode
if(Measured.phaseADCValues[0] == 0 && Measured.phaseADCValues[1] == 0){
Measured.foc.error_alpha = 0;
Measured.foc.error_beta = 0;
}else{
// e_alpha[k] = u_alpha[k] - R_s * i_alpha[k] - L_s * (i_alpha[k] - i_alpha[k-1]) / T_s
// e_beta[k] = u_beta[k] - R_s * i_beta[k] - L_s * (i_beta[k] - i_beta[k-1]) / T_s
//Ts sample time 1s 10e6
Measured.foc.error_alpha = ((((Valpa - ((Rs * Ialpa)) - (Ls* (error_alpha_filtered)))) + 9) - 4 ) *100 ;
Measured.foc.error_beta = ((Vbeta - (Rs * Ibeta)) - (Ls *(error_beta_filtered)) + 4) * 100;
}
}
#define FILTER_SIZE 5
int16_t angle_buffer[FILTER_SIZE] = {0};
int index = 0;
// Integer-based atan2 approximation using fixed-point math
int32_t fast_atan2_fixed(int32_t y, int32_t x) {
int32_t abs_y = (y < 0) ? -y : y;
int32_t angle;
if (x >= 0) {
//180/3 = 60 == 14043
//30 == 5461
int32_t r = ((x - abs_y) * 8191) / (x + abs_y + 1);
angle = 8191 - r; // π/4 - r
} else {
int32_t r = ((x + abs_y) *8191) / (abs_y - x + 1);
angle = 16383 - r; // π/2 - r
}
return (y < 0) ? -angle : angle;
}
void CalculateRotorAngle(int32_t ealpha, int32_t ebeta) {
int16_t raw_angle = (int16_t) fast_atan2_fixed(ebeta, ealpha); // Get raw rotor angle
// Apply moving average filter
angle_buffer[index] = raw_angle;
index = (index + 1) % FILTER_SIZE; // Circular buffer index
int32_t sum = 0;
for (int i = 0; i < FILTER_SIZE; i++) {
sum += angle_buffer[i];
}
Measured.foc.rotorAngle =(int16_t) (sum / FILTER_SIZE) ; // Smoothed angle
Measured.foc.rotorAngle += 10000;
}
Thanks in advance!
2025-03-28 2:11 AM
Hello,
May I suggest using the atan computation method provided in our MCSDK. Based on the CORDIC algorithm, it should enhance your angle estimation accuracy.
This method uses the back-EMF (alpha, beta) in stationary coordinates as input for angle computation.
Additionally, we offer a complete FOC sensorless solution (X-CUBE-MCSDK) based on the Luenberger State Observer, which is compatible with the STM32F103.
Best regards,
Fouad
2025-03-29 12:31 AM
Thank you so much for your reply sir , i have written my own control for this , tell me according to my code what can cause issue.
2025-04-09 9:56 PM
Hello happy to tell you that issue is solved when we increase bemf (Phase ADC values are increase)
2026-02-03 1:25 AM
I’m working on sensorless FOC using a Sliding Mode Observer (SMO) on the STM32 SPIN-3202 evaluation board using STM32 Motor Control Workbench.
The Workbench–generated code uses the built-in STO + PLL observer for rotor angle estimation. For academic reasons, I’m trying to understand how to implement my own SMO and use it to estimate the electrical rotor angle within the existing FOC framework.
I’m able to access:
α–β currents and voltages
Observer-related structures generated by the SDK
However, I’m unclear about:
The correct integration point for a custom SMO in the Motor Control SDK
How to replace or bypass STO+PLL and feed the SMO-estimated angle into FOC safely
If anyone has experience with:
Custom observer integration in STM32 Motor Control SDK
Replacing STO/PLL with SMO
Relevant application notes or code references
your guidance would be greatly appreciated.