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.

TMS320F28054M: Motor controller cannot withhold zero speed

Part Number: TMS320F28054M
Other Parts Discussed in Thread: MOTORWARE

Hi,

We have a problem when sending a zero reference speed to the motor as the motor starts to oscillate and vibrates. How can we disable such oscillation?

Things we have tried:

1. Hardcoding the speed values (that are within abs(100) rpm, or close to zero) within which we use the ForceAngle:

 if (global_speed < 100 && global_speed > -100){
                EST_setFlag_enableForceAngle(obj->estHandle,true);
                gMotorVars.Flag_enableForceAngle = true;
            }
            else {
                EST_setFlag_enableForceAngle(obj->estHandle, false);
                gMotorVars.Flag_enableForceAngle = false;
            }

2. Disabling PWM and DRV but I believe this is not a good solution.

What can we do to overcome this problem? I am attaching our main.c and user.h for you reference

src_main.c
/* --COPYRIGHT--,BSD
 * Copyright (c) 2012, LineStream Technologies Incorporated
 * Copyright (c) 2012, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
* *  Neither the names of Texas Instruments Incorporated, LineStream
 *    Technologies Incorporated, nor the names of its contributors may be
 *    used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --/COPYRIGHT--*/
//! \file   solutions/instaspin_motion/src/proj_lab05d.c
//! \brief  InstaSPIN-MOTION SpinTAC Speed Controller
//!
//! (C) Copyright 2012, LineStream Technologies, Inc.
//! (C) Copyright 2011, Texas Instruments, Inc.

//! \defgroup PROJ_LAB05d PROJ_LAB05d
//@{

//! \defgroup PROJ_LAB05d_OVERVIEW Project Overview
//!
//! Running the SpinTAC Velocity Controller
//!

// **************************************************************************
// the includes

// system includes
#include <math.h>
#include "main.h"
#include "uavcan.h"

#ifdef FLASH
#pragma CODE_SECTION(mainISR,"ramfuncs");
#endif

// Include header files used in the main function
//#define LEARN



#define SCIENCE_MODE_HZ  10
#ifdef SCIENCE_MODE_HZ
int16_t gScienceCnt = 0;
#endif

// **************************************************************************
// the defines

#define LED_BLINK_FREQ_Hz   10
#define TACHO_SEND_FREQ_HZ  50
#define STATUS_SEND_FREQ_HZ  1
#define SPEED_RX_TIMEOUT_MS     500
#define LIFT_RX_TIMEOUT_MS     500

#define TEST_SPEED_TIMEOUT_HZ    0.5



uint32_t LIFT_ENC_LIMIT = 45000; // ticks
uint32_t enc = 0;
// **************************************************************************
// the globals

uint_least16_t gCounter_updateGlobals = 0;

bool Flag_Latch_softwareUpdate = true;

CTRL_Handle ctrlHandle;

HAL_Handle halHandle;

USER_Params gUserParams;

HAL_PwmData_t gPwmData = {_IQ(0.0), _IQ(0.0), _IQ(0.0)};

HAL_AdcData_t gAdcData;

_iq gMaxCurrentSlope = _IQ(0.0);

volatile int32_t tacho = 0;
int32_t global_speed = 0;

#ifdef FAST_ROM_V1p6
CTRL_Obj *controller_obj;
#else
CTRL_Obj ctrl;              //v1p7 format
#endif

ST_Obj st_obj;
ST_Handle stHandle;

uint16_t gLEDcnt = 0;
uint16_t gTACHOcnt = 0;
uint16_t gTIMEOUT_SPEEDcnt = 0;
uint16_t gTIMEOUT_LIFTcnt = 0;

bool LIFT_MANUAL_FLAG = false;

int16_t gTestcnt = 0;

volatile MOTOR_Vars_t gMotorVars = MOTOR_Vars_INIT;

#ifdef FLASH
// Used for running BackGround in flash, and ISR in RAM
extern
uint16_t *RamfuncsLoadStart, *RamfuncsLoadEnd, *RamfuncsRunStart;
#endif



typedef struct{
     uint16_t mbox_num;
     uint32_t can_id;
     uint16_t dlc;
}can_id_map_t;

can_id_map_t can_id_target_speed_rx_map;
can_id_map_t can_id_control_rx_map;
can_id_map_t can_id_auto_lift_rx_map;
can_id_map_t can_id_manual_lift_rx_map;

can_id_map_t can_id_tacho_tx_map;
can_id_map_t can_id_lift_done_tx_map;

//#define TL
#define TR
//#define BL
//#define BR

#ifdef TL
#define UAVCAN_PORT_TARGET_SPEED_RX 900
#define UAVCAN_PORT_CONTROL_RX 9001
#define UAVCAN_PORT_AUTO_LIFT_RX 9002
#define UAVCAN_PORT_MANUAL_LIFT_RX 9003

#define UAVCAN_PORT_TACHO_TX 1240
#define UAVCAN_PORT_LIFT_DONE_TX 9004
#define REVERSED 1
#endif

#ifdef TR
#define UAVCAN_PORT_TARGET_SPEED_RX 901
#define UAVCAN_PORT_CONTROL_RX 9101
#define UAVCAN_PORT_AUTO_LIFT_RX 9102
#define UAVCAN_PORT_MANUAL_LIFT_RX 9103

#define UAVCAN_PORT_TACHO_TX 1241
#define UAVCAN_PORT_LIFT_DONE_TX 9104
#define REVERSED 1
#endif

#ifdef BL
#define UAVCAN_PORT_TARGET_SPEED_RX 902
#define UAVCAN_PORT_CONTROL_RX 9201
#define UAVCAN_PORT_AUTO_LIFT_RX 9202
#define UAVCAN_PORT_MANUAL_LIFT_RX 9203

#define UAVCAN_PORT_TACHO_TX 1242
#define UAVCAN_PORT_LIFT_DONE_TX 9204
#define REVERSED 0
#endif

#ifdef BR
#define UAVCAN_PORT_TARGET_SPEED_RX 903
#define UAVCAN_PORT_CONTROL_RX 9301
#define UAVCAN_PORT_AUTO_LIFT_RX 9302
#define UAVCAN_PORT_MANUAL_LIFT_RX 9303

#define UAVCAN_PORT_TACHO_TX 1243
#define UAVCAN_PORT_LIFT_DONE_TX 9304
#define REVERSED 0
#endif

uint16_t pwm_cnt = 0;
uint32_t pwm_tics_num = (USER_ISR_FREQ_Hz / 1000); // pwm 1khz
uint16_t duty_cycle_percent = 0;

void pwm_generator(uint16_t duty_cycle_percent)
{
    uint32_t pwm_high_tics = (uint32_t)((pwm_tics_num * duty_cycle_percent) / 100);
    if(pwm_cnt <= pwm_high_tics){
        GPIO_setHigh(halHandle->gpioHandle, LIFT_PWM.gpio_num);
    }
    else if(pwm_cnt < pwm_tics_num && pwm_cnt > pwm_high_tics){
        GPIO_setLow(halHandle->gpioHandle, LIFT_PWM.gpio_num);
    }
    else if(pwm_cnt >= pwm_tics_num){
        pwm_cnt = 0;
    }
}



void sendParams(){
    can_configure_tx_mbox(15, 0x00000001, 8);
    int32_t kp_spd = _IQtoF(gMotorVars.Kp_spd) * 1e6;
    int32_t ki_spd = _IQtoF(gMotorVars.Ki_spd) * 1e6;
    uint64_t data_k_spd = (uint64_t)kp_spd << 32 | (uint32_t)ki_spd;//| ki_spd;
    can_write(15, data_k_spd);
    can_configure_tx_mbox(16, 0x00000002, 8);
    int32_t kp_idq = _IQtoF(gMotorVars.Kp_Idq) * 1e6;
    int32_t ki_idq = _IQtoF(gMotorVars.Ki_Idq) * 1e6;
    uint64_t data_k_idq = (uint64_t)kp_idq << 32 | (uint32_t)ki_idq;
    can_write(16, data_k_idq);
    can_configure_tx_mbox(17, 0x00000003, 8);
    int32_t i_bias0 = _IQtoF(gMotorVars.I_bias.value[0]) * 1e6;
    int32_t v_bias0 = _IQtoF(gMotorVars.V_bias.value[0]) * 1e6;
    uint64_t data_bias0 = (uint64_t)i_bias0 << 32 | (uint32_t)v_bias0;
    can_write(17, data_bias0);
    can_configure_tx_mbox(18, 0x00000004, 8);
    int32_t i_bias1 = _IQtoF(gMotorVars.I_bias.value[1]) * 1e6;
    int32_t v_bias1 = _IQtoF(gMotorVars.V_bias.value[1]) * 1e6;
    uint64_t data_bias1 = (uint64_t)i_bias1 << 32 | (uint32_t)v_bias1;
    can_write(18, data_bias1);
    can_configure_tx_mbox(19, 0x00000005, 8);
    int32_t i_bias2 = _IQtoF(gMotorVars.I_bias.value[2]) * 1e6;
    int32_t v_bias2 = _IQtoF(gMotorVars.V_bias.value[2]) * 1e6;
    uint64_t data_bias2 = (uint64_t)i_bias2 << 32 | (uint32_t)v_bias2;
    can_write(19, data_bias2);
    can_configure_tx_mbox(20, 0x00000006, 8);
    int32_t rs_om = gMotorVars.Rs_Ohm * 1e6;
    int32_t flux = gMotorVars.Flux_VpHz * 1e6;
    uint64_t rs_flux = (uint64_t)rs_om << 32 | (uint32_t)flux;
    can_write(20, rs_flux);
    can_configure_tx_mbox(21, 0x00000007, 8);
    uint32_t lsd = (uint32_t)(gMotorVars.Lsd_H * 1e9);
    uint32_t lsq = (uint32_t)(gMotorVars.Lsq_H * 1e9);//(uint32_t)(0.0000114935112 * 1e9);
    uint64_t lsd_lsq = (uint64_t)lsd << 32 | (uint32_t)lsq;
    can_write(21, lsd_lsq);
    can_configure_tx_mbox(22, 0x00000008, 8);
    int32_t est_state = gMotorVars.EstState;
    int32_t ctrl_state = gMotorVars.CtrlState;
    uint64_t state = (uint64_t)ctrl_state << 32 | (uint32_t)est_state;
    can_write(22, state);
    can_configure_tx_mbox(23, 0x00000009, 8);
    uint32_t vbus = _IQtoF(gMotorVars.VdcBus_kV) * 1e3;
    can_write(23, vbus);
    can_configure_tx_mbox(24, 0x00000010, 2);
    uint16_t MotorIdentified =  gMotorVars.Flag_MotorIdentified;
    can_write(24, MotorIdentified);

}


void lift(uint16_t duty, uint16_t dir)
{
    if(dir == 0x00) {
        GPIO_setHigh(halHandle->gpioHandle, LIFT_CW_DIR.gpio_num);
        GPIO_setLow(halHandle->gpioHandle, LIFT_CCW_DIR.gpio_num);
    }
    else if(dir == 0xFF) {
        GPIO_setLow(halHandle->gpioHandle, LIFT_CW_DIR.gpio_num);
        GPIO_setHigh(halHandle->gpioHandle, LIFT_CCW_DIR.gpio_num);
    }
    if(duty == 0){
        duty_cycle_percent = duty;
        GPIO_setLow(halHandle->gpioHandle,LIFT_CW_DIR.gpio_num);
        GPIO_setLow(halHandle->gpioHandle,LIFT_CCW_DIR.gpio_num);
    }
    else if(duty > 100){
        duty = 100;
    }

    duty_cycle_percent = duty;
}


void trace(unsigned char e) {
    unsigned char i = 1;
    GPIO_setHigh(halHandle->gpioHandle,GPIO_Number_8);
    for (i = 0; i < e; ++i) {
        GPIO_toggle(halHandle->gpioHandle,GPIO_Number_8);
    }
    GPIO_setLow(halHandle->gpioHandle,GPIO_Number_8);
}



_iq _IQdivRem(_iq in1, _iq in2)
{
    _iq res = _IQdiv(in1, in2) & 0x00FFFFFF;
    return res;
}

volatile _iq prev_angle = _IQ(0.0);
void tachoObs(_iq flux_angle)
{
    _iq delta = flux_angle - prev_angle;
    if(delta < 0 && delta <= _IQ(-0.5))
    {
        delta += _IQ(1.0);
    }
    else if(delta > 0 && delta >= _IQ(0.5))
    {
        delta -= _IQ(1.0);
    }
    if(delta > 0) {
        if (delta >= _IQ(0.1666)) {
            tacho += 1;
            prev_angle = flux_angle;
        }
    }
    else
    {
        if (delta <= _IQ(-0.1666)) {
            tacho -= 1;
            prev_angle = flux_angle;
        }
    }
}


//DRV_SPI_8323_Vars_t gDrvSpi8323Vars;

_iq gFlux_pu_to_Wb_sf;

_iq gFlux_pu_to_VpHz_sf;

_iq gTorque_Ls_Id_Iq_pu_to_Nm_sf;

_iq gTorque_Flux_Iq_pu_to_Nm_sf;

// **************************************************************************
// the functions


void clb(CANMboxNumber mbox_num) {
    volatile CANMsgData data;
    can_read(mbox_num, &data);
    if(mbox_num == can_id_target_speed_rx_map.mbox_num) {
        int32_t speed = getDataFromUavCan(data);
        global_speed = speed;

        if (speed > 5000){
            speed = 5000;
        }
        else if (speed < -5000){
            speed = -5000;
        }


        float sp_ref = (float) speed / 1000;
        if (REVERSED == 1)
        {
            sp_ref = -1.0 * ((float)speed / 1000);
        }
        gTIMEOUT_SPEEDcnt = 0;
        gMotorVars.SpeedRef_krpm = _IQ(sp_ref);
    }
    else if(mbox_num == can_id_control_rx_map.mbox_num) {
        uint32_t control = getDataFromUavCan(data);
        if (control == 1) {
            gMotorVars.Flag_enableSys = true;
            gMotorVars.Flag_Run_Identify = true;
        } else if (control == 0) {
            gMotorVars.Flag_enableSys = false;
            gMotorVars.Flag_Run_Identify = false;
        }
    }
    else if(mbox_num == can_id_auto_lift_rx_map.mbox_num) {
        uint16_t lift_auto_data = getDataFromUavCan(data);
        uint16_t lift_auto_duty = lift_auto_data & 0x00FF;
        uint16_t lift_auto_dir = (lift_auto_data & 0xFF00) >> 8;
        LIFT_MANUAL_FLAG = false;
        enc = 0;
        lift(lift_auto_duty, lift_auto_dir);
    }
    else if(mbox_num == can_id_manual_lift_rx_map.mbox_num) {
        uint16_t lift_manual_data = getDataFromUavCan(data);
        uint16_t lift_manual_duty = lift_manual_data & 0x00FF;
        uint16_t lift_manual_dir = (lift_manual_data & 0xFF00) >> 8;
        gTIMEOUT_LIFTcnt = 0;
        LIFT_MANUAL_FLAG = true;
        lift(lift_manual_duty, lift_manual_dir);
    }
}

void main(void)
{
    uint_least8_t estNumber = 0;

#ifdef FAST_ROM_V1p6
    uint_least8_t ctrlNumber = 0;
#endif

    // Only used if running from FLASH
    // Note that the variable FLASH is defined by the project
#ifdef FLASH
    // 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);
 // trace(2);
#endif

    GPIO_setHigh(halHandle->gpioHandle,RED_LED.gpio_num);
    // initialize the hardware abstraction layer
    halHandle = HAL_init(&hal,sizeof(hal));


    // check for errors in user parameters
    //USER_checkForErrors(&gUserParams);


    // store user parameter error in global variable
    gMotorVars.UserErrorCode = USER_getErrorCode(&gUserParams);

    //HAL_toggleLed(halHandle,(GPIO_Number_e)HAL_Gpio_LED2);
    //HAL_turnLedOn(halHandle,(GPIO_Number_e)HAL_Gpio_LED3);



    // do not allow code execution if there is a user parameter error
    /*if(gMotorVars.UserErrorCode != USER_ErrorCode_NoError)
    {
        for(;;)
        {
            gMotorVars.Flag_enableSys = false;
        }
    }*/


    // initialize the user parameters
    USER_setParams(&gUserParams);
    //trace(3);

    // set the hardware abstraction layer parameters
    HAL_setParams(halHandle,&gUserParams);
    //trace(4);

    // initialize the controller
#ifdef FAST_ROM_V1p6
    ctrlHandle = CTRL_initCtrl(ctrlNumber, estNumber);          //v1p6 format (06xF and 06xM devices)
  controller_obj = (CTRL_Obj *)ctrlHandle;
#else
    ctrlHandle = CTRL_initCtrl(estNumber,&ctrl,sizeof(ctrl));   //v1p7 format default
#endif


    {
        CTRL_Version version;

        // get the version number
        CTRL_getVersion(ctrlHandle,&version);

        gMotorVars.CtrlVersion = version;
    }


    // set the default controller parameters
    CTRL_setParams(ctrlHandle,&gUserParams);


    // setup faults
    HAL_setupFaults(halHandle);


    // initialize the interrupt vector table
    HAL_initIntVectorTable(halHandle);

    // enable the ADC interrupts
    HAL_enableAdcInts(halHandle);

    /* Enable the eCAN interrupts at the PIE and CPU level. */
    HAL_enableECanaInts(halHandle);

    // enable global interrupts
    HAL_enableGlobalInts(halHandle);


    // enable debug interrupts
    HAL_enableDebugInt(halHandle);


    // disable the PWM
    HAL_disablePwm(halHandle);


    /* for (int i = 0; i < 10; ++i) {
           for(int j = 0 ; j < 1e7; j++) {
               GPIO_setLow(halHandle->gpioHandle,GREEN_LED.gpio_num);
               GPIO_setLow(halHandle->gpioHandle,RED_LED.gpio_num);
           }
          for(int j = 0 ; j < 1e7; j++) {
             GPIO_setHigh(halHandle->gpioHandle,GREEN_LED.gpio_num);
             GPIO_setHigh(halHandle->gpioHandle,RED_LED.gpio_num);
          }
     }*/
    //GPIO_setLow(halHandle->gpioHandle,GPIO_Number_12);
    //GPIO_setLow(halHandle->gpioHandle,GPIO_Number_14);


    // initialize the SpinTAC Components
    stHandle = ST_init(&st_obj, sizeof(st_obj));


    // setup the SpinTAC Components
    ST_setupVelCtl(stHandle);
#ifndef LEARN
    ST_setupVelMove(stHandle);
#endif
    // turn on the DRV8323 if present
    HAL_enableDrv(halHandle);
    // initialize the DRV8323 interface
    //HAL_setupDrvSpi(halHandle,&gDrvSpi8323Vars);

    // enable DC bus compensation
    CTRL_setFlag_enableDcBusComp(ctrlHandle, true);


    // compute scaling factors for flux and torque calculations
    gFlux_pu_to_Wb_sf = USER_computeFlux_pu_to_Wb_sf();
    gFlux_pu_to_VpHz_sf = USER_computeFlux_pu_to_VpHz_sf();
    gTorque_Ls_Id_Iq_pu_to_Nm_sf = USER_computeTorque_Ls_Id_Iq_pu_to_Nm_sf();
    gTorque_Flux_Iq_pu_to_Nm_sf = USER_computeTorque_Flux_Iq_pu_to_Nm_sf();


    //trace(100);
    //gPwmData.Tabc.value[0] = _IQ(0.5);
    //gPwmData.Tabc.value[1] = _IQ(0.46);
    //gPwmData.Tabc.value[2] = _IQ(0.5);
    //HAL_writePwmData(halHandle,&gPwmData);


    gMotorVars.Flag_enableSys = false;
    gMotorVars.Flag_Run_Identify = false;
#ifdef LEARN
    gMotorVars.Flag_enableUserParams = false; // false - learn
    gMotorVars.Flag_enableForceAngle = true; // true - learn
#else
    gMotorVars.Flag_enableUserParams = true; // false - learn
    gMotorVars.Flag_enableForceAngle = true; // true - learn
#endif
    gMotorVars.Flag_enableFieldWeakening = false;
    gMotorVars.Flag_enableRsRecalc = true;
    gMotorVars.Flag_enableOffsetcalc = true;





#ifndef LEARN
/*
    gMotorVars.Ki_Idq = _IQ(0.192);//_IQ(0.192);//_IQ(0.00276); /// 0.292
    gMotorVars.Kp_Idq = _IQ(0.0358);//_IQ(0.0358);//_IQ(2.810699); /// 0.0458
    gMotorVars.Ki_spd = _IQ(0.08);//0.08, _IQ(10.0);
    gMotorVars.Kp_spd = _IQ(12.0);// 4.0 _IQ(50.818);
    gMotorVars.SpeedRef_krpm = _IQ(0.1);
    gMotorVars.MaxAccel_krpmps = _IQ(0.1);
    gMotorVars.SpinTAC.VelMoveCurveType = ST_MOVE_CUR_STCRV;

    CTRL_setKi(ctrlHandle,CTRL_Type_PID_Id, gMotorVars.Ki_Idq);
    CTRL_setKi(ctrlHandle,CTRL_Type_PID_Iq, gMotorVars.Ki_Idq);
    CTRL_setKp(ctrlHandle,CTRL_Type_PID_Id, gMotorVars.Kp_Idq);
    CTRL_setKp(ctrlHandle,CTRL_Type_PID_Iq, gMotorVars.Kp_Idq);
    CTRL_setKi(ctrlHandle,CTRL_Type_PID_spd, gMotorVars.Ki_spd);
    CTRL_setKp(ctrlHandle,CTRL_Type_PID_spd, gMotorVars.Kp_spd);

    */

    gMotorVars.SpeedRef_krpm = _IQ(0.0);
    gMotorVars.MaxAccel_krpmps = _IQ(3.0);
    gMotorVars.SpinTAC.VelMoveCurveType = ST_MOVE_CUR_STCRV;

#endif
//-------------rx-----------------//
    can_id_target_speed_rx_map.mbox_num = 26;
    can_id_target_speed_rx_map.can_id = getMsgIdUavCan(UAVCAN_PORT_TARGET_SPEED_RX, 10, UCP_Nominal);
    can_id_target_speed_rx_map.dlc = 5;

    can_id_control_rx_map.mbox_num = 27;
    can_id_control_rx_map.can_id = getMsgIdUavCan(UAVCAN_PORT_CONTROL_RX, 10, UCP_Nominal);
    can_id_control_rx_map.dlc = 8;

    can_id_auto_lift_rx_map.mbox_num = 28;
    can_id_auto_lift_rx_map.can_id = getMsgIdUavCan(UAVCAN_PORT_AUTO_LIFT_RX, 10, UCP_Nominal);
    can_id_auto_lift_rx_map.dlc = 3;

    can_id_manual_lift_rx_map.mbox_num = 29;
    can_id_manual_lift_rx_map.can_id = getMsgIdUavCan(UAVCAN_PORT_MANUAL_LIFT_RX, 10, UCP_Nominal);
    can_id_manual_lift_rx_map.dlc = 3;
//-------------tx-----------------//
    can_id_tacho_tx_map.mbox_num = 25;
    can_id_tacho_tx_map.can_id = getMsgIdUavCan(UAVCAN_PORT_TACHO_TX, 10, UCP_Nominal);
    can_id_tacho_tx_map.dlc = 5;

    can_id_lift_done_tx_map.mbox_num = 24;
    can_id_lift_done_tx_map.can_id = getMsgIdUavCan(UAVCAN_PORT_LIFT_DONE_TX, 10, UCP_Nominal);
    can_id_lift_done_tx_map.dlc = 2;

//-------------can_init-----------------//
    can_init();

    can_configure_tx_mbox(can_id_tacho_tx_map.mbox_num,  can_id_tacho_tx_map.can_id, can_id_tacho_tx_map.dlc);

    can_configure_rx_mbox(can_id_target_speed_rx_map.mbox_num, can_id_target_speed_rx_map.can_id, false);
    can_configure_rx_mbox(can_id_control_rx_map.mbox_num, can_id_control_rx_map.can_id, false);
    can_configure_rx_mbox(can_id_auto_lift_rx_map.mbox_num, can_id_auto_lift_rx_map.can_id, false);
    can_configure_rx_mbox(can_id_manual_lift_rx_map.mbox_num, can_id_manual_lift_rx_map.can_id, false);

    can_register_mbox_irq_callback(RX, clb);
    can_init_irqs();
    GPIO_setHigh(halHandle->gpioHandle,GREEN_LED.gpio_num);
    //HAL_turnLedOff(halHandle,(GPIO_Number_e)HAL_Gpio_LED3);
    /* for(;;)
     {
         trace(100);
     }*/
    for(;;)
    {
        //can_write(25, 0x01010101DEADBEEFull);
        // Waiting for enable system flag to be set
        while(!(gMotorVars.Flag_enableSys));

        // Dis-able the Library internal PI.  Iq has no reference now
#ifdef LEARN
        CTRL_setFlag_enableSpeedCtrl(ctrlHandle, false); // false - learn
#else
        CTRL_setFlag_enableSpeedCtrl(ctrlHandle, true); // false - learn
#endif

        // loop while the enable system flag is true
        while(gMotorVars.Flag_enableSys)
        {
            CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle;
            ST_Obj *stObj = (ST_Obj *)stHandle;

            //int32_t ang = (int32_t)(_IQtoF(EST_getAngle_pu(obj->estHandle)) * 1000);
            //int32_t sp = (int32_t)(_IQtoF(gMotorVars.Speed_krpm) * 1000);

            // increment counters
            gCounter_updateGlobals++;

            // enable/disable the use of motor parameters being loaded from user.h
            CTRL_setFlag_enableUserMotorParams(ctrlHandle,gMotorVars.Flag_enableUserParams);

            // enable/disable Rs recalibration during motor startup
            EST_setFlag_enableRsRecalc(obj->estHandle,gMotorVars.Flag_enableRsRecalc);

            // enable/disable automatic calculation of bias values
            CTRL_setFlag_enableOffset(ctrlHandle,gMotorVars.Flag_enableOffsetcalc);


            if(CTRL_isError(ctrlHandle))
            {
                // set the enable controller flag to false
                CTRL_setFlag_enableCtrl(ctrlHandle,false);

                // set the enable system flag to false
                gMotorVars.Flag_enableSys = false;

                // disable the PWM
                HAL_disablePwm(halHandle);
            }
            else
            {
                // update the controller state
                bool flag_ctrlStateChanged = CTRL_updateState(ctrlHandle);

                // enable or disable the control
                CTRL_setFlag_enableCtrl(ctrlHandle, gMotorVars.Flag_Run_Identify);

                if(flag_ctrlStateChanged)
                {
                    CTRL_State_e ctrlState = CTRL_getState(ctrlHandle);

                    if(ctrlState == CTRL_State_OffLine)
                    {
                        // enable the PWM
                        HAL_enablePwm(halHandle);
                    }
                    else if(ctrlState == CTRL_State_OnLine)
                    {
                        if(gMotorVars.Flag_enableOffsetcalc == true)
                        {
                            // update the ADC bias values
                            HAL_updateAdcBias(halHandle);
                        }
                        else
                        {
                            // set the current bias
                            HAL_setBias(halHandle,HAL_SensorType_Current,0,_IQ(I_A_offset));
                            HAL_setBias(halHandle,HAL_SensorType_Current,1,_IQ(I_B_offset));
                            HAL_setBias(halHandle,HAL_SensorType_Current,2,_IQ(I_C_offset));

                            // set the voltage bias
                            HAL_setBias(halHandle,HAL_SensorType_Voltage,0,_IQ(V_A_offset));
                            HAL_setBias(halHandle,HAL_SensorType_Voltage,1,_IQ(V_B_offset));
                            HAL_setBias(halHandle,HAL_SensorType_Voltage,2,_IQ(V_C_offset));
                        }

                        // Return the bias value for currents
                        gMotorVars.I_bias.value[0] = HAL_getBias(halHandle,HAL_SensorType_Current,0);
                        gMotorVars.I_bias.value[1] = HAL_getBias(halHandle,HAL_SensorType_Current,1);
                        gMotorVars.I_bias.value[2] = HAL_getBias(halHandle,HAL_SensorType_Current,2);

                        // Return the bias value for voltages
                        gMotorVars.V_bias.value[0] = HAL_getBias(halHandle,HAL_SensorType_Voltage,0);
                        gMotorVars.V_bias.value[1] = HAL_getBias(halHandle,HAL_SensorType_Voltage,1);
                        gMotorVars.V_bias.value[2] = HAL_getBias(halHandle,HAL_SensorType_Voltage,2);

                        // enable the PWM
                        HAL_enablePwm(halHandle);
                    }
                    else if(ctrlState == CTRL_State_Idle)
                    {
                        // disable the PWM
                        HAL_disablePwm(halHandle);
                        gMotorVars.Flag_Run_Identify = false;
                    }

                    if((CTRL_getFlag_enableUserMotorParams(ctrlHandle) == true) &&
                       (ctrlState > CTRL_State_Idle) &&
                       (gMotorVars.CtrlVersion.minor == 6))
                    {
                        // call this function to fix 1p6
                        USER_softwareUpdate1p6(ctrlHandle);
                    }

                }
            }


            if(EST_isMotorIdentified(obj->estHandle))
            {
                // set the current ramp
                EST_setMaxCurrentSlope_pu(obj->estHandle,gMaxCurrentSlope);
                gMotorVars.Flag_MotorIdentified = true;

                // set the speed reference
                CTRL_setSpd_ref_krpm(ctrlHandle,gMotorVars.SpeedRef_krpm);

                // set the speed acceleration
                CTRL_setMaxAccel_pu(ctrlHandle,_IQmpy(MAX_ACCEL_KRPMPS_SF,gMotorVars.MaxAccel_krpmps));

                // enable the SpinTAC Speed Controller
                STVELCTL_setEnable(stObj->velCtlHandle, true);

                if(EST_getState(obj->estHandle) != EST_State_OnLine)
                {
                    // if the estimator is not running, place SpinTAC into reset
                    STVELCTL_setEnable(stObj->velCtlHandle, false);

                    // if the estimator is not running, set SpinTAC Move start & end velocity to 0
                    STVELMOVE_setVelocityEnd(stObj->velMoveHandle, _IQ(0.0));
                    STVELMOVE_setVelocityStart(stObj->velMoveHandle, _IQ(0.0));

                }

                if(Flag_Latch_softwareUpdate)
                {
                    Flag_Latch_softwareUpdate = false;

                    USER_calcPIgains(ctrlHandle);

                    // initialize the watch window kp and ki current values with pre-calculated values
                    //gMotorVars.Kp_Idq = CTRL_getKp(ctrlHandle,CTRL_Type_PID_Id);
                    //gMotorVars.Ki_Idq = CTRL_getKi(ctrlHandle,CTRL_Type_PID_Id);

                    //gMotorVars.Kp_spd = CTRL_getKp(ctrlHandle,CTRL_Type_PID_spd);
                    //gMotorVars.Ki_spd = CTRL_getKi(ctrlHandle,CTRL_Type_PID_spd);

                    // initialize the watch window Bw value with the default value
#ifndef LEARN
                    gMotorVars.SpinTAC.VelCtlBw_radps = STVELCTL_getBandwidth_radps(stObj->velCtlHandle);
#endif
                    // initialize the watch window with maximum and minimum Iq reference
                    gMotorVars.SpinTAC.VelCtlOutputMax_A = _IQmpy(STVELCTL_getOutputMaximum(stObj->velCtlHandle), _IQ(USER_IQ_FULL_SCALE_CURRENT_A));
                    gMotorVars.SpinTAC.VelCtlOutputMin_A = _IQmpy(STVELCTL_getOutputMinimum(stObj->velCtlHandle), _IQ(USER_IQ_FULL_SCALE_CURRENT_A));
                }

            }
            else
            {
                Flag_Latch_softwareUpdate = true;

                // the estimator sets the maximum current slope during identification
                gMaxCurrentSlope = EST_getMaxCurrentSlope_pu(obj->estHandle);

            }


            // when appropriate, update the global variables
            if(gCounter_updateGlobals >= NUM_MAIN_TICKS_FOR_GLOBAL_VARIABLE_UPDATE)
            {
                // reset the counter
                gCounter_updateGlobals = 0;

                updateGlobalVariables_motor(ctrlHandle, stHandle);
            }


            // update Kp and Ki gains
            //updateKpKiGains(ctrlHandle);

            // set the SpinTAC (ST) bandwidth scale
#ifndef LEARN
            STVELCTL_setBandwidth_radps(stObj->velCtlHandle, gMotorVars.SpinTAC.VelCtlBw_radps);
#endif
            // set the maximum and minimum values for Iq reference
            STVELCTL_setOutputMaximums(stObj->velCtlHandle, _IQmpy(gMotorVars.SpinTAC.VelCtlOutputMax_A, _IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A)), _IQmpy(gMotorVars.SpinTAC.VelCtlOutputMin_A, _IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A)));

            // enable/disable the forced angle
            //EST_setFlag_enableForceAngle(obj->estHandle,gMotorVars.Flag_enableForceAngle);
            if (global_speed < 100 && global_speed > -100){
                EST_setFlag_enableForceAngle(obj->estHandle,true);
                gMotorVars.Flag_enableForceAngle = true;
            }
            else {
                EST_setFlag_enableForceAngle(obj->estHandle, false);
                gMotorVars.Flag_enableForceAngle = false;
            }

            // enable or disable power warp
            CTRL_setFlag_enablePowerWarp(ctrlHandle,gMotorVars.Flag_enablePowerWarp);

            //HAL_writeDrvData(halHandle,&gDrvSpi8323Vars);
            //sendParams();
            //HAL_readDrvData(halHandle,&gDrvSpi8323Vars);
        } // end of while(gFlag_enableSys) loop


        // disable the PWM
        HAL_disablePwm(halHandle);

        // set the default controller parameters (Reset the control to re-identify the motor)
        CTRL_setParams(ctrlHandle,&gUserParams);
        gMotorVars.Flag_Run_Identify = false;

        // setup the SpinTAC Components
        ST_setupVelCtl(stHandle);
#ifndef LEARN
        ST_setupVelMove(stHandle);
#endif

    } // end of for(;;) loop

} // end of main() function

uint16_t fl = 0;

bool prev_gpio_state = 0;

interrupt void mainISR(void)
{
    GPIO_setHigh(halHandle->gpioHandle,GPIO_Number_8);
    static uint16_t stCnt = 0;

    pwm_generator(duty_cycle_percent);
    pwm_cnt++;

    bool lift_enc_state = GPIO_read(halHandle->gpioHandle,LIFT_ENC.gpio_num);
    if(lift_enc_state == 0 && prev_gpio_state == 1)
    {
        enc++;
    }
    prev_gpio_state = lift_enc_state;

    // toggle status LED

#ifdef SCIENCE_MODE_HZ
    if(++gScienceCnt>= (uint_least32_t)(USER_ISR_FREQ_Hz / SCIENCE_MODE_HZ))
    {
        //gMotorVars.SpeedRef_krpm = _IQ(0.0);
        //sendParams();
        can_configure_tx_mbox(17, 0x00000003, 8);
        can_write(17, enc);
        can_configure_tx_mbox(18, 0x00000004, 8);
        can_write(18, gMotorVars.Flag_enableSys);
        can_configure_tx_mbox(10, 0x00000005, 4);
       /* can_configure_tx_mbox(18, 0x00000004, 8);
        can_write(18, lift_enc_state);
        can_configure_tx_mbox(19, 0x00000005, 8);
        can_write(19, prev_gpio_state);
*/
        gScienceCnt = 0;
    }
#endif


    if(++gTIMEOUT_SPEEDcnt >= (uint_least32_t)(USER_ISR_FREQ_Hz / (1000 /  SPEED_RX_TIMEOUT_MS)))
    {
        gMotorVars.SpeedRef_krpm = _IQ(0.0);
        gTIMEOUT_SPEEDcnt = 0;
    }

    if(++gTIMEOUT_LIFTcnt >= (uint_least32_t)(USER_ISR_FREQ_Hz / (1000 /  LIFT_RX_TIMEOUT_MS))){
        //gMotorVars.SpeedRef_krpm = _IQ(0.0);
        if (LIFT_MANUAL_FLAG == true){
            lift(0 , 0xFF);
        }
        gTIMEOUT_LIFTcnt = 0;
    }

    if(LIFT_MANUAL_FLAG == false){
        if(enc >= LIFT_ENC_LIMIT){
            lift(0 , 0xFF);
            can_write(can_id_lift_done_tx_map.mbox_num, getUavCanPayload(0x01));
            enc = 0;
        }
    }

    /*if(++gTestcnt  >= (uint_least32_t)(USER_ISR_FREQ_Hz / TEST_SPEED_TIMEOUT_HZ))
    {
        if(fl == 0) {
#ifndef LEARN
            gMotorVars.SpeedRef_krpm = _IQ(-0.1);
#endif
            fl = 1;
        }
        else if (fl == 1)
        {
#ifndef LEARN
            gMotorVars.SpeedRef_krpm = _IQ(0.1);
#endif
            fl = 0;
        }
        gTestcnt  = 0;
    }*/

    if(++gLEDcnt >= (uint_least32_t)(USER_ISR_FREQ_Hz / LED_BLINK_FREQ_Hz))
    {
        //GPIO_toggle(halHandle->gpioHandle,GREEN_LED.gpio_num);
        GPIO_toggle(halHandle->gpioHandle,RED_LED.gpio_num);

        gLEDcnt = 0;
    }

    tachoObs(EST_getAngle_pu(ctrlHandle->estHandle));

    // Send tachometer on 100HZ
    if(++gTACHOcnt >= (uint_least32_t)(USER_ISR_FREQ_Hz / TACHO_SEND_FREQ_HZ))
    {
        int32_t tacho_copy = tacho;
        if (REVERSED == 1) tacho_copy *= -1;
        can_write(can_id_tacho_tx_map.mbox_num, getUavCanPayload(tacho_copy));
        gTACHOcnt = 0;
    }

    // acknowledge the ADC interrupt
    HAL_acqAdcInt(halHandle,ADC_IntNumber_1);


    // convert the ADC data
    HAL_readAdcData(halHandle,&gAdcData);


    // Run the SpinTAC Components
    if(stCnt++ >= ISR_TICKS_PER_SPINTAC_TICK) {
#ifndef LEARN
        ST_runVelMove(stHandle, ctrlHandle);
#endif
        ST_runVelCtl(stHandle, ctrlHandle);
        stCnt = 1;
    }

    //trace(11);
    // run the controller
    CTRL_run(ctrlHandle,halHandle,&gAdcData,&gPwmData);


    // write the PWM compare values
    HAL_writePwmData(halHandle,&gPwmData);


    // setup the controller
    CTRL_setup(ctrlHandle);

    GPIO_setLow(halHandle->gpioHandle,GPIO_Number_8);
    return;
} // end of mainISR() function


void updateGlobalVariables_motor(CTRL_Handle handle, ST_Handle sthandle)
{
    CTRL_Obj *obj = (CTRL_Obj *)handle;
    ST_Obj *stObj = (ST_Obj *)sthandle;


    // get the speed estimate
    gMotorVars.Speed_krpm = EST_getSpeed_krpm(obj->estHandle);

    // get the real time speed reference coming out of the speed trajectory generator
    gMotorVars.SpeedTraj_krpm = _IQmpy(CTRL_getSpd_int_ref_pu(handle),EST_get_pu_to_krpm_sf(obj->estHandle));

    // get the torque estimate
    gMotorVars.Torque_Nm = USER_computeTorque_Nm(handle, gTorque_Flux_Iq_pu_to_Nm_sf, gTorque_Ls_Id_Iq_pu_to_Nm_sf);

    // get the magnetizing current
    gMotorVars.MagnCurr_A = EST_getIdRated(obj->estHandle);

    // get the rotor resistance
    gMotorVars.Rr_Ohm = EST_getRr_Ohm(obj->estHandle);

    // get the stator resistance
    gMotorVars.Rs_Ohm = EST_getRs_Ohm(obj->estHandle);

    // get the stator inductance in the direct coordinate direction
    gMotorVars.Lsd_H = EST_getLs_d_H(obj->estHandle);

    // get the stator inductance in the quadrature coordinate direction
    gMotorVars.Lsq_H = EST_getLs_q_H(obj->estHandle);

    // get the flux in V/Hz in floating point
    gMotorVars.Flux_VpHz = EST_getFlux_VpHz(obj->estHandle);

    // get the flux in Wb in fixed point
    gMotorVars.Flux_Wb = USER_computeFlux(handle, gFlux_pu_to_Wb_sf);

    // get the controller state
    gMotorVars.CtrlState = CTRL_getState(handle);

    // get the estimator state
    gMotorVars.EstState = EST_getState(obj->estHandle);

    // Get the DC buss voltage
    gMotorVars.VdcBus_kV = _IQmpy(gAdcData.dcBus,_IQ(USER_IQ_FULL_SCALE_VOLTAGE_V/1000.0));

    // get the Iq reference from the speed controller
    gMotorVars.IqRef_A = _IQmpy(STVELCTL_getTorqueReference(stObj->velCtlHandle), _IQ(USER_IQ_FULL_SCALE_CURRENT_A));

    // gets the Velocity Controller status
    gMotorVars.SpinTAC.VelCtlStatus = STVELCTL_getStatus(stObj->velCtlHandle);

    // get the inertia setting
    gMotorVars.SpinTAC.InertiaEstimate_Aperkrpm = _IQmpy(STVELCTL_getInertia(stObj->velCtlHandle), _IQ(ST_SPEED_PU_PER_KRPM * USER_IQ_FULL_SCALE_CURRENT_A));

    // get the friction setting
    gMotorVars.SpinTAC.FrictionEstimate_Aperkrpm = _IQmpy(STVELCTL_getFriction(stObj->velCtlHandle), _IQ(ST_SPEED_PU_PER_KRPM * USER_IQ_FULL_SCALE_CURRENT_A));

    // get the Velocity Controller error
    gMotorVars.SpinTAC.VelCtlErrorID = STVELCTL_getErrorID(stObj->velCtlHandle);
#ifndef LEARN
    // get the Velocity Move status
    gMotorVars.SpinTAC.VelMoveStatus = STVELMOVE_getStatus(stObj->velMoveHandle);

    // get the Velocity Move profile time
    gMotorVars.SpinTAC.VelMoveTime_ticks = STVELMOVE_getProfileTime_tick(stObj->velMoveHandle);

    // get the Velocity Move error
    gMotorVars.SpinTAC.VelMoveErrorID = STVELMOVE_getErrorID(stObj->velMoveHandle);
#endif


    return;
} // end of updateGlobalVariables_motor() function


void updateKpKiGains(CTRL_Handle handle)
{
    if((gMotorVars.CtrlState == CTRL_State_OnLine) && (gMotorVars.Flag_MotorIdentified == true) && (Flag_Latch_softwareUpdate == false))
    {
        // set the kp and ki speed values from the watch window
        CTRL_setKp(handle,CTRL_Type_PID_spd,gMotorVars.Kp_spd);
        CTRL_setKi(handle,CTRL_Type_PID_spd,gMotorVars.Ki_spd);

        // set the kp and ki current values for Id and Iq from the watch window
        CTRL_setKp(handle,CTRL_Type_PID_Id,gMotorVars.Kp_Idq);
        CTRL_setKi(handle,CTRL_Type_PID_Id,gMotorVars.Ki_Idq);
        CTRL_setKp(handle,CTRL_Type_PID_Iq,gMotorVars.Kp_Idq);
        CTRL_setKi(handle,CTRL_Type_PID_Iq,gMotorVars.Ki_Idq);
    }

    return;
} // end of updateKpKiGains() function

void ST_runVelMove(ST_Handle handle, CTRL_Handle ctrlHandle)
{

    ST_Obj *stObj = (ST_Obj *)handle;
    CTRL_Obj *ctrlObj = (CTRL_Obj *)ctrlHandle;

    // Run SpinTAC Move
    // If we are not in reset, and the SpeedRef_krpm has been modified
    if((EST_getState(ctrlObj->estHandle) == EST_State_OnLine) && (_IQmpy(gMotorVars.SpeedRef_krpm, _IQ(ST_SPEED_PU_PER_KRPM)) != STVELMOVE_getVelocityEnd(stObj->velMoveHandle))) {
        // Get the configuration for SpinTAC Move
        STVELMOVE_setCurveType(stObj->velMoveHandle, gMotorVars.SpinTAC.VelMoveCurveType);
        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)));
        // Enable SpinTAC Move
        STVELMOVE_setEnable(stObj->velMoveHandle, true);
        // If starting from zero speed, enable ForceAngle, otherwise disable ForceAngle
        //if(_IQabs(STVELMOVE_getVelocityStart(stObj->velMoveHandle)) < _IQ(ST_MIN_ID_SPEED_PU)) {
        if (global_speed < 100 && global_speed > -100){
            EST_setFlag_enableForceAngle(ctrlObj->estHandle, true);
            gMotorVars.Flag_enableForceAngle = true;
        }
        else {
            EST_setFlag_enableForceAngle(ctrlObj->estHandle, false);
            gMotorVars.Flag_enableForceAngle = false;
        }
    }
    STVELMOVE_run(stObj->velMoveHandle);
}

void ST_runVelCtl(ST_Handle handle, CTRL_Handle ctrlHandle)
{
    _iq speedFeedback, iqReference;
    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
#ifndef LEARN
    STVELCTL_setVelocityReference(stObj->velCtlHandle, STVELMOVE_getVelocityReference(stObj->velMoveHandle));
    STVELCTL_setAccelerationReference(stObj->velCtlHandle, STVELMOVE_getAccelerationReference(stObj->velMoveHandle));
#else
    STVELCTL_setVelocityReference(stObj->velCtlHandle, TRAJ_getIntValue(ctrlObj->trajHandle_spd));
    STVELCTL_setAccelerationReference(stObj->velCtlHandle, _IQ(0.0));   // Internal ramp generator does not provide Acceleration Reference
#endif
    STVELCTL_setVelocityFeedback(stObj->velCtlHandle, speedFeedback);
    STVELCTL_run(stObj->velCtlHandle);

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

    // Set the Iq reference that came out of SpinTAC Velocity Control
    CTRL_setIq_ref_pu(ctrlHandle, iqReference);
}


//@} //defgroup
// end of file
include_user (1).h