Hey guys, poured some hours this weekend into fixing low-speed FOC braking in the unity firmware. This change can easily be applied to any VESC based design as well if/when I confirm it works well without introducing any unforeseen behaviors on different builds.
Let’s start with the TLDR. Would love it if some experienced people with builds that contain a focbox unity could download and test this FW update. Bonus points if your build experiences the low-speed braking issue. Should be safe I’ve ridden like 10-20 miles on my board with this FW rev but maybe take it slow to start. PLEASE ONLY DO THIS IF YOU ARE FAMILIAR WITH FW UPDATES FOR VESC BASED CONTROLLERS
DOWNLOAD LINK FOR FOCBOX UNITY TEST FW
Now for the details. For context this is a thread discussing the issue:
Maybe slightly wrong to start new topic but I need testers and want to make sure this wasn’t a post buried in a thread. I tried tons of different stuff and what ended up fixing the issue is the following snippet (this is how it is currently) :
// When the filtered duty cycle in sensorless mode becomes low in brake mode, the
// observer has lost tracking. Use duty cycle control with the lowest duty cycle
// to get as smooth braking as possible.
if (m_control_mode == CONTROL_MODE_CURRENT_BRAKE
&& fabsf(duty_filtered) < 0.03) {
control_duty = true;
duty_set = 0.0;
}
And changed it to:
if (m_control_mode == CONTROL_MODE_CURRENT_BRAKE
&& fabsf(duty_filtered)*GET_INPUT_VOLTAGE() < 0.5
&& (fmax( m_iq_set , 0.5/m_conf->foc_motor_r ) > (double) fabsf(m_motor_state.iq_filter))) {
control_duty = true;
duty_set = 0.0;
}
Essentially before, anytime your board dropped to 3% of the maximum voltage (AKA you were going 3% of max speed) while braking the motor controller would short all leads together. This is necessary because brakes should always oppose motion and at very low speed even a sensored motor only has a good sense of speed and not of its velocity. Thus the sign of the velocity might change rapidly and cause the motor to vibrate, so instead by shorting the leads of the motor we guarantee a viscous damping force. Problem is the 3% duty cycle means different things for different setups. Imagine a build running 12V and 0.1 ohm winding resistance for the sake of example. At 3% duty cycle shorting the motor leads induces a current of
0.03*12V/(2/3*0.1ohm) = 5.4 Amps
This is probably not going to result in much braking force. Now imagine a build running 50V and 20 mOhm winding resistance (probably a high kv motor 6374 or bigger)
0.03*50V/(2/3*0.02ohm) = 112 Amps
This is an extreme example but 112 amps is likely to throw lots of people from their boards. So the first change I made was to remove the dependence of source voltage on the switch-over to duty-cycle control. Instead of 3% duty cycle we instead switch over at 0.5V (duty cycle*source voltage). This is acceptable because the voltage resolution of ADC doesn’t change with different source voltages (fixed resistor voltage dividers for this measurement) so if 3% duty cycle works at 12V then that voltage should work for any source voltage. Here is the part of the if statement that handles that:
fabsf(duty_filtered)*GET_INPUT_VOLTAGE() < 0.5
The second change I made is a bit trickier, this is to fix the brakes “sticking” so to speak. Once you enter this low speed mode the duty is commanded to zero and you never stop shorting the motor leads until you either exceed the maximum motor amps or you release the brake fully. Mainly this is noticeable on steep downhills, hold in your brakes till you come to a complete stop then feather off most of the way but not all. You will realize your board is locked in with very strong braking force regardless of how you feather the throttle. This was a bit trickier to make an exit condition for. Essentially you don’t want to exit if either the current commanded motor amps are less than the induced amps OR if your current phase voltage would be too low to brake properly. Trouble is we have commanded the phase voltage to zero, so instead we have to figure out what the phase voltage would be if we weren’t shorting the leads. This can be done since we know the amps flowing and the winding resistance. Note that I compute it with a bit of added cushion to try and introduce a bit of hysteresis to prevent rapid mode switching or inaccuracies due to changing winding resistance. This is the part of the if statement that computes this:
fmax( m_iq_set , 0.5/m_conf->foc_motor_r ) > (double) fabsf(m_motor_state.iq_filter)