This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RsOnline oscillating

Other Parts Discussed in Thread: DRV8301, MOTORWARE

Hello,

we have a problem with the rsonline feature. We are using a 28027F with DRV8301.

We got two different programs, one which has the RsOnline feature working and one which don't. Let me explain:

Application 1 (working RsOnline):

After application start the system is enabled with RsOfflineRecalc and OffsetRecalc enabled and Speed set to zero. After this "calibration" which is always done we are actively holding the motor at zero speed until an external speed reference is set. This allows for fast startups because the rotors are already aligned.

While accelerating and at steady speed the RsOnline feature is activated and runs as expected without problems. (In other cases it is deactivated, see code below)

Application 2 (RsOnline problem):

This application works the same as Application 1 with THE ONLY difference that we are not holding at zero speed because the motor should be moving freely without an external speed reference. This means that if the speed is zero (also after calibration) we are deactivating the control and reactivate it when a speedreference is set.

In this scenario as soon as we are activating RsOnline calculation the RsOnline value starts oscillating between 0 and 0.8 (roughly) and also the motor speed is not as accurate as it is in application 1. If we disable RsOnline calculation at least the speed accuracy improves.

What could cause this behaviour?

Here is our RsOnline implementation taken from the motorware manual pdf:

#ifdef USE_ACTIVEHOLD
   if((CTRL_getState(ctrlHandle) <= CTRL_State_OffLine) ||
      ((CTRL_getState(ctrlHandle) == CTRL_State_OnLine) &&
       (EST_getState(ctrlHandle->estHandle) == EST_State_Rs)))
   {/* rs online off, zero out values, causes:
     * external request,
     * do not inject while calibrating,
     * do not inject while estimating rs on startup
     */
      EST_setRsOnLine_qFmt(ctrlHandle->estHandle,
                                                     EST_getRs_qFmt(ctrlHandle->estHandle));
      EST_setRsOnLineId_mag_pu(ctrlHandle->estHandle, _IQ(0.0));
      EST_setRsOnLineId_pu(ctrlHandle->estHandle, _IQ(0.0));
      EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, false);
      EST_setFlag_updateRs(ctrlHandle->estHandle, false);
   }
   else
   {/* check if we want it to */
      if((!isRsOnlinePossible) || (!gMotorVars.Flag_CalibrationComplete))
      {/* external off */
         EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, false);
         EST_setFlag_updateRs(ctrlHandle->estHandle, false);
      }
      else
      {/* run it */
         _iq sf = _IQ(1.0 / USER_IQ_FULL_SCALE_CURRENT_A);
         _iq Rs_pu = EST_getRs_pu(ctrlHandle->estHandle);
         _iq RsOnLine_pu = EST_getRsOnLine_pu(ctrlHandle->estHandle);
         _iq Rs_error_pu = RsOnLine_pu - Rs_pu;
         EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, true);
         EST_setRsOnLineId_mag_pu(ctrlHandle->estHandle,
                                                                      _IQmpy(gMotorVars.RsOnLineCurrent_A, sf));
         /* Enable updates when Rs Online is only
         5% different from Rs Offline */
         if ((_IQabs(Rs_error_pu) < _IQmpy(Rs_pu, _IQ(0.05))) &&
             (isRsOnlineUpdatePossible))
            EST_setFlag_updateRs(ctrlHandle->estHandle, true);
         else
            EST_setFlag_updateRs(ctrlHandle->estHandle, false);
      }
   }
#endif

  • Patrick, let me look at this one some more tomorrow. I'm traveling today.

    In both applications the motor is the same? Same HW? Is SW very similar?

  • Hi Chris,

    I am just changing my define for ACTIVEHOLD which only affects these lines of code in the main loop:

    if (gMotorVars.Flag_CalibrationComplete)
    {/* calibration is complete, so turnoff recalcs */
       EST_setFlag_enableRsRecalc(ctrlHandle->estHandle, false);
       CTRL_setFlag_enableOffset(ctrlHandle, false);
       #ifdef USE_ACTIVEHOLD
          CTRL_setFlag_enableCtrl(ctrlHandle, true);
       #else
          if(gMotorVars.SpeedRef_krpm != _IQ(0.0))
             CTRL_setFlag_enableCtrl(ctrlHandle, true);
          else
             CTRL_setFlag_enableCtrl(ctrlHandle, false);
       #endif
    }

    other than that same software, same hardware, same compiler, just uncommenting/commenting the define.

  • I'm having trouble following the logic when I don't see where it's placed in the rest of the system code.

    all of the logic in your first post only runs if USER_ACTIVEHOLD is defined, right?

    it seems like if it is not defined you bypass all of that logic.
  • Hello Chris,

    sorry for the confusion. I tried to strip away all "company logic" so I can post the whole main here. It should be just a like a lab file plus the forced automatic calibration part.

    Just defining/undefining "USE_ACTIVEHOLD" causes RsOnline to work/oscillate.

    I am using motorware v15 without any modifications.

    /********************* P R I V A T E   F U N C T I O N S *********************/
    static void USERCTRL_RsOnlineCalculation(bool isRsOnlinePossible,
                                              bool isRsOnlineUpdatePossible)
    {/* handle rsOnline */
       if((CTRL_getState(ctrlHandle) <= CTRL_State_OffLine) ||
          ((CTRL_getState(ctrlHandle) == CTRL_State_OnLine) &&
           (EST_getState(ctrlHandle->estHandle) == EST_State_Rs)))
       {/* rs online off, zero out values, causes:
         * external request,
         * do not inject while calibrating,
         * do not inject while estimating rs on startup
         */
          EST_setRsOnLine_qFmt(ctrlHandle->estHandle,
                                         EST_getRs_qFmt(ctrlHandle->estHandle));
          EST_setRsOnLineId_mag_pu(ctrlHandle->estHandle, _IQ(0.0));
          EST_setRsOnLineId_pu(ctrlHandle->estHandle, _IQ(0.0));
          EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, false);
          EST_setFlag_updateRs(ctrlHandle->estHandle, false);
       }
       else
       {/* check if we want it to */
          if((!isRsOnlinePossible) || (!gMotorVars.Flag_CalibrationComplete))
          {/* external off */
             EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, false);
             EST_setFlag_updateRs(ctrlHandle->estHandle, false);
          }
          else
          {/* run it */
             _iq sf = _IQ(1.0 / USER_IQ_FULL_SCALE_CURRENT_A);
             _iq Rs_pu = EST_getRs_pu(ctrlHandle->estHandle);
             _iq RsOnLine_pu = EST_getRsOnLine_pu(ctrlHandle->estHandle);
             _iq Rs_error_pu = RsOnLine_pu - Rs_pu;
             EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, true);
             EST_setRsOnLineId_mag_pu(ctrlHandle->estHandle,
                                         _IQmpy(gMotorVars.RsOnLineCurrent_A, sf));
             /* Enable updates when Rs Online is only
             5% different from Rs Offline */
             if ((_IQabs(Rs_error_pu) < _IQmpy(Rs_pu, _IQ(0.05))) &&
                 (isRsOnlineUpdatePossible))
                EST_setFlag_updateRs(ctrlHandle->estHandle, true);
             else
                EST_setFlag_updateRs(ctrlHandle->estHandle, false);
          }
       }
    }
    static void USERCTRL_SetCtrlParameter(_iq KpId, _iq KiId, _iq KpSpd, _iq KiSpd,
                                  _iq Accel, _iq Speed)
    {/* set all control parameters (periodically) */
       CTRL_setKp(ctrlHandle, CTRL_Type_PID_spd, KpSpd);
       CTRL_setKi(ctrlHandle, CTRL_Type_PID_spd, KiSpd);
       CTRL_setKp(ctrlHandle, CTRL_Type_PID_Id, KpId);
       CTRL_setKi(ctrlHandle, CTRL_Type_PID_Id, KiId);
       CTRL_setKp(ctrlHandle, CTRL_Type_PID_Iq, KpId);
       CTRL_setKi(ctrlHandle, CTRL_Type_PID_Iq, KiId);
       CTRL_setMaxAccel_pu(ctrlHandle, _IQmpy(MAX_ACCEL_KRPMPS_SF, Accel));
       CTRL_setSpd_ref_krpm(ctrlHandle, Speed);
    }
    /********************** P U B L I C   F U N C T I O N S **********************/
    void main(void)
    {
       /* Only used if running from FLASH
        * Note that the variable FLASH is defined by the project
        * Copy time critical code and Flash setup code to RAM
        * The RamfuncsLoadStart, RamfuncsLoadEnd, and RamfuncsRunStart
        * symbols are created by the linker. Refer to the linker files.
        */
       memCopy((uint16_t*)&RamfuncsLoadStart,
             (uint16_t*)&RamfuncsLoadEnd,
             (uint16_t*)&RamfuncsRunStart);
       /* Init HAL and USER params */
       halHandle = HAL_init(&hal, sizeof(hal));
       USER_setParams(&gUserParams);
       HAL_setParams(halHandle, &gUserParams);
       /* Controller init */
       ctrlHandle = CTRL_initCtrl(0, &ctrl, sizeof(ctrl));
       /* HAL setup peripherals */
       HAL_setupFaults(halHandle);
       HAL_initIntVectorTable(halHandle);
       HAL_enableAdcInts(halHandle);
       HAL_enableGlobalInts(halHandle);
       HAL_enableDebugInt(halHandle);
       HAL_disablePwm(halHandle);
       HAL_enableDrv(halHandle);
       HAL_setupDrvSpi(halHandle, &gDrvSpi8301Vars);
       CTRL_setFlag_enableDcBusComp(ctrlHandle, true);
       /* set default controller parameters from user.h */
       CTRL_setParams(ctrlHandle, &gUserParams);
       /* set all flags and controller parameters for first start */
       CTRL_setFlag_enableUserMotorParams(ctrlHandle, true);
       USERCTRL_SetCtrlParameter(gMotorVars.Kp_Idq,
                                gMotorVars.Ki_Idq,
                                gMotorVars.Kp_spd,
                                gMotorVars.Ki_spd,
          ACCEL_RUN,
                                _IQ(0.0));
       USERCTRL_RsOnlineCalculation(false, false);
       CTRL_setFlag_enableSpeedCtrl(ctrlHandle, true);
       EST_setFlag_enableForceAngle(ctrlHandle->estHandle, true);
       for (;;)
       {
          if ((gMotorVars.CtrlState == CTRL_State_OnLine) &&
             (gMotorVars.EstState == EST_State_MotorIdentified))
          {/* check for calibration, if we are online and identified its over */
             gMotorVars.Flag_CalibrationComplete = true;
          }
          if (gMotorVars.Flag_CalibrationComplete)
          {/* calibration is complete, so turnoff recalcs */
             EST_setFlag_enableRsRecalc(ctrlHandle->estHandle, false);
             CTRL_setFlag_enableOffset(ctrlHandle, false);
    #ifdef USE_ACTIVEHOLD
             CTRL_setFlag_enableCtrl(ctrlHandle, true);
    #else
             if(gMotorVars.SpeedRef_krpm != _IQ(0.0))
              CTRL_setFlag_enableCtrl(ctrlHandle, true);
             else
              CTRL_setFlag_enableCtrl(ctrlHandle, false);
    #endif
          }
          else
          {/* force calibration */
             EST_setFlag_enableRsRecalc(ctrlHandle->estHandle, true);
             CTRL_setFlag_enableOffset(ctrlHandle, true);
             CTRL_setFlag_enableCtrl(ctrlHandle, true);
          }
          if (CTRL_updateState(ctrlHandle))
          {/* ctrl changed its state, react */
             CTRL_State_e ctrlState = CTRL_getState(ctrlHandle);
             if (ctrlState == CTRL_State_OffLine)
             {/* enable pwm */
              HAL_enablePwm(halHandle);
             }
             else if (ctrlState == CTRL_State_OnLine)
             {/* enable pwm and update adc bias values after recalculation */
                HAL_updateAdcBias(halHandle);
                HAL_enablePwm(halHandle);
             }
             else if (ctrlState == CTRL_State_Idle)
             {/* disable the pwm */
                HAL_disablePwm(halHandle);
             }
          }
          if (EST_isMotorIdentified(ctrlHandle->estHandle))
          {/* motor is identified so do something with it */
             /* set pre-estimated current ramp */
             EST_setMaxCurrentSlope_pu(ctrlHandle->estHandle,
                            gMotorVars.MaxCurrentSlope);
             /* this is a simplified version below, but the real logic 
                doesn't affect the outcome */
             USERCTRL_SetCtrlParameter(gMotorVars.Kp_Idq,
                                      gMotorVars.Ki_Idq,
                                      gMotorVars.Kp_spd,
                                      gMotorVars.Ki_spd,
                                      ACCELERATION_RUN,
                                      gMotorVars.SpeedTarget_krpm);
             USERCTRL_RsOnlineCalculation(true, false);
          }
          else
          {/* the estimator sets the maximum current slope during identification */
             gMotorVars.MaxCurrentSlope =
                         EST_getMaxCurrentSlope_pu(ctrlHandle->estHandle);
          }
          /* get calculated and estimated motor variables */
          gMotorVars.Rs_Ohm       = EST_getRs_Ohm(ctrlHandle->estHandle);
          gMotorVars.RsOnLine_Ohm = EST_getRsOnLine_Ohm(ctrlHandle->estHandle);
          gMotorVars.CtrlState    = CTRL_getState(ctrlHandle);
          gMotorVars.EstState     = EST_getState(ctrlHandle->estHandle);
          gMotorVars.Speed_krpm   = EST_getSpeed_krpm(ctrlHandle->estHandle);
          gMotorVars.Id_A         = _IQmpy(CTRL_getId_in_pu(ctrlHandle),
                                      _IQ(USER_IQ_FULL_SCALE_CURRENT_A));
          gMotorVars.Iq_A         = _IQmpy(CTRL_getIq_in_pu(ctrlHandle),
                                      _IQ(USER_IQ_FULL_SCALE_CURRENT_A));
          gMotorVars.VdcBus_kV    = _IQmpy(gMotorVars.AdcData.dcBus,
                                     _IQ(USER_IQ_FULL_SCALE_VOLTAGE_V / 1000.0));
          /* handle the drv8301 */
          HAL_writeDrvData(halHandle, &gDrvSpi8301Vars);
          HAL_readDrvData(halHandle, &gDrvSpi8301Vars);
       }
    }
    interrupt void mainISR(void)
    {/* main interrupt, called every adc shot (pwm cycle) */
       /* ack ISR */
       HAL_acqAdcInt(halHandle, ADC_IntNumber_1);
       /* convert ADC data */
       HAL_readAdcData(halHandle, (HAL_AdcData_t*)&gMotorVars.AdcData);
       /* run the controller */
       CTRL_run(ctrlHandle, halHandle,
                   (const HAL_AdcData_t*)&gMotorVars.AdcData,
                   (HAL_PwmData_t*)&gMotorVars.PwmData);
       /* write pwm */
       HAL_writePwmData(halHandle, (HAL_PwmData_t*)&gMotorVars.PwmData);
       /* and setup the controller */
       CTRL_setup(ctrlHandle);
    }
  • so if you define
    #define USE_ACTIVEHOLD

    then everything works correctly. You command zero speed. The motor pretty much holds near zero speed. And the RsOnline is updating correctly, and your logic to only set the Rs in the EST if RsOnline is within 5% of the current EST Rs value is functioning correctly?

    that that is controlled by:

    #ifdef USE_ACTIVEHOLD

    CTRL_setFlag_enableCtrl(ctrlHandle, true);

    However, when you don't define USE_ACTIVEHOLD the following logic is used:

    #else

    if(gMotorVars.SpeedRef_krpm != _IQ(0.0))

    CTRL_setFlag_enableCtrl(ctrlHandle, true);

    else

    CTRL_setFlag_enableCtrl(ctrlHandle, false);

    #endif


    and you test this by setting a zero speed at start-up, meaning the Ctrl should be disabled by this logic. During this time you still run
    USERCTRL_RsOnlineCalculation

    and the RsOnline value oscillates?
    Does the 5% logic insure that the bad values aren't passed through to the EST?

    Have you tried starting with a non-zero value? In this case it seems the logic should be identical to that with USE_ACTIVE_HOLD, so you should see no issues.



    My only thought is that disabling the Ctrl is a problem. Have you instead considered to keep running the Ctrl but just disable the PWM during this logic?

    #else
    if(gMotorVars.SpeedRef_krpm != _IQ(0.0))

    CTRL_setFlag_enableCtrl(ctrlHandle, true);
    HAL_enablePwm(halHandle);

    else

    HAL_disablePwm(halHandle);

    #endif
  • Hi Chris,

    thanks for your answer. Mostly you are correct about the behaviour.

    Your answer helped alot! Just disabling the PWM and keeping the Control alive and furthermore if RsOnline feature is disabled setting its value so it has a starting point (EST_setRsOnLine_pu(ctrlHandle->estHandle, EST_getRs_pu(ctrlHandle->estHandle));) did the trick for me. Now the RsOnline is only dropping on the first run below 0.2 and then regains the correct value and stops oscillating. Still a bit strange but this can be handled.

    Thanks!

  • Unfortunately I need to reopen this thread because on a long run with different motors the suggested answer didnt do the trick.
    We got major field problems with oscillating Rs values.
    Do you guys have any suggestions, hints or ideas?
  • Patrick,
    I'm seeing if I can get another set of eyes to look at this.
  • Patrick,

    It's not easy to give a proper comment with a limited your source code. Can you show us the source code of USERCTRL_RsOnlineCalculation() function related with RS online if possible?  

    The one importance thing is that the control variables like PI integrators and RS online variables should be initialized to zero or initial value at start-up when PWM is ON. If you use CTRL_setFlag_enableCtrl() function for enabling controller, the control variables are automatically initialized. However, If you only enable PWM ON, you should do initialization of all PI integrator variables manually before PWM ON.

    The other key thing is that RS online function should be disabled with EST_setFlag_enableRsOnLine(obj->estHandle,false) during PWM OFF. It means that RS online function only properly works when current control is in normal operation.

    -Steve

  • Hi,
    thank you for your answer, I'll try that immediately.
    I posted all related source code, also the USERCTRL_RsONlineCalculation function but here it is again:
    /********************* P R I V A T E F U N C T I O N S *********************/
    static void USERCTRL_RsOnlineCalculation(bool isRsOnlinePossible,
    bool isRsOnlineUpdatePossible)
    {/* handle rsOnline */
    if((CTRL_getState(ctrlHandle) <= CTRL_State_OffLine) ||
    ((CTRL_getState(ctrlHandle) == CTRL_State_OnLine) &&
    (EST_getState(ctrlHandle->estHandle) == EST_State_Rs)))
    {/* rs online off, zero out values, causes:
    * external request,
    * do not inject while calibrating,
    * do not inject while estimating rs on startup
    */
    EST_setRsOnLine_qFmt(ctrlHandle->estHandle,
    EST_getRs_qFmt(ctrlHandle->estHandle));
    EST_setRsOnLineId_mag_pu(ctrlHandle->estHandle, _IQ(0.0));
    EST_setRsOnLineId_pu(ctrlHandle->estHandle, _IQ(0.0));
    EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, false);
    EST_setFlag_updateRs(ctrlHandle->estHandle, false);
    }
    else
    {/* check if we want it to */
    if((!isRsOnlinePossible) || (!gMotorVars.Flag_CalibrationComplete))
    {/* external off */
    EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, false);
    EST_setFlag_updateRs(ctrlHandle->estHandle, false);
    }
    else
    {/* run it */
    _iq sf = _IQ(1.0 / USER_IQ_FULL_SCALE_CURRENT_A);
    _iq Rs_pu = EST_getRs_pu(ctrlHandle->estHandle);
    _iq RsOnLine_pu = EST_getRsOnLine_pu(ctrlHandle->estHandle);
    _iq Rs_error_pu = RsOnLine_pu - Rs_pu;
    EST_setFlag_enableRsOnLine(ctrlHandle->estHandle, true);
    EST_setRsOnLineId_mag_pu(ctrlHandle->estHandle,
    _IQmpy(gMotorVars.RsOnLineCurrent_A, sf));
    /* Enable updates when Rs Online is only
    5% different from Rs Offline */
    if ((_IQabs(Rs_error_pu) < _IQmpy(Rs_pu, _IQ(0.05))) &&
    (isRsOnlineUpdatePossible))
    EST_setFlag_updateRs(ctrlHandle->estHandle, true);
    else
    EST_setFlag_updateRs(ctrlHandle->estHandle, false);
    }
    }
    }
    static void USERCTRL_SetCtrlParameter(_iq KpId, _iq KiId, _iq KpSpd, _iq KiSpd,
    _iq Accel, _iq Speed)
    {/* set all control parameters (periodically) */
    CTRL_setKp(ctrlHandle, CTRL_Type_PID_spd, KpSpd);
    CTRL_setKi(ctrlHandle, CTRL_Type_PID_spd, KiSpd);
    CTRL_setKp(ctrlHandle, CTRL_Type_PID_Id, KpId);
    CTRL_setKi(ctrlHandle, CTRL_Type_PID_Id, KiId);
    CTRL_setKp(ctrlHandle, CTRL_Type_PID_Iq, KpId);
    CTRL_setKi(ctrlHandle, CTRL_Type_PID_Iq, KiId);
    CTRL_setMaxAccel_pu(ctrlHandle, _IQmpy(MAX_ACCEL_KRPMPS_SF, Accel));
    CTRL_setSpd_ref_krpm(ctrlHandle, Speed);
    }
    /********************** P U B L I C F U N C T I O N S **********************/
    void main(void)
    {
    /* Only used if running from FLASH
    * Note that the variable FLASH is defined by the project
    * Copy time critical code and Flash setup code to RAM
    * The RamfuncsLoadStart, RamfuncsLoadEnd, and RamfuncsRunStart
    * symbols are created by the linker. Refer to the linker files.
    */
    memCopy((uint16_t*)&RamfuncsLoadStart,
    (uint16_t*)&RamfuncsLoadEnd,
    (uint16_t*)&RamfuncsRunStart);
    /* Init HAL and USER params */
    halHandle = HAL_init(&hal, sizeof(hal));
    USER_setParams(&gUserParams);
    HAL_setParams(halHandle, &gUserParams);
    /* Controller init */
    ctrlHandle = CTRL_initCtrl(0, &ctrl, sizeof(ctrl));
    /* HAL setup peripherals */
    HAL_setupFaults(halHandle);
    HAL_initIntVectorTable(halHandle);
    HAL_enableAdcInts(halHandle);
    HAL_enableGlobalInts(halHandle);
    HAL_enableDebugInt(halHandle);
    HAL_disablePwm(halHandle);
    HAL_enableDrv(halHandle);
    HAL_setupDrvSpi(halHandle, &gDrvSpi8301Vars);
    CTRL_setFlag_enableDcBusComp(ctrlHandle, true);
    /* set default controller parameters from user.h */
    CTRL_setParams(ctrlHandle, &gUserParams);
    /* set all flags and controller parameters for first start */
    CTRL_setFlag_enableUserMotorParams(ctrlHandle, true);
    USERCTRL_SetCtrlParameter(gMotorVars.Kp_Idq,
    gMotorVars.Ki_Idq,
    gMotorVars.Kp_spd,
    gMotorVars.Ki_spd,
    ACCEL_RUN,
    _IQ(0.0));
    USERCTRL_RsOnlineCalculation(false, false);
    CTRL_setFlag_enableSpeedCtrl(ctrlHandle, true);
    EST_setFlag_enableForceAngle(ctrlHandle->estHandle, true);
    for (;;)
    {
    if ((gMotorVars.CtrlState == CTRL_State_OnLine) &&
    (gMotorVars.EstState == EST_State_MotorIdentified))
    {/* check for calibration, if we are online and identified its over */
    gMotorVars.Flag_CalibrationComplete = true;
    }
    if (gMotorVars.Flag_CalibrationComplete)
    {/* calibration is complete, so turnoff recalcs */
    EST_setFlag_enableRsRecalc(ctrlHandle->estHandle, false);
    CTRL_setFlag_enableOffset(ctrlHandle, false);
    #ifdef USE_ACTIVEHOLD
    CTRL_setFlag_enableCtrl(ctrlHandle, true);
    #else
    if(gMotorVars.SpeedRef_krpm != _IQ(0.0))
    CTRL_setFlag_enableCtrl(ctrlHandle, true);
    else
    CTRL_setFlag_enableCtrl(ctrlHandle, false);
    #endif
    }
    else
    {/* force calibration */
    EST_setFlag_enableRsRecalc(ctrlHandle->estHandle, true);
    CTRL_setFlag_enableOffset(ctrlHandle, true);
    CTRL_setFlag_enableCtrl(ctrlHandle, true);
    }
    if (CTRL_updateState(ctrlHandle))
    {/* ctrl changed its state, react */
    CTRL_State_e ctrlState = CTRL_getState(ctrlHandle);
    if (ctrlState == CTRL_State_OffLine)
    {/* enable pwm */
    HAL_enablePwm(halHandle);
    }
    else if (ctrlState == CTRL_State_OnLine)
    {/* enable pwm and update adc bias values after recalculation */
    HAL_updateAdcBias(halHandle);
    HAL_enablePwm(halHandle);
    }
    else if (ctrlState == CTRL_State_Idle)
    {/* disable the pwm */
    HAL_disablePwm(halHandle);
    }
    }
    if (EST_isMotorIdentified(ctrlHandle->estHandle))
    {/* motor is identified so do something with it */
    /* set pre-estimated current ramp */
    EST_setMaxCurrentSlope_pu(ctrlHandle->estHandle,
    gMotorVars.MaxCurrentSlope);
    /* this is a simplified version below, but the real logic
    doesn't affect the outcome */
    USERCTRL_SetCtrlParameter(gMotorVars.Kp_Idq,
    gMotorVars.Ki_Idq,
    gMotorVars.Kp_spd,
    gMotorVars.Ki_spd,
    ACCELERATION_RUN,
    gMotorVars.SpeedTarget_krpm);
    USERCTRL_RsOnlineCalculation(true, false);
    }
    else
    {/* the estimator sets the maximum current slope during identification */
    gMotorVars.MaxCurrentSlope =
    EST_getMaxCurrentSlope_pu(ctrlHandle->estHandle);
    }
    /* get calculated and estimated motor variables */
    gMotorVars.Rs_Ohm = EST_getRs_Ohm(ctrlHandle->estHandle);
    gMotorVars.RsOnLine_Ohm = EST_getRsOnLine_Ohm(ctrlHandle->estHandle);
    gMotorVars.CtrlState = CTRL_getState(ctrlHandle);
    gMotorVars.EstState = EST_getState(ctrlHandle->estHandle);
    gMotorVars.Speed_krpm = EST_getSpeed_krpm(ctrlHandle->estHandle);
    gMotorVars.Id_A = _IQmpy(CTRL_getId_in_pu(ctrlHandle),
    _IQ(USER_IQ_FULL_SCALE_CURRENT_A));
    gMotorVars.Iq_A = _IQmpy(CTRL_getIq_in_pu(ctrlHandle),
    _IQ(USER_IQ_FULL_SCALE_CURRENT_A));
    gMotorVars.VdcBus_kV = _IQmpy(gMotorVars.AdcData.dcBus,
    _IQ(USER_IQ_FULL_SCALE_VOLTAGE_V / 1000.0));
    /* handle the drv8301 */
    HAL_writeDrvData(halHandle, &gDrvSpi8301Vars);
    HAL_readDrvData(halHandle, &gDrvSpi8301Vars);
    }
    }
    interrupt void mainISR(void)
    {/* main interrupt, called every adc shot (pwm cycle) */
    /* ack ISR */
    HAL_acqAdcInt(halHandle, ADC_IntNumber_1);
    /* convert ADC data */
    HAL_readAdcData(halHandle, (HAL_AdcData_t*)&gMotorVars.AdcData);
    /* run the controller */
    CTRL_run(ctrlHandle, halHandle,
    (const HAL_AdcData_t*)&gMotorVars.AdcData,
    (HAL_PwmData_t*)&gMotorVars.PwmData);
    /* write pwm */
    HAL_writePwmData(halHandle, (HAL_PwmData_t*)&gMotorVars.PwmData);
    /* and setup the controller */
    CTRL_setup(ctrlHandle);
    }
  • We did some further testing and it seems to be that we have a greater underlying problem but don't know where it comes from.
    At first we thought that the oscillating RsOnline is causing some weird motor behaviour but it seems to be the other way round because it is also present if we completely disable RsOnline calculation. The behaviour is as follows:

    At first if you block the motor everything is fine, it tries to "work" against the heavy load and if you release the motor it starts spinning again as expected. If you do this over and over and over again every time you block the motor it starts vibrating in the blocked position and the vibrating "frequency" gets higher and higher but still if you release the motor it starts spinning again. In these states you can feel that the torque gets less and less with every block of the motor. When the vibrating reaches a certain point the motor remains in that state even if you release the load and it should start spinning again. It just stalls and vibrates and consumes the maximum current until you give it an external spin, then its working again. At this point usually RsOnline also starts to freak out if its enabled, also if you once reached that point the slightest load applied causes that state again, you don't need to really block the motor any more just "touch it". If you cycle power everything is fine again.

    At an external point of view it seems that if something inside is slowly saturating over time until it reaches a maximum point. Could that be possible and is there a way to cleanly restart the whole control without a power cycle?

    I hope I made myself clear, its hard to explain this behaviour in a different language.

    Regards,
    Patrick
  • Patrick,

    Are you using TI EVM(F28027F+DRV8301) or your own board? How long did you block your motor?

    In your source code, the following code does not work properly because the EstState can't go to the EST_State_MotorIndentified with the TRUE of enable USER motor parameters( CTRL_setFlag_enableUserMotorParams(ctrlHandle, true)).  

    if ((gMotorVars.CtrlState == CTRL_State_OnLine) && (gMotorVars.EstState == EST_State_MotorIdentified))
    { /* check for calibration, if we are online and identified its over */
         gMotorVars.Flag_CalibrationComplete = true;
    }

    For the stall recovery you mentioned, a motor can be unstable generally during stall recovery if your board doesn't have a enough SNR and resolution for voltage and current feedback signals. I need more time to check stall recovery function with the scenario you did. Let me get back to you after some testing for stall recovery.

  • Hello Steve,
    thank you very much for your fast reply.

    We are using our own board with the same schematic as the TI EVM with F28027F and DRV8301.

    What do you mean with the EstState problem? The "calibration" process is working, because I only set a speed reference after that flag is set to true (to have always Rs and Offset calibration before a run)

    Our hardware developer thinks that the SNR should be sufficient but is willing to send you the layout and schematics if you want?


    Some further notes from testing:
    It is like the motor is losing torque after every stalling until you reach the errornous behaviour.
    Tomorrow we can measure the torque and provide real data to the problem.

    Regards
  • Patrick,

    Can you attach your user.h file? (use rich formatting,Insert File toolbar or Drag & Drop)

    In the sensorless control, it's hard to sustain torque at zero speed or stall condition without a special IPD algorithm like High Frequency Injection( refer to Lab21). In other word, angle error is getting large and large at zero speed. So, you need to use IPD solution for keeping torque at near zero speed for over a few second. However, InstaSPIN-FOC can re-start with light load once stall condition is removed even though the motor get lost torque at stall condition. In case of high load condition, you may need re-align or IPD to recover from stall condition.

    For the EstState, In case of offset and Rs-recalculation, the EstState does not go to "EST_State_MotorIdentified". In this case, the EstState goes from EST_State_Idle to EST_State_Rs. The EstState can go into "EST_State_MotorIdentified" state when finishing a full Motor Identification with CTRL_setFlag_enableUserMotorParams(ctrlHandle, false). You can refer to the User guide 6.2.2 for EST state machine. 

    So, I recommend to use "EST_State_OnLine" insted of "EST_State_MotorIdentified" as following code if you don't need gMotorVars.Flag_CalibrationComple go back to FALSE state again.

      if ((gMotorVars.CtrlState ==  EST_State_OnLine) && (gMotorVars.EstState == EST_State_OnLine))
      {/* check for calibration, if we are online and identified its over */
       gMotorVars.Flag_CalibrationComplete = true;
      }

  • 1663.user.h

    Hello Steve,

    thanks for your reply! I attached my user.h file and will get back with more information after our testing today!

  • Do you have any new information on the topic?

    The motor stalling was a parameter problem, but the oscillating RsOnline still remains in some cases. Attached is a plot from three different motors RsOnline value after starting the machine.

    One is behaving correctly (blue), one is slightly oscillating (yellow) and the third is just increasing (red) until we detect an error and shut it down.

    Even the blue one is going too high for a short amount of time there.

    What could cause such a behaviour?

  • Do the three difference motors means that three different type of motors? If so, did you set the right parameters for each motors?

    Also, Isn't there any issue at current and speed control with disabling RS_Online function for all motors? 

  • Hi,
    these are three identical motors running in parallel on three identical hardwares. All have set the same parameters and run at the same software version.
    Did you look at my user.h file, or the source i posted? Is something wrong with that? Did you ever encounter such behaviour? Do you have any idea what could cause the oscillating or - much worse - ramping up? Or in genereal wrong RsOnline calculation?

    Disabling is unfortunately not an option because we need to detect an unplugged motor.
  • Hello again,
    is there no support you can give on that matter at all? Any help would be aprecciated.
    Regards,
    Patrick
  • The graph you showed us is very strange. If some parameters like filter coefficient in RS online function are not match with your system, the RS online feedback value may have some oscillation. But your test result seems that it's not tuning issue since the graph you show us goes high sharply. In my experience, when the current controller does not work properly, RS online value can be also unstable.

    Hence, I like to know again if your system works well without any issue in all operation range including start-up in case of disabling RS online.

  • Hello Steve,

    yes everything is fine without Rs Online so far. And the only problem occuring in the example i gave was that the motor with ramping up RsOnline jerks and oscillates for a few seconds before really starting up.
    In the meantime i tried disabling RsOnline while starting up and waiting until the motor is running stable at given speed, now it occurs that RsOnline is not ramping UP but ramping DOWN to 0.18, staying there for a few seconds and then going back to normal value.
    Is there an issue with the timing at which one has to active RsOnline calculation?