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.

Most accurate method for position tracking of sine wave



I'm just beginning to experiment with the instaspin system and would like to identify the best methods for tracking positions. I have a BLDC motor with a 1250 count encoder and have an experiment set up to command a 1-2Hz sine wave using the position controller with position commands sent over CANbus at ~1000Hz. The motor seems to tick around like the second hand of a clock and position errors are +-10 degrees.

Is this performance using the position controller to be expected? Would a more accurate method be to use a velocity control mode with a control loop around postion feedback? Or commanding motor currents directly using position feedback?

Thanks,

Steve

  • which proj_lab## are you using? With which kit?

    with proper encoder feedback you can get extremely high precision and excellent position or velocity control, especially with InstaSPIN-MOTION

     

  • I've been using labs 13a and 13b with DRV8312-C2-KIT.

  • Steve,

    Have you used lab 05c to identify your system inertia?  Have you adjusted the bandwidth of the position controller?  Are you providing this sine wave as the reference to the position controller?

  • Hi Adam,

    Yes, I've worked through the labs and identified the inertia/adjusted the bandwidth. I've run the system with the sine wave input to the position controller as absolute values, as well as relative input to the position profile system.

    I've identified some possible issues in other parts of the system. I'm going to look into the rest of the test setup to confirm that the problems aren't originating there.

    Thanks,

    Steve

  • Steve,

    Is your position reference < 1 revolution?  Our position system does a windowed approach to position control.  It does this in order to maintain accuracy.  I've attached a document that shows what the position reference looks like for large position steps.

    2022.SpinTAC_Position_Move_Rollover.pdf

  • I've been testing with lab13b, using a motor with an encoder that has 1250 lines per rev, 5000 counts per rev. Based on this, it seems that a position reference of 0.002 revolutions should rotate the system by one encoder count. This is not the case in my testing. The system responds to commands of 0.004 rev or higher. This error does not seem to accumulate. Instead of two commands of 0.002 resulting in a move of 2 encoder counts, these commands seem to be lost. Is this different that your understanding of how the system should operate?

    Thanks,
    Steve

  • Steve,

    This is different that what I would expect.  I've been able to do single encoder count steps with motors in this solution.  

    Can you attach or paste the code that you modified to run the sine wave?  I'm concerned that maybe there is a fixed point math issue with the reference.

  • Adam,

    The test result I just mention was found by manipulating values by hand in the CCS debugger. I dont think there should have been any numerical issues.

    On another note, I'd like to get some clarification on the units used on the position control references to make sure I'm understanding them properly. I'm inputting my position reference with: 

    STPOSCTL_setPositionReference_mrev(stObj->posCtlHandle, _IQ24(newPosEncTicks / USER_MOTOR_ENCODER_LINES));

    The velocity ref is inputted using the calculation:

    int32_t velocity = _IQ24( ((newPosEncTicks - prevPosEncTicks) / USER_MOTOR_ENCODER_LINES) / timestep * 1000);

    Which I believe should result in the velocity in krpm/s, then:

    STPOSCTL_setVelocityReference(stObj->posCtlHandle, velocity);

    And finally, acceleration is:

    STPOSCTL_setAccelerationReference(stObj->posCtlHandle, _IQ24((velocity - prevVelocity) ) );

    I'm not certain I understand the pu/s unit convention; does this seem correct to you?

    I've attached a photo showing the tracking results I'm seeing on a sine wave, showing radians on the y-axis and seconds on the x-axis.

    It seems like we're getting closer, but there must still be something missing from my understanding of the system. Thanks for your help so far.

    -Steve

  • Steve,

    Thanks for the great information, this really help me understand what you are seeing.  

    You are right, when using the CCS debugger there should be no numerical issues.  I'll try to replicate your test with my motor tomorrow.

    In looking at your code I think there are a couple issues.  In the position reference signal you are dividing by USER_MOTOR_ENCODER_LINES, with is 1250 and not 5000.  For the velocity reference, it looks like a calculation that is producing rpm and not the scaled unit.  Acceleration also has a similar issue.

    In this system, velocity is scaled as follows:

    1 pu/s = (USER_IQ_FULL_SCALE_FREQ_Hz * 60) / USER_MOTOR_NUM_POLE_PAIRS rpm

    Acceleration/Deceleration and Jerk also us this same scaling.

    I would try the following:

    1. Set the velocity reference and acceleration reference to 0.  What I think it happening is that the velocity and acceleration references are too large, and are causing the controller to overshoot.  I've been able to get great performance running at 1rpm without the velocity and acceleration references.

    2. Try the following for references ( I did not test this, the velocity calculation might not be fixed point safe)

    STPOSCTL_setPositionReference_mrev(stObj->posCtlHandle, _IQ24(newPosEncTicks / (USER_MOTOR_ENCODER_LINES*4))); // this will allow you to do single encoder counts and not lines
    
    _iq velocity = _IQmpy(_IQ24(((((newPosEncTicks - prevPosEncTicks)/(USER_MOTOR_ENCODER_LINES*4))/ST_SAMPLE_TIME)*60)/1000), _IQ24(ST_SPEED_PU_PER_KRPM));  // should convert the reference into krpm, than multiply by the scalar that will convert into pu/s
    
    STPOSCTL_setVelocityReference(stObj->posCtlHandle, velocity);
    
    STPOSCTL_setAccelerationReference(stObj->posCtlHandle, _IQdiv((velocity - prevVelocity), _IQ24(ST_SAMPLE_TIME));