[应用相关] 调试ST电机库5.20遇到的问题

[复制链接]
 楼主| 发给她更好fh 发表于 2021-11-29 10:17 | 显示全部楼层 |阅读模式
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读到的霍尔状态
4866461a4381ecfee6.png

 楼主| 发给她更好fh 发表于 2021-11-29 10:18 | 显示全部楼层
用示波器测到到霍尔波形

3496761a4385d77bda.png

阅读ST电机库中hall_speed_pos_fdbk.c源码中的void * HALL_TIMx_CC_IRQHandler( void * pHandleVoid )函数。
 楼主| 发给她更好fh 发表于 2021-11-29 10:19 | 显示全部楼层
  1. void * HALL_TIMx_CC_IRQHandler( void * pHandleVoid )
  2. {
  3.   HALL_Handle_t * pHandle = ( HALL_Handle_t * ) pHandleVoid;
  4.   TIM_TypeDef * TIMx = pHandle->TIMx;
  5.   uint8_t bPrevHallState;
  6.   uint32_t wCaptBuf;
  7.   uint16_t hPrscBuf;
  8.   uint16_t hHighSpeedCapture;

  9.   if ( pHandle->SensorIsReliable )
  10.   {
  11.     /* A capture event generated this interrupt */
  12.     bPrevHallState = pHandle->HallState;

  13.     if ( pHandle->SensorPlacement == DEGREES_120 )
  14.     {
  15.       pHandle->HallState  = LL_GPIO_IsInputPinSet( pHandle->H3Port, pHandle->H3Pin ) << 2
  16.                             | LL_GPIO_IsInputPinSet( pHandle->H2Port, pHandle->H2Pin ) << 1
  17.                             | LL_GPIO_IsInputPinSet( pHandle->H1Port, pHandle->H1Pin );
  18.     }
  19.     else
  20.     {
  21.       pHandle->HallState  = ( LL_GPIO_IsInputPinSet( pHandle->H2Port, pHandle->H2Pin ) ^ 1 ) << 2
  22.                             | LL_GPIO_IsInputPinSet( pHandle->H3Port, pHandle->H3Pin ) << 1
  23.                             | LL_GPIO_IsInputPinSet( pHandle->H1Port, pHandle->H1Pin );
  24.     }

  25.     switch ( pHandle->HallState )
  26.     {
  27.       case STATE_5:
  28.         if ( bPrevHallState == STATE_4 )
  29.         {
  30.           pHandle->Direction = POSITIVE;
  31.           pHandle->MeasuredElAngle = pHandle->PhaseShift;
  32.         }
  33.         else if ( bPrevHallState == STATE_1 )
  34.         {
  35.           pHandle->Direction = NEGATIVE;
  36.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_60_PHASE_SHIFT );
  37.         }
  38.         else
  39.         {
  40.         }
  41.         break;

  42.       case STATE_1:
  43.         if ( bPrevHallState == STATE_5 )
  44.         {
  45.           pHandle->Direction = POSITIVE;
  46.           pHandle->MeasuredElAngle = pHandle->PhaseShift + S16_60_PHASE_SHIFT;
  47.         }
  48.         else if ( bPrevHallState == STATE_3 )
  49.         {
  50.           pHandle->Direction = NEGATIVE;
  51.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT );
  52.         }
  53.         else
  54.         {
  55.         }
  56.         break;

  57.       case STATE_3:
  58.         if ( bPrevHallState == STATE_1 )
  59.         {
  60.           pHandle->Direction = POSITIVE;
  61.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT );
  62.         }
  63.         else if ( bPrevHallState == STATE_2 )
  64.         {
  65.           pHandle->Direction = NEGATIVE;
  66.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT +
  67.                                                   S16_60_PHASE_SHIFT );
  68.         }
  69.         else
  70.         {
  71.         }

  72.         break;

  73.       case STATE_2:
  74.         if ( bPrevHallState == STATE_3 )
  75.         {
  76.           pHandle->Direction = POSITIVE;
  77.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift + S16_120_PHASE_SHIFT
  78.                                                   + S16_60_PHASE_SHIFT );
  79.         }
  80.         else if ( bPrevHallState == STATE_6 )
  81.         {
  82.           pHandle->Direction = NEGATIVE;
  83.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_120_PHASE_SHIFT );
  84.         }
  85.         else
  86.         {
  87.         }
  88.         break;

  89.       case STATE_6:
  90.         if ( bPrevHallState == STATE_2 )
  91.         {
  92.           pHandle->Direction = POSITIVE;
  93.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_120_PHASE_SHIFT );
  94.         }
  95.         else if ( bPrevHallState == STATE_4 )
  96.         {
  97.           pHandle->Direction = NEGATIVE;
  98.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_60_PHASE_SHIFT );
  99.         }
  100.         else
  101.         {
  102.         }
  103.         break;

  104.       case STATE_4:
  105.         if ( bPrevHallState == STATE_6 )
  106.         {
  107.           pHandle->Direction = POSITIVE;
  108.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift - S16_60_PHASE_SHIFT );
  109.         }
  110.         else if ( bPrevHallState == STATE_5 )
  111.         {
  112.           pHandle->Direction = NEGATIVE;
  113.           pHandle->MeasuredElAngle = ( int16_t )( pHandle->PhaseShift );
  114.         }
  115.         else
  116.         {
  117.         }
  118.         break;

  119.       default:
  120.         /* Bad hall sensor configutarion so update the speed reliability */
  121.         //pHandle->SensorIsReliable = false;

  122.         break;
  123.     }


  124. #ifdef HALL_MTPA
  125.     {
  126.       pHandle->_Super.hElAngle = pHandle->MeasuredElAngle;
  127.     }
  128. #endif

  129.     /* Discard first capture */
  130.     if ( pHandle->FirstCapt == 0u )
  131.     {
  132.       pHandle->FirstCapt++;
  133.       LL_TIM_IC_GetCaptureCH1( TIMx );
  134.     }
  135.     else
  136.     {
  137.       /* used to validate the average speed measurement */
  138.       if ( pHandle->BufferFilled < pHandle->SpeedBufferSize )
  139.       {
  140.         pHandle->BufferFilled++;
  141.       }

  142.       /* Store the latest speed acquisition */
  143.       hHighSpeedCapture = LL_TIM_IC_GetCaptureCH1( TIMx );
  144.       wCaptBuf = ( uint32_t )hHighSpeedCapture;
  145.       hPrscBuf =  LL_TIM_GetPrescaler ( TIMx );

  146.       /* Add the numbers of overflow to the counter */
  147.       wCaptBuf += ( uint32_t )pHandle->OVFCounter * 0x10000uL;

  148.       if ( pHandle->OVFCounter != 0u )
  149.       {
  150.         /* Adjust the capture using prescaler */
  151.         uint16_t hAux;
  152.         hAux = hPrscBuf + 1u;
  153.         wCaptBuf *= hAux;

  154.         if ( pHandle->RatioInc )
  155.         {
  156.           pHandle->RatioInc = false;  /* Previous capture caused overflow */
  157.           /* Don't change prescaler (delay due to preload/update mechanism) */
  158.         }
  159.         else
  160.         {
  161.           if ( LL_TIM_GetPrescaler ( TIMx ) < pHandle->HALLMaxRatio ) /* Avoid OVF w/ very low freq */
  162.           {
  163.             LL_TIM_SetPrescaler ( TIMx, LL_TIM_GetPrescaler ( TIMx ) + 1 ); /* To avoid OVF during speed decrease */
  164.             pHandle->RatioInc = true;   /* new prsc value updated at next capture only */
  165.           }
  166.         }
  167.       }
  168.       else
  169.       {
  170.         /* If prsc preload reduced in last capture, store current register + 1 */
  171.         if ( pHandle->RatioDec ) /* and don't decrease it again */
  172.         {
  173.           /* Adjust the capture using prescaler */
  174.           uint16_t hAux;
  175.           hAux = hPrscBuf + 2u;
  176.           wCaptBuf *= hAux;

  177.           pHandle->RatioDec = false;
  178.         }
  179.         else  /* If prescaler was not modified on previous capture */
  180.         {
  181.           /* Adjust the capture using prescaler */
  182.           uint16_t hAux = hPrscBuf + 1u;
  183.           wCaptBuf *= hAux;

  184.           if ( hHighSpeedCapture < LOW_RES_THRESHOLD ) /* If capture range correct */
  185.           {
  186.             if ( LL_TIM_GetPrescaler ( TIMx ) > 0u ) /* or prescaler cannot be further reduced */
  187.             {
  188.               LL_TIM_SetPrescaler ( TIMx, LL_TIM_GetPrescaler ( TIMx ) - 1 ); /* Increase accuracy by decreasing prsc */
  189.               /* Avoid decrementing again in next capt.(register preload delay) */
  190.               pHandle->RatioDec = true;
  191.             }
  192.           }
  193.         }
  194.       }

  195. #if 0
  196.       /* Store into the buffer */
  197.       /* Null Speed is detected, erase the buffer */
  198.       if ( wCaptBuf > pHandle->MaxPeriod )
  199.       {
  200.         uint8_t bIndex;
  201.         for ( bIndex = 0u; bIndex < pHandle->SpeedBufferSize; bIndex++ )
  202.         {
  203.           pHandle->SensorSpeed[bIndex]  = 0;
  204.         }
  205.         pHandle->BufferFilled = 0 ;
  206.         pHandle->SpeedFIFOSetIdx = 1;
  207.         pHandle->SpeedFIFOGetIdx = 0;
  208.         /* Indicate new speed acquisitions */
  209.         pHandle->NewSpeedAcquisition = 1;
  210.         pHandle->ElSpeedSum = 0;
  211.       }
  212.       /* Filtering to fast speed... could be a glitch  ? */
  213.       /* the HALL_MAX_PSEUDO_SPEED is temporary in the buffer, and never included in average computation*/
  214.       else
  215. #endif
  216.         if ( wCaptBuf < pHandle->MinPeriod )
  217.         {
  218.           pHandle->CurrentSpeed = HALL_MAX_PSEUDO_SPEED;
  219.           pHandle->NewSpeedAcquisition = 0;
  220.         }
  221.         else
  222.         {
  223.           pHandle->ElSpeedSum -= pHandle->SensorSpeed[pHandle->SpeedFIFOIdx]; /* value we gonna removed from the accumulator */
  224.           if ( wCaptBuf >= pHandle->MaxPeriod )
  225.           {
  226.             pHandle->SensorSpeed[pHandle->SpeedFIFOIdx]  = 0;
  227.           }
  228.           else
  229.           {
  230.             pHandle->SensorSpeed[pHandle->SpeedFIFOIdx] = ( int16_t ) ( pHandle->PseudoFreqConv / wCaptBuf );
  231.             pHandle->SensorSpeed[pHandle->SpeedFIFOIdx] *= pHandle->Direction;
  232.             pHandle->ElSpeedSum += pHandle->SensorSpeed[pHandle->SpeedFIFOIdx];
  233.           }
  234.           /* Update pointers to speed buffer */
  235.           pHandle->CurrentSpeed = pHandle->SensorSpeed[pHandle->SpeedFIFOIdx];
  236.           pHandle->SpeedFIFOIdx++;
  237.           if ( pHandle->SpeedFIFOIdx == pHandle->SpeedBufferSize )
  238.           {
  239.             pHandle->SpeedFIFOIdx = 0u;
  240.           }
  241.           /* Indicate new speed acquisitions */
  242.           pHandle->NewSpeedAcquisition = 1;
  243.         }
  244.       /* Reset the number of overflow occurred */
  245.       pHandle->OVFCounter = 0u;
  246.     }
  247.   }
  248.   return MC_NULL;
  249. }
 楼主| 发给她更好fh 发表于 2021-11-29 10:20 | 显示全部楼层
其中pHandle->HallState是通过读取三个霍尔传感器的引脚电平得到的。当出现0或7时,程序设置传感器不可靠pHandle->SensorIsReliable = false;,并将速度设成0,不再进行速度读取。当我把这行注释掉,电机可以运行,不会再停下来。但是会出现异音的情况。我猜是因为霍尔的位置检测有错误时,电角度的位置和方向信息都不会更新,而这些信息在后面的FOC控制中会用到,所以导致转子转动不连贯,出现了震动。
 楼主| 发给她更好fh 发表于 2021-11-29 10:21 | 显示全部楼层
2.B-Emf constant这三个参数只有在使用观测器时才会用到。RS、LS在计算电流环KP KI时用到了。

3859061a4391e286c9.png
 楼主| 发给她更好fh 发表于 2021-11-29 10:25 | 显示全部楼层
 楼主| 发给她更好fh 发表于 2021-11-29 10:25 | 显示全部楼层
上图中的wc为带宽系数

在使用霍尔控制,没有用观测器时,ST电机库生成的代码只有parameters_conversion.h中的下面这段代码使用了这三个参数。
 楼主| 发给她更好fh 发表于 2021-11-29 10:27 | 显示全部楼层
  1. /************************* OBSERVER + PLL PARAMETERS **************************/
  2. #define MAX_BEMF_VOLTAGE  (uint16_t)((MAX_APPLICATION_SPEED * 1.2 *\
  3.                            MOTOR_VOLTAGE_CONSTANT*SQRT_2)/(1000u*SQRT_3))

  4. /*max phase voltage, 0-peak Volts*/
  5. #define MAX_VOLTAGE (int16_t)((MCU_SUPPLY_VOLTAGE/2)/BUS_ADC_CONV_RATIO)

  6. #define MAX_CURRENT (MCU_SUPPLY_VOLTAGE/(2*RSHUNT*AMPLIFICATION_GAIN))

  7. #define C1 (int32_t)((((int16_t)F1)*RS)/(LS*TF_REGULATION_RATE))
  8. #define C2 (int32_t) GAIN1
  9. #define C3 (int32_t)((((int16_t)F1)*MAX_BEMF_VOLTAGE)/(LS*MAX_CURRENT*TF_REGULATION_RATE))
  10. #define C4 (int32_t) GAIN2
  11. #define C5 (int32_t)((((int16_t)F1)*MAX_VOLTAGE)/(LS*MAX_CURRENT*TF_REGULATION_RATE))

  12. #define PERCENTAGE_FACTOR    (uint16_t)(VARIANCE_THRESHOLD*128u)      
  13. #define OBS_MINIMUM_SPEED        (uint16_t) (OBS_MINIMUM_SPEED_RPM/6u)
  14. #define HFI_MINIMUM_SPEED        (uint16_t) (HFI_MINIMUM_SPEED_RPM/6u)

  15. /*********************** OBSERVER + CORDIC PARAMETERS *************************/
  16. #define CORD_C1 (int32_t)((((int16_t)CORD_F1)*RS)/(LS*TF_REGULATION_RATE))
  17. #define CORD_C2 (int32_t) CORD_GAIN1
  18. #define CORD_C3 (int32_t)((((int16_t)CORD_F1)*MAX_BEMF_VOLTAGE)/(LS*MAX_CURRENT\
  19.                                                            *TF_REGULATION_RATE))
  20. #define CORD_C4 (int32_t) CORD_GAIN2
  21. #define CORD_C5 (int32_t)((((int16_t)CORD_F1)*MAX_VOLTAGE)/(LS*MAX_CURRENT*\
  22.                                                           TF_REGULATION_RATE))
  23. #define CORD_PERCENTAGE_FACTOR    (uint16_t)(CORD_VARIANCE_THRESHOLD*128u)      
  24. #define CORD_MINIMUM_SPEED        (uint16_t) (CORD_MINIMUM_SPEED_RPM/6u)
 楼主| 发给她更好fh 发表于 2021-11-29 10:28 | 显示全部楼层
3.仅使用编码器作为位置反馈时,效果比仅使用霍尔的时候要好。测得的速度也要稳定。如果启动电机,电机不转并且电流一直上升,可能是因为编码器AB相的接线反了。另外启动电机前需要进行Encoder Align 操作。
 楼主| 发给她更好fh 发表于 2021-11-29 10:29 | 显示全部楼层
4.仅使用编码器作为位置反馈时,我发现测得的速度变化时都是以6的倍数来变化的。并且当速度过小,电机可能转不起来。另外当电机速度很小,力矩会比较小。力矩增大需要速度PI控制器的误差积分慢慢增加来提高输出力矩。
 楼主| 发给她更好fh 发表于 2021-11-29 10:30 | 显示全部楼层
5.我发现st电机库中采样a,b相电流后没有进行数字滤波就直接使用了。用DAC的debug功能在示波器上看到相电流的正弦波形上会有杂波。另外,当设定好Iq和Id参考值后,Iq和Id对应的PI控制器输出相应的Vq和Vd,经过反Park变换后送到SVPWM模块生成相应的PWM波形控制6个MOS管。
 楼主| 发给她更好fh 发表于 2021-11-29 10:31 | 显示全部楼层
 楼主| 发给她更好fh 发表于 2021-11-29 10:33 | 显示全部楼层
这个过程中测量得到的Iq和Id一直在参考线上波动。如下图:
2146461a43bd8c539b.png
 楼主| 发给她更好fh 发表于 2021-11-29 10:34 | 显示全部楼层
6.只使用编码盘作为速度反馈时,电机在低速时不能正常运行,有时会反转成最大速度。另外电机在100rpm这个转速运行时,会突然变速,有时会导致under voltage报警。

 楼主| 发给她更好fh 发表于 2021-11-29 10:34 | 显示全部楼层
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

563

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部