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.

Changing Velocity, Acceleration, Jerk values



I created a custom project using Lab6b as my baseline. I am trying to figure out what functions to use to set my values for velocity, acceleration, and jerk values instead of the system automatically setting them for me.


Suggestions?

Cristhian

  • Cristhian,

    In the ST_runVelMove function in Lab 06b we provide the Velocity, Acceleration, and Jerk limits to SpinTAC Move in order to generate the profile.  I've copied the functions below that set those values in the SpinTAC component.

    STVELMOVE_setVelocityEnd(stObj->velMoveHandle, _IQmpy(gMotorVars.SpeedRef_krpm, _IQ(ST_SPEED_PU_PER_KRPM)));
    STVELMOVE_setAccelerationLimit(stObj->velMoveHandle, _IQmpy(gMotorVars.MaxAccel_krpmps, _IQ(ST_SPEED_PU_PER_KRPM)));
    STVELMOVE_setJerkLimit(stObj->velMoveHandle, _IQ20mpy(gMotorVars.MaxJrk_krpmps2, _IQ20(ST_SPEED_PU_PER_KRPM)));

    It is important to note that these functions expect the input to be in scaled units.  Which is why we multiply the gMotorVars value with the conversion factor ST_SPEED_PU_PER_KRPM.

  • Yes, I noticed those functions. I ended up changing the gMotorVars structure values for speed, acceleration, and jerk.

    One other note. When running the lab, I am getting a VelCtlErrorID = 1016. I checked the documentation and it states "Friction is out of bounds" and no action to be taken. What should I do to my program to remove this error?

  • What is the value in user.h for USER_SYSTEM_FRICTION?  Our controller expects the friction to vary between (0, 5).  The error doesn't impact the operation.  If you want to get rid of the error you can reduce the friction to something slightly less than 5.  This should have very little impact on the controller performance since the friction value is not as important as bandwidth or inertia.

  • It was set to a negative number (-0.004059374332). I removed the sign from it and the error went away. I thought that it didn't affect my system since I was running my motor without incident.

  • We saturate the friction value between (0, 5) but will warn if you provide a value outside those bounds.  Glad to hear you were able to clean up the error.

  • Adam,

    When setting up my velocity plan using STVELPLAN_addCfgState function, what timer is used as the StateTimer? And what is the purpose of  'L' to the value?

    //Example: STVELPLAN_addCfgState(handle,VelSetpoint[pups],StateTimer[ticks]);
    STVELPLAN_addCfgState(stObj->velPlanHandle,                                 0,   0L); // State A
    STVELPLAN_addCfgState(stObj->velPlanHandle, _IQ( 8.00 * ST_SPEED_PU_PER_KRPM), 500L); // State B

    Cristhian

  • Cristhian,

    The StateTimer in Plan does not use a hardware timer on the CPU.  It counts the number of interrupts in order to time based on that.  So a StateTimer value of 500 means that the Plan will be called at least 500 times before it leaves that state.

    The L that is appended tells the compiler to treat that number as a long.  

  • Alright. Below is my clocks and timers from my user.h file:

    //! \brief CLOCKS & TIMERS
    // **************************************************************************
    #define USER_SYSTEM_FREQ_MHz  (90.0)
    #define USER_PWM_FREQ_kHz     (40.0)
    
    #define USER_MAX_VS_MAG_PU    (1.0)    // Set to 1.0 if a current reconstruction technique is not used.  Look at the module svgen_current in lab10a-x for more info.
    
    #define USER_PWM_PERIOD_usec  (1000.0/USER_PWM_FREQ_kHz)
    
    #define USER_ISR_FREQ_Hz      ((float_t)USER_PWM_FREQ_kHz * 1000.0 / (float_t)USER_NUM_PWM_TICKS_PER_ISR_TICK)
    
    #define USER_ISR_PERIOD_usec  (USER_PWM_PERIOD_usec * (float_t)USER_NUM_PWM_TICKS_PER_ISR_TICK)
    
    //! \brief DECIMATION
    // **************************************************************************
    #define USER_NUM_PWM_TICKS_PER_ISR_TICK        (2)    //@PWM freq 45 = 3
    
    #define USER_NUM_ISR_TICKS_PER_CTRL_TICK       (1)    // 2 Example, controller clock rate (CTRL) runs at PWM / 2; ex 30 KHz PWM, 15 KHz control
    
    #define USER_NUM_CTRL_TICKS_PER_CURRENT_TICK   (1)    // 1 Typical, Forward FOC current controller (Iq/Id/IPARK/SVPWM) runs at same rate as CTRL. 
    
    #define USER_NUM_CTRL_TICKS_PER_EST_TICK       (1)    // 1 Typical, FAST estimator runs at same rate as CTRL;
    
    #define USER_NUM_CTRL_TICKS_PER_SPEED_TICK     (20)   // 15 Typical to match PWM, ex: 15KHz PWM, controller, and current loop, 1KHz speed loop
    
    #define USER_NUM_CTRL_TICKS_PER_TRAJ_TICK      (20)   // 15 Typical to match PWM, ex: 10KHz controller & current loop, 1KHz speed loop, 1 KHz Trajectory
    
    #define USER_CTRL_FREQ_Hz     (uint_least32_t)(USER_ISR_FREQ_Hz/USER_NUM_ISR_TICKS_PER_CTRL_TICK)
    
    #define USER_EST_FREQ_Hz      (uint_least32_t)(USER_CTRL_FREQ_Hz/USER_NUM_CTRL_TICKS_PER_EST_TICK)
    
    #define USER_TRAJ_FREQ_Hz     (uint_least32_t)(USER_CTRL_FREQ_Hz/USER_NUM_CTRL_TICKS_PER_TRAJ_TICK)
    
    #define USER_CTRL_PERIOD_usec (USER_ISR_PERIOD_usec * USER_NUM_ISR_TICKS_PER_CTRL_TICK)
    
    #define USER_CTRL_PERIOD_sec  ((float_t)USER_CTRL_PERIOD_usec/(float_t)1000000.0)

    Am I correct to say that my ISR is running at 20 kHz and that every 20 kHz I will increment my plan time?

  • Cristhian,

    Your ISR is running at 20kHz, but the speed loop elements are running at 1kHz.  This is based on the following calculation:

    USER_PWM_FREQ_kHz / USER_NUM_PWM_TICKS_PER_ISR_TICK / USER_NUM_ISR_TICKS_PER_CTRL_TICK / USER_NUM_CTRL_TICKS_PER_SPEED_TICK
    40kHz / 2 / 1 / 20 -> 1kHz

    So your plan time will increment at 1kHz.

  • Thanks for the clarification. So all SpinTAC code is from from the USER_NUM_CTRL_TICKS_PER_SPEED_TICK define? Could I run the speed loop faster without error? I am aiming for 1 us (10kHz) tick.

  • Correct, all SpinTAC code is ran based on the USER_NUM_CTRL_TICKS_PER_SPEED_TICK define.

    You can run the speed loop faster.  I've ran at 10kHz with out issues before.  The biggest challenge you will run into is that you will end up consuming more of the processor for motor control.

  • it is unlikely you need to run the estimator at 20 KHz, you are using most of your CPU MIPS at the moment (there is a CPU usage function in proj_lab03 you can use to monitor).

    You also may not need to run the current loop at 20 KHz either. You typically only need to go to 20 KHz in a velocity application if you are nearing 2 KHz electrical frequency or for very fast response servo position control.

     

  • I seem to be noticing than when I run my velocity plan algorithm, I notice the motor sputter occasionally before it starts to spin. Is it possible that too high of a jerk or acceleration can cause this?

  • Cristhian,

    Is this when the motor starts from zero speed?  It could be that the acceleration and jerk are not large enough.  If they are very small this means that the motor will take a long time to get away from zero speed.  Since this is a sensorless motor, that means that there is a minimum speed that the motor is controllable at.  Below that speed you will run into a lot of control challenges.

  • It is from zero speed that the motor exhibits this behavior. I have my acceleration and jerk set to 100 and 700 respectively.

    My application consists of moving the motor CW then CCW for a short period of time, cycling the motor on and off with the CW/CCW plan. I have a push button on the board to start the SpinTAC move plan. I normally see the motor sputter when I have long pauses between cycles.

    Should I set my limits to max values?

  • Cristhian,

    I think those limits should be fast enough.  Are you setting the speed reference back to zero at the end of your plan?  In the lab project 06b, ForceAngle which helps with motor start up is only enabled when the system is starting from a zero speed reference.

    In between the CW/CCW cycles does your motor need to hold zero speed or could you turn off the PWMs during that time?  If you go through a brief RsRecalibration that will help with startup because it will align the motor prior to beginning motion.

  • Yes, I am setting the speed to zero at the end of the plan. I do not need to hold zero speed. I am going CW at 8krpm immediately to CCW at -8krpm.

    I attempted to integrate the code from lab7 for Rs Recalibration but was getting that sputter even without starting the motor.

  • Cristhian,

    I'm not sure how much the RsOnline will help with startup issues.  I was referring to turning the PWMs off and then back on, which will reestimate the motor resistance before starting the motor.  During that resistance reestimation, the motor will be aligned and will have a smooth startup.

  • Adam,

    Using HAL_diablePWM() & HAL_enablePWM(), my motor intermittently will sputter from zero speed. Not sure if the placement of toggling the PWM on/off has to do with it. I almost feel as if the timing has to be right when I enable my plan for the motor to sputter.

  • Cristhian,

    Have you tired using gMotorVars.Flag_Run_Identify to start and stop the PWMs?  This will run those initial startup routines.  

    The issue is that the sensorless estimator is losing the angle when you are sitting at zero speed.  It than takes some time before the angle is regained and the motor operates correctly.  There is some additional IPD work that TI is doing which should help with some of these issues.

  • To much of a delay between setting the flag on/off. My application requires an initiate signal to start my plan. There could be several milliseconds between initiates.


    I was using some functions in the Main ISR to run my application. I moved those functions into my main forever loop and seems to be performing a little better.

    All in all, I'm pleased with the performance I am getting out of the system. Just need to optimize my code in general.

    Thanks Adam, for the help. I really appreciate it.

    Cristhian

  • Adam,

    When setting up a configuration transition within the ST_setupVelPlan() funciton, it seems to be the AccLim and JrkLim values are scaled. For example:

    STVELPLAN_addCfgTran(stObj->velPlanHandle, STATE_A,   STATE_B, ST_COND_NC, 0,        0,         _IQ(4.13),      _IQ20(28.928));	// From StateA to StateB
    STVELPLAN_addCfgTran(stObj->velPlanHandle, STATE_B,   STATE_C, ST_COND_NC, 0,        0,         _IQ(4.13),      _IQ20(28.928));	// From StateB to StateC
    STVELPLAN_addCfgTran(stObj->velPlanHandle, STATE_C,   STATE_A, ST_COND_NC, 0,        0,         _IQ(4.13),      _IQ20(28.928));	// From StateC to StateD

    When I run my velocity plan in debug, these values end up becoming much bigger:

    Could you explain why? How come if I typed in _IQ(4.13) for my AccLim I don't get that same value when I run my plan?

    ~Cristhian

  • Cristhian,

    Correct, the AccLim & JrkLim used in Velocity Plan are pu values.  They can be converted back into krpm values by multiplying the pu values with this calculation:

    ((0.001 * 60.0 * USER_IQ_FULL_SCALE_FREQ_Hz) / USER_MOTOR_NUM_POLE_PAIRS)

    This calculation is provided in the macro ST_SPEED_KRPM_PER_PU found in spintac_velocity.h.  The reverse calculation to convert from krpm into pu is provided in ST_SPEED_PU_PER_KRPM.  

    The values in the gMotorVars structure have been multiplied by the scaler, so that you can see the profile limits in real units.  This is done in the ST_runVelPlan function:

    // Send the profile configuration to SpinTAC Velocity Profile Generator
    gMotorVars.SpeedRef_krpm = _IQmpy(STVELPLAN_getVelocitySetpoint(stObj->velPlanHandle), _IQ(ST_SPEED_KRPM_PER_PU));
    gMotorVars.MaxAccel_krpmps = _IQmpy(STVELPLAN_getAccelerationLimit(stObj->velPlanHandle), _IQ(ST_SPEED_KRPM_PER_PU));
    gMotorVars.MaxJrk_krpmps2 = _IQ20mpy(STVELPLAN_getJerkLimit(stObj->velPlanHandle), _IQ20(ST_SPEED_KRPM_PER_PU));

    When the gMotorVars variables are passed into Velocity Move they are scaled back into pu since this is the unit system that all of the components use.  This is done in the ST_runVelMove function:

    STVELMOVE_setVelocityEnd(stObj->velMoveHandle, _IQmpy(gMotorVars.SpeedRef_krpm, _IQ(ST_SPEED_PU_PER_KRPM)));
    STVELMOVE_setAccelerationLimit(stObj->velMoveHandle, _IQmpy(gMotorVars.MaxAccel_krpmps, _IQ(ST_SPEED_PU_PER_KRPM)));
    STVELMOVE_setJerkLimit(stObj->velMoveHandle, _IQ20mpy(gMotorVars.MaxJrk_krpmps2, _IQ20(ST_SPEED_PU_PER_KRPM)));

    Hope this helps explain some of the confusion.