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.

Analog Encoder for Sensored Commutation using TMS320F28069 Piccolo Motor Controller

Other Parts Discussed in Thread: TMS320F28069

How would you recommend using either hall sensors or an analog encoder for sensored commutation using the TMS320F28069 Piccolo Motor Controller? I see there is an option for an encoder, but it appears to be designed for a digital incremental encoder. I remember reading that sensored commutation may be coming for hall sensors in the near future. Is this option available in a beta release? And if not, how would I go about making changes for a hall sensor for commutation? Would it be better to configure the software for hall sensors or an analog encoder?

Thanks in advance for your support.

Best regards,

Chris

  • Chris,

    InstaSPIN-MOTION can work with any type of encoder.  We only provide examples for working with an incremental type encoder.  We have customers who have modified the software in order t make their absolute encoders work.

    The hall sensor commutation is not yet available for any beta release.  The issue with using hall sensors for commutation is that they are not appropriate for position control applications.  Since the hall sensor resolution is only about 30deg electrically while a position controlled motor often needs sub-degree accuracy.  

    So if you are trying to work on a position control application, an analog encoder would be a much better option than hall sensors.

  • Hi Adam,

    Thanks for the feedback. This is actually for a speed controlled application, but we require extremely good starting and low speed performance. Do you have any examples or suggestions on where to make the necessary modifications to use an absolute encoder? Should I create a new encoder driver, and then set the electric angle as needed?

    Also, does InstaSPIN-MOTION use the encoder only for low speed commutation, and the estimated motor flux for high speed commutation? I would think that the estimated flux would provide a better signal for commutation at high speeds.

    Best regards,

    Chris

  • Chris,

    What I would recommend is that you have a look at lab 12b.  This lab replaces the FAST software encoder with an incremental encoder.  Each time the incremental encoder is used there is a function call to the ENC module.  So for your system you would need to be able to provide the same information from your absolute encoder module.  At a minimum this would be just the motor electrical angle.

    You would need to format the electrical angle from your encoder to vary between 0 and 1 in an IQ24 variable.  This would also need to be aligned with the electrical angle of the motor itself.  In the lab projects this is accomplished by injecting Id current into the motor before it starts to align the motor to a known electrical angle position.

    InstaSPIN-MOTION uses the encoder to replace the FAST software encoder.  So with labs 12+ they are using the encoder in all situations.  Depending on the encoder, the software encoder might do a better job at high speed.  This would be especially true if the encoder does not have very many bits of resolution.

  • Excellent, I'll give that a try. Thanks again for your help!

  • we have it on our to-do list to publish our working project that uses Hall for start-up and then transition to FAST.

  • Hi Chris and Adam,

    I've added an analog encoder and am successfully using the electric angle estimate from its output. The startup performance has significantly improved with sensored commutation. However, I still believe there may be room for improvement. The controller only ramps up to maybe 3-4 amps of current draw from my 15 amp supply, despite there being a much higher limit in my user.h file (27 amps). My only guess at this stage is that either the current estimate is somehow not correct, such that the controller believes it is driving 27 amps while it is only 3-4 amps, or perhaps the motor velocity estimate is not correct, such that the controller believes there is only a small speed error. Would there be an benefit to also replacing the estimated motor frequency based on my analog encoder signal? Would that only be a matter of replacing the following function in bold with my estimate?

    // when appropriate, run the PID speed controller

    if(CTRL_doSpeedCtrl(handle))
    {
    _iq refValue = TRAJ_getIntValue(obj->trajHandle_spd);
    _iq fbackValue = EST_getFm_pu(obj->estHandle);
    _iq outMax = TRAJ_getIntValue(obj->trajHandle_spdMax);
    _iq outMin = -outMax;

    // reset the speed count
    CTRL_resetCounter_speed(handle);

    PID_setMinMax(obj->pidHandle_spd,outMin,outMax);

    PID_run_spd(obj->pidHandle_spd,refValue,fbackValue,CTRL_getSpd_out_addr(handle));
    }

    Further, would there be a benefit to also setting the electric angle of the estimator with the command EST_setAngle_pu, particularly at low speeds? If so, where should I set the electric angle (e.g. before I run the estimator)?

    EST_setAngle_pu(handle, Overwrite_Flux_Angle_pu);

    Do you have any other suggestions to improve startup torque now that I have an accurate electric angle ?

    Best regards,

    Chris

    Here's my modification to the CTRL_runOnLine function to pass in the electric angle for reference:

    inline void CTRL_runOnLine_User_myfun(CTRL_Handle handle,
    const HAL_AdcData_t *pAdcData,
    HAL_PwmData_t *pPwmData,
    uint32_t electricalAngle)
    {
    CTRL_Obj *obj = (CTRL_Obj *)handle;

    _iq angle_pu;

    MATH_vec2 phasor;


    // run Clarke transform on current
    CLARKE_run(obj->clarkeHandle_I,&pAdcData->I,CTRL_getIab_in_addr(handle));


    // run Clarke transform on voltage
    CLARKE_run(obj->clarkeHandle_V,&pAdcData->V,CTRL_getVab_in_addr(handle));


    // run the estimator
    EST_run(obj->estHandle,CTRL_getIab_in_addr(handle),CTRL_getVab_in_addr(handle),
    pAdcData->dcBus,TRAJ_getIntValue(obj->trajHandle_spd));


    // generate the motor electrical angle
    angle_pu = EST_getAngle_pu(obj->estHandle);


    // Update electrical angle from the sensor
    angle_pu = electricalAngle;


    // compute the sin/cos phasor
    CTRL_computePhasor(angle_pu,&phasor);

    ....

    }

  • Chris Lightcap said:
    The startup performance has significantly improved with sensored commutation. However, I still believe there may be room for improvement. The controller only ramps up to maybe 3-4 amps of current draw from my 15 amp supply, despite there being a much higher limit in my user.h file (27 amps). 

    Please clarify...

    What sort of load is on the system?  If it is not a full load, your control system will not produce a full torque request of 27A.  If the motor is starting up then you are controlling the current appropriately to create the torque necessary to meet the speed controller goals.

    Chris Lightcap said:
    Would there be an benefit to also replacing the estimated motor frequency based on my analog encoder signal? Would that only be a matter of replacing the following function in bold with my estimate?

    You should be using the sensored angle to produce a speed estimate, and this sensored estimate should be used as the feedback to the speed controller.  If you are using the estimate from FAST for the speed controller this is an issue as the FAST feedback will be incorrect initially and until the actual speed is high enough for high precision estimates.

  • Chris,

    Does your motor not seem to be producing the expected torque?

    It could be possible that the PI based speed controller is not adequate enough for your application.  Have you tried using the SpinTAC speed controller provided in Labs 5d-6d, and 12b?

  • Hi Chris,

    Thanks for your quick feedback!

    The motor is starting up during a heavy load / stall condition, e.g. I'm clamping onto the rotor with my hand. The target speed increases as high as 17000 rpm, the measured speed is close to zero (which is correct), and the Iq_A estimate is ~27 amps (my user current limit). However, I'm only pulling roughly 3-4 amps from my supply! Why is there such a descrepancy between motor and power supply current. I understand that it may not be 100% duty cycle, and that there are other loads present, but I'd expect to see much more current pulled from my supply during stall.

    If my battery supply can yield, let's say 40 amps, should I set the max motor current to a much higher number considering the duty cycle?

    In regards to your second response, how do I use the sensored angle to produce a speed estimate? Should I replace the EST_getFm_pu function in the CTRL_run function with the sensored angle estimate?

    if(CTRL_doSpeedCtrl(handle))

    {
    _iq refValue = TRAJ_getIntValue(obj->trajHandle_spd);
    _iq fbackValue = EST_getFm_pu(obj->estHandle);
    _iq outMax = TRAJ_getIntValue(obj->trajHandle_spdMax);
    _iq outMin = -outMax;

    // reset the speed count
    CTRL_resetCounter_speed(handle);

    PID_setMinMax(obj->pidHandle_spd,outMin,outMax);

    PID_run_spd(obj->pidHandle_spd,refValue,fbackValue,CTRL_getSpd_out_addr(handle));
    }

  • Hi Adam,

    Thank you again for your quick response!

    I haven't tested on a dyno yet, but it doesn't seem that I'm pulling the peak current from the motor during a stall condition. I'm only seeing 3-4 amps from my supply when stalled, but the Iq_A estimate is 27 amps (limited because of my user motor current limit = 27 amps). Would you expect to see this much of a discrepancy while under stall?

    I modified lab 5f, and am using the SpinTAC controller (I believe). I'm computing the angle of my analog encoder in mainISR and replacing the electric angle in CTRL_runOnLine_User. It's actually quite an improvement compared to sensorless commutation at low speeds, except for not pulling the expected current from my supply.

    Let me know what you think might be causing the problem.

    Best regards,

    Chris

  • Chris,

    I would expect to see a pretty big discrepancy.  The USER_MOTOR_MAX_CURRENT_A is the maximum current that the speed controller will request.  From that speed controller request current it will transform the DC current into AC signals that can be modulated on the motor.  Also there are capacitors on the DC bus that will help support large current demands from the motor.  

    Glad to hear that you are working with the SpinTAC Controller.  If you are calculating the speed feedback from your analog encoder you can provide it as the feedback to the SpinTAC Controller.  Look for the function ST_runVelCtl.  This function is where we call the SpinTAC speed controller.  There you can update the speed feedback source.

  • USER_MOTOR_MAX_CURRENT - when used with a Speed Controller - limits the amplitude of the current phases, which may not be the same as the input power supply.

    Iq_Ref_A is the peak value being commanded/requested, but that's only during the PWM on-time and still depends on your Vbus.

    Is the Iq Feedback value reaching 27A?  What is the value of Vs?  (you can see how we pull this in proj_lab10a)

    In my experience with compressor pumps I have had to increase the Iq_Ref_A to double the value you "expect" but you will still see the power supply current much lower.

    another item that trips people up is what this max current value should be.

    Just to give you an idea, take a look at this datasheet of this motor: http://anaheimautomation.com/manuals/brushless/L010228%20-%20BLY17%20Series%20Product%20Sheet.pdf

     

    For the first motor: BLY171S-15V-8000

     

    It shows the rated current is: 2.2A
    But considering their torque constant of 1.98 oz-in/A, with a limit of 2.2A you can only develop 2.2*1.98 = 4.356 oz-in. However, in their peak torque spec, they have 14 oz-in! so you would never get this peak torque with a max current of 2.2A. What you need to do is specify the max current so that you get the peak torque. So the max current of this motor would be the peak torque over the constant, so 14 / 1.98 = 7.07 A, instead of 2.2A.

    USER_MOTOR_MAX_CURRENT limits the amplitude of the current phases, which may not be the same as the input power supply.

  • Hi Adam,

    To confirm, if I'm using the SpinTAC controller than I'm closing the PI speed loop in ST_runVelCtl and need to update the speed feedback in this function. On the other hand, if I'm using FAST, then I'll need to update the speed feedback in the function CTRL_RunOnLine_User. In other words, CTRL_doSpeedCtrl(handle) returns false if I'm using the SpinTAC controller.

    I've added both functions here for reference.

    Thanks,

    Chris

    void ST_runVelCtl(ST_Handle handle, CTRL_Handle ctrlHandle)
    {

    _iq speedFeedback, iqReference, gSpdError, gUp, gUi;
    ST_Obj *stObj = (ST_Obj *)handle;
    CTRL_Obj *ctrlObj = (CTRL_Obj *)ctrlHandle;

    // Get the mechanical speed in pu
    speedFeedback = EST_getFm_pu(ctrlObj->estHandle);

    // Run the SpinTAC Controller
    // Note that the library internal ramp generator is used to set the speed reference
    STVELCTL_setVelocityReference(stObj->velCtlHandle, TRAJ_getIntValue(ctrlObj->trajHandle_spd));
    STVELCTL_setAccelerationReference(stObj->velCtlHandle, _IQ(0.0)); // Internal ramp generator does not provide Acceleration Reference
    STVELCTL_setVelocityFeedback(stObj->velCtlHandle, speedFeedback);
    STVELCTL_run(stObj->velCtlHandle);

    // select SpinTAC Velocity Controller
    iqReference = STVELCTL_getTorqueReference(stObj->velCtlHandle);

    if(gMotorVars.SpinTAC.VelCtlEnb == true) {
    // Set the Iq reference that came out of SpinTAC Velocity Control
    CTRL_setIq_ref_pu(ctrlHandle, iqReference);
    // Update internal PI integrator, if running SpinTAC
    gSpdError = TRAJ_getIntValue(ctrlObj->trajHandle_spd) - speedFeedback;
    gUp = _IQmpy(gSpdError, CTRL_getKp(ctrlHandle, CTRL_Type_PID_spd));
    gUi = _IQmpy(gSpdError, CTRL_getKi(ctrlHandle, CTRL_Type_PID_spd));
    CTRL_setUi(ctrlHandle, CTRL_Type_PID_spd, iqReference - gUp - gUi);
    }
    }

    // when appropriate, run the PID speed controller
    if(CTRL_doSpeedCtrl(handle))
    {
    _iq refValue = TRAJ_getIntValue(obj->trajHandle_spd);
    _iq fbackValue = EST_getFm_pu(obj->estHandle);
    _iq outMax = TRAJ_getIntValue(obj->trajHandle_spdMax);
    _iq outMin = -outMax;

    // reset the speed count
    CTRL_resetCounter_speed(handle);

    PID_setMinMax(obj->pidHandle_spd,outMin,outMax);

    PID_run_spd(obj->pidHandle_spd,refValue,fbackValue,CTRL_getSpd_out_addr(handle));
    }

  • Hi Chris,

    Yes, the Iq feedback is reaching 27A on my 9.8V supply. I'm surprised that there is such a large difference between that measured in the current phase, and that from my supply, but thanks for the feedback.

    Best regards,

    Chris

  • Chris,

    You can use FAST and SpinTAC in the same project.  That is what is done in lab 05f.  

    To clarify, FAST is a sensorless estimator that returns the motor's Angle and Speed feedbacks.  SpinTAC is an advanced speed controller.  So it takes the speed feedback from FAST and will close the speed loop.

    At the beginning of the lab 05f the CTRL object is told to not run it's speed controller with the function: CTRL_setFlag_enableSpeedCtrl.  Instead the speed loop is closed with SpinTAC.  

  • Adam,

    He's using an encoder now, so he should be using proj_lab12x

    Chris,

    In proj_lab12x + the encoder is used for angle and speed feedback (replacing the outputs from FAST, though FAST is still running and producing an estimate in this SW).  It isn't clear to me if you used these projects or tried to implement the encoder yourself into proj_lab5x

  • Hi Chris,

    I've added our analog encoder to proj_lab5x, as I wanted to easily switch between sensorless and sensored control, and I don't have a traditional encoder object. I see from proj_lab12x that I should also run ST_runPosConv in order to set the electric angle

    void ST_runPosConv(ST_Handle handle, ENC_Handle encHandle, CTRL_Handle ctrlHandle)

    and then pull the encoder velocity using

    // Get the mechanical speed in pu
    speedFeedback = STPOSCONV_getVelocityFiltered(stObj->posConvHandle);

    Since I'm working with a custom encoder, it was much easier to modify proj_lab5x and use the encoder's electric angle, rather than try to use the ENC module and CtrlQEP controller.

    I'll give this a try and let you know if I have any success.

    Best regards,

    Chris

  • Hi Chris, Adam,

    I'm able to use sensored commutation with my analog encoder, however the speed estimate from the SpinTAC converter is not accurate for RPM > ~9500. When comparing the SpinTAC estimated speed to my encoder estimated speed (using STPOSCONV), they are very close for low RPM, but start to drift apart around ~10k, and eventually the encoder estimated speed becomes a large negative number of several krpm (e.g. -6krpm). Why is this occuring? Should I be running my spinTAC estimator at a faster period? Is there something not scaled correctly in my user.h file?

    Thanks again for all your help on this project. Your timely feedback has been extremely helpful.

    Here's a snippit of code from my main.c file:

    void ST_runPosConv(ST_Handle handle, CTRL_Handle ctrlHandle, _iq electricalAngle)

    {
    ST_Obj *stObj = (ST_Obj *)handle;

    // set the electrical angle
    STPOSCONV_setElecAngle_erev(stObj->posConvHandle, electricalAngle);

    // run the SpinTAC Position Converter
    STPOSCONV_run(stObj->posConvHandle);
    }

    void ST_runVelCtl(ST_Handle handle, CTRL_Handle ctrlHandle)
    {

    _iq speedFeedback, iqReference, gSpdError, gUp, gUi;
    ST_Obj *stObj = (ST_Obj *)handle;
    CTRL_Obj *ctrlObj = (CTRL_Obj *)ctrlHandle;

    // Get the mechanical speed in pu
    speedFeedback = EST_getFm_pu(ctrlObj->estHandle);

    // Get the mechanical speed in pu
    //speedFeedback = STPOSCONV_getVelocityFiltered(stObj->posConvHandle);

    // Run the SpinTAC Controller
    // Note that the library internal ramp generator is used to set the speed reference
    STVELCTL_setVelocityReference(stObj->velCtlHandle, TRAJ_getIntValue(ctrlObj->trajHandle_spd));
    STVELCTL_setAccelerationReference(stObj->velCtlHandle, _IQ(0.0)); // Internal ramp generator does not provide Acceleration Reference
    STVELCTL_setVelocityFeedback(stObj->velCtlHandle, speedFeedback);
    STVELCTL_run(stObj->velCtlHandle);

    // select SpinTAC Velocity Controller
    iqReference = STVELCTL_getTorqueReference(stObj->velCtlHandle);

    if(gMotorVars.SpinTAC.VelCtlEnb == true) {
    // Set the Iq reference that came out of SpinTAC Velocity Control
    CTRL_setIq_ref_pu(ctrlHandle, iqReference);

    // Update internal PI integrator, if running SpinTAC
    gSpdError = TRAJ_getIntValue(ctrlObj->trajHandle_spd) - speedFeedback;
    gUp = _IQmpy(gSpdError, CTRL_getKp(ctrlHandle, CTRL_Type_PID_spd));
    gUi = _IQmpy(gSpdError, CTRL_getKi(ctrlHandle, CTRL_Type_PID_spd));
    CTRL_setUi(ctrlHandle, CTRL_Type_PID_spd, iqReference - gUp - gUi);
    }

  • Chris,

    Can you provide some more information about your system?  Can you provide your user.h?  I want to check some systems scalings to see if there is any potential issues with rollover.

  • Hi Adam,

    Here's my user.h file. After giving it more thought, the problem might be that the sampling is not occuring fast enough at higher speeds. If the SpinTAC controller is only measuring the encoder position once per revolution, would it believe that the motor is spinning backwards if the next sample is more than 180 degrees?

    5040.user.h

    Thanks,

    Chris

    user.h
  • Chris,

    I agree that the sampling is too low.  I ran your settings in my simulation, and we need to sample more often in order to produce a good output at that electrical speed.  We need at least 3 samples per electrical revolution in order to generate good speed feedback.

    With your setup 10000rpm / 60 sec/min * 3 Pole Pairs -> 500 electrical rev/sec is the electrical speed of your system.

    The update rate you have setup is 1kHz for the speed loop which means we only get two samples per electrical revolution.  

    I would recommend reducing USER_NUM_CTRL_TICKS_PER_SPEED_TICK to 5 or 10.

  • Excellent, that fixed the problem. Thank you for your support!

    Best regards,

    Chris