Unfortunately with this particular hardware, it’s not possible to select the best 2 phases as there are only 2 phases. But the only disadvantage is the lower possible voltage/duty cycle.
Slightly shifting the sampling could compensate for the switching delay and allow a little more time for sampling. This can be done by using CH4 for triggering the sampling, or adding a first dummy sample in the sequence. (e.g. on the hoverboard firmware the DC current was sampled first)
And if in the future more than one ADC would be used in parallel, it would make the sampling faster also.
But that’s a lot of work for maybe 2-3% higher duty cycle maybe.
Regarding this issue, I think when the driver is disabled, the pwm is not generated anymore, but adc is still running and sampling while the low side mosfet is off.
It could be those wrong values are then used for clarke-park-pids for a short time.
Maybe a delay after disabling or enabling would help.
Yes, but why should this suddenly generate a large negative differential voltage?
I have had another thought about the cause:
for low side sensing the ADC depends on an event/interrupt from the timer peripheral, which gets generated when it hits the overflow (which is the centre of the low-side on period). When the duty cycle is 0 or 100%, there is no centre, so maybe there is no event generated for the ADC. Then the ADC read doesn’t return a good value.
I started to experiment now.
After disabling and enabling the driver, I also get a current peak that triggers my PSU OCP, so I can reproduce the issue.
Even when the driver is disabled, the adc interrupt is triggered at the right time.
As the driver is disabled and I am moving the motor, you can see very high values are measured.
[EDIT] I tried disabling/enabling in voltage mode, no issue, so it’s really related to current sense and PIDs.
[EDIT2] Wait what I was doing was wrong, I was disabling the driver and not motor, so d/q currents were still updated in loopfoc.
But after disabling/enabling motor, I still have a peak.
The delay seems to help a bit.
could this be the explanation?so fro me it indeed looks like a pid problem,when enabling back on, the pwm output is still close to the output from before disabling (becasue of the integral term), but because your motor slowed down, that will be to high and you get a current peak. When adding delay it is less important because the integral term of the pid has more time to “catch back up”. so maybe some manual-automatic switching from the pid (with output tracking) should be implemented to the code, and then when disabling the motor you set pid output to track the value that would be equal to the motor bemf? Now when you enable back on, the pid output is equal to the motor bemf (and thus the integral term is directly close to where it should be) so basically freewheeling and no current peak, and after you got some ok values from the adc, you switch back to automatic mode.
The delay I added was to make sure the adc has time to sample proper values after the driver is enabled and before loopfoc is running thus using phase currents, but even with a 50ms delay there was a small peak which is surprising. If the adc sampling and foc were synchronous (interrupt), this wouldn’t be a problem.
Keep in mind I experienced those peaks when disabling/enabling the motor while the motor wasn’t even spinning.
This code used, motor stopped, in first ME0 in second ME1
void loop() {
current = currentSense.getPhaseCurrents();
current_magnitude = currentSense.getDCCurrent(); // https://docs.simplefoc.com/inline_current_sense#example-code
bool is_enabled = motor.enabled;
command.run();
if (motor.enabled && !is_enabled) { // if we have a change in enabled state, reset the PID
motor.PID_velocity.reset();
motor.PID_current_q.reset();
motor.PID_current_d.reset();
_delay(50);
}
if (!motor.enabled) { // in the disabled state, update the target to match the current velocity
motor.target = motor.shaft_velocity;
}
motor.move();
motor.loopFOC(); // loopFOC() after move, to make sure new targets are set
}
looking at your results, it is defenitely the pid that’s not right. when enabling back on the output is completely bad and thus a voltage spike happens wich results in a current spike. I think what we need to do is get the bemf of the motor, pass it trough park and clark, and update the integral terms of the pid’s to what we get(not simply resetting them to 0 like you did). when enabling, the integral terms will be close to what they should be and thus no voltage or current spike. for simplicity try to work in torque control for now so that there is only the current pid that is having effect
Ok, but I’ve tested almost all the modes to adjust the P.i.D., and apart from this problem,
I’ve never seen any overshoot, and frankly, the engine runs really smoothly…
Try adding timestamp_prev = _micros() in PIDController::reset (at the bottom of src/common/pid.cpp). It may be the Ts range sanity check on line 22 setting Ts = .001 together with the division on line 46 causing it to spike to the output ramp limit.
EDIT: Actually that might cause divide by zero and make it even worse… Seems like output_prev needs to be initialized to the measured value rather than 0.