Part Number: TMS320F280037C
This post accidentally marked resolved, see new thread: e2e.ti.com/.../tms320f280037c-tms320f280037c-universal-motor-control-lab-estimator-estoutputdata-bad-despite-good-inputs-dmc_level_3-from-successful-dmc_level_2
Hey,
Spinning a BLDC motor, attempting to implement FAST. I have tested this motor on an evaluation kit using the InstaSPIN labs successfully.
I had some trouble getting DMC_LEVEL_2 to spin my motor on custom hardware.
On closer examination of the code, the V/Hz angle generator was NOT being used to command the motor, but the Estimator was instead.
I ended up stumbling on this because the InstaSPIN labs 'is03' the angle generator in the open loop V/Hz control DID work on my prototype, and it (properly?) bypasses the angle generated by the estimator.
I then turned on the estimator, without hooking it up to the control system, just to see if it was working correctly.
Here is the ISR I am using:
__interrupt void motor1CtrlISR(void)
{
//motorVars_M1.ISRCount++;
MOTOR_Vars_t *obj = (MOTOR_Vars_t *)motorHandle_M1;
USER_Params *objUser = (USER_Params *)(obj->userParamsHandle);
HAL_ackMtr1ADCInt(); // acknowledge the ADC interrupt
HAL_readMtr1ADCData(&obj->adcData); // read the ADC data with offsets
obj->ISRCount++;
obj->adcData.V_V.value[0] -=obj->adcData.offset_V_sf.value[0] * obj->adcData.VdcBus_V; // remove offsets
obj->adcData.V_V.value[1] -=obj->adcData.offset_V_sf.value[1] * obj->adcData.VdcBus_V;
obj->adcData.V_V.value[2] -=obj->adcData.offset_V_sf.value[2] * obj->adcData.VdcBus_V;
// Verifies the ADC for current and voltage, offset compensation,
// clarke / park transformations. (Without using estimator angle)
MATH_Vec2 phasor;
CLARKE_run(obj->clarkeHandle_I, &obj->adcData.I_A, &obj->estInputData.Iab_A);
CLARKE_run(obj->clarkeHandle_V, &obj->adcData.V_V, &obj->estInputData.Vab_V);
#if (DMC_BUILDLEVEL == DMC_LEVEL_2)
//---------------------------------------
if(obj->flagRunIdentAndOnLine == true){
obj->counterTrajSpeed++;
if(obj->counterTrajSpeed >= objUser->numIsrTicksPerTrajTick){
obj->counterTrajSpeed = 0;
TRAJ_run(obj->trajHandle_spd); // run a trajectory for speed reference, so the reference changes with a ramp instead of a step
obj->estInputData.speed_ref_Hz= TRAJ_getIntValue(obj->trajHandle_spd);
}
//obj->enableCurrentCtrl = obj->flagEnableCurrentCtrl;
//obj->enableSpeedCtrl = obj->flagEnableSpeedCtrl;
}
else{
obj->enableSpeedCtrl = false;
obj->enableCurrentCtrl = false;
}
obj->estInputData.dcBus_V = obj->adcData.VdcBus_V;
obj->speed_int_Hz = obj->estInputData.speed_ref_Hz;
EST_run(obj->estHandle, &obj->estInputData, &obj->estOutputData);
//obj->oneOverDcBus_invV = obj->estOutputData.oneOverDcBus_invV;
//obj->estOutputData.oneOverDcBus_invV = 1.0 / obj->estInputData.dcBus_V;
obj->oneOverDcBus_invV = 1.0 / obj->estInputData.dcBus_V;
ANGLE_GEN_run(obj->angleGenHandle, obj->estInputData.speed_ref_Hz);
obj->angleGen_rad = ANGLE_GEN_getAngle(obj->angleGenHandle);//angleFoc_rad = ANGLE_GEN_getAngle(obj->angleGenHandle);
obj->angleFOC_rad = obj->angleGen_rad;
VS_FREQ_run(obj->VsFreqHandle, obj->estInputData.speed_ref_Hz);
obj->Vdq_out_V.value[0] = VsFreq_M1.Vdq_out.value[0];//VS_FREQ_getVd_out(obj->VsFreqHandle);
obj->Vdq_out_V.value[1] = VsFreq_M1.Vdq_out.value[1];//VS_FREQ_getVq_out(obj->VsFreqHandle);
phasor.value[0] = __cos(obj->angleFOC_rad);
phasor.value[1] = __sin(obj->angleFOC_rad);
IPARK_setPhasor(obj->iparkHandle_V, &phasor); // set the phasor in the inverse Park transform
IPARK_run(obj->iparkHandle_V, &obj->Vdq_out_V, &obj->Vab_out_V); // run the inverse Park module
//SVGEN_setup(obj->svgenHandle, obj->estOutputData.oneOverDcBus_invV); // setup the space vector generator (SVGEN) module
SVGEN_setup(obj->svgenHandle, obj->oneOverDcBus_invV);
SVGEN_run(obj->svgenHandle, &obj->Vab_out_V, &obj->pwmData.Vabc_pu); // run the space vector generator (SVGEN) module
if(HAL_getPwmEnableStatus(obj->halMtrHandle) == false)
{
obj->pwmData.Vabc_pu.value[0] = 0.0;
obj->pwmData.Vabc_pu.value[1] = 0.0;
obj->pwmData.Vabc_pu.value[2] = 0.0;
}
HAL_writePWMData(obj->halMtrHandle, &obj->pwmData);
Note here that the estimator is NOT used to generate the phase angle for the PWM; the ANGLE_GEN_Run directly receives the target speed and provides phasors to the PWM signal chain.
Here are some datalog snaps of the ADC readings using V/Hz control method:
(for each set of 4 graphs: top left, top right, bottom left, bottom right)
(edit)(left) I_A.value[0], I_A.value[1], I_A.value[2], angleGen_rad
(middle) V_V.value[0], V_V.value[1], V_V.value[2], angleGen_rad
(right) Iab_A.value[0], Iab_A.value[1], Vab_V.value[0], Vab_V.value[1]

So the Clarke transform outputs pretty sharp looking waveforms given the inputs. These are produced commanding a fairly low speed of 20 Hz. One would think the estimator would have no problem finding, for example, the rotor position from this feedback.
Instead, I get this:

when the motor isnt spinning, angle_rad is an actual number between -pi and pi, and when the motor starts spinning it immediately shoots to +Inf.
oneOverDcBus_invV is constant.
All the other numbers wildly change. RPS swings between -25000 and 25000.
How do I fix my estimator?