Jelajahi Sumber

1. PI 控制器修改,统一使用串联或并联PI
2. 油门开度通过指数函数处理,后段对应的扭矩更大
3. 先不区分加减速,统一通过油门开度获取当前扭矩指令
4. 加入MC124 R1电机+编码器的最新配置文件,主要修改了限速,定速,限功率的PI的参数

Signed-off-by: kevin <huhui@sharkgulf.com>

kevin 2 tahun lalu
induk
melakukan
5263794bd7

+ 33 - 5
Applications/app/app.c

@@ -92,6 +92,24 @@ static void test_vbus_vol(void) {
 }
 
 #endif
+static bool expf_b = false;
+static float y1[101], x1[101];
+static int exp_idx = 101;
+static measure_time_t exp_m;
+static void expf_benchmark(void) {
+	float thro_curve = 0.0f;
+	float K = -1.5f;
+	u32 mask = cpu_enter_critical();
+	time_measure_start(&exp_m);
+	for (int i = 0; i < 101; i++) {
+		y1[i] = throttle_curve(K, thro_curve);
+		x1[i] = thro_curve;
+		thro_curve += 0.01f;
+	}
+	time_measure_end(&exp_m);
+	cpu_exit_critical(mask);
+	sys_debug("time = %d, %f, %f\n", exp_m.exec_time, y1[0], y1[100]);
+}
 
 static void app_print_log(void) {
 	//sys_debug("Slow: %d - %d, err:%d, %d\n", g_meas_MCTask.intval_time, g_meas_MCTask.exec_time, g_meas_MCTask.exec_max_error_time, g_meas_MCTask.exec_time_error);
@@ -109,6 +127,7 @@ static void app_print_log(void) {
 	//throttle_log();
 	//sys_debug("Trq: %f-%f-%f\n", motor.controller.ramp_input_torque.target, motor.controller.ramp_input_torque.interpolation, motor.controller.ramp_input_torque.step);
 	sys_debug("FOC is %s, %d,%d\n", mot_contrl_is_start(mot_contrl())?"start":"stop", motor.foc_start_cnt, motor.foc_stop_cnt);
+	sys_debug("VelLim Ki=%f, %f\n", mot_contrl()->pi_vel_lim.ki, mot_contrl()->pi_vel_lim.kp);
 	//F_debug();
 	//eCtrl_debug_log();
 	//sys_debug("enc err %d, %d\n", foc_observer_enc_errcount(), foc_observer_sensorless_stable());
@@ -117,6 +136,10 @@ static void app_print_log(void) {
 	//test_mos_temp();
 	//test_mos_temp();
 	//test_vbus_vol();
+	if (expf_b) {
+		expf_benchmark();
+		expf_b = false;
+	}
 }
 
 static u32 app_report_task(void *p) {
@@ -152,9 +175,14 @@ static u32 app_report_task(void *p) {
 	if (++loop % 10 == 0) {
 		app_print_log();
 	}
+	if (!expf_b && exp_idx < 101) {
+		can_plot2((s16)(y1[exp_idx] * 100.0f), (s16)(x1[exp_idx] * 100.0f));
+		exp_idx++;
+	}
+
 	return 200;
 }
-int plot_type = 1;
+int plot_type = 0;
 static void plot_smo_angle(void) {
 	u32 mask = cpu_enter_critical();
 	float smo_angle = foc_observer_sensorless_angle();
@@ -168,7 +196,7 @@ static void plot_smo_angle(void) {
 }
 static u32 app_plot_task(void * args) {
 	if (plot_type == 1) {
-		s16 plot_arg1 = (s16)foc_observer_sensorless_speed();
+		s16 plot_arg1 = mot_contrl()->ramp_vel_lim.interpolation;
 		s16 plot_arg2 = (s16)mot_contrl_get_speed(&motor.controller);
 		if (mot_contrl()->mode_running == CTRL_MODE_SPD) {
 			if (mc_is_cruise_enabled()) {
@@ -177,10 +205,9 @@ static u32 app_plot_task(void * args) {
 				plot_arg1 = mot_contrl()->ramp_target_vel.target;
 			}
 		}
-		can_plot2(plot_arg1, plot_arg2);
+		can_plot3(plot_arg1, plot_arg2, mot_contrl()->ramp_vel_lim.target);
 	}else if (plot_type == 2) {
-		//can_plot2(mot_contrl_get_final_torque(&motor.controller), mot_contrl()->target_torque);
-		can_plot2(mot_contrl()->dc_lim_iq_ff, mot_contrl()->target_torque);
+		can_plot3(mot_contrl()->ramp_torque_lim.interpolation, mot_contrl()->ramp_input_torque.interpolation, mot_contrl()->target_torque);
 	}else if (plot_type == 3) {
 		plot_smo_angle();
 	}else if (plot_type == 4) {
@@ -207,6 +234,7 @@ static u32 app_plot_task(void * args) {
 	}else if (plot_type == 12) {
 		can_plot2((s16)motor.controller.dc_curr_filted, (s16)motor.controller.dc_curr_calc);
 	}
+
 	return 20;
 }
 static u32 app_low_task(void *args) {

+ 12 - 71
Applications/foc/core/PI_Controller.h

@@ -10,9 +10,7 @@ typedef struct {
 	float  max;
 	float  min;
 	float  ui;
-	float  sat;
 	float  ts;
-	bool   is_sat;
 }PI_Controller;
 
 static __INLINE void PI_Controller_Change_Kpi(PI_Controller *pi, float kp, float ki) {
@@ -27,97 +25,40 @@ static __INLINE void PI_Controller_max(PI_Controller *pi, float max, float min)
 }
 static __INLINE void PI_Controller_Reset(PI_Controller *pi, float init) {
 	pi->ui = (init);
-	pi->sat = 0.0f;
-	pi->is_sat = false;
 }
 
-static __INLINE float PI_Controller_Run(PI_Controller *pi, float err, float ff) {
-	float kp_err = (err) * pi->kp;
-	float ki_err = (err) * pi->ki;
-	float integral = ki_err * pi->ts;
-
-	pi->ui = pi->ui + integral;
-	float out = pi->ui + kp_err + ff;
-	if (out > pi->max) {
-		out = pi->max;
-		pi->ui = out - kp_err;
-		pi->is_sat = true;
-	}else if (out < pi->min) {
-		out = pi->min;
-		pi->ui = out - kp_err;
-		pi->is_sat = true;
-	}else {
-		pi->is_sat = false;
-	}
-	return out;
-}
-
-static __INLINE float PI_Controller_RunVel(PI_Controller *pi, float err) {
-	float kp_err = (err) * pi->kp;
-	float ki_err = (kp_err) * pi->ki;
-	float integral = ki_err * pi->ts;
-
-	pi->ui = pi->ui + integral;
-	float out = pi->ui + kp_err;
+static __INLINE float PI_Controller_Parallel(PI_Controller *pi, float err, float ff) {
+	pi->ui += err * pi->ki * pi->ts;
+	float out = pi->ui + err * pi->kp + ff;
+	float out_presat = out;
 	if (out > pi->max) {
 		out = pi->max;
-		pi->ui = out - kp_err;
-		pi->is_sat = true;
+		pi->ui += (out - out_presat);
 	}else if (out < pi->min) {
 		out = pi->min;
-		pi->ui = out - kp_err;
-		pi->is_sat = true;
-	}else {
-		pi->is_sat = false;
+		pi->ui += (out - out_presat);
 	}
 	return out;
 }
 
 
 /* 电流环,PI 串联结构 */
-static __INLINE float PI_Controller_Current(PI_Controller *pi, float err, float ff) {
-	float kp_err = (err) * pi->kp;
-	float ki_err = (kp_err) * pi->ki;
-	float integral = ki_err * pi->ts;
-
-	pi->ui = pi->ui + integral;
+static __INLINE float PI_Controller_Serial(PI_Controller *pi, float err, float ff) {
+	float kp_err = err * pi->kp;
+	pi->ui += kp_err * pi->ki * pi->ts;
 	float out = pi->ui + kp_err + ff;
+	float out_presat = out;
 	if (out > pi->max) {
 		out = pi->max;
-		pi->is_sat = true;
-		pi->ui = out - (kp_err + ff);
+		pi->ui += (out - out_presat);
 	}else if (out < pi->min) {
 		out = pi->min;
-		pi->is_sat = true;
-		pi->ui = out - (kp_err + ff);
-	}else {
-		pi->is_sat = false;
+		pi->ui += (out - out_presat);
 	}
 	return out;
 }
 
 
-static __INLINE float PI_Controller_RunSerial(PI_Controller *pi, float err) {
-	float kp_err = (err) * pi->kp;
-	float ki_err = (kp_err) * pi->ki;
-	float integral = ki_err * pi->ts;
-
-	pi->ui = pi->ui + integral;
-	float out = pi->ui + kp_err;
-	if (out > pi->max) {
-		out = pi->max;
-		pi->is_sat = true;
-		pi->ui = out - kp_err;
-	}else if (out < pi->min) {
-		out = pi->min;
-		pi->is_sat = true;
-		pi->ui = out - kp_err;
-	}else {
-		pi->is_sat = false;
-	}
-	return out;
-}
-
 static __INLINE float _fmod(float v, s32 m) {
 	int v_i = (int)v;
 	int m_i = v_i % m;

+ 9 - 10
Applications/foc/core/controller.c

@@ -50,10 +50,10 @@ bool mot_contrl_enable(mot_contrl_t *ctrl, bool start) {
 		line_ramp_init(&ctrl->ramp_target_current, CONFIG_CURRENT_RAMP_TIME);
 		line_ramp_init(&ctrl->ramp_input_torque, CONFIG_DEFAULT_TORQUE_RAMP_TIME);
 		line_ramp_init(&ctrl->ramp_adv_angle, CONFIG_CURRENT_RAMP_TIME);
-		mot_contrl_pid(ctrl);
 		mot_contrl_ulimit(ctrl);
 		mot_contrl_rtlimit(ctrl);
 	}
+	mot_contrl_pid(ctrl);
 	ctrl->b_ebrk_running = false;
 	ctrl->b_AutoHold = false;
 	ctrl->b_cruiseEna = false;
@@ -293,8 +293,8 @@ bool mot_contrl_update(mot_contrl_t *ctrl) {
 	float lowpass = 0.001f;
 	LowPass_Filter(ctrl->out_idq_filterd.d, foc->out.curr_dq.d ,lowpass);
 	LowPass_Filter(ctrl->out_idq_filterd.q, foc->out.curr_dq.q ,lowpass);
-	LowPass_Filter(ctrl->out_vdq_filterd.d, foc->out.vol_dq.d ,lowpass);
-	LowPass_Filter(ctrl->out_vdq_filterd.q, foc->out.vol_dq.q ,lowpass);
+	LowPass_Filter(ctrl->out_vdq_filterd.d, foc->out.vol_dq.d ,lowpass/1.5f);
+	LowPass_Filter(ctrl->out_vdq_filterd.q, foc->out.vol_dq.q ,lowpass/1.5f);
 
 	/* 计算母线电流 */
 	float vd = ctrl->out_vdq_filterd.d;
@@ -332,17 +332,16 @@ static __INLINE float mot_contrl_dc_curr_limiter(mot_contrl_t *ctrl, float maxTr
 	}else {
 		ctrl->dc_lim_iq_ff = iq_ff;
 	}
-	ctrl->pi_power.max = min(maxTrq, ctrl->dc_lim_iq_ff);
+	ctrl->pi_power.max = maxTrq;
 	float errRef = dc_lim - ctrl->dc_curr_filted;
-	return PI_Controller_Run(&ctrl->pi_power, errRef, ctrl->dc_lim_iq_ff);
+	return PI_Controller_Parallel(&ctrl->pi_power, errRef, ctrl->dc_lim_iq_ff);
 }
 
 static __INLINE float mot_contrl_vel_limiter(mot_contrl_t *ctrl, float maxTrq) {
 	ctrl->pi_vel_lim.max = maxTrq;
 	ctrl->pi_vel_lim.min = 0;
-
 	float err = line_ramp_get_interp(&ctrl->ramp_vel_lim) - ctrl->foc.in.mot_velocity;
-	return PI_Controller_RunVel(&ctrl->pi_vel_lim, err);
+	return PI_Controller_Parallel(&ctrl->pi_vel_lim, err, 0);
 }
 
 /* current vector or torque to dq axis current */
@@ -426,7 +425,7 @@ void mot_contrl_dq_calc(mot_contrl_t *ctrl) {
 		ctrl->pi_lock.min = -hold_torque;
 		float vel_count = motor_encoder_get_vel_count();
 		float errRef = 0 - vel_count;
-		ctrl->target_torque = PI_Controller_Run(&ctrl->pi_lock ,errRef, 0);
+		ctrl->target_torque = PI_Controller_Parallel(&ctrl->pi_lock ,errRef, 0);
 		mot_contrl_dq_assign(ctrl);
 		return;
 	}
@@ -476,7 +475,7 @@ void mot_contrl_dq_calc(mot_contrl_t *ctrl) {
 			ctrl->pi_vel.min = 0; //防止倒转
 		}
 		float errRef = refSpeed - ctrl->foc.in.mot_velocity;
-		float maxTrq = PI_Controller_RunVel(&ctrl->pi_vel, errRef);
+		float maxTrq = PI_Controller_Parallel(&ctrl->pi_vel, errRef, 0);
 		ctrl->target_torque_raw = mot_contrl_dc_curr_limiter(ctrl, maxTrq);
 		crosszero_step_towards(&ctrl->target_torque, ctrl->target_torque_raw);
 	}
@@ -884,7 +883,7 @@ void mot_contrl_calc_current(mot_contrl_t *ctrl) {
 
 	float raw_idc = get_vbus_current();
 	if (raw_idc != NO_VALID_CURRENT) {
-		LowPass_Filter(ctrl->dc_curr_filted, raw_idc, 0.05f);
+		LowPass_Filter(ctrl->dc_curr_filted, raw_idc, 0.04f);
 	}else {
 		ctrl->dc_curr_filted = ctrl->dc_curr_calc;
 	}

+ 2 - 2
Applications/foc/core/foc.c

@@ -72,7 +72,7 @@ void foc_update(foc_t *foc) {
 		foc->daxis.min = -max_vd;
 		float err = line_ramp_step(&foc->in.target_id) - foc->out.curr_dq.d;
 		float id_ff = id_feedforward(foc);
-		foc->in.target_vol_dq.d = PI_Controller_Current(&foc->daxis, err, id_ff);
+		foc->in.target_vol_dq.d = PI_Controller_Serial(&foc->daxis, err, id_ff);
 
 		/* limiter Vq output for PI controller */
 		float max_vq = sqrtsub2_f(max_vd, foc->in.target_vol_dq.d);
@@ -80,7 +80,7 @@ void foc_update(foc_t *foc) {
 		foc->qaxis.min = -max_vq;
 		err = line_ramp_step(&foc->in.target_iq) - foc->out.curr_dq.q;
 		float iq_ff = iq_feedforward(foc);
-		foc->in.target_vol_dq.q = PI_Controller_Current(&foc->qaxis, err, iq_ff);
+		foc->in.target_vol_dq.q = PI_Controller_Serial(&foc->qaxis, err, iq_ff);
 	}else {
 		float max_vd = max_Vdc * SQRT3_BY_2;
 		foc->in.target_vol_dq.d = fclamp(foc->in.target_vol_dq.d, -max_vd, max_vd);

+ 2 - 2
Applications/foc/motor/motor.c

@@ -295,9 +295,9 @@ float mc_gear_max_torque(s16 vel, u8 gear_n) {
 	if (vel_idx >= CONFIG_GEAR_SPEED_TRQ_NUM -1 ) {
 		return gear_rpm_2_torque(gear->torque[CONFIG_GEAR_SPEED_TRQ_NUM-1], gear->max_torque);
 	}
-	float torque_1 = gear_rpm_2_torque(gear->torque[vel_idx-1], gear->max_torque);
+	float torque_1 = gear_rpm_2_torque(gear->torque[vel_idx], gear->max_torque);
 	float min_rpm = vel_idx * 1000;
-	float torque_2 = gear_rpm_2_torque(gear->torque[vel_idx], gear->max_torque);
+	float torque_2 = gear_rpm_2_torque(gear->torque[vel_idx + 1], gear->max_torque);
 	float max_rpm = min_rpm + 1000;
 	return f_map((float)vel, min_rpm, max_rpm, torque_1, torque_2);
 }

+ 10 - 73
Applications/foc/motor/throttle.c

@@ -128,13 +128,17 @@ void throttle_force_detect(void) {
 }
 
 /* 获取转把电压对应的油门开度 */
+#define THRO_CURVE_K  (-1.5f)
+
 float throttle_vol_to_opening(float thro_val) {
 	if (thro_val <= throttle_start_vol()) {
 		return 0;
 	}
 	float delta = thro_val - throttle_start_vol();
 	int ration = (delta * 100.0f) / throttle_vol_range();
-	return ((float)ration)/100.0f;
+	float opening = ((float)ration)/100.0f;
+	float curve = throttle_curve(THRO_CURVE_K, opening);
+	return curve;
 }
 
 /* 获取油门开度 */
@@ -206,48 +210,6 @@ void throttle_detect(bool ready) {
 	}
 }
 
-static float _throttle_torque_for_accelerate(float ration) {
-	float max_torque = mc_gear_max_torque((s16)_throttle.vel_filted, _throttle.gear);
-	float thro_torque = max_torque * ration;
-
-	float acc_r = 1.0f;
-	if (_throttle.throttle_opening_last < 1.0f) {
-		acc_r = (ration - _throttle.throttle_opening_last)/ (1.0f - _throttle.throttle_opening_last);
-	}
-	acc_r = fclamp(acc_r, 0, 1.0f);
-	float acc_torque = _throttle.torque_real + acc_r * (max_torque - _throttle.torque_real);
-	if (acc_torque < 0) {
-		acc_torque = 0;
-	}
-	/*
-	   直接获取油门开度对应的加速扭矩thro_torque 不小于间接计算得到的 acc_torque
-	*/
-	float torque_acc_ = thro_torque - acc_torque;
-	float step = 0.0f;
-	if (torque_acc_ > 0) {
-		float acc_t = mc_gear_conf()->accl_time;
-		step = torque_acc_ / (acc_t + 0.00001f);
-	}else {
-		torque_acc_ = 0;
-	}
-	step_towards(&_throttle.torque_acc_, torque_acc_, step);
-	return (acc_torque + _throttle.torque_acc_);
-}
-
-
-static float throttle_torque_for_accelerate(void) {
-	return _throttle_torque_for_accelerate(_throttle.throttle_opening);
-}
-
-static float throttle_torque_for_decelerate(void) {
-	if (_throttle.throttle_opening_last == 0.0f) {
-		return 0;
-	}
-	float dec_r = _throttle.throttle_opening / _throttle.throttle_opening_last;
-	dec_r = fclamp(dec_r, 0.0f, 1.0f);
-	return dec_r * _throttle.torque_real;
-}
-
 float throttle_get_open_ration_filted(void) {
 	return _throttle.throttle_opening;
 }
@@ -258,37 +220,15 @@ float throttle_get_torque(mot_contrl_t * ctrl, float vol) {
 	float vel = mot_contrl_get_speed(ctrl);
 	_throttle.gear = mc_get_internal_gear();
 	LowPass_Filter(_throttle.vel_filted, vel, THRO_RPM_LP_CEOF);
-
 	if (throttle_opening > _throttle.throttle_opening) {
-		if (!_throttle.accl) {
-			_throttle.throttle_opening_last = _throttle.throttle_opening;
-			_throttle.torque_real = _throttle.torque_req;
-			if (_throttle.torque_real < 0) { //电子刹车的时候,扭矩可能为负
-				_throttle.torque_real = 0;
-			}
-			_throttle.torque_acc_ = 0;
-		}
 		_throttle.accl = true;
 	}else if (throttle_opening < _throttle.throttle_opening) {
-		if (_throttle.accl) {
-			_throttle.throttle_opening_last = _throttle.throttle_opening;
-			_throttle.torque_real = ctrl->target_torque_raw;
-			/* 如果扭矩给定的ramp没有结束,使用原始扭矩请求作为减扭矩的起始点 */
-			if (_throttle.torque_req - line_ramp_get_interp(&ctrl->ramp_input_torque) >= 10.0f ) {
-				_throttle.torque_real = _throttle.torque_req;
-			}
-			if (_throttle.torque_real < 0) { //电子刹车的时候,扭矩可能为负
-				_throttle.torque_real = 0;
-			}
-		}
 		_throttle.accl = false;
 	}
 	_throttle.throttle_opening = throttle_opening;
-	if (_throttle.accl) {
-		return throttle_torque_for_accelerate();
-	}else {
-		return throttle_torque_for_decelerate();
-	}
+
+	float max_torque = mc_gear_max_torque((s16)_throttle.vel_filted, _throttle.gear);
+	return max_torque * throttle_opening;
 }
 
 void throttle_set_torque(mot_contrl_t * ctrl, float torque) {
@@ -329,7 +269,6 @@ void throttle_set_torque(mot_contrl_t * ctrl, float torque) {
 		}
 		_throttle.torque_req = ref_torque;
 	}else {
-		float ref_torque = throttle_torque_for_decelerate();
 		/* autohold 启动的情况下,转把在0位置附近小幅抖动 */
 		if (curr_vel <= CONFIG_ZERO_SPEED_RPM) {
 			float hold_torque = ctrl->autohold_torque;
@@ -342,10 +281,8 @@ void throttle_set_torque(mot_contrl_t * ctrl, float torque) {
 
 /* 定速巡航需要判断是否需要加速 */
 float get_user_request_torque(void) {
-	if (_throttle.accl) {
-		return throttle_torque_for_accelerate();
-	}
-	return throttle_torque_for_decelerate();
+	float max_torque = mc_gear_max_torque((s16)_throttle.vel_filted, _throttle.gear);
+	return max_torque * _throttle.throttle_opening;
 }
 
 

+ 11 - 0
Applications/math/fast_math.c

@@ -28,6 +28,17 @@ float avg_filter_do(avg_filter_t *f, float sample) {
 	return f->sum/f->len;
 }
 
+
+float throttle_curve(float K, float x) {
+	float y1 = 1.0f - (expf(K*( 1- x)) - 1)/(expf(K) - 1);
+	if (y1 >= 0.999f) {
+		y1 = 1.0f;
+	}
+	y1 = fclamp(y1, 0, 1.0f);
+	int yi = y1 * 100.0f;
+	return (float)yi/100.0f;
+}
+
 #if 0
 /*
 生成sin/cos 查找表,(0-90°,间隔0.1°)

+ 2 - 0
Applications/math/fast_math.h

@@ -183,5 +183,7 @@ typedef struct {
 void avg_filter_init(avg_filter_t *f, int len);
 float avg_filter_do(avg_filter_t *f, float sample);
 
+float throttle_curve(float K, float x);
+
 #endif /* _Fast_Math_H__ */
 

+ 243 - 0
configs/mc124_R1_V2.yml

@@ -0,0 +1,243 @@
+##### 配置文件自动生成,不要手动修改!! 2024/1/3 18:56:20
+Version: 1
+CheckCrc: 0
+Motor:
+  Poles: 5
+  Ld: 5.4E-05
+  Lq: 7E-05
+  Rs: 0.015
+  Flux: 0.018
+  PLLBand: 200
+  EpmPLL: 400
+  PosPLL: 500
+  VehicleW: 190
+  WheelC: 145
+  GearRatio: 6.25
+  MaxFwDCurr: 100
+  MaxTorque: 350
+  EncOffset: 0
+Foc:
+  MaxDCVol: 90
+  MinDCVol: 40
+  MaxPhaseCurr: 350
+  MaxRPM: 9000
+  MaxEPMRPM: 300
+  MaxEPMTorque: 100
+  MaxEPMRPMBk: 170
+  MaxEPMTorqueBk: 80
+  MaxTorque: 350
+  MaxEbrkTorque: 40
+  MaxIDC: 200
+  MaxAutoHoldTorque: 100
+  ThroStartVol: 0.9
+  ThroEndVol: 4
+  ThroMinVol: 0.4
+  ThroMaxVol: 4.6
+  CurrCtrlBandWith: 400
+  ThroDecTime: 50
+  PID:
+    VelLim:
+      Kp: 0.15
+      Ki: 2.5
+      Kd: 0
+    VelCtrl:
+      Kp: 0.2
+      Ki: 0.02
+      Kd: 0
+    Autohold:
+      Kp: 0.01
+      Ki: 0.2
+      Kd: 0
+    IDCLim:
+      Kp: 0
+      Ki: 5
+      Kd: 0
+    EPM:
+      Kp: 0.2
+      Ki: 7.5
+      Kd: 0
+Settings:
+  AutoHold: 1
+  BrkShutPower: 1
+  TcsEnable: 0
+Gear:
+- MaxSpeed: 3500
+  MaxTorque: 250
+  MaxIdc: 30
+  ZeroAccl: 300
+  NormalAccl: 100
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 80
+  - 20
+  - 0
+  - 0
+  - 0
+  - 0
+  - 0
+- MaxSpeed: 4500
+  MaxTorque: 250
+  MaxIdc: 45
+  ZeroAccl: 300
+  NormalAccl: 80
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 80
+  - 60
+  - 40
+  - 0
+  - 0
+  - 0
+  - 0
+- MaxSpeed: 5500
+  MaxTorque: 300
+  MaxIdc: 60
+  ZeroAccl: 500
+  NormalAccl: 50
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 90
+  - 80
+  - 70
+  - 50
+  - 0
+  - 0
+  - 0
+- MaxSpeed: 7000
+  MaxTorque: 300
+  MaxIdc: 150
+  ZeroAccl: 500
+  NormalAccl: 30
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 90
+  - 80
+  - 70
+  - 70
+  - 50
+  - 50
+  - 0
+GearLow:
+- MaxSpeed: 1000
+  MaxTorque: 100
+  MaxIdc: 30
+  ZeroAccl: 500
+  NormalAccl: 100
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 0
+  - 0
+- MaxSpeed: 1000
+  MaxTorque: 100
+  MaxIdc: 30
+  ZeroAccl: 500
+  NormalAccl: 100
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 0
+  - 0
+- MaxSpeed: 1000
+  MaxTorque: 100
+  MaxIdc: 30
+  ZeroAccl: 500
+  NormalAccl: 100
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 0
+  - 0
+- MaxSpeed: 1000
+  MaxTorque: 100
+  MaxIdc: 30
+  ZeroAccl: 500
+  NormalAccl: 100
+  Torque:
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 100
+  - 0
+  - 0
+Protect:
+  Motor:
+  - Entry: 130
+    Exit: 120
+    Value: 0
+  - Entry: 120
+    Exit: 110
+    Value: 34
+  - Entry: 100
+    Exit: 90
+    Value: 66
+  MosFet:
+  - Entry: 100
+    Exit: 95
+    Value: 0
+  - Entry: 95
+    Exit: 90
+    Value: 34
+  - Entry: 90
+    Exit: 85
+    Value: 66
+  Voltage:
+  - Entry: 40
+    Exit: 42
+    Value: 0
+EnergyRecovery:
+- Torque: 0
+  Time: 600
+- Torque: 10
+  Time: 500
+- Torque: 15
+  Time: 400
+- Torque: 20
+  Time: 300
+- Torque: 35
+  Time: 200
+- Torque: 40
+  Time: 200
+- Torque: 40
+  Time: 200
+- Torque: 40
+  Time: 200
+- Torque: 40
+  Time: 200
+- Torque: 40
+  Time: 200
+CrossZero:
+  Low: 2
+  High: 7
+  MinStep: 0.1
+  NorStep: 5