调试ST电机库5.20遇到的问题

2019-04-13 13:05发布

1.使用带霍尔的无刷电机运行ST MotorControl Workbench 5.2.0生成的例程。霍尔状态经常出现0或者7,是因为霍尔信号干扰太大了吗?正常的霍尔状态为1-6,一出现0或7电机就不能转了。Iq的目标值变成6067(为标称最大电流值,这个值是用标称电流3.8A转换的)。Iq的目标值是由于速度PI控制器输出的。当霍尔状态为0或7,程序将pHandle->SensorIsReliable = false; 认为此时速度传感器不可靠,将测到的速度值设成0了。由于0和设定的目标速度相差很大,同时电机不能转速度一直是0,速度PI控制器输出的Iq的目标值立马就超过了标称值6067. 下图为用STMStudio读到的霍尔状态 用示波器测到到霍尔波形 阅读ST电机库中hall_speed_pos_fdbk.c源码中的void * HALL_TIMx_CC_IRQHandler( void * pHandleVoid )函数。 void * HALL_TIMx_CC_IRQHandler( void * pHandleVoid ) { HALL_Handle_t * pHandle = ( HALL_Handle_t * ) pHandleVoid; TIM_TypeDef * TIMx = pHandle->TIMx; uint8_t bPrevHallState; uint32_t wCaptBuf; uint16_t hPrscBuf; uint16_t hHighSpeedCapture; if ( pHandle->SensorIsReliable ) { /* A capture event generated this interrupt */ bPrevHallState = pHandle->HallState; if ( pHandle->SensorPlacement == DEGREES_120 ) { pHandle->HallState = LL_GPIO_IsInputPinSet( pHandle->H3Port, pHandle->H3Pin ) << 2 | LL_GPIO_IsInputPinSet( pHandle->H2Port, pHandle->H2Pin ) << 1 | LL_GPIO_IsInputPinSet( pHandle->H1Port, pHandle->H1Pin ); } else { pHandle->HallState = ( LL_GPIO_IsInputPinSet( pHandle->H2Port, pHandle->H2Pin ) ^ 1 ) << 2 | LL_GPIO_IsInputPinSet( pHandle->H3Port, pHandle->H3Pin ) << 1 | LL_GPIO_IsInputPinSet( pHandle->H1Port, pHandle->H1Pin ); } switch ( pHandle->HallState ) { case STATE_5: if ( bPrevHallState == STATE_4 ) { pHandle->Direction = POSITIVE; pHandle->MeasuredElAngle = pHandle->PhaseShift; } else if ( bPrevHallState == STATE_1 ) { pHandle->Direction = NEGATIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_60_PHASE_SHIFT ); } else { } break; case STATE_1: if ( bPrevHallState == STATE_5 ) { pHandle->Direction = POSITIVE; pHandle->MeasuredElAngle = pHandle->PhaseShift + S16_60_PHASE_SHIFT; } else if ( bPrevHallState == STATE_3 ) { pHandle->Direction = NEGATIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT ); } else { } break; case STATE_3: if ( bPrevHallState == STATE_1 ) { pHandle->Direction = POSITIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT ); } else if ( bPrevHallState == STATE_2 ) { pHandle->Direction = NEGATIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT + S16_60_PHASE_SHIFT ); } else { } break; case STATE_2: if ( bPrevHallState == STATE_3 ) { pHandle->Direction = POSITIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT + S16_60_PHASE_SHIFT ); } else if ( bPrevHallState == STATE_6 ) { pHandle->Direction = NEGATIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_120_PHASE_SHIFT ); } else { } break; case STATE_6: if ( bPrevHallState == STATE_2 ) { pHandle->Direction = POSITIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_120_PHASE_SHIFT ); } else if ( bPrevHallState == STATE_4 ) { pHandle->Direction = NEGATIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_60_PHASE_SHIFT ); } else { } break; case STATE_4: if ( bPrevHallState == STATE_6 ) { pHandle->Direction = POSITIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_60_PHASE_SHIFT ); } else if ( bPrevHallState == STATE_5 ) { pHandle->Direction = NEGATIVE; pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift ); } else { } break; default: /* Bad hall sensor configutarion so update the speed reliability */ //pHandle->SensorIsReliable = false; break; } #ifdef HALL_MTPA { pHandle->_Super.hElAngle = pHandle->MeasuredElAngle; } #endif /* Discard first capture */ if ( pHandle->FirstCapt == 0u ) { pHandle->FirstCapt++; LL_TIM_IC_GetCaptureCH1( TIMx ); } else { /* used to validate the average speed measurement */ if ( pHandle->BufferFilled < pHandle->SpeedBufferSize ) { pHandle->BufferFilled++; } /* Store the latest speed acquisition */ hHighSpeedCapture = LL_TIM_IC_GetCaptureCH1( TIMx ); wCaptBuf = ( uint32_t )hHighSpeedCapture; hPrscBuf = LL_TIM_GetPrescaler ( TIMx ); /* Add the numbers of overflow to the counter */ wCaptBuf += ( uint32_t )pHandle->OVFCounter * 0x10000uL; if ( pHandle->OVFCounter != 0u ) { /* Adjust the capture using prescaler */ uint16_t hAux; hAux = hPrscBuf + 1u; wCaptBuf *= hAux; if ( pHandle->RatioInc ) { pHandle->RatioInc = false; /* Previous capture caused overflow */ /* Don't change prescaler (delay due to preload/update mechanism) */ } else { if ( LL_TIM_GetPrescaler ( TIMx ) < pHandle->HALLMaxRatio ) /* Avoid OVF w/ very low freq */ { LL_TIM_SetPrescaler ( TIMx, LL_TIM_GetPrescaler ( TIMx ) + 1 ); /* To avoid OVF during speed decrease */ pHandle->RatioInc = true; /* new prsc value updated at next capture only */ } } } else { /* If prsc preload reduced in last capture, store current register + 1 */ if ( pHandle->RatioDec ) /* and don't decrease it again */ { /* Adjust the capture using prescaler */ uint16_t hAux; hAux = hPrscBuf + 2u; wCaptBuf *= hAux; pHandle->RatioDec = false; } else /* If prescaler was not modified on previous capture */ { /* Adjust the capture using prescaler */ uint16_t hAux = hPrscBuf + 1u; wCaptBuf *= hAux; if ( hHighSpeedCapture < LOW_RES_THRESHOLD ) /* If capture range correct */ { if ( LL_TIM_GetPrescaler ( TIMx ) > 0u ) /* or prescaler cannot be further reduced */ { LL_TIM_SetPrescaler ( TIMx, LL_TIM_GetPrescaler ( TIMx ) - 1 ); /* Increase accuracy by decreasing prsc */ /* Avoid decrementing again in next capt.(register preload delay) */ pHandle->RatioDec = true; } } } } #if 0 /* Store into the buffer */ /* Null Speed is detected, erase the buffer */ if ( wCaptBuf > pHandle->MaxPeriod ) { uint8_t bIndex; for ( bIndex = 0u; bIndex < pHandle->SpeedBufferSize; bIndex++ ) { pHandle->SensorSpeed[bIndex] = 0; } pHandle->BufferFilled = 0 ; pHandle->SpeedFIFOSetIdx = 1; pHandle->SpeedFIFOGetIdx = 0; /* Indicate new speed acquisitions */ pHandle->NewSpeedAcquisition = 1; pHandle->ElSpeedSum = 0; } /* Filtering to fast speed... could be a glitch ? */ /* the HALL_MAX_PSEUDO_SPEED is temporary in the buffer, and never included in average computation*/ else #endif if ( wCaptBuf < pHandle->MinPeriod ) { pHandle->CurrentSpeed = HALL_MAX_PSEUDO_SPEED; pHandle->NewSpeedAcquisition = 0; } else { pHandle->ElSpeedSum -= pHandle->SensorSpeed[pHandle->SpeedFIFOIdx]; /* value we gonna removed from the accumulator */ if ( wCaptBuf >= pHandle->MaxPeriod ) { pHandle->SensorSpeed[pHandle->SpeedFIFOIdx] = 0; } else { pHandle->SensorSpeed[pHandle->SpeedFIFOIdx] = ( int16_t ) ( pHandle->PseudoFreqConv / wCaptBuf ); pHandle->SensorSpeed[pHandle->SpeedFIFOIdx] *= pHandle->Direction; pHandle->ElSpeedSum += pHandle->SensorSpeed[pHandle->SpeedFIFOIdx]; } /* Update pointers to speed buffer */ pHandle->CurrentSpeed = pHandle->SensorSpeed[pHandle->SpeedFIFOIdx]; pHandle->SpeedFIFOIdx++; if ( pHandle->SpeedFIFOIdx == pHandle->SpeedBufferSize ) { pHandle->SpeedFIFOIdx = 0u; } /* Indicate new speed acquisitions */ pHandle->NewSpeedAcquisition = 1; } /* Reset the number of overflow occurred */ pHandle->OVFCounter = 0u; } } return MC_NULL; }  其中pHandle->HallState是通过读取三个霍尔传感器的引脚电平得到的。当出现0或7时,程序设置传感器不可靠pHandle->SensorIsReliable = false;,并将速度设成0,不再进行速度读取。当我把这行注释掉,电机可以运行,不会再停下来。但是会出现异音的情况。我猜是因为霍尔的位置检测有错误时,电角度的位置和方向信息都不会更新,而这些信息在后面的FOC控制中会用到,所以导致转子转动不连贯,出现了震动。   2.B-Emf constant这三个参数只有在使用观测器时才会用到。RS、LS在计算电流环KP KI时用到了。 上图中的wc为带宽系数 在使用霍尔控制,没有用观测器时,ST电机库生成的代码只有parameters_conversion.h中的下面这段代码使用了这三个参数。 /************************* OBSERVER + PLL PARAMETERS **************************/ #define MAX_BEMF_VOLTAGE (uint16_t)((MAX_APPLICATION_SPEED * 1.2 * MOTOR_VOLTAGE_CONSTANT*SQRT_2)/(1000u*SQRT_3)) /*max phase voltage, 0-peak Volts*/ #define MAX_VOLTAGE (int16_t)((MCU_SUPPLY_VOLTAGE/2)/BUS_ADC_CONV_RATIO) #define MAX_CURRENT (MCU_SUPPLY_VOLTAGE/(2*RSHUNT*AMPLIFICATION_GAIN)) #define C1 (int32_t)((((int16_t)F1)*RS)/(LS*TF_REGULATION_RATE)) #define C2 (int32_t) GAIN1 #define C3 (int32_t)((((int16_t)F1)*MAX_BEMF_VOLTAGE)/(LS*MAX_CURRENT*TF_REGULATION_RATE)) #define C4 (int32_t) GAIN2 #define C5 (int32_t)((((int16_t)F1)*MAX_VOLTAGE)/(LS*MAX_CURRENT*TF_REGULATION_RATE)) #define PERCENTAGE_FACTOR (uint16_t)(VARIANCE_THRESHOLD*128u) #define OBS_MINIMUM_SPEED (uint16_t) (OBS_MINIMUM_SPEED_RPM/6u) #define HFI_MINIMUM_SPEED (uint16_t) (HFI_MINIMUM_SPEED_RPM/6u) /*********************** OBSERVER + CORDIC PARAMETERS *************************/ #define CORD_C1 (int32_t)((((int16_t)CORD_F1)*RS)/(LS*TF_REGULATION_RATE)) #define CORD_C2 (int32_t) CORD_GAIN1 #define CORD_C3 (int32_t)((((int16_t)CORD_F1)*MAX_BEMF_VOLTAGE)/(LS*MAX_CURRENT *TF_REGULATION_RATE)) #define CORD_C4 (int32_t) CORD_GAIN2 #define CORD_C5 (int32_t)((((int16_t)CORD_F1)*MAX_VOLTAGE)/(LS*MAX_CURRENT* TF_REGULATION_RATE)) #define CORD_PERCENTAGE_FACTOR (uint16_t)(CORD_VARIANCE_THRESHOLD*128u) #define CORD_MINIMUM_SPEED (uint16_t) (CORD_MINIMUM_SPEED_RPM/6u) 3.仅使用编码器作为位置反馈时,效果比仅使用霍尔的时候要好。测得的速度也要稳定。如果启动电机,电机不转并且电流一直上升,可能是因为编码器AB相的接线反了。另外启动电机前需要进行Encoder Align 操作。 4.仅使用编码器作为位置反馈时,我发现测得的速度变化时都是以6的倍数来变化的。并且当速度过小,电机可能转不起来。另外当电机速度很小,力矩会比较小。力矩增大需要速度PI控制器的误差积分慢慢增加来提高输出力矩。 5.我发现st电机库中采样a,b相电流后没有进行数字滤波就直接使用了。用DAC的debug功能在示波器上看到相电流的正弦波形上会有杂波。另外,当设定好Iq和Id参考值后,Iq和Id对应的PI控制器输出相应的Vq和Vd,经过反Park变换后送到SVPWM模块生成相应的PWM波形控制6个MOS管。 这个过程中测量得到的Iq和Id一直在参考线上波动。如下图:   6.只使用编码盘作为速度反馈时,电机在低速时不能正常运行,有时会反转成最大速度。另外电机在100rpm这个转速运行时,会突然变速,有时会导致under voltage报警。