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
/* --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