SimpleFOC v2 - understanding sensor align

Hi All,

I’m currently working with the SimpleFOC library 2.1.0. My hardware setup is:

Everything worked really well for me when I was using a gimbal motor. However, I recently switched to the above mentioned low resistance motor, and have been running into some problems. One of the issues I face is when running the “single_full_control_example” without changing the hardware in any way, I sometimes get:

MOT: Align current sense.
MOT: Align error!
(and the motor jerks around)

and sometimes get:

MOT: Align current sense.
MOT: Success: 3
(and the motor runs smoothly)

I traced this down to different results within the “driverAlign” function. Sometimes the measured ab_ratio is neither ~2 or ~0.5 but rather ~1.0. I don’t understand this possibility. Also, it seems that the same function can return different values when the hardware hasn’t changed. Please help. What is going wrong?

Best,
Nat

1 Like

Hey @ngalin, welcome to the community :slight_smile:

I suspect your problem might be related to the voltage this function sets to the phases to calculate the direction and relation phase/shunt resistor. I suggest you try limit the align voltage like so:

motor.voltage_limit = numberLessThanPowerSourceVoltage; 

Which should be done when using low resistance motors. Alternatively, you can skip the alignment and add this to your code (should work only for SimpleFOCshield v2):

// invert phase b gain
current_sense.gain_b *=-1;
// skip alignment
current_sense.skip_align = true;
...
// align all sensors
motor.initFOC();

Hi David,

Thanks for your response. I forgot to mention, but I do set the voltage limit to a low value. In my case it is:
motor.voltage_limit = 4;
So this doesn’t fix the problem.

But your second suggestion does. Thanks!

This suggestion works because on the SimpleFOCShield v2 driver board, the gains are flipped between the two phases (as per this post: The inline current sensing) right?

I still have the question though: “why” the firmware was returning different values when nothing had changed in H/W or F/M. Can you help me understand this?

Best,
Nat

Hey Nat,

The initFOC function has three main functions:

  1. Align sensor direction with motor direction
    • turn the motor one electrical revolution and save this direction as the good one (fails initFOC if the sensor does not move)
    • check if the pole pairs number is right when you are there (does’t fail if initFOC if it does but it tells you the estimated value)
    • You can skip it by setting motor.sensor_direction before initFOC
  2. Align position sensor angle with the motor electrical angle
    • Set voltage in direction -90 degree electrically and let the motor settle
    • Find the sensor angle on which motor electrical zero angle is zero (the position of the sensor when the motor settled) and store it
    • You can skip it by setting motor.zero_electrical_angle before initFOC
  3. Align the current sensing to the motor direction (Only if using current sensing)
    • This part of the code will put voltage on the phases A and B of the motor and see if the currents align with those voltages. In general if it puts a voltage to phase A then the current sense A channel should measure current with twice magnitude than the B and C.
    • This part of the code can invert gains of the particular current sense channel if necessary and it can switch pinouts of the current sense channels A and B for example. And it will let you know what did it do if you use monitoring : see in docs
    • And finally it will fail if it could not figure out what to do to align the current sense with the motor phases.
    • You can skip it by setting current_sense.skip_align = true before initFOC

The reason why current alignment sometimes returns different value is because of the noise of current sensing. It sets the voltage to the motor phases and in then measures the currents. It will only pass the alignment if the measured current ratio is correct.

The procedure goes as follows:
For example, current sense alignment procedure puts motor.voltage_sensor_align voltage to the motor phase A and the phases B and C to 0. It should be measuring Ca = voltage_sensor_align/(1.5*phase_resistance) Amps on current sense channel A and exactly half of it Ca/2 on the other channels.

  • If you measure Ca on A and 2*Ca on B, the procedure will switch the A and B current sense channels
  • If you measure -Ca instead of Ca the procedure will invert the gain of the phase A
  • If you measure Ca on A ~Ca on B then it will will fail the alignment because it could not deduce what to do to make it aligned.

So for the motors with lower resistance the current measurement noise is higher and it sometimes triggers misbehavior. To avoid this from happening there are really three things you can do:

  • Use the highest reasonable value of the motor.voltage_sensor_align to magnify the current magnitude to be measure and minimize the noise influence
  • Go to the code and use longer period of time and increase filtering of current acquisition, I’ve fixed it to 100 points and averaged it with a simple exponential filter: see in the code
  • Don’t use this feature, just skip it. It does not do anything else but checks if your specified pinout and gains are well set. If they are it will not change anything. This check is here to prevent mistakes really nothing more :smiley:
1 Like

Hi Antun,

Great, thanks very much for the detailed explanation, and useful suggestions for fixing the problem.

So, yes, I’ve now understood that the problem is definitely with measurement of the phase currents. I have tried a few different filtering approaches, and I haven’t yet achieved anything sensible. The only configuration that works at all for me is:
motor.torque_controller = TorqueControlType::voltage;
(neither dc_current, nor foc_current work - setting torque control to these settings causes the motor to jerk as the current in the phases toggles between some max value to 0 and then back again).

The phase resistance of the motor is 39mOhm, which is the same order of magnitude as the current sensing resistor (10mOhm) so perhaps this is contributing to the problem?

Would really appreciate further suggestions for reliably measuring phase current in low-resistance motors. Anyone else tried this?

Best,
Nat

Can you explain about this more detailed?

Try using battery rather than PSU with CCCV mode.
Sometimes it might cause problem.
Or decrease motor.voltage_sensor_align.

Hey Nat,

I’ve been using current sensing with my low-resistance motors, it was very hard to get the parameters right. I have some suggestions:

  • Set a limit to both Q and D with motor.PID_current_q.limit and motor.PID_current_d.limit. I suggest you try with small values at first, something like 0.5, 1, 1.5, etc.
  • Set the P value for both Q and D some orders of magnitude smaller than I, I have P set to 0.01 and I set to 10.
  • Even though Antun and I agree that the ramp value should be big enough that it doesn’t affect anything, try setting a low ramp value (around 50 or so), this will help avoid the effect you have of the phases toggling between max and 0 fast. Keep in mind this will make accelerations a bit slower.
  • Low-pass filtering made everything worse for my set-up, maybe don’t use it at first and after you start to get good results check if filtering can improve the response.
  • Make sure you have a very good sensor alignment, so PP check passes every time.

Hey @hbozyq,

At the begining of the code you only know where your sensor zero angle is, and not really where your motor’s electrical zero angle is. Therefore in order to find it you do we do a small experiment. We know that the motor is going to respond to the magnetic field produced by the windings by aligning itself exactly 90 degrees out of phase. 90 degrees out of phase means that it will align the rotor permanent magnets in exactly opposite orientation to your “virtual magnets” induces in windings by passing in the current through them.
So in order to find electrical zero of the motor, we apply the voltage (or better said current) vector in the direction of -90 degrees electrically for that motor and wait for the motor to respond. Once when it has moved, and aligned it to the magnetic field then we declare that position as the electrical zero position because:

- 90(what we have set) + 90(how much the motor will move) = 0

Then we just read the sensor angle in that location and remember it in the code. This value you can find in motor.zero_electrical_angle.

@ngalin did you manage to run the current control for any motor?
@David_Gonzalez has some good points :smiley:

40mOhm motor is really an overkill for this system, but it should still work. I was able to get some good results with some pretty powerful motors. But for me I had to use a lot of filtering and slow down the current control loop by lowering the PID parameters values:

// these values are very conservative but they can be a good start
motor.PID_current_q.P = 0.5; 
motor.PID_current_q.I = 1;
motor.PID_current_d.P = 0.5;
motor.PID_current_d.I = 1;
motor.LFP_current_q.Tf = 0.05; // even 0.1
motor.LFP_current_d.Tf = 0.05; // even 0.1

Alright. But why -90?

So that the motor moves it’s 90 degrees it is placed exactly at 0 degrees electrically.
You don’t agree?

I mean, is it related to generating sinusoidal magnetic field which is 90 degree(E angle) ahead of the permanent magnet’s magnetic field?

Yes. Its using the sinusoidal or space vector modulation to set the voltage to the motor armature which will generate the magnetic field that is 90 degrees ahead the motor electrical angle.

Well, that make sense.Im just wonder about this

Hi Antun,

“Yes. Its using the sinusoidal or space vector modulation to set the voltage to the motor armature which will generate the magnetic field that is 90 degrees ahead the motor electrical angle.”

Is this to do with having maximum torque output for a given current? i.e. “The maximum torque is produced when the magnetic vector of the rotor is at 90 degrees to the magnetic vector of the stator.”

Best,
Nat

Thanks @David_Gonzalez and @Antun_Skuric for the suggestions, will have a look at this asap. Glad to hear that you’ve got low-resistance motors working, so it’s definitely possible. Will let you know how I go.

Yes, thats exactly how FOC work.

@hbozyq - Glad we are on the same page :slight_smile:

@Antun_Skuric
In order to find the zero-electrical angle, in my previous attempts at motor controllers, I had a bit of code that set Id to some non-zero value, and then searched around for a motor position which would lead to “close to” zero Iq - the encoder value/angle would then be recorded as the angle offset. Confirming the same goal achieved with the “electrical zero angle” code?

Exaclty the same thing!

When the motor does not move there is no back emf. And the current q is exactly proportional to the voltage q and the current d is proportional to the volatge d.
The approach of the library at this point is to use voltages.

So what we do basically is setting the voltage in certain the in the negative d direction (equivalent to -90 degrees - voltage_q = 0, voltage_d = -voltage_sensor_align) and the motor will align itself. But during the alignment we do not do foc, because we do not know what the motor electrical angle is. So we just apply the some negative d voltage statically and let the motor settle. One when it is settled we know that is its zero electrical angle.

Let me know if you still find it confusing. You guys have dived really deeply in the library and if you find these things not clear there are probably much more people who have the same questions. I’ll try to write a bit better explanation after the release today/tomorrow. :smiley:

1 Like

One thing to mention is possibly that the motor needs to be relatively lightly loaded or unloaded when doing the alignment.
I had the case recently that the 0-angle wasn’t found correctly because the motor was quite heavily loaded and the alignment code didn’t move it quite far enough.
I guess in such situations the sensor align has to be performed in advance, while unloaded, and stored for later reuse.