simplefoc / Arduino-FOC

Arduino FOC for BLDC and Stepper motors - Arduino Based Field Oriented Control Algorithm Library
https://docs.simplefoc.com
MIT License
2.1k stars 538 forks source link

Motor stops due to direction change - voltages NaN #192

Closed runger1101001 closed 2 years ago

runger1101001 commented 2 years ago

This is a simplified template, feel free to change it if it does not fit your case.

Describe the bug The motor stops sometimes when it changes direction. The calculated voltages are NaN - causing this behaviour. See: https://community.simplefoc.com/t/inrush-current-problem-with-our-bldc-driver-board/2052/25

Describe the hardware setup For us it is very important to know what is the hardware setup you're using in order to be able to help more directly

IDE you are using

Tried the Getting started guide? - if applicable See forum post - we've been trying to get the motor driver running, and have run into this problem.

askuric commented 2 years ago

Could this be realted to this issue #177 ?

runger1101001 commented 2 years ago

Doesn't seem so - it's STM32 rather than ESP32, and Adharsh doesn't have the phase resistance set. An interesting difference in his setup is that he has pre-aligned the sensor to the motor, and so he initialises initFOC() with a value of 0.0f - that's probably a fairly unique feature of his setup. But otherwise he's just doing velocity control, no current limiting.

markovica commented 2 years ago

I did some debugging, and void BLDCMotor::setPhaseVoltage(float Uq, float Ud, float angle_el) is being fed NaN for Uq, which seems to be coming from the PID of loopFoc. Normalized angle was reading correct values, even when the motor was stalled.

kadharsh commented 2 years ago

Yes @markovica, the value Uq is being fed NaN, I did some testing and my findings are updated in the forum thread. https://community.simplefoc.com/t/inrush-current-problem-with-our-bldc-driver-board/2052/38?u=adharsh_k

The problem is coming from Sensor::getVelocity() returning INF one time while running and this screws up all other functions which rely on this value. And in the end the Uq is fed NaN and the motor stops. The function getVelocity() continues to work.

sens_vel: -3.26 lpf_velo: -3.26 retVal: -3.15 sens_vel: -3.26 lpf_velo: -3.26 retVal: -3.19 sens_vel: 0.00 lpf_velo: 0.00 retVal: -2.00 sens_vel: -3.09 lpf_velo: -3.09 retVal: -2.40 sens_vel: inf lpf_velo: inf retVal: inf <- This is where the problem happens ie: Sensor::getVelocity() returning INF sens_vel: 0.00 lpf_velo: nan retVal: inf sens_vel: 0.00 lpf_velo: nan retVal: inf sens_vel: 0.00 lpf_velo: nan retVal: inf sens_vel: 0.00 lpf_velo: nan retVal: inf

where sens_vel is the value returned by Sensor::getVelocity() lpf_velo is the value after low pass filter, retVal is the value returned by the function FOCMotor::shaftVelocity()

kadharsh commented 2 years ago

For a quick fix you can modify the function FOCMotor::shaftVelocity() like this:

float FOCMotor::shaftVelocity() {
  // if no sensor linked return previous value ( for open loop )
  if(!sensor) return shaft_velocity;

  float vel = sensor->getVelocity();
  if(vel < -1000 || vel > 1000)    vel = 0;   //if velocity is out of range then make it zero
  return sensor_direction*LPF_velocity(vel);
}
markovica commented 2 years ago

Thank you @kadharsh

I moved your fix to HallSensor::getVelocity() as it makes more sense to me since this seems to be a hall sensor issue and it seems it's working perfectly.

float HallSensor::getVelocity(){
  if (pulse_diff == 0 || ((long)(_micros() - pulse_timestamp) > pulse_diff) ) { // last velocity isn't accurate if too old
    return 0;
  } else {
    // quick fix https://github.com/simplefoc/Arduino-FOC/issues/192
    float vel = direction * (_2PI / (float)cpr) / (pulse_diff / 1000000.0f);
    if(vel < -1000 || vel > 1000)    vel = 0;   //if velocity is out of range then make it zero
    //return direction * (_2PI / (float)cpr) / (pulse_diff / 1000000.0f);
    return vel;
  }
kadharsh commented 2 years ago

as it makes more sense to me since this seems to be a hall sensor issue and it seems it's working perfectly.

Yes, you are right, I just put it there just in case.

Khanmmk commented 2 years ago

That's nice work and you guys are able to solve the issue, but I was looking at the source code, and over there vel is not declared. Kindly you can highlight where you declared the vel value. Thanks

kadharsh commented 2 years ago

That's nice work and you guys are able to solve the issue, but I was looking at the source code, and over there vel is not declared. Kindly you can highlight where you declared the vel value. Thanks The actual HallSensor::getVelocity() code in src/sensors/HallSensor.cpp is


float HallSensor::getVelocity(){
if (pulse_diff == 0 || ((long)(_micros() - pulse_timestamp) > pulse_diff) ) { // last velocity isn't accurate if too old
return 0;
} else {
return direction * (_2PI / (float)cpr) / (pulse_diff / 1000000.0f);
}

}


just replace it with this:

> Thank you @kadharsh
> 
> I moved your fix to HallSensor::getVelocity() as it makes more sense to me since this seems to be a hall sensor issue and it seems it's working perfectly.
> 
> ```
> float HallSensor::getVelocity(){
>   if (pulse_diff == 0 || ((long)(_micros() - pulse_timestamp) > pulse_diff) ) { // last velocity isn't accurate if too old
>     return 0;
>   } else {
>     // quick fix https://github.com/simplefoc/Arduino-FOC/issues/192
>     float vel = direction * (_2PI / (float)cpr) / (pulse_diff / 1000000.0f);
>     if(vel < -1000 || vel > 1000)    vel = 0;   //if velocity is out of range then make it zero
>     //return direction * (_2PI / (float)cpr) / (pulse_diff / 1000000.0f);
>     return vel;
>   }
> ```

And it should work! 

Happy hacking : )