A thread for finally figuring out sensorless drive strategies

Flux_linkage can be tweaked as I show in the video, until getting sinusoidal waves for flux_a and flux_b.

I did my test on a b-g431b-esc1, I don’t see any noise issue. I only added the ADC calibration, I think the phase currents were more balanced then. Better adc offsets means more balanced phase currents means less noise on d and q currents.

I would be grateful if someone having a setup with an encoder could compare the electrical angle based on encoder angle and the flux observer electrical angle.
This could show us at what minimum speed we get accurate angle, and if we need to add any offset to this angle.

I am still new to SimpleFOC as a contributor, I have difficulties to see how this would be implemented as a sensor class.
But I think some of the refactoring I did helps simplify the implementation:

  • split the foc algorithm into smaller fonctions (Park, Clarke, …)
  • add members to the BLDCMotor class to store intermediate results (e.g. Alpha beta currents and voltages)
    That way some of those values are available for other algorithms without having to rerun the FOC algorithm partially (e.g. running getDCcurrent does that).

FYI, in the branch of SimpleFOC I shared, I commented out the use of phase_resistance in velocity_openloop because I need phase_resistance for the flux observer but I don’t want to use it for estimating the current.

Then HFI is another topic, we need to go step by step…


I have a fan set up on my desk, and I can set up my calibrated magnetic angle sensor again. I calibrated the sensor by runnign the fan in forward and then reverse direction and collecting about a hundred data pairs in each direction. Each data pair contains the electrical angle and the magnetic angle reading. Then I combined the forward and reverse data sets, assuming the actual angle that should be coming from the sensor was half way between the forward and reverse for a given electrical anlge (at a given RPM and voltage, the fan is very symmetrical so the load is the same in either direction and thus the motor timing should be pretty close to the same under the same voltage and rpm). Then I made a data set that allows me to go backwards from the angle sensor reading to what should be reasonably close to the legit angle. FActors in all the various distortions that these sensors suffer.

so it’s not an optical encoder and it would take me a little while to set it back up again, but I stil lhave the calibration file somewhere.

Then I could plot the angle from your sub system vs the angle from the sensor.

Do you have some code I could run to do the ADC calibration and then later on compute the angle as you describe?

I could get an optical encoder another time which is probably a good idea but they are kind of expensive and I would have to interface it to the motor and stuff. I think my little calibrated angle sensor would help a lot at least.

The angle calibration is done using a raspberry pi pico which communicates with the b-g431 board but the calibration is already done so I don’t need them to communicate any more. The pico would request the electrical angle from the g431 board and then I got it so the timing was good and stuff, I think the calibration is legit good. I tested and inspected things.

Oh, I actually have an optical encoder here, It’s built into a servo motor, which has some cogging which could complicate things potentially. I could use that then, but I would have to design and print an interface to it so I can mount the motor and stuff.

I am willing to do that if you want, if you can do most of the work to write the code you want me to run. IDL how many pulses per revolution it is, I think it’s 512, on the low side. It’s an AB type, two output pins, no index.

edit: I could buy this one Photoelectric Incremental Rotary Encoder 600p/r 6mm Shaft 5-24vdc AB Phase for Length Measurement + Coupling : Amazon.ca: Industrial & Scientific looks like a good quality one at least. I would have to print a system to hold all the parts in position etc.

This branch of SimpleFOC I already shared has:

  • some refactoring of FOC algorithm
  • the adc calibration for g4
  • deadtime compensation (off by default), so that I get smoother openloop on the hoverboard motor for the experimentation
  • commented current estimation for velocity_openloop

This is my b-g431b-esc1 project with the flux observer running in the main loop.

Based on the previous comments about soldering on the b-g431b-esc1, I will get sensorless working before I can manage to solder the hall sensor wires on it lol.

I don’t have the equipment to fit an encoder to a hoverboard motor now.
I should probably invest in a rig with a motor + encoder, any advice is welcome.

I can do the CAD for that encoder and your motor so you can connect them, I can even print parts and mail them to you if you want, they aren’t very heat resistant though. I would need the cad model of your motor and either to buy the encoder and model it or download the cad model. I FI do that I might as well mail you the encoder too.

To solder the wires on the board was remarkably hard and even using a new, sharp soldering iron bit, tinning both areas and carefully connecting them I actually short circuited the 5 volts to ground, they are right next to each other. Fortunately the thermal shutdown of the voltage regulator saved me and I was able to fix it.

I compared the electrical_angle generated by velocity_openloop and the flux observer angle and it seemed ok, so I went ahead even if it’s too early, I couldn’t resist:

Over 3 volts the d axis current becomes really bad. That’s bad sensorless but that’s still sensorless :sweat_smile:

I had to hack SimpleFOC to:

  • not fail in InitFOC because there is no sensor
  • not do any sensor alignment
  • use the flux observer angle

That was just for fun, this would need proper implementation but it gives hints what would need to change for sensorless.

1 Like

I posted some code for this board that just impements open loop, but with ramped voltage and stuff. Good for testing. You could run it without load in each direction, open loop, and print the electrical angld and the flux observer angle. Then graph them with the arduino serial tool, see if the angle accrding to the flux observer consistently says it’s slightly behind the electrical, which we know the rotor must be in open loop. You could then run it the other direction, or load it with your finger and see if it responds appropriately i.e. the angle between electrical and the flux observer should increase.

As long as it increases with motor timing and the relationship betwen motor timing is consistent across rpm and current etc, it could be used. Some kind of calibration could be done to mop up whatever source of error there is, as long as it’s repeatable.

I was running this in voltage mode and with lag compensation because of the phase_inductance parameter. That was probably a mistake.

Tomorrow I will try with FOC, and compensate with an angle offset if needed.

If the flux observer angle turns out to work well, it means:

  • no need for an interrupt for the sensor
  • no need for smoothing
1 Like

Let me know if I can help.

1 Like

I think I also understood how HFI works now, or at least one method.

Salient motors have a different inductance on q axis (Lq) and d axis (Ld).
When you measure the inductance and spin the motor, the inductance goes higher when aligned with q axis and lower with d axis.

HFI injects a high frequency square wave, basically you add a voltage to the dq voltages before the SVPWM on one PWM cycle, and substract it on the alternate cycle.
Then you calculate the dq currents difference between the highs and lows.
This let’s you calculate the inductance as we discussed here.

Once you know the inductance, you can derive the angle. For example
if Lq is 300 uH and Lq is 250 uH, and I measure 275 uH, I am half way.
The less salient the motor is, the worse this will work.

So with this SimpleFOC would be able to measure the inductance.
But I think for that it should be interrupt based as I mentionned here.

[EDIT] I might be missing some details about inductance measurement and converting it to an angle, I will update when I know more.

Another nice paper about flux observer.

And more details about that particular flux observer in MESC book.

1 Like

Now I integrated the flux observer in foc_current.
I made a motor.sensorless variable to switch sensorless on or off.
This defines if the flux observer angle should be used for foc, otherwise it’s using the hall/encoder angle if available.
I added an offset variable for my tests but it’s useless, the raw angle from the observer is good enough.
Added a faster _atan2 function but it would work without it.

The flux observer seems to be sensitive to the flux linkage value.
This formula can be used to calculate it:
Flux linkage = 60/ (sqrt(3) * pi * kv * pole count)
After tweaking it, I could run a hoverboard motor at 13v, I haven’t tried higher.

It’s probably good enough to try now. With a power supply of course :laughing:

1 Like

Nice, I could try it with my fan at some point. I would have to try various KV values as I can measure the peak to peak back emf per rpm the motor produces, but it does not seem to be the same.

Do you have example arduino code you can post that is good for a quick test? I can try to weave it together into a testing program that can be controlled over serial by combining it with my open loop tester program.

Now I am calculating the flux linkage here based on the formula I previously shared.

And my sketch doesn’t have anything special anymore, I am just calling BLDCmotor with pole_pairs, KV, phase_resistance and phase_inductance.

I am initializing Hall sensor so the init doesn’t complain but I don’t even have the wires soldered.

What you have to do is only set motor.sensorless to 1 when using foc_current mode.
The flux observer is only used for commutation now, shaft velocity will be zero.
I will check now if I could add the flux observer as a sensor.

You want to see a Magic trick?


Nice! I would need actual code though if I am to do any testing any time soon. The fan and board is still sitting set up ready to go on my desk, so now is a fairly good chance to investigate. But it would take me a long time to reproduce the steps to implement things you have taken thus far. Even if you can just post your code verbatim, I can try to edit it down to the elementals and debug that, but doing everything de-novo I cannot spare the time for, unfortunately.

I don’t get your point.
You have my simplefoc modified code and my sketch on github.

That’s just so nice :slight_smile:

I think we should try to integrate it into SimpleFOC, but this will take a little bit of time before the next release, in order to integrate all of Candas awesome changes…

But I looked at it and I see a section where you calculate the flux linkage, but I don’t see the function that accepts the current values and then spits out the actual rotor angle anywhere…I could peer into the documents you posted and try to follow the steps you took to concoct it but it would take a while.

What’s the actual main.cpp you are running right now, an exactly what libraries need to be present to compile it? The branch of simplefoc I get, I uninstall my old simplefoc library and get that one installed.

It sounds like you are using platformio which could complicate the compiling process, I haven’t tried platformio although it sounds good it also sounds kind of complicated to get started.

I think what we need is a single function that takes the flux linkage value and whateve relse it needs and gives you the rotor angle, or the angle between the electrical and the rotor at some instant.

I know what to do from there, the mystery has always been how to infer rotor angle from current data and whatever other data there is. My understanding of a state observer is that that’s the essence of what it does, it takes what you know, and, over time (may require some time stamped historical data points), tells you something you didn’t know. In this case, the actual rotor angle. Using a model of the physics of the system, basically. Gets complicated, but that’s the essence of it.

We have the data we need, I think with adequately low noise and time resolution.

Oh, I would have to calibrate the adc too, I can try reading up on that but why don’t you just post exactly the main.cpp and whatever you are using? That’s what I always do. It takes time to make and debug even short programs. Many times I have even dug up my old forum posts because I lose track of what the best program is and that’s a known good point, or I wouldn’t bother posting it.

I already shared my branch of SimpleFOC with the flux observer and adc calibration, and I also shared my sketch. Not sure what else I can do.

Maybe you should wait for this change to possibly be in the dev branch then, but it will take time.

I understand it’s not easy to contribute to SimpleFOC, I am trying to help but I hardly get feedback from the community.

1 Like

Can you tell us where the code that does the flux observer stuff is located? I can’t find it anywhere :frowning:

Thanks for the contributions, it is good to have a feather in your cap and it’s also a really good way to learn. The community does contribute but it is a slow moving phenomenon, I agree it would be nice if things were better. There aren’t many of us and the incentives are not aligned very well.