vedderb / bldc

The VESC motor control firmware
2.1k stars 1.32k forks source link

Motor phase calculation (with and without hal sensors) in FOC mode #139

Open blezalex opened 4 years ago

blezalex commented 4 years ago

I've been using VESC for a few years now, it works well, but it fails in a few cases:

  1. Very low speed operation
  2. Sudden changes in motor load

My motor has hall sensors, so I would assume those conditions should not be a problem, but they are. Motor seems to loose sync and looses torque suddenly for very short time (no faults)

There are a few functions that look wrong to me, maybe I'm reading them incorrectly, but hopefully you can explain and add comments for them.

pll_run

static void pll_run(float phase, float dt, volatile float *phase_var, volatile float *speed_var) {
...
    float delta_theta = phase - *phase_var;
...
       *phase_var += (*speed_var + m_conf->foc_pll_kp * delta_theta) * dt;
...
    *speed_var += m_conf->foc_pll_ki * delta_theta * dt;
}

My reading of it:

float distance = new_phase - current_phase;
current_phase  = current_phase + speed * dt + distance * dt * p

Why do you multiply distance by dt? now P effectively scales with switching frequency, and may become more than 1 if p > (1/dt), it is also very hard to get intuitive understanding of p when it is scaled this way.

Next: speed = speed + distance * dt * i

But distance * dt != speed. It looks like you were supposed to divide distance by time here.

hal sensors and phase tracking

Does m_motor_state.phase store current motor phase or it stores phase with some advance?

hal detection code loops 0-360, overrides current phase (open loop). If I understand that correctly, rotor is driven into that phase position and once it is there, motor produces NO torque. VESC records the center position for each hal sensor value, and that is exactly the position of ZERO torque! Am I missing something?

What is the purpose of timer_thread, openloop code when hal or encoder is used? If that is what gives phase some advance to get motor spinning, then it is not clear why that advance is not necessary beyond openloop speed.

blezalex commented 4 years ago

I also noticed that some motors have hal sensors installed pretty badly:

hal

As you can see, the angle between hal reading changes are far from theoretical 60 degrees.

I want to get precise speed tracking, at low speed, which seems to be impossible with current hal code. Hal sensor code collects center positions for each sensor, which hides the switching points and averages them, which makes speed calculation very imprecise.

I'm working on a change to improve low speed hal tracking, but I need you to tell me the meaning of m_motor_state.phase variable as well as how motor is supposed to produce torque when there is no advance in angle (zero torque position is remembered for each hal sensor value at calibration stage)

nitrousnrg commented 4 years ago

In case it helps, here's the m_motor_state.phase when vesc is running with hall sensors (yellow) In green you can see the observer angle

image

Sensored signal is jumpy, this is at steady speed, no load, I think it was 8kerpm IIRC.

vedderb commented 4 years ago

pll_run is a PI tracker of the phase (position), and the integrator will converge to the speed. In this line:

*speed_var += m_conf->foc_pll_ki * delta_theta * dt;

delta_theta is the error of the last phase estimate, which is driven to 0 with the foc_pll_ki gain. Thus, when speed_var is the true speed, delta_theta will be 0 when there is no acceleration. This is an effective way to get a speed estimate with low noise, but it has some phase lag (that can be controlled by adjusting the gains). I'm sure that it converges to the correct speed, because all other math based on this speed estimate works out. There is also m_speed_est_fast that is a simpler way to estimate the speed with lower latency, which is required for HFI, but it is much noisier.

The hall sensor detection is done in open loop, and yes there is no torque when the motor is aligned with the field, which means that there is a bit of slip if the motor is not rotating freely. How much slip the friction/load causes is impossible to know in open loop. Therefore the hall sensor detection is done with one electrical revolution forwards and one revolution backwards, and the average is taken. The "slip" should be roughly the same in both directions, which should take the error out. So far this has been working well for me.

As you can see on Marcos plot, the hall sensor estimator is pretty close to the observer, and the jump in it come from the fact that the hall sensors are not spaced exactly 60 degrees apart, which is an assumption the interpolator makes. It can probably be improved a bit by using the exact spacing, but for most motors this works good enough. The plot you show (not sure how you collected that data) with 30 to 84 degrees spacing seems like an extremely bad motor, and I have never seen something even close to this bad that isn't broken. For me the hall sensors are usually less than +- 5 degrees, which is quite fine.

  1. Very low speed operation
  2. Sudden changes in motor load

Sudden load changes should be handled perfectly, if the motor parameters are set correct and the current controllers are tuned to be fast enough. Very low speed operation (depending on how low) will always be a problem with hall sensors, even if they are perfectly spaced and/or perfectly calibrated. The reason is that there are no updates between the discrete 60 degree position updates, and if you spend a lot of time there it becomes a problem to control the motor smoothly as you are blind. If you are operating on too low speeds there is no other choice than using some sort of encoder with higher resolution than hall sensors provide.

blezalex commented 4 years ago

Thank you for explaining the logic of pll_run. What is the main advantage of using PI controller VS a low pass filter or something else? I believe current approach gives correct speed, due to the fact that dt is effectively a constant, but it has unexpected side effects when user is changing the switching frequency during tuning.

I have 3 flipsky BLDC Belt Motor 6354 190KV 2450W motors, all of them have hal sensors like that. Mitch Lustig (the author of balance app) has the same issue with his motors (same brand, different model, I also checked his with saleae logic analyzer)

The graph I posted is from saleae logic analyzer, capturing raw data directly from hal sensor pins. If you look at hal table, it does not look too far off, i think it comes from the fact that current code stores center position for each value, effectively shifting both boundaries to the mean:

hal positions

Sampled data looks way off spinning at 1000 ERPM

1000erpm

One more, from second motor

Capture

I clearly don't understand something in VESC code, please tell me what i'm missing

We agreed that if rotor physical position matches m_motor_state.phase, motor produces no torque. HAL table stores the position of no torque for each hal sensor value. (since that is what you get by running open loop and storing the values)

So let's say rotor is at angle 30, exactly in the middle of first hal position. Code looks at hal sensor, checks hal table and sees that the center is indeed 30 degrees. It sets m_motor_state.phase to 30, motor produces no torque. Why would motor spin? I guess some openloop code can accelerate the motor, but once openloop operation is done, why would motor accelerate any further?

If observer returns a true phase of the motor (no advance) and if setting m_motor_state.phase to true phase yields no torque, why does the motor spin?

ddosoff commented 4 years ago

You can try magnetic encoder. But my experiments shows that most important issue on low speeds is motor cogging. It is possible to compensate cogging, like odrive did. They measure cogging and build compensation table for each angle. But yep, you have to know exact angle.

blezalex commented 4 years ago

I can see how cogging can cause issues at very low speeds, but I don't think i'm running my motors in that speed range.

The picture I posted is from motor running at 1000 ERPM.

I need to understand vesc code to see if I can improve it. The biggest unknown is how torque is produced, and why motor accelerates past openloop operation given observer and hal sensor return true motor hub angle (described at the bottom of previous post)

Mitchlol commented 4 years ago

I wanted to share a video with my findings that match what alex is saying. Hopefully we can help him sort this out, because it would help balance users a lot.

https://photos.app.goo.gl/i2xfJkYSTtJ7VWrZ6

I also want to add 2 notes to my video that 1) The current and PID graphs don't show this dip 2) I changed no settings other than HFI to Hall Sensor between the two tests on the board thing, and if anything I rode more aggressively on the HFI test, because I knew it could handle it.

Sadly I cant seem to get HFI to work on the EUC, also the HFI issues I mentioned elsewhere, I now believe are just the can bus motor restarting its tracking when the direction changes at low speed, they don't show up here because i changed directions aggressively (but this is a topic for another thread, i plan to debug it more tho).

blezalex commented 4 years ago

ok. looks like m_motor_state.phase does take "true" rotor position.

But hal detection code is still confusing me.

Detection code sets angle in openloop 0-360. When m_phase_now_override is set to 0, rotor does not go to position 0, it goes to position 90 deg ahead of 0, since setting m_phase_now_override would generate a field rotated by 90 deg, rotor will escape that field.

(i kind of confirmed that by setting m_iq_set = -current, which makes rotor jump (likely by 180 degs)

Assuming i got that right, i don't see where hal detection code compensates for that 90 deg offset..

danilolattaro commented 3 years ago

Did this topic evolve? I believe it is somewhat related to this: https://vesc-project.com/node/2588

blezalex commented 3 years ago

There are some good improvements made to vesc code, helping fight the noise picked up on hal wires.

The link you sent may be describing, many things:

Aquaharmonics commented 10 months ago

I have been using VESC's since around 2015 and usually with small high speed motors, and only recently (last year or so) began experimenting more with large pole count, low speed hub motors. I was chasing some instability in the transition under load from sensored to sensorless when using halls (HW 6.0, FW 6.0) and found that at whichever time constant being used to calculate Kp or Ki on the current gains( default is 1000µs), the calculated Ki gain seems to have a large effect on the transition. By halving the Ki gain, the under-load transition behavior is dramatically improved (I have not double checked with capturing data of phase currents yet, but visibly/tactically improved). This seems to be similar to the solution in the post here that increasing the Kp gains helped. As a side note, using the IMU for feedback to control motor current without the right kind of filtering seems to make noise that limits the stability margins of the current controller, and lowering the calculated Ki gain at the selected time constant also helped in this case, to a point.

Aquaharmonics commented 10 months ago

Just wanted to post an update on this, if anyone else is still having problems. I found a resolution for my setup that I thought I would share. I am using a 100/250 from Trampa and a 3kW 32 pole hubmotor from QS motor . As mentioned before, I found some improvement by changing the integral gain by cutting it in half from what the default or modified time constant calculates. However, it seems very dependent on when the crossover ERPM is set for from sensored to sensorless. By moving this point further out the ERPM range (say, 4000 to 6000 ERPM ), it can help "soften" the transition, but it also can make the motor feel "growly" at higher ERPM using halls. Moving this point down the range( say 800 to 1200 ERPM) can minimize the transient, but this is also where the motor operates at highest phase current under load, so can also feel rough. Its not so bad if the operating range is not varying a lot, but if you are repeatedly going from maximum throttle/output to maximum braking, for instance, or if you hover operation around the transition point, it doesn't seem that great. There was some small effect by changing the current filter constant, lower seemed better. Some small improvement by increasing the number of extra hall signals, but I wouldn't say these were a fix. Additionally, there was a greater effect by cutting the Observer gain in half, but sometimes half would cause instability at full braking/regen, so something like 2/3 or 3/4 of the calculated Observer gain seemed to make improvement without having issues. All that being said, the thing that I found actually seemed to fix it entirely was going to SMALLER time constants for the gain calculations. Default is 1000us, and stepping incrementally from 1000, to 900, 800, 700, etc, all the way down to 200 us made huge improvements. Depending on use this may or may not make the drive/motor noisier, so there is a bit of finding the sweet spot for your application. If , for example, you are using an IMU for feedback, you might need to introduce Kalman filters as the default Low Pass filters seem to cause ringing that can become unstable using higher current gains, especially limiting use of a PID derivative term . Additionally, the smoothest operation/compromise was found by using something like 600us as the time constant for gain calculation, cutting the calculated Observer to 2/3, using otherwise default open loop settings for "Heavy Inertial Load" and also using FOC_OBSERVER_MXLEMMING_LAMBDA_COMP with a compensation of 10%, setting the open loop transition to 100ERPM, setting the hall interpolation ERPM to 1 (something lower than the transition anyways), and the Sensorless transition to around 2000 ERPM. Also, I started using 30kHz instead of initial 16kHz switching frequency with 10 extra hall samples, which means I have Sample in V0 and V7 disabled. With these settings the transition issues seem to be non-existent for my use.

Aquaharmonics commented 9 months ago

Just wanted to post another update on this topic. If you are running something like a hub motor using halls and having issues with a rough transition between sensored to sensorless, and also using phase filters, you might consider incrementally lower the values of the phase filter Maximum ERPM transition from the default 4000 ERPM, to say 3000 ERPM and testing, then 2000 ERPM... etc and see if there is an improvement. : image

From the description below, it makes a lot of sense that if we are operating in a region with phase filters causing too much delay/attenuation on the signal, the transition from sensored to sensorless will be rough :

image

From experiments running at low unloaded current, with the default time constant used for gain calculation of 1000uS and with the default ERPM setting of 4000, the motor would not get above the threshold ERPM of 4000: image

Lowering the threshold and retesting at the same current unloaded allowed the motor to continue to increase in ERPM: image

Another experiment to highlight earlier experiences is shown below with the current gains calculated using a time constant of only 300 uS and the same 4000 ERPM limit on phase filters with the same unloaded motor current:

image

From this, one can clearly see the discontinuity in transition around 4000 ERPM, and this is with no load on the motor at a low current. Of interest is that the higher current gains enabled the motor to climb in ERPM above the 4000 ERPM threshold wheras before it would not.

Lowering this threshold completely eliminated the rough transition for my application and allowed running much less aggressive current loop gains.