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?
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
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
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
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?
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.
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.
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
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.
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?
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.
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.