SimpleFOC v2 - understanding 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.

@David_Gonzalez @Antun_Skuric

Thanks both of you! Lowering the PID and ramp values did the trick. I now have a reasonably behaved motor controlled with the current sense based FOC.

1 Like

@ngalin, I’m glad you got it working! Can you share with us your final values?

Hi @David_Gonzalez,

Yup, absolutely. I’ve included here a table of various control loop variables to get sensible (but not perfect) operation of the ODrive motor in the following control configuration:

motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
motor.controller = MotionControlType::velocity;
motor.torque_controller = TorqueControlType::foc_current;

The test harness I have setup cycles the target velocity of the motor from: 0 --> 6 --> 0 (rad/s) every 4 seconds. It’s not perfect, as there are still times when various control loops saturate, but it’s nothing compared to the jerky/non-rotating behavior I was getting before:

Parameter Value
voltage limit 4
current limit 2
velocity limit 20
PID_current_q:
P 0.5
I 0.1
D 0
output_ramp 50
limit 1
PID_current_d:
P 1
I 0.5
D 0.01
output_ramp 100
limit 2
PID_velocity:
P 1
I 0.2
D 0.05
output_ramp 1000
limit 500
LPF_current_q 0.1
LPF_current_d 0
LPF_velocity 1
2 Likes

Can you explain this more? If the rotor permanant magnets are exactly opposite of the virtual magnets, wouldn’t that be 180 degrees out of phase?

Hi @schwghrt , welcome to SimpleFOC!

The 90deg referred to here is 90deg of electrical angle. It’s not the same as the physical angle.

A BLDC motor will have N electrical rotations per full physical turn of the motor, where N is equal to the number of pole pairs of the motor.
When driving the motor with FOC, you keep the force applied by the coils at 90deg electrical to the motors current position. This maximizes torque for the energy put in.

When aligning the motor, we set the coils to -90deg electrical and the motor “snaps to” the closest zero position.

You can read more about it in our documentation, in the “theory corner” section on FOC…

“When aligning the motor, we set the coils to -90deg electrical and the motor “snaps to” the closest zero position.”

Ah, of course. Thank you.

@runger, or anyone else, please check me on this…

We want to put the rotor’s electrical angle to zero. Essentially, we want the rotor’s magnetic field to point in the I_alpha (and the I_a) direction (U_beta = 0, U_alpha > 0). I am assuming this is the 0 degree direction.

We want the stator/coil electrical angle to be 180 degrees out of phase. This way the rotor will ‘snap’ to the right direction. (N to S, and S to N). So, we want the coil’s electric field to point in the (-) I_alpha direction (U_beta = 0, and U_alpha < 0).

Using the Inverse Park transform, we need to choose Uq, Ud and the electrical angle (e_angle) to accomplish this. The code sets Ud to zero, and Uq to an arbitrary positive value.

From the park transform:
U_alpha = -Sin(e_angle) Uq + Cos(e_angle) Ud
U_beta = Cos(e_angle) Uq + Sin(e_angle) Ud

Since Ud = 0, that simplifies to:
U_alpha = -Sin(e_angle) Uq
U_beta = Cos(e_angle) Uq

We want U_beta = 0, so e_angle must be PI/2 or 3PI/2.
And for U_alpha to be negative, e_angle must be PI/2.

But the code sets Uq > 0, and the angle to 3PI/2. Essentially, aligning the stator(coil) electrical field to zero degrees instead of the rotor (motor’s) electrical field to zero.

Is that the convention? It seems backwards to me.