Explorar o código

限流等级保存,恢复低等级限流需要转把释放后,避免突然加速

Signed-off-by: huhui <huhui@sharkgulf.com>
huhui %!s(int64=3) %!d(string=hai) anos
pai
achega
db54c20bd1

+ 1 - 0
Applications/app/app.c

@@ -137,6 +137,7 @@ static u32 _app_report_task(void *p) {
 		//thro_torque_log();
 		//sys_debug("_>%f, %f, %f\n", ladrc_observer_get()->ld, ladrc_observer_get()->lq, ladrc_observer_get()->poles);
 		encoder_log();
+		motor_debug();
 		//sample_log();
 		PMSM_FOC_LogDebug();
 		//F_debug();

+ 7 - 3
Applications/foc/core/PMSM_FOC_Core.c

@@ -796,15 +796,19 @@ void PMSM_FOC_idqCalc(void) {
 	PMSM_FOC_idq_Assign();
 }
 
-bool PMSM_FOC_RunTime_Limit(void) {
-	bool changed = false;
+u8 PMSM_FOC_RunTime_Limit(void) {
+	u8 changed = FOC_LIM_NO_CHANGE;
 	float dc_lim = (float)vbus_current_vol_lower_limit();
 	float torque_lim = (float)torque_temp_high_limit();
 
 	if (gFoc_Ctrl.protLim.s_iDCLim != dc_lim || gFoc_Ctrl.protLim.s_TorqueLim != torque_lim) {
+		if ((dc_lim > gFoc_Ctrl.protLim.s_iDCLim) || (torque_lim > gFoc_Ctrl.protLim.s_TorqueLim)) {
+			changed = FOC_LIM_CHANGE_H;
+		}else {
+			changed = FOC_LIM_CHANGE_L;
+		}
 		gFoc_Ctrl.protLim.s_iDCLim = dc_lim;
 		gFoc_Ctrl.protLim.s_TorqueLim = torque_lim;
-		changed = true;
 	}
 	return changed;
 }

+ 5 - 1
Applications/foc/core/PMSM_FOC_Core.h

@@ -212,6 +212,10 @@ typedef struct {
 #define FOC_CALIMOD_HALL               ((u8) 1U)
 #define FOC_CALIMOD_MTPA               ((u8) 2U)
 
+#define FOC_LIM_NO_CHANGE  0
+#define FOC_LIM_CHANGE_H   1
+#define FOC_LIM_CHANGE_L   2
+
 #if 1
 #define SECTOR_1  0u
 #define SECTOR_2  1u
@@ -292,7 +296,7 @@ void PMSM_FOC_GetPid(u8 id, float *kp, float *ki, float *kd);
 bool PMSM_FOC_AutoHoldding(void);
 void PMSM_FOC_Slow_Task(void);
 void PMSM_FOC_Set_PlotType(Plot_t t);
-bool PMSM_FOC_RunTime_Limit(void);
+u8   PMSM_FOC_RunTime_Limit(void);
 void PMSM_FOC_RT_PhaseCurrLim(float lim);
 void PMSM_FOC_RT_LimInit(void);
 float PMSM_FOC_Get_Real_dqVector(void);

+ 8 - 4
Applications/foc/limit.c

@@ -10,7 +10,7 @@ static limter_t motor_temp_lim[3];
 static limter_t mos_temp_lim[3];
 static limter_t vol_under_lim[1];
 static bool _inited = false;
-
+static bool _can_recovery = true;
 static void limiter_init(void) {
 	mc_limit_t *limiter = nv_get_limter();
 	for (int i = 0; i < TEMP_LIMITER_NUM; i++) {
@@ -97,9 +97,10 @@ static u16 _motor_limit(void) {
 		if (lim_value != HW_LIMIT_NONE) {
 			if (lim_value == 0) {
 				mc_set_critical_error(FOC_CRIT_MOTOR_TEMP_Err);
-			}else {
+			}else if (_can_recovery){
 				mc_clr_critical_error(FOC_CRIT_MOTOR_TEMP_Err);
 			}
+			mc_set_motor_lim_level(i + 1);
 			err_add_record(FOC_CRIT_MOTOR_TEMP_Err, temp);
 			return lim_value;
 		}
@@ -116,10 +117,11 @@ static u16 _mos_limit(void) {
 		if (lim_value != HW_LIMIT_NONE) {
 			if (lim_value == 0) {
 				mc_set_critical_error(FOC_CRIT_MOS_TEMP_Err);
-			}else {
+			}else if (_can_recovery){
 				mc_clr_critical_error(FOC_CRIT_MOS_TEMP_Err);
 			}
 			err_add_record(FOC_CRIT_MOS_TEMP_Err, temp);
+			mc_set_mos_lim_level(i + 1);
 			return lim_value;
 		}
 	}
@@ -152,6 +154,8 @@ u16 vbus_current_vol_lower_limit(void) {
 			return lim_value;
 		}
 	}
-	mc_clr_critical_error(FOC_CRIT_UN_Vol_Err);
+	if (_can_recovery) {
+		mc_clr_critical_error(FOC_CRIT_UN_Vol_Err);
+	}
 	return HW_LIMIT_NONE;
 }

+ 24 - 8
Applications/foc/motor/motor.c

@@ -41,6 +41,8 @@ static motor_t motor = {
 	.n_gear = 0,
 	.b_is96Mode = false,
 	.mode = CTRL_MODE_OPEN,
+	.mos_lim = 0,
+	.motor_lim = 0,
 };
 static motor_err_t mc_error;
 
@@ -159,6 +161,7 @@ static void _mc_internal_init(u8 mode, bool start) {
 	motor.b_wait_brk_release = false;
 	motor.b_force_run = false;
 	motor.b_cruise = false;
+	motor.b_limit_pending = false;
 }
 
 static void _led_off_timer_handler(shark_timer_t *t) {
@@ -208,10 +211,6 @@ motor_t * mc_params(void) {
 	return &motor;
 }
 
-void mc_need_update(void) {
-	motor.b_updated = true;
-}
-
 mc_gear_t *mc_get_gear_config_by_gear(u8 n_gear) {
 	mc_gear_t *gears;
 
@@ -346,6 +345,14 @@ bool mc_stop(void) {
 	return true;
 }
 
+void mc_set_mos_lim_level(u8 l) {
+	motor.mos_lim = l;
+}
+
+void mc_set_motor_lim_level(u8 l) {
+	motor.motor_lim = l;
+}
+
 bool mc_set_gear(u8 gear) {
 	if (gear >= CONFIG_MAX_GEAR_NUM) {
 		PMSM_FOC_SetErrCode(FOC_Param_Err);
@@ -954,7 +961,9 @@ void MC_Protect_IRQHandler(void){
 }
 
 void motor_debug(void) {
-	sys_debug("err: %f, %f, %f, %d\n", (float)mc_error.vbus_x10/10.0f, (float)mc_error.id_ref_x10/10.0f, (float)mc_error.iq_ref_x10/10.0f, mc_error.run_mode);
+	sys_debug("err1: %f, %f, %f, %d\n", (float)mc_error.vbus_x10/10.0f, (float)mc_error.id_ref_x10/10.0f, (float)mc_error.iq_ref_x10/10.0f, mc_error.run_mode);
+	sys_debug("err2: %f, %f, %f, %f\n", (float)mc_error.id_x10/10.0f, (float)mc_error.iq_x10/10.0f, (float)mc_error.vd_x10/10.0f, (float)mc_error.vq_x10/10.0f);
+	sys_debug("err3: %f, %d, %d, %d, %d\n", (float)mc_error.ibus_x10/10.0f, mc_error.b_smo_running, mc_error.mos_temp, mc_error.mot_temp, mc_error.enc_error);
 }
 
 int mc_get_phase_errinfo(u8 *data, int dlen) {
@@ -1212,7 +1221,7 @@ void Sched_MC_mTask(void) {
 	u8 runMode = PMSM_FOC_CtrlMode();
 
 	/*保护功能*/
-	bool limted = PMSM_FOC_RunTime_Limit();
+	u8 limted = PMSM_FOC_RunTime_Limit();
 	/* 母线电流,实际采集的相电流矢量大小的计算 */
 	PMSM_FOC_Calc_Current();
 
@@ -1231,10 +1240,17 @@ void Sched_MC_mTask(void) {
 		return;
 	}
 
-	if (mc_detect_vbus_mode() || limted) {
+	if (mc_detect_vbus_mode() || (limted == FOC_LIM_CHANGE_L)) {
+		mc_gear_vmode_changed();
+		motor.b_limit_pending = false;
+	}else if (limted == FOC_LIM_CHANGE_H) {
+		motor.b_limit_pending = true;
+	}
+	/* 如果取消高温,欠压等限流需要释放转把后才生效,确保不会突然加速 */
+	if (motor.b_limit_pending && mc_throttle_released()) {
+		motor.b_limit_pending = false;
 		mc_gear_vmode_changed();
 	}
-
 	/* 堵转处理 */
 	if (mc_run_stall_process(runMode) || (motor.mode == CTRL_MODE_CURRENT)) {
 		eCtrl_Running();

+ 6 - 3
Applications/foc/motor/motor.h

@@ -39,10 +39,12 @@ typedef struct {
 	u8     mode;
 	bool   b_is96Mode;
 	u8     n_gear;
+	bool   b_limit_pending;
 	mc_gear_t *gear_cfg;
 	u32    n_autohold_time;
 	bool   b_wait_brk_release;
-	bool   b_updated;
+	u8     mos_lim;
+	u8     motor_lim;
 	fan_t  fan[2];
 }motor_t;
 
@@ -83,7 +85,6 @@ bool mc_start_epm_move(EPM_Dir_t dir, bool is_command);
 void mc_get_running_status(u8 *data);
 bool mc_command_epm_move(EPM_Dir_t dir);
 bool mc_throttle_epm_move(EPM_Dir_t dir);
-void mc_need_update(void);
 bool mc_is_start(void);
 bool mc_set_gear(u8 gear);
 u8 mc_get_gear(void);
@@ -100,8 +101,10 @@ bool mc_set_cruise_speed(bool rpm_abs, float target_rpm);
 void mc_set_idc_limit(s16 limit);
 mc_gear_t *mc_get_gear_config(void);
 mc_gear_t *mc_get_gear_config_by_gear(u8 n_gear);
-
 int mc_get_phase_errinfo(u8 *data, int dlen);
+void mc_set_motor_lim_level(u8 l);
+void mc_set_mos_lim_level(u8 l);
+void motor_debug(void);
 
 static __INLINE float motor_encoder_get_angle(void) {
 #ifdef USE_ENCODER_HALL

+ 1 - 0
Applications/prot/can_foc_msg.c

@@ -88,6 +88,7 @@ void can_report_foc_status(u8 can) {
 	encode_s16(data + 9, get_mos_temp());
 	encode_u24(data + 11, shark_get_seconds());
 	encode_u8(data + 14, mc_get_gear());
+	encode_u8(data + 15, mc_params()->mos_lim | (mc_params()->motor_lim<<4));
 	can_send_message(get_indicator_can_id(can), data, sizeof(data), 0);
 }
 

+ 200 - 0
Simulink/phi_dq_torque.m

@@ -0,0 +1,200 @@
+close all
+clc
+
+%%%%%%%%%%%%%%%%%%%%%%%%% 可修改定义区 %%%%%%%%%%%%%%%%%%%%%%%%% 特别注意!!!电流都应该用幅值
+I_max = 495;              % 这里是幅值,扫描电流的最大值
+I_min = 1;                % 这里是幅值,扫描电流的最小值
+U_max = 30.022;           % 这是 RMS
+p = 3;                    % 极对数
+Rs = 0;                   % 定子相电阻 0.0191238
+kw = 0.99493;                   % 斜槽引起的转矩削弱
+
+%%%%%%%%%% 调整转速、电流的步长和下面插值的k可以修复map图右下角的马赛克 %%%%%%%%%% 
+speed = [200:400:3400 3400:10:8000];   % 计算速度
+current =(I_min:10:I_max);               % 计算的电流
+k = 200;                                  % 总的插值次数, 这里多插值可以改善map图右下角马赛克
+
+%%%%%%%%%%%%%%%%%%%%%% 读取文件,都是原始值 %%%%%%%%%%%%%%%%%%%%%%
+data = load('dq_results.mat');
+id_init = data.id;
+iq_init = data.iq;
+Psid_init = data.psid;
+Psiq_init = data.psiq;
+Psim_init = data.psim;  % 永磁同步电机需要Psim, 同步磁阻电机不需要
+Is_init = sqrt(id_init .*id_init +iq_init .*iq_init);        % 峰值电流
+
+ID=zeros(size(speed, 2));
+IQ=zeros(size(speed, 2));
+US=zeros(size(speed, 2));
+TORQUE=zeros(size(speed, 2));
+Torque_all=zeros(size(speed, 2));
+ID_all=zeros(size(speed, 2));
+IQ_all=zeros(size(speed, 2));
+US_all=zeros(size(speed, 2));
+
+n_current = 0;                 %定义最大电流循环步数
+for I_max = current
+n_current = n_current+1;
+
+n_step = 0;                    %定义最大转速循环步数
+for n = speed
+
+n_step = n_step + 1 ;      %当前最大转速循环次数
+f = n*p/60;                % 计算供电频率
+Omega = 2*pi*f;            % 计算电角频率
+
+%%%%%%%%%%%%% 对数据进行进行插值%%%%%%%%%%%%%%%% !!!必须放在循环中间是因为每次dq轴参数需要重置
+[M,N] =size(id_init);
+[X,Y] =meshgrid(1:N,1:M);
+
+N_step = (N-1)/k;                      % N的插值步长
+M_step = (M-1)/k;                      % M的插值步长
+
+[Xq,Yq] =meshgrid((1:N_step:N),(1:M_step:M)); % 对横纵坐标进行插值
+
+id = interp2(X,Y,id_init,Xq,Yq);
+iq = interp2(X,Y,iq_init,Xq,Yq);
+Psid = interp2(X,Y,Psid_init,Xq,Yq);
+Psiq = interp2(X,Y,Psiq_init,Xq,Yq);
+Is = interp2(X,Y,Is_init,Xq,Yq);
+
+%%%%%%%%%%%%%%%%%%%% 计算转矩和端电压 %%%%%%%%%%%%%%%%%%%%%%%% 
+Torque = 3/2*p*(Psid.*iq-Psiq.*id)*kw;                                   % 永磁同步电机公式    
+
+%%%%%%%%%%%%%%%%%%%  峰值电流计算公式 %%%%%%%%%%%%%%%%%%% 
+%Torque = 3/2*p*(Psid.*iq-Psiq.*id)*kw;                                    % 同步磁阻电机公式  
+Us = sqrt(Psid.^2+Psiq.^2)*Omega/sqrt(2)+sqrt(iq.^2+id.^2)/sqrt(2)*Rs;    % 这是RMS因为除以了根号2
+
+%%%%%%%%%%%%%%%%%%%  有效值电流计算公式 %%%%%%%%%%%%%%%%%%%
+%Torque = 3/2*p*(Psid.*iq-Psiq.*id)*kw*sqrt(2);                                      % 同步磁阻电机公式,需要将电流换为峰值电流 
+%Us = sqrt(Psid.^2+Psiq.^2)*Omega/sqrt(2)+sqrt(iq.^2+id.^2)*Rs;                      % 这里的Psi和i都是有效值
+
+Is(Is>I_max)=NaN;         % 剔除超过电流幅值的点
+Us(Us>U_max)=NaN;         % 剔除超过电压幅值的点 
+Torque = Torque.*(Is./Is).*(Us./Us); % 剔除超过电压电流幅值的转矩点
+%%%%%%%%%%%%%%% 查找转矩最大值,以及对应的行数、列数 %%%%%%%%%%%%%%%
+Torque_max  = max(max(Torque));
+[x,y] = find(Torque == Torque_max);
+
+
+if ~isnan(Torque_max)           
+   ID(n_step) = id(x,y);
+   IQ(n_step) = iq(x,y);
+   US(n_step) = Us(x,y);
+   TORQUE(n_step) = Torque(x,y);
+else                       %% 如果转矩为NaN则说明电压电流超了,此时都赋为NaN然后继续往下扫描
+   ID(n_step) = NaN;
+   IQ(n_step) = NaN;
+   US(n_step) = NaN;
+   TORQUE(n_step) = NaN;
+end
+
+end
+Torque_all(n_current,:) = TORQUE;
+ID_all(n_current,:) = ID;
+IQ_all(n_current,:) = IQ;
+US_all(n_current,:) = US;
+end
+
+%%%%%%%%%%%%%%% 转矩图 %%%%%%%%%%%%%%% 
+
+figure(1);
+plot(speed,Torque_all,'MarkerSize',15,'Marker','.');
+grid on;
+set(gca,'GridLineStyle',':','GridColor','k','GridAlpha',1);
+set(gcf,'color','w');
+set(gca,'FontSize',14,'FontName','Times New Roman');
+xlabel('Speed, [rpm]');
+ylabel('Torque, [Nm]');
+%title('Torque');
+set(gca,'Xlim',[200,8000]);
+set(gca,'XTick',(200:400:8000));
+% set(gca,'Ylim',[0,200]);
+% set(gca,'YTick',[0:20:200]);
+
+%%%%%%%%%%%%%%% 画转矩、电流、电压相互关联的图 %%%%%%%%%%%%%%% 
+
+[M,N] = size(Torque_all);
+[X,Y] = meshgrid(1:1:N,1:1:M);
+
+figure(2);
+stem3(X,Y,Torque_all);
+grid on;
+set(gcf,'color','w');
+set(gca,'FontSize',16,'FontName','Times New Roman');
+xlabel('X');
+ylabel('Y');
+title('Torque');
+view(2);
+
+figure(3);
+stem3(X,Y,ID_all);
+grid on;
+set(gcf,'color','w');
+set(gca,'FontSize',16,'FontName','Times New Roman');
+xlabel('x position');
+ylabel('y position');
+title('Id');
+view(2);
+
+figure(4);
+stem3(X,Y,IQ_all);
+grid on;
+set(gcf,'color','w');
+set(gca,'FontSize',16,'FontName','Times New Roman');
+xlabel('x position');
+ylabel('y position');
+title('Iq');
+view(2);
+
+
+figure(5);
+stem3(X,Y,US_all);
+grid on;
+set(gcf,'color','w');
+set(gca,'FontSize',16,'FontName','Times New Roman');
+xlabel('x position');
+ylabel('y position');
+title('Us');
+view(2);
+
+Gama_all = atand(abs(IQ_all)./ID_all)+180;        % 对永磁同步电机为:Gama,同步磁阻电机为Kappa
+figure(6);
+stem3(X,Y,Gama_all);
+grid on;
+set(gcf,'color','w');
+set(gca,'FontSize',16,'FontName','Times New Roman');
+xlabel('x position');
+ylabel('y position');
+title('Gama');
+view(2);
+
+%%%%%%%%%%%%%%%%%%%  永磁同步电机角度输出 %%%%%%%%%%%%%%%%%%% 
+% Gama_all = atand(abs(ID_all)./IQ_all)+90;
+% figure(6);
+% stem3(X,Y,Gama_all);
+% grid on;
+% set(gcf,'color','w');
+% set(gca,'FontSize',16,'FontName','Times New Roman');
+% xlabel('x position');
+% ylabel('y position');
+% title('Gama');
+% view(2);
+
+%%%%%%%%%%%%%%%%%%%  转速输出 %%%%%%%%%%%%%%%%%%% 
+Speed_all = repelem(speed,M,1);
+figure(7);
+stem3(X,Y,Speed_all);
+grid on;
+set(gcf,'color','w');
+set(gca,'FontSize',16,'FontName','Times New Roman');
+xlabel('x position');
+ylabel('y position');
+title('Speed');
+view(2);
+
+%%%%%%%%%%%%% 写入参数  %%%%%%%%%%%%%
+% xlswrite('Torque_Id_Iq',Torque_all,'Torque');% xlswrite('Torque_Id_Iq',ID_all,'Id');
+% xlswrite('Torque_Id_Iq',IQ_all,'Iq');
+% xlswrite('Torque_Id_Iq',Speed_all,'Speed_all');
+%save('Torque_Id_Iq', 'Torque_all', 'ID_all', 'IQ_all','Speed_all');