Other Parts Discussed in Thread: TMS320F28069
Hey all,
I'm currently struggling with implementing an insta-spin solution for the TMS320F28069 using the DRV8301-HC kit; I'm mostly having issues with the API for controlling system behavior.
My current setup is primarly based on the insta-spin labs (Lab 2a/3a), with changes to allow me to set the motor parameters (Rs, Ls, flux, etc) in run-time. The goal of this is to allow the finished device to perform an identification, saving parameters to nonvolatile memory. Afterwards the device uses the saved parameters for operation. An alternate use case is externally input parameters, such as over an UART interface. So far, what I have done is set all the motor parameters in user.h to 0/NULL, in other words;
- I_A/B/C_offset = 0
- V_A/B/C_offset = 0
- USER_MOTOR_TYPE = NULL
- USER_MOTOR_NUM_POLE_PAIRS = NULL
- ... down to ...
- USER_MOTOR_MAX_CURRENT = NULL
- USER_MOTOR_FLUX_EST_FREQ_Hz = NULL
- ... along with the dependant defines ...
- USER_MAX_CURRENT_SLOPE_EPL <removed>
- USER_MAX_CURRENT_SLOPE <removed>
I've written a function
void motorcontrol_load_motorparams(unsigned int polepairs, float i_max, float rs, float ls, float flux, float i_rs){
CTRL_Obj *obj = (CTRL_Obj *)ctrlHandle;
gUserParams.motor_type = MOTOR_Type_Pm;
gUserParams.motor_numPolePairs = polepairs;
gUserParams.motor_Rr = NULL;
gUserParams.motor_Rs = rs;
gUserParams.motor_Ls_d = ls;
gUserParams.motor_Ls_q = ls;
gUserParams.motor_ratedFlux = flux;
gUserParams.maxCurrent = i_max;
gUserParams.maxCurrent_resEst = i_rs;
/* Set derived motor parameters based on input.
* Normally these are calculated in a #define in user.h */
gUserParams.maxCurrentSlope = (i_rs/USER_IQ_FULL_SCALE_CURRENT_A/USER_TRAJ_FREQ_Hz);
gUserParams.maxCurrentSlope_epl = (0.3*i_rs/USER_IQ_FULL_SCALE_CURRENT_A/USER_TRAJ_FREQ_Hz);
CTRL_setParams(ctrlHandle,&gUserParams); // Seed gUserParams struct with new values
CTRL_setFlag_enableUserMotorParams(ctrlHandle, true); // Enable loading parameters from gUserParams struct
CTRL_setFlag_enableOffset(ctrlHandle, true); // Enable offset ...
gMotorVars.Flag_enableOffsetcalc = true;
EST_setFlag_enableRsRecalc(obj->estHandle, true); // ... and Rs recalculation for a short calibration ...
gMotorVars.Flag_Run_Identify = true; // ... which is run ...
motorcontrol_set_en(); // ... now.
}
Which I intend to run on startup. From what I've understood of the seeding function USER_setParams(&gUserParams) this should fully define the motor parameters and calculate the relevant offset currents/voltages as well as the motor winding resistance Rs.
On startup I run the same initialization routines as done in the labs, ie;
USER_setParams(&gUserParams);
DRV_setParams(drvHandle,&gUserParams);
#ifdef FAST_ROM_V1p6
ctrlHandle = CTRL_initCtrl(CTRLNUM, ESTNUM); //v1p6 format (06xF and 06xM devices)
controller_obj = (CTRL_Obj *)ctrlHandle;
#else
ctrlHandle = CTRL_initCtrl(ESTNUM,&ctrl,sizeof(ctrl)); //v1p7 format default
#endif
CTRL_setParams(ctrlHandle,&gUserParams);
DRV_setupFaults(drvHandle);
DRV_initIntVectorTable(drvHandle);
DRV_enableAdcInts(drvHandle);
DRV_enableDebugInt(drvHandle);
DRV_disablePwm(drvHandle);
CTRL_setFlag_enableDcBusComp(ctrlHandle, true);
Followed a while later by my seeding function (for now with compile-time constants);
motorcontrol_load_motorparams(7, 25, 9.8e-9, 19.8e-6, 0.01608, 5);
When I run my own function and I view the real-time watch window in CCS I can see that the estimation of Rs tends towards very small values (around 3e-8, IE. tiny) on startup. If I try to run the motor using a dummy motor_run function along the lines of;
CTRL_setFlag_enableOffset(ctrlHandle, true);
CTRL_setFlag_enableSpeedCtrl(ctrlHandle, true);
gMotorVars.Flag_enableSys = true;
DRV_enablePwm(drvHandle);
CTRL_setFlag_enableCtrl(ctrlHandle, true);
The motor only moves a few degrees in each direction and the estimated motor speeds (in the watch window) jumps all over the place. Question 1 Does anyone have any pointers as to what to look for or what to try next?
I've written an identification function, for identifying an arbitrary motor which seems to work completely;
void motorcontrol_start_identify(unsigned int polepairs, unsigned int roverl_f, float i_max, float i_rs, float i_ls, float vph_f){
if(mc_init == 0 || motorcontrol_get_error()){
gMotorVars.Flag_Run_Identify = false;
return;
}
motorcontrol_set_dis();
// Set motor parameters to the input
gUserParams.motor_type = MOTOR_Type_Pm;
gUserParams.motor_numPolePairs = polepairs;
gUserParams.RoverL_estFreq_Hz = roverl_f;
gUserParams.maxCurrent_resEst = i_rs;
gUserParams.maxCurrent_indEst = i_ls;
gUserParams.maxCurrent = i_max;
gUserParams.fluxEstFreq_Hz = vph_f;
/* Set derived motor parameters based on input.
* Normally these are calculated in a #define in user.h */
gUserParams.maxCurrentSlope = (i_rs/USER_IQ_FULL_SCALE_CURRENT_A/USER_TRAJ_FREQ_Hz);
gUserParams.maxCurrentSlope_epl = (0.3*i_rs/USER_IQ_FULL_SCALE_CURRENT_A/USER_TRAJ_FREQ_Hz);
gUserParams.estWaitTime[EST_State_RampUp] = (uint_least32_t)((5.0 + vph_f / USER_MAX_ACCEL_EST_Hzps) * USER_EST_FREQ_Hz);
// Zero out any old parameters to ensure they are all gone through
gUserParams.motor_Rr = NULL;
gUserParams.motor_Rs = NULL;
gUserParams.motor_Ls_d = NULL;
gUserParams.motor_Ls_q = NULL;
gUserParams.motor_ratedFlux = NULL;
gUserParams.IdRated = NULL;
// Update the controller and set other flags
gMotorVars.Flag_MotorIdentified = false;
CTRL_setParams(ctrlHandle,&gUserParams);
CTRL_setFlag_enableUserMotorParams(ctrlHandle, false);
gMotorVars.Flag_enableOffsetcalc = true;
gMotorVars.Flag_Run_Identify = true;
gMotorVars.Flag_enableSys = true;
DRV_enablePwm(drvHandle);
CTRL_setFlag_enableCtrl(ctrlHandle, true);
}
If I run this function (and fully go through an identification routine) I can then run the motor exactly as expected using the previously mentioned dummy motor_run function. Question 2: What is the automatic motor identification routine doing that I'm not seeding in my motorcontrol_load_motorparams() function? In the previously described motorcontrol_load_motorparams() I am seeding gUserParsms.maxCurrent and gUserParams.maxCurrent_resEst...
There a few more points that I'm struggling with at the moment that seem ill defined in the insta-spin manual that could also use clarification;
Question 3: How is the gMaxCurrentSlope global variable related to the EST_setMaxCurrentSlope_pu () and EST_getMaxCurrentSlope_pu() functions? (And more generally, how are the parameters in the gMotorVars global variable associated with their equivalent get() and set() functions (both for CTRL_ and EST_) in the insta-spin API?)
Question 4: How should the gMaxCurrentSlope variable be set? In the labs, this value is set after a motor identification, is this the cannonical method? (Perform identification, store calibrated value?)
Question 5: Is there any functional difference between
Question 6: Are all parameters in the global variables (gUserParams, gMotorVars, gMaxCurrentSlope) guaranteed to be atomically written/read?
I realize this is a pretty extensive post with a lot of questions; I would very much appreciate any help I could get with any/all of these questions. In the event that this goes beyond the range of what is reasonable to ask in "for free" I would appreciate where/who to get in touch with for commercial help... Cheers!