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.

Second Encoder over SPI

Hello again,

i want to connect a second Encoder to the Regulation of the InstaSpin Motion. I get the Position and the Velocity of the Encoder over the SPI. Now i want to take this Encoder informations to the InstaSpin Controller Regulation. How should i do this?

I am using the DRV8301-HC-C2-Kit with the TSM320C2000 (F28069MISO Controlcard) microrcontroller and a programmcode which is based an Lab12B

1)  In what time should the Encoder Position and Velocity updated to take this informations as regulations Parameters?

2)  Could you give me a tip to implement this in the code based on Lab12B?

I hope you could help me with this application.

Thank you very much for answer.   

  • Christian,

    Christian Dold said:
    1)  In what time should the Encoder Position and Velocity updated to take this informations as regulations Parameters?

    The encoder position should be calculated each time the FOC is called via the main isr.  The encoder position is passed into the FOC via an input parameter to the CTRL_run function in lab 12b.  

    The encoder velocity should be calculated each time the speed loop is updated.  This happens at the decimated rate specified with this if statement:

    if(stCnt++ >= ISR_TICKS_PER_SPINTAC_TICK)

    Christian Dold said:
    2)  Could you give me a tip to implement this in the code based on Lab12B?

    In lab 12b there are numerous calls to the ENC module.  You should make sure that you implement your own functions that replicate the functionality of this module.  Using the existing ENC module as a guide would be a good starting point.

  • Hi Adam,

    thanks for your answer. I have implement my own functions and creat a ENC_Module for my new Encoder. The handle a Little bit different to the encHandle but i Change the calls of the function to get it run.

    But i have a Problem with the velocity control. I start the Motor. The Motor spin a Little bit to the reference. This is normal and it works fine. Now the engine should start at the rated Speed but it runs always on his highest Speed. What could be the Problem?

    Here are my implementation:

    In proj_12b.c:

    ENC_Handle_HFDSL encHandle_HFDSL;
    ENC_Obj_HFDSL enc_HFDSL;

    ENC_setup_HFDSL(encHandle_HFDSL, 1, USER_MOTOR_NUM_POLE_PAIRS, USER_MOTOR_ENCODER_LINES_EKx, 0, USER_IQ_FULL_SCALE_FREQ_Hz, USER_ISR_FREQ_Hz, 8000.0);

    MainISR:
    ENC_calcElecAngle_HFDSL(encHandle_HFDSL, u32EncoderPos);

    // After : if(stCnt++ >= ISR_TICKS_PER_SPINTAC_TICK) {
    ST_runPosConv(stHandle, encHandle, encHandle_HFDSL, ctrlHandle);

    // IN: ST_runPosConv(stHandle, encHandle, encHandle_HFDSL, ctrlHandle);

    if(oChosenEnc==0)
    {
    STPOSCONV_setElecAngle_erev(stObj->posConvHandle, ENC_getElecAngle(encHandle));
    }
    else if(oChosenEnc==1)
    {
    STPOSCONV_setElecAngle_erev(stObj->posConvHandle, ENC_getElecAngle_HFDSL(encHandle_HFDSL));
    }

    In Enc.c:

    void ENC_setup_HFDSL(ENC_Handle_HFDSL encHandle, const int16_t sample_period, const uint16_t num_pole_pairs, const uint32_t num_enc_slots, const uint32_t enc_zero_offset, const float_t full_scale_freq, const float_t speed_update_freq, const float_t speed_cutoff)
    {
    ENC_Obj_HFDSL *enc;
    float_t temp;
    float_t speed_cutoff_radians;
    int16_t i;

    // create an object pointer for manipulation
    enc = (ENC_Obj_HFDSL *) encHandle;

    // setup the encoder sample rate
    enc->sample_count = 0;
    enc->sample_period = sample_period;

    // copy the spi handle into the data structure
    // enc->qepHandle = qepHandle;

    // copy the parameters into the data structure
    enc->num_enc_slots = num_enc_slots;
    enc->num_pole_pairs = num_pole_pairs;
    enc->enc_zero_offset = enc_zero_offset;
    enc->full_scale_freq = full_scale_freq;
    enc->delta_enc = 0;
    enc->prev_enc = 0;

    // initialize the electrical angle
    enc->enc_elec_angle = 0;

    // compute the gain which translates the mech into the elec angle
    enc->mech_angle_gain = (_iq)((((uint32_t)1)<<24)/(num_enc_slots));

    // compute the speed gain
    temp = ((float_t)num_pole_pairs*speed_update_freq*ENC_SPEED_SCALING_FACTOR) / ((float_t)num_enc_slots*full_scale_freq*(float_t)sample_period);
    enc->speed_gain = (int32_t) temp;

    // compute the rpm gain
    temp = (float_t)((full_scale_freq*60.0)/num_pole_pairs);
    enc->rpm_gain = (int32_t) temp;

    // compute the speed coefficients and initialize the low-pass filtered output
    enc->speed_cutoff = speed_cutoff;
    speed_cutoff_radians = ENC_2PI*speed_cutoff;
    temp = speed_cutoff_radians/(speed_update_freq+speed_cutoff_radians);
    enc->speed_lpf_cx = (int32_t) (ENC_SPEED_COEFF_SCALING*temp);
    enc->speed_lpf_cy = ENC_SPEED_COEFF_SCALING - enc->speed_lpf_cx;
    enc->speed_lpf_out = 0;

    // setup the encoder log
    enc->log_state = ENC_LOG_STATE_IDLE;
    enc->run_flag = 0;
    enc->trigger_idx = 0;
    enc->trigger_delta = 0;
    enc->log_idx = 0;
    enc->post_trigger_len = ENC_LOG_LEN>>1;
    enc->post_trigger_cnt = enc->post_trigger_len;
    for (i=0; i<ENC_LOG_LEN; i++)
    {
    enc->log[i] = 0;
    }

    return;
    } // end of ENC setup function



    void ENC_calcElecAngle_HFDSL(ENC_Handle_HFDSL encHandle, uint32_t u32CurrentPosition)
    {
    ENC_Obj_HFDSL *enc;
    uint32_t temp;

    // create an object pointer for manipulation
    enc = (ENC_Obj_HFDSL *) encHandle;
    enc->enc_slip_angle=0;
    enc->incremental_slip=0;

    // compute the mechanical angle
    temp = (u32CurrentPosition)*enc->mech_angle_gain;
    // add in calibrated offset
    temp += enc->enc_zero_offset;
    // convert to electrical angle
    temp = temp * enc->num_pole_pairs;
    // wrap around 1.0 (Q24)
    temp &= ((uint32_t) 0x00ffffff);
    // store encoder electrical angle
    enc->enc_elec_angle = (_iq)temp;
    // update the slip angle
    enc->enc_slip_angle = enc->enc_slip_angle + enc->incremental_slip;
    // wrap around 1.0 (Q24)
    enc->enc_slip_angle &= ((uint32_t) 0x00ffffff);
    // add in compensation for slip
    temp = temp + enc->enc_slip_angle;
    // wrap around 1.0 (Q24)
    temp &= ((uint32_t) 0x00ffffff);
    // store encoder magnetic angle
    enc->enc_magnetic_angle = (_iq)temp;

    return;
    } // end of ENC_calc_elec_angle() function

    I hope you could help me with my Problem. What i also found in testing is the the variabel VelLpf is after Spinning not on on the value Zero. It stays on a -0,3 Value.
  • Christian,

    Christian Dold said:
    But i have a Problem with the velocity control. I start the Motor. The Motor spin a Little bit to the reference. This is normal and it works fine. Now the engine should start at the rated Speed but it runs always on his highest Speed. What could be the Problem?

    There area couple of things you need to check.  

    1. Check the output from your new encoder module is the same magnitude as the previous encoder module.  The expectation is that the encoder module would output a sawtooth signal from 0 to 1 for each electrical angle of the motor.  Also that the value of 0 is aligned to a 0 degree electrical angle on the motor.

    2. It is also important that the encoder output is the same direction as the motor.  So that when positive torque is applied to the motor, that positive motion is seen on the motor.

    If you can confirm these two things, that would be ideal.  Either of these issues could cause your problem.  

    Also, in the example code you sent over did you update the encoder angle that is being passed into the FOC so that it uses the angle from the new encoder?

  • Hi Adam,

    thanks for your reply. I found the Solution of my Problem. The value of my Encoder at the start was not Zero. The Encoder has also a absolute track on his code disc so the Encoder give me the absolute angle of the Encoder. Now i save the first pos i get from my Encoder in subtract this to my CurrentValue so i get the same magnitude like the other enchandle.
    But know i have a other Problem.
    When i start the Motor spin also a Little bit to the refernce. Then the Motor spins for 1-2 seconds in the wrong direction with a Speed of 200rpm. After that the Motor spins with the rated spin in the right direction. Have you a reason for the Problem. Could it be a Problem with my refresh rate of my Encoder Position?

    Regards

    Christian

  • Christian Dold said:
    When i start the Motor spin also a Little bit to the refernce. Then the Motor spins for 1-2 seconds in the wrong direction with a Speed of 200rpm. After that the Motor spins with the rated spin in the right direction. Have you a reason for the Problem. Could it be a Problem with my refresh rate of my Encoder Position?

    Were you able to verify that the direction of your new encoder matches the direction of your old encoder?  So if you manually spin the motor both encoders are increasing in the same direction?  

    It could be related to the update rate of your new encoder.  How often are you getting a new encoder position from the SPI encoder?

    Are you calibrating the new encoder similarly to how the old encoder was calibrated?  In the mainISR look for this code:

    // if we are forcing alignment, using the Rs Recalculation, align the eQEP angle with the rotor angle
    if((EST_getState(obj->estHandle) == EST_State_Rs) && (USER_MOTOR_TYPE == MOTOR_Type_Pm))
    {
      ENC_setZeroOffset(encHandle, (uint32_t)(ENC_getPositionMax(encHandle) - ENC_getRawEncoderCounts(encHandle)));
    }

    This is how we align the encoder position against the actual position of the motor poles.