Files
foc_Gimbal/APP/foc.c
2024-01-24 15:56:10 +08:00

400 lines
11 KiB
C

//
// Created by hu123456 on 2024/1/16.
//
#include "foc.h"
#define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
float Voltage_PowerSupply = 12;
float Pole_Pairs = 14;
float Voltage_Limit = 6.9;
float Velocity_Limit = 100;
float V_Acc_Limit = 100;
float dir = 1;
FOCTypeDef FOCStruct_X={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
FOCTypeDef FOCStruct_Y={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
void PID_Iint(void)
{
FOCStruct_X.ZT_KP = 2;
FOCStruct_X.ZT_KI = 0;
FOCStruct_X.ZT_KD = 0.2;
FOCStruct_X.V_KP = 0.1;
FOCStruct_X.V_KI = 1.5;
FOCStruct_X.V_KD = 0;
//2024/1/2 Y轴效果不错
FOCStruct_Y.ZT_KP = 2;
FOCStruct_Y.ZT_KI = 0;
FOCStruct_Y.ZT_KD = 0.5;
FOCStruct_Y.V_KP = 0.1;
FOCStruct_Y.V_KI = 1;
FOCStruct_Y.V_KD = 0;
////2024/1/23 xY轴效果不错
// FOCStruct_X.ZT_KP = 2;
// FOCStruct_X.ZT_KI = 0;
// FOCStruct_X.ZT_KD = 0.2;
//
// FOCStruct_X.V_KP = 0.1;
// FOCStruct_X.V_KI = 1;
// FOCStruct_X.V_KD = 0;
////2024/1/22 Y轴效果不错
// FOCStruct_Y.ZT_KP = 2;
// FOCStruct_Y.ZT_KI = 0;
// FOCStruct_Y.ZT_KD = 0.5;
//
// FOCStruct_Y.V_KP = 0.1;
// FOCStruct_Y.V_KI = 1;
// FOCStruct_Y.V_KD = 0;
}
void setPhaseVoltage(unsigned char motor,float Uq, float Ud, double angle_el)
{
float Uout;
unsigned int sector;
float T0,T1,T2;
float Ta,Tb,Tc;
if(Ud) // only if Ud and Uq set
{
Uout = sqrt(Ud*Ud + Uq*Uq) / Voltage_PowerSupply;
// angle normalisation in between 0 and 2pi
// only necessary if using _sin and _cos - approximation functions
angle_el = _normalizeAngle(angle_el + atan2(Uq, Ud));
}
else
{// only Uq available - no need for atan2 and sqrt
Uout = Uq / Voltage_PowerSupply;
// angle normalisation in between 0 and 2pi
// only necessary if using _sin and _cos - approximation functions
angle_el = _normalizeAngle(angle_el + _PI_2);
}
if(Uout> 0.577)Uout= 0.577;
if(Uout<-0.577)Uout=-0.577;
sector = (angle_el / _PI_3) + 1;
T1 = sqrt(3)*sin(sector*_PI_3 - angle_el) * Uout;
T2 = sqrt(3)*sin(angle_el - (sector-1.0)*_PI_3) * Uout;
T0 = 1 - T1 - T2;
// calculate the duty cycles(times)
switch(sector)
{
case 1:
Ta = T1 + T2 + T0/2;
Tb = T2 + T0/2;
Tc = T0/2;
break;
case 2:
Ta = T1 + T0/2;
Tb = T1 + T2 + T0/2;
Tc = T0/2;
break;
case 3:
Ta = T0/2;
Tb = T1 + T2 + T0/2;
Tc = T2 + T0/2;
break;
case 4:
Ta = T0/2;
Tb = T1+ T0/2;
Tc = T1 + T2 + T0/2;
break;
case 5:
Ta = T2 + T0/2;
Tb = T0/2;
Tc = T1 + T2 + T0/2;
break;
case 6:
Ta = T1 + T2 + T0/2;
Tb = T0/2;
Tc = T1 + T0/2;
break;
default: // possible error state
Ta = 0;
Tb = 0;
Tc = 0;
}
if (motor == motory)
{
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,Ta*4800);
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,Tb*4800);
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_3,Tc*4800);
}
else if (motor == motorx)
{
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,Ta*4800);
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,Tb*4800);
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_3,Tc*4800);
}
}
void speed_closed_loop(unsigned motor,FOCTypeDef *FOCStruct,float V_Target)
{
float Uq,Ud;
double electrical_angle;
unsigned long Time_Now;
double Ts;
Time_Now = __HAL_TIM_GET_COUNTER(&htim5); //100ns
if(Time_Now > FOCStruct->Time_Prev)Ts = (float)(Time_Now - FOCStruct->Time_Prev)*1e-7f;
else
Ts = (float)(0xFFFFFFFF - FOCStruct->Time_Prev + Time_Now)*1e-7f;
FOCStruct->Time_Prev = Time_Now;
if(Ts == 0 || Ts > 400) Ts = 1e-3f;
//获取角度求出V_Now
double Angle_Now=getAngle(motor);
double V_Now = (Angle_Now - FOCStruct->Angle_Prev)/Ts;
FOCStruct->Angle_Prev = Angle_Now;
V_Now = dir*LPF_velocity(V_Now,FOCStruct);
double V_Error = V_Target - V_Now;
float V_Pid_P = FOCStruct->V_KP * V_Error;
float V_Pid_I = FOCStruct->V_Pid_IPrev + FOCStruct->V_KI*Ts*0.5*(V_Error + FOCStruct->V_Error_Prev);
V_Pid_I = _constrain(V_Pid_I, -Voltage_Limit, Voltage_Limit);
float V_Out = V_Pid_P+V_Pid_I;
V_Out = _constrain(V_Out, -Voltage_Limit, Voltage_Limit);
float V_Acc_Now = (V_Out - FOCStruct->V_Out_Prev)/Ts;
if(V_Acc_Now > V_Acc_Limit) V_Out = FOCStruct->V_Out_Prev + V_Acc_Limit*Ts;
else if(V_Acc_Now < -V_Acc_Limit) V_Out = FOCStruct->V_Out_Prev - V_Acc_Limit*Ts;
FOCStruct->V_Pid_IPrev = V_Pid_I;
FOCStruct->V_Out_Prev = V_Out;
FOCStruct->V_Error_Prev = V_Error;
Uq = V_Out;
Ud = 0;
// double shaft_angle = dir*Angle_Now;
double shaft_angle = dir*Angle_Now;
// electrical_angle = _normalizeAngle((shaft_angle ) * Pole_Pairs);
electrical_angle = _normalizeAngle((shaft_angle ) * Pole_Pairs - FOCStruct->zero_electric_angle);
setPhaseVoltage(motor,Uq,Ud,electrical_angle);
}
void Zitai_closed_loop(unsigned motor,FOCTypeDef *FOCStruct,float ZT_Error)
{
float Uq,Ud;
double electrical_angle;
unsigned long Time_Now;
double Ts;
Time_Now = __HAL_TIM_GET_COUNTER(&htim5); //100ns
if(Time_Now > FOCStruct->Time_Prev)Ts = (float)(Time_Now - FOCStruct->Time_Prev)*1e-7f;
else
Ts = (float)(0xFFFFFFFF - FOCStruct->Time_Prev + Time_Now)*1e-7f;
FOCStruct->Time_Prev = Time_Now;
if(Ts == 0 || Ts > 400) Ts = 1e-3f;
//姿态环
float V_Target = FOCStruct->ZT_KP * ZT_Error + FOCStruct->ZT_KD * (ZT_Error - FOCStruct->ZT_ErrorPrev) / Ts;
V_Target = _constrain(V_Target, -Velocity_Limit, Velocity_Limit);
FOCStruct->ZT_ErrorPrev = ZT_Error;
//速度环
//获取角度求出V_Now
double Angle_Now=getAngle(motor);
double V_Now = (Angle_Now - FOCStruct->Angle_Prev)/Ts;
FOCStruct->Angle_Prev = Angle_Now;
V_Now = dir*LPF_velocity(V_Now,FOCStruct);
double V_Error = V_Target - V_Now;
float V_Pid_P = FOCStruct->V_KP * V_Error;
float V_Pid_I = FOCStruct->V_Pid_IPrev + FOCStruct->V_KI*Ts*0.5*(V_Error + FOCStruct->V_Error_Prev);
V_Pid_I = _constrain(V_Pid_I, -Voltage_Limit, Voltage_Limit);
float V_Out = V_Pid_P+V_Pid_I;
V_Out = _constrain(V_Out, -Voltage_Limit, Voltage_Limit);
float V_Acc_Now = (V_Out - FOCStruct->V_Out_Prev)/Ts;
if(V_Acc_Now > V_Acc_Limit) V_Out = FOCStruct->V_Out_Prev + V_Acc_Limit*Ts;
else if(V_Acc_Now < -V_Acc_Limit) V_Out = FOCStruct->V_Out_Prev - V_Acc_Limit*Ts;
FOCStruct->V_Pid_IPrev = V_Pid_I;
FOCStruct->V_Out_Prev = V_Out;
FOCStruct->V_Error_Prev = V_Error;
Uq = V_Out;
Ud = 0;
// double shaft_angle = dir*Angle_Now;
double shaft_angle = dir*Angle_Now;
// electrical_angle = _normalizeAngle((shaft_angle ) * Pole_Pairs);
electrical_angle = _normalizeAngle((shaft_angle ) * Pole_Pairs - FOCStruct->zero_electric_angle);
setPhaseVoltage(motor,Uq,Ud,electrical_angle);
}
void Angel_closed_loop(unsigned motor,FOCTypeDef *FOCStruct,float Angle_target)
{
float Uq,Ud;
double electrical_angle;
unsigned long Time_Now;
double Ts;
Time_Now = __HAL_TIM_GET_COUNTER(&htim5); //100ns
if(Time_Now > FOCStruct->Time_Prev)Ts = (float)(Time_Now - FOCStruct->Time_Prev)*1e-7f;
else
Ts = (float)(0xFFFFFFFF - FOCStruct->Time_Prev + Time_Now)*1e-7f;
FOCStruct->Time_Prev = Time_Now;
if(Ts == 0 || Ts > 400) Ts = 1e-3f;
//角度环
double Angle_Now=getAngle(motor);
float error = Angle_target - Angle_Now;
Uq = 20 * error;
Uq = _constrain(Uq, -Voltage_Limit, Voltage_Limit);
double shaft_angle = dir*Angle_Now;
electrical_angle = _normalizeAngle((shaft_angle ) * Pole_Pairs - FOCStruct->zero_electric_angle);
setPhaseVoltage(motor,Uq,Ud,electrical_angle);
}
double LPF_velocity(double x,FOCTypeDef *FOCStruct)
{
float y = 0.9*(FOCStruct->V_Prev)+ 0.1*x;
FOCStruct->V_Prev=y;
return y;
}
// normalizing radian angle to [0,2PI]
double _normalizeAngle(float angle)
{
float a = fmod(angle, _2PI);
return a >= 0 ? a : (a + _2PI);
}
void PWM_Start()
{
HAL_TIM_Base_Start(&htim2); //启动定时器
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
HAL_TIM_Base_Start(&htim3); //启动定时器
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
}
void moto_Init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,1);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,1);
PWM_Start();
HAL_Delay(1000);
alignSensor(motory,&FOCStruct_Y);
alignSensor(motorx,&FOCStruct_X);
HAL_Delay(50);
}
int alignSensor(unsigned char moto,FOCTypeDef * FOCStruct)
{
long i;
float angle;
float mid_angle = 0,end_angle = 0;
float moved;
float q = 3.5;
printf("MOT: Align sensor.\r\n");
// find natural direction
// move one electrical revolution forward
HAL_Delay(100);
for(i=0; i<=500; i++)
{
angle = _3PI_2 + _2PI * i / 500.0;
setPhaseVoltage(moto,q, 0, angle);
HAL_Delay(2);
}
mid_angle=getAngle(moto);
for(i=500; i>=0; i--)
{
angle = _3PI_2 + _2PI * i / 500.0 ;
setPhaseVoltage(moto,q, 0, angle);
HAL_Delay(2);
}
end_angle=getAngle(moto);
setPhaseVoltage(moto,0, 0, 0);
HAL_Delay(200);
printf("mid_angle=%.4f\r\n",mid_angle);
printf("end_angle=%.4f\r\n",end_angle);
moved = fabs(mid_angle - end_angle);
if((mid_angle == end_angle)||(moved < 0.02)) //相等或者几乎没有动
{
printf("MOT: Failed to notice movement loop222.\r\n");
// M1_Disable; //电机检测不正常,关闭驱动
return 0;
}
else if(mid_angle < end_angle)
{
printf("MOT: sensor_direction==CCW\r\n");
// dir = -1;
}
else
{
printf("MOT: sensor_direction==CW\r\n");
// dir = 1;
}
printf("MOT: PP check: \n"); //计算Pole_Pairs
int pp;
if( fabs(moved*Pole_Pairs - _2PI) > 0.5 ) // 0.5 is arbitrary number it can be lower or higher!
{
printf("fail - estimated pp\n");
pp = _2PI/moved+0.5; //浮点数转整形,四舍五入
printf("pp=%d\r\n",pp);
}
else
printf("OK!\r\n");
setPhaseVoltage(moto,q,0,_3PI_2); //计算零点偏移角度
HAL_Delay(700);
FOCStruct->zero_electric_angle = _normalizeAngle(dir*getAngle(moto) * Pole_Pairs);
// delay_ms(20);
// printf("MOT: Zero elec. angle:");
// printf("%.4f\r\n",zero_electric_angle);
setPhaseVoltage(moto,0, 0, 0);
HAL_Delay(50);
return 1;
}