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.
Hello,
In lab_13a project, I'd like to align the eQEP angle with the rotor angle without using the following code in proj_lab13a.c :
if((EST_getState(obj->estHandle) == EST_State_Rs) && (USER_MOTOR_TYPE == MOTOR_Type_Pm))
{
ENC_setZeroOffset(encHandle, (uint32_t)(HAL_getQepPosnMaximum(halHandle) - HAL_getQepPosnCounts(halHandle)));
}
any solutions?
best regards,
Hi Chris,
I don't want to force the rotor at starting of the motor.
Otherwise, Knowing inside my motor a hall effect sensor is implemented, I want to occur the zero offset of the encoder. currently 'enc_zero_offset' =0.
But at starting we don't know this offest, that is why I'd like to integrate some code of hall sensors into instaspin motion, just for getting this offset and refresh the
" temp += enc->enc_zero_offset " .
thank you in advance for your collaboration.
Best regards
Hi chris,
" but it really won't be that accurate "
what's the best method for the alignment without forcing the rotor?
"hall sensors will give you 15 degrees maximum"
Why 15 degrees?
"there are a few threads about adding hall sensor readings to MotorWare"
I have some threads (code C to configure hall sensors), but I encountered difficulties to adapt it with project lab_13a, are you have some diagrams or steps to follow, for getting a best configurations ?
think you in advance
Regards,
" this is based on having 6 states and 3 sensors "
I found a sector of 20 degrees, 360/6 = 60 degrees electrical angle, and 60/3 = 20 degrees (3 sensors). I am a taker if you exhibit the mode operating of the three hall sensors!
" You can only say the rotor is in a sector, not at a specific location "
Is that by using eCAP setup?
In this case, how can I encode the digital states of the hall sensors ?
Hi Chris,
Now I am with the configuration of the hall sensor.
I have another question about the direction of the motor, knowing I ran labs 12 and 13 successfuly, my motor give sometimes a positive torque, and sometimes a negative torque!
any suggestions?
Regards,
When these changes are happened, it's not good for my project.
adam, usually each time the motor is runnig must produce the same torque for the same iq_reference.
I miss something!
Hi Adam & Chris,
I am sorry to bother you, perhaps I have a beug in my project.
Can you take a look (torque control with an incremental encoder):
/* --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_lab13a.c //! \brief Tuning the InstaSPIN-MOTION Position Controller //! //! (C) Copyright 2012, LineStream Technologies, Inc. //! (C) Copyright 2011, Texas Instruments, Inc. //! \defgroup PROJ_LAB13A PROJ_LAB13A //@{ //! \defgroup PROJ_LAB13A_OVERVIEW Project Overview //! //! Tuning the InstaSPIN-MOTION Position Controller //! // ************************************************************************** // the includes // system includes #include <math.h> #include "main_position.h" #ifdef FLASH #pragma CODE_SECTION(mainISR,"ramfuncs"); #endif // Include header files used in the main function #include "sw/modules/ctrl/src/32b/ctrl.h" // drivers #include "sw/drivers/qep/src/32b/f28x/f2806x/qep.h" // etait juste "hal_obj.h" #include "sw/modules/hal/boards/drv8312kit_revD/f28x/f2806x/src/hal_obj.h" #include "sw/modules/ctrl/src/32b/ctrl_obj.h" #include "sw/modules/ctrl/src/32b/ctrlQEP.h" #include "sw/modules/enc/src/32b/enc.h" #include "sw/modules/hal/boards/drv8312kit_revD/f28x/f2806x/src/hal.h" #include "sw/modules/iqmath/src/32b/IQmathLib.h" // ************************************************************************** // the defines #define LED_BLINK_FREQ_Hz 5 // ************************************************************************** // 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); // ----------------------------- -arez added- -------------------------------------------- // !!! le courant limite : min , max / en respectant la plage du fonctionnement nominale // !!! variables du moteur // !!! voir la datasheet du moteur Faulhaber : 'EN_2250_BX4_DFF' _iq courant_max = _IQ(1.0); // courant max _iq courant_min = _IQ(-1.0); // courant min _iq15 K_motor = _IQ15(0.0375); // la constante Km du moteur [Nm/A] // !!! les variables intermideaire du programme _iq convVitesse = _IQ(0.0); // une variable intermediare pour la conversion de la vitesse en SI _iq posMrev = _IQ(0.0); _iq15 IqRef_Amper_Iq15 = _IQ15(0.0); // !!! les termes de position _iq15 Pos_Motor_rad = _IQ15(0.0); _iq15 Pos_Articulaire_rad = _IQ15(0.0); float_t Pos_Articulaire_degre = 0.0; int32_t Position_Brut = 0 ; // ! essayer avec int32_t int32_t Position_Brut_init = 0 ; // revoir le type de position float_t Potard_Actuel = 0.0; // la position du potard en per unit float_t Pos_Mot_issuPotar_rad = 0.0 ; // position du moteur issue de potar float_t Pos_Art_Reel = 0.0 ; // position articulaire reel float_t Pos_Art_Reel_rad = 0.0; // position reel en rad float_t offset_absolu = 0.0 ; // offset entre encodeur et le potar float_t potar_simulation = 4095.0 ; // la position en pleine acceleration float_t Pos_Art_Reel_degre = 0.0; // position absolue en degre float_t Position_Moteur_offset_rad = 0.0 ; // position du moteur avec l'offset de potar // !!! les termes de vitesse _iq15 Vitesse_Motor_rad_s = _IQ15(0.0); _iq15 Vitesse_Motor_rad_s1 = _IQ15(0.0); _iq24 vitesse_encodeur_Hz = _IQ24(0.0); int16_t vitesse_encodeur_rpm = 0; _iq15 vitesse_encodeur_radps = _IQ15(0.0); _iq encAngle = _IQ(0.0); // !!! les unit�s de conversion en SI // ajouter aussi le sens de rotation float_t unitePosition = 0.001533981 ; // ( 2 * PI) /gMotorVars.IMPULSION_Tour , 4*nb, nb = 1024 ; _iq15 uniteVitesse = _IQ15(649.2624816); // 1000 * PI * 6.2/30 //_iq15 uniteVitesse = _IQ15(104.7197551); // 1000 * PI/30 //----------------------------------------------------------------------------------------------------------- #ifdef FAST_ROM_V1p6 CTRL_Obj *controller_obj; #else CTRL_Obj ctrl; //v1p7 format #endif ENC_Handle encHandle; ENC_Obj enc; SLIP_Handle slipHandle; SLIP_Obj slip; ST_Obj st_obj; ST_Handle stHandle; uint16_t gLEDcnt = 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 #ifdef DRV8301_SPI // Watch window interface to the 8301 SPI DRV_SPI_8301_Vars_t gDrvSpi8301Vars; #endif _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 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); #endif // 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); // 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); // set the hardware abstraction layer parameters HAL_setParams(halHandle,&gUserParams); // 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 global interrupts HAL_enableGlobalInts(halHandle); // enable debug interrupts HAL_enableDebugInt(halHandle); // disable the PWM HAL_disablePwm(halHandle); // initialize the ENC module encHandle = ENC_init(&enc, sizeof(enc)); // setup the ENC module : arez: au lieu hal_obj->qepHandle[0] �tait 1 //HAL_Obj *hal_obj = (HAL_Obj *)halHandle; // ancienne version de motorware // type : void ENC_setup(ENC_Handle encHandle, const int16_t sample_period, const uint16_t num_pole_pairs, const uint16_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) // attention l'offset n'est pas zero ENC_setup(encHandle,1, USER_MOTOR_NUM_POLE_PAIRS, USER_MOTOR_ENCODER_LINES, 0, USER_IQ_FULL_SCALE_FREQ_Hz, USER_ISR_FREQ_Hz, 8000.0); // initialize the SLIP module slipHandle = SLIP_init(&slip, sizeof(slip)); // setup the SLIP module SLIP_setup(slipHandle, _IQ(gUserParams.ctrlPeriod_sec)); // initialize the SpinTAC Components stHandle = ST_init(&st_obj, sizeof(st_obj)); // setup the SpinTAC Components ST_setupPosConv(stHandle); // ST_setupPosCtl(stHandle); #ifdef DRV8301_SPI // turn on the DRV8301 if present HAL_enableDrv(halHandle); // initialize the DRV8301 interface HAL_setupDrvSpi(halHandle,&gDrvSpi8301Vars); #endif // 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(); for(;;) { // Waiting for enable system flag to be set while(!(gMotorVars.Flag_enableSys)); // Dis-able the Library internal PI. Iq has no reference now CTRL_setFlag_enableSpeedCtrl(ctrlHandle, false); // loop while the enable system flag is true while(gMotorVars.Flag_enableSys) { CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle; ST_Obj *stObj = (ST_Obj *)stHandle; // 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,STPOSMOVE_getVelocityReference(stObj->posMoveHandle)); // set the speed acceleration // CTRL_setMaxAccel_pu(ctrlHandle,_IQmpy(MAX_ACCEL_KRPMPS_SF,gMotorVars.MaxAccel_krpmps)); // enable the SpinTAC Position Controller // STPOSCTL_setEnable(stObj->posCtlHandle, true); /* if(EST_getState(obj->estHandle) != EST_State_OnLine) { // if the system is not running, disable SpinTAC Position Controller STPOSCTL_setEnable(stObj->posCtlHandle, false); }*/ if(Flag_Latch_softwareUpdate) { Flag_Latch_softwareUpdate = false; // arez : y'a aussi la mise � jour des gains 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); // initialize the watch window Bw value with the default value //gMotorVars.SpinTAC.PosCtlBw_radps = STPOSCTL_getBandwidth_radps(stObj->posCtlHandle); // initialize the watch window with maximum and minimum Iq reference // gMotorVars.SpinTAC.PosCtlOutputMax_A = _IQmpy(STPOSCTL_getOutputMaximum(stObj->posCtlHandle), _IQ(USER_IQ_FULL_SCALE_CURRENT_A)); //gMotorVars.SpinTAC.PosCtlOutputMin_A = _IQmpy(STPOSCTL_getOutputMinimum(stObj->posCtlHandle), _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); } // !!! Effort Articulaire : send a torque reference // ! type float TorqueArti_Nm = Torque.effort; // !!! Torque Motor de type float // !!! division over the gear TorqueMotor_Nm = (TorqueArti_Nm / Reducteur); // conversion torque motor to iq15 // !!! IqRef_Amper_Iq15 is the current equivalent of the effort [Amper] IqRef_Amper_Iq15 = _IQ15div(_IQ15(TorqueMotor_Nm) , K_motor); // I = T/ K // !!! send force to the motor /* ----------------------------------------------------------------------------- manipuler les consignes sous forme des courants ---------------------------------------------------------------------------- */ // !!! la conversion du courant en format IQ 24 gMotorVars.IqRef_A = _IQ15toIQ(IqRef_Amper_Iq15); // !!! Saturation du courant de r�ference if (gMotorVars.IqRef_A > courant_max ) { gMotorVars.IqRef_A = courant_max; // borne max + } else if (gMotorVars.IqRef_A < courant_min) { gMotorVars.IqRef_A = courant_min; // borne min - } /*''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' */ // !!! gMotorVars.IqRef_A : est calcul� par la relation precedente // !!! arez lab5a : update Iq reference updateIqRef (ctrlHandle); // resultats mieux que dans mainISR // update Kp and Ki gains updateKpKiGains(ctrlHandle); // set the SpinTAC (ST) bandwidth scale //STPOSCTL_setBandwidth_radps(stObj->posCtlHandle, gMotorVars.SpinTAC.PosCtlBw_radps); // set the maximum and minimum values for Iq reference //STPOSCTL_setOutputMaximums(stObj->posCtlHandle, _IQmpy(gMotorVars.SpinTAC.PosCtlOutputMax_A, _IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A)), _IQmpy(gMotorVars.SpinTAC.PosCtlOutputMin_A, _IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A))); // enable/disable the forced angle // arez gMotorVars.Flag_enableForceAngle = 0; EST_setFlag_enableForceAngle(obj->estHandle,gMotorVars.Flag_enableForceAngle); // enable or disable power warp CTRL_setFlag_enablePowerWarp(ctrlHandle,gMotorVars.Flag_enablePowerWarp); #ifdef DRV8301_SPI HAL_writeDrvData(halHandle,&gDrvSpi8301Vars); HAL_readDrvData(halHandle,&gDrvSpi8301Vars); #endif } // 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_setupPosConv(stHandle); //ST_setupPosCtl(stHandle); } // end of for(;;) loop } // end of main() function interrupt void mainISR(void) { static uint16_t stCnt = 0; CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle; // toggle status LED if(gLEDcnt++ > (uint_least32_t)(USER_ISR_FREQ_Hz / LED_BLINK_FREQ_Hz)) { HAL_toggleLed(halHandle,(GPIO_Number_e)HAL_Gpio_LED2); gLEDcnt = 0; } // compute the electrical angle ENC_calcElecAngle(encHandle, HAL_getQepPosnCounts(halHandle)); //ENC_run(encHandle, uint32_t posnCounts, uint16_t indextFlag, uint16_t dirFlag, int16_t log_flag); //! \brief Based on the encoder reading, computes the electrical angle and the electrical "speed" //! \param[in] encHandle Handle to the ENC object //! \param[in] posnCounts Current position counts from encoder //! \param[in] indextFlag If set, there was an index //! \param[in] dirFlag Indicates direction of rotation //! \param[in] log_flag If set, logs the encoder data //! \return Nothing // arez: ENC_run(ENC_Handle encHandle, uint32_t posnCounts, uint16_t indextFlag, uint16_t dirFlag, int16_t log_flag) //ENC_run(encHandle, HAL_getQepPosnCounts(halHandle), HAL_getQepIndexFlag(halHandle), 0 , 0); //arez: calculer la vitesse en hz � partir de l'encodeur //vitesse_encodeur_Hz = ENC_getFilteredSpeed(encHandle); //arez: calculer la vitesse en tour par minute //vitesse_encodeur_rpm = ENC_getSpeedRPM(encHandle); // arez: calculer l'angle electrique � partir de l'encodeur //encAngle = ENC_getElecAngle(encHandle); // 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) { ST_runPosConv(stHandle, encHandle, ctrlHandle); //ST_runPosCtl(stHandle, ctrlHandle); // on remplace CTRL_setIq_ref_pu d�fini dans ST_runPosCtl par celle du FOC : //updateIqRef (ctrlHandle); //voir la difference entre maisISR er dans main // conclusion : cause une mise � jour rapide qui influence sur CTRL, moins d'effort stCnt = 1; } if(USER_MOTOR_TYPE == MOTOR_Type_Induction) { // update the electrical angle for the SLIP module SLIP_setElectricalAngle(slipHandle, ENC_getElecAngle(encHandle)); // compute the amount of slip SLIP_run(slipHandle); // run the controller CTRL_run(ctrlHandle,halHandle,&gAdcData,&gPwmData,SLIP_getMagneticAngle(slipHandle)); } else { // run the controller CTRL_run(ctrlHandle,halHandle,&gAdcData,&gPwmData,ENC_getElecAngle(encHandle)); } // write the PWM compare values HAL_writePwmData(halHandle,&gPwmData); // setup the controller CTRL_setup(ctrlHandle); //----------------------------------------------------------------------------------------------------------------------------- // if we are forcing alignment, using the Rs Recalculation, align the eQEP angle with the rotor angle // I disabled Rs recalibration if((EST_getState(obj->estHandle) == EST_State_Rs) && (USER_MOTOR_TYPE == MOTOR_Type_Pm)) { ENC_setZeroOffset(encHandle, (uint32_t)(HAL_getQepPosnMaximum(halHandle) - HAL_getQepPosnCounts(halHandle))); } 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 = _IQmpy(STPOSCONV_getVelocityFiltered(stObj->posConvHandle), _IQ(ST_SPEED_KRPM_PER_PU)); // get the position error gMotorVars.PositionError_MRev = STPOSCTL_getPositionError_mrev(stObj->posCtlHandle); // 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 position controller //gMotorVars.IqRef_A = _IQmpy(STPOSCTL_getTorqueReference(stObj->posCtlHandle), _IQ(USER_IQ_FULL_SCALE_CURRENT_A)); //gMotorVars.IqRef_A =_IQ15toIQ(IqRef_Amper_Iq15); // gets the Position Controller status //gMotorVars.SpinTAC.PosCtlStatus = STPOSCTL_getStatus(stObj->posCtlHandle); // get the inertia setting //gMotorVars.SpinTAC.InertiaEstimate_Aperkrpm = _IQmpy(STPOSCTL_getInertia(stObj->posCtlHandle), _IQ(ST_SPEED_PU_PER_KRPM * USER_IQ_FULL_SCALE_CURRENT_A)); // get the friction setting //gMotorVars.SpinTAC.FrictionEstimate_Aperkrpm = _IQmpy(STPOSCTL_getFriction(stObj->posCtlHandle), _IQ(ST_SPEED_PU_PER_KRPM * USER_IQ_FULL_SCALE_CURRENT_A)); // get the Position Controller error //gMotorVars.SpinTAC.PosCtlErrorID = STPOSCTL_getErrorID(stObj->posCtlHandle); // get the Position Converter error gMotorVars.SpinTAC.PosConvErrorID = STPOSCONV_getErrorID(stObj->posConvHandle); return; } // end of updateGlobalVariables_motor() function /******************************** arez function ********************************************************* */ void updateIqRef(CTRL_Handle handle) { _iq iq_ref = _IQmpy(gMotorVars.IqRef_A,_IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A)); // set the speed reference so that the forced angle rotates in the correct direction for startup if(_IQabs(gMotorVars.Speed_krpm) < _IQ(0.01)) { if(iq_ref < _IQ(0.0)) { CTRL_setSpd_ref_krpm(handle,_IQ(-0.01)); } else if(iq_ref > _IQ(0.0)) { CTRL_setSpd_ref_krpm(handle,_IQ(0.01)); } } // Set the Iq reference that use to come out of the PI speed control CTRL_setIq_ref_pu(handle, iq_ref); return; } // end of updateIqRef() 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_runPosConv(ST_Handle handle, ENC_Handle encHandle, CTRL_Handle ctrlHandle) { ST_Obj *stObj = (ST_Obj *)handle; // get the electrical angle from the ENC module STPOSCONV_setElecAngle_erev(stObj->posConvHandle, ENC_getElecAngle(encHandle)); if(USER_MOTOR_TYPE == MOTOR_Type_Induction) { // The CurrentVector feedback is only needed for ACIM // get the vector of the direct/quadrature current input vector values from CTRL STPOSCONV_setCurrentVector(stObj->posConvHandle, CTRL_getIdq_in_addr(ctrlHandle)); } // run the SpinTAC Position Converter STPOSCONV_run(stObj->posConvHandle); if(USER_MOTOR_TYPE == MOTOR_Type_Induction) { // The Slip Velocity is only needed for ACIM // update the slip velocity in electrical angle per second, Q24 SLIP_setSlipVelocity(slipHandle, STPOSCONV_getSlipVelocity(stObj->posConvHandle)); } } /*void ST_runPosCtl(ST_Handle handle, CTRL_Handle ctrlHandle) { ST_Obj *stObj = (ST_Obj *)handle; // static float myPosRef=0; // provide the updated references to the SpinTAC Position Control STPOSCTL_setPositionReference_mrev(stObj->posCtlHandle, myPosRef); // _IQ(myPosRef) STPOSCTL_setVelocityReference(stObj->posCtlHandle, 0); STPOSCTL_setAccelerationReference(stObj->posCtlHandle, 0); // provide the feedback to the SpinTAC Position Control STPOSCTL_setPositionFeedback_mrev(stObj->posCtlHandle, STPOSCONV_getPosition_mrev(stObj->posConvHandle)); // Run SpinTAC Position Control STPOSCTL_run(stObj->posCtlHandle); // Provide SpinTAC Position Control Torque Output to the FOC CTRL_setIq_ref_pu(ctrlHandle, STPOSCTL_getTorqueReference(stObj->posCtlHandle)); } */ //@} //defgroup // end of file
thank you in advance
no, we will not review your code line by line looking for "bugs"
you haven't even described the problem fully
Hi Chris,
As I told you on the previous posts :
I am contolling the motor on the torque by inspiring from lab5a and 13a. I run my project successfully, I gave a positive Iq_ref as
current reference , then my motor ( has a load on the shaft ) spins in one direction, but after several tests, the direction changes the
sense and of the same reference of Iq_ref ,in this case, for preserving the first direction I was obliged to change the sense of current
reference (then negative one). 'I checked all parameters : IQ math format, frequencies, ...'
I hope it's clear clearman ^-^
Best regards,
Hi Chris,
" so you are using an encoder, but removing the position and velocity outputs from proj_lab13 to treat it as a torque control only? "
that is correct
" encoder alignment "
I run lab 12 and 13 successfully
" when you run in torque mode are you still setting a speed reference with the same sign as the torque Iq_Ref_A? "
as you can see it in my project, I set " updateIqRef (ctrlHandle); " before " updateKpKiGains(ctrlHandle); " , and updateIqRef
(ctrlHandle) insure a matching direction as :
void updateIqRef(CTRL_Handle handle) { _iq iq_ref = _IQmpy(gMotorVars.IqRef_A,_IQ(1.0/USER_IQ_FULL_SCALE_CURRENT_A)); // set the speed reference so that the forced angle rotates in the correct direction for startup if(_IQabs(gMotorVars.Speed_krpm) < _IQ(0.01)) { if(iq_ref < _IQ(0.0)) { CTRL_setSpd_ref_krpm(handle,_IQ(-0.01)); } else if(iq_ref > _IQ(0.0)) { CTRL_setSpd_ref_krpm(handle,_IQ(0.01)); } } // Set the Iq reference that use to come out of the PI speed control CTRL_setIq_ref_pu(handle, iq_ref); return; } // end of updateIqRef() function
note that I disabled the 'forced angle', I still setup my effect hall sensor to define my enc.offset.
Best regards,
if you have disabled RsRecal and aren't taking care of it in some other way, you aren't performing the zero'ing offset between the mechanical encoder and the electrical angle.
I know that altering my control strategy, but not the direction as I know, isn't it ?
So, that is my problem now .!
I am configuring the hall sensor as the example defined in this Rich's answer :
after computing the Hall offset, can I put it directely into 'enc.enc_zero_offset'?
Hi Chris,
After computing electrical angle by hall sensors, I took care of the mechanical and electrical angle.
knowing " ElecAngle = hallBits * SEGMENT_SIZE + MID_EDGE ", I found that varying "MID_EDGE" value is altering the sense of
rotation.
I don't find how to fix "MID_EDGE" value in my datasheets , do you have any suggestions?
Best regards,
Hi Wil,
- I am using projects in motor ware wich are based on the InstaSpin FOC & Motion.
- By default, in Labs12 & 13 with encoder (sensored projects), the angle zero is set it by the FAST observer (no code because it is defined in the library 'ROM'), this alignment is done by moving the rotor on open loop, when it settle down the FAST read this angle (enc.offset), which is integrated with electrical angle as : <electricalAngle = p * mechanicalAngle + offset >, where p=pole pair, offset is this angle which you called angle zero.
- Now, especially to my project, I read directely the hall sensors once, without FAST, so I replaced :
if((EST_getState(obj->estHandle) == EST_State_Rs) && (USER_MOTOR_TYPE == MOTOR_Type_Pm)) { ENC_setZeroOffset(encHandle, (uint32_t)(HAL_getQepPosnMaximum(halHandle) - HAL_getQepPosnCounts(halHandle))); }
by my code.
Best regards,
if((EST_getState(obj->estHandle) == EST_State_Rs) && (USER_MOTOR_TYPE == MOTOR_Type_Pm))
{
ENC_setZeroOffset(encHandle, (uint32_t)(HAL_getQepPosnMaximum(halHandle) - HAL_getQepPosnCounts(halHandle)));
}
Hi Wil,
ok. I try to help you.
" HALL sensors reading " --> these sensors measure the presence of a magnetic field, then just at start-up I read the position by coding the hallBits without moving the motor (from GPIOs as shown in last post where I posted my diagram), after some transformation (IQ24, pu, ..) I put gMotorElecAngle_pu as my enc.offset.
concerning the segment_size and mid egde I reffered to Rich's answers as :
refering to my maps, I have six discrete angles that I can observe with three bits (2 ^ 3 - 2). That's 180 / 6 which is 30 degrees. The midpoint from edge offset then needs to be half of that so that my reported angle is in the middle of the angle segment. So in this case is 15 . And the segment size is 30."
In your case Wil I don't know what you have as mapping halls!. you can follow my discussion with Rich and deduct your own mapping.
Best regards,
Hi Wil,
Yes, I am still doing FOC, I can read my offset correctely but the program is not stable, so I have the problem of change direction of the motor!
If you want post me your hall sensors datasheet for getting more information.
Best regards,