|
|
@@ -18,8 +18,6 @@
|
|
|
#include "encoder_off5.h"
|
|
|
#endif
|
|
|
#endif
|
|
|
-static void encoder_do_offset_calibrate(void) ;
|
|
|
-static void _detect_off_finished(void);
|
|
|
|
|
|
/* 磁编码器使用一对极的磁铁,所以编码器获取的角度和机械角度相同需要转为电角度*/
|
|
|
|
|
|
@@ -58,7 +56,7 @@ void encoder_init(void) {
|
|
|
|
|
|
void encoder_set_direction(s8 direction) {
|
|
|
g_encoder.direction = direction;
|
|
|
- g_encoder.cali_angle = INVALID_ANGLE;
|
|
|
+ //g_encoder.cali_angle = INVALID_ANGLE;
|
|
|
}
|
|
|
|
|
|
void encoder_set_bandwidth(float bandwidth) {
|
|
|
@@ -77,9 +75,14 @@ void encoder_init_clear(void) {
|
|
|
g_encoder.est_vel_counts = 0;
|
|
|
g_encoder.position = 0.0f;
|
|
|
g_encoder.interpolation = 0.0f;
|
|
|
- g_encoder.cali_angle = INVALID_ANGLE;
|
|
|
+ //g_encoder.cali_angle = INVALID_ANGLE;
|
|
|
g_encoder.enc_count_off = 0xFFFFFFFF;
|
|
|
g_encoder.b_cali_err = false;
|
|
|
+ g_encoder.produce_error = false;
|
|
|
+ g_encoder.last_delta_cnt = MAX_S16;
|
|
|
+ g_encoder.enc_maybe_err = false;
|
|
|
+ g_encoder.start_dianostic_cnt = 0;
|
|
|
+ g_encoder.pwm_time_ms = get_tick_ms();
|
|
|
_init_pll();
|
|
|
}
|
|
|
|
|
|
@@ -143,6 +146,56 @@ static __INLINE float _eccentricity_compensation(int cnt) {
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+#define CONFIG_ENC_DIANOSTIC_MIN_CNT (10.0F * ENC_MAX_RES * FOC_CTRL_US) //600rpm
|
|
|
+
|
|
|
+static void encoder_detect_error(u32 cnt) {
|
|
|
+#ifdef CONFIG_ENC_DETECT_ERR
|
|
|
+ if (!g_encoder.enc_maybe_err) {
|
|
|
+ s16 delta_cnt = cnt - g_encoder.last_cnt;
|
|
|
+ bool skip = false;
|
|
|
+ if (g_encoder.b_timer_ov) {
|
|
|
+ delta_cnt = (cnt + ENC_MAX_RES) - g_encoder.last_cnt;
|
|
|
+ }
|
|
|
+#ifdef CONFIG_ENC_ERR_TEST
|
|
|
+ if (g_encoder.produce_error) {
|
|
|
+ delta_cnt = 0;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ if (g_encoder.last_delta_cnt == MAX_S16) {
|
|
|
+ g_encoder.last_delta_cnt = delta_cnt;
|
|
|
+ skip = true;
|
|
|
+ }
|
|
|
+ if ((g_encoder.last_delta_cnt <= CONFIG_ENC_DIANOSTIC_MIN_CNT*1.2f) && get_delta_ms(g_encoder.pwm_time_ms) >= 4) {
|
|
|
+ g_encoder.enc_maybe_err = true;
|
|
|
+ }
|
|
|
+ if (g_encoder.start_dianostic_cnt < 0xFFFF) {
|
|
|
+ g_encoder.start_dianostic_cnt ++;
|
|
|
+ }
|
|
|
+ if (!skip && (g_encoder.last_delta_cnt > CONFIG_ENC_DIANOSTIC_MIN_CNT) && (g_encoder.start_dianostic_cnt >= 1000)) {
|
|
|
+ float last_delta = (float)g_encoder.last_delta_cnt;
|
|
|
+ float r = (float)delta_cnt / (last_delta + 0.0000001f);
|
|
|
+ r = ABS(r);
|
|
|
+ float r_thr;
|
|
|
+ if (g_encoder.last_delta_cnt <= CONFIG_ENC_DIANOSTIC_MIN_CNT * 2) {
|
|
|
+ r_thr = 0.3f;
|
|
|
+ }else if (g_encoder.last_delta_cnt <= CONFIG_ENC_DIANOSTIC_MIN_CNT * 4) {
|
|
|
+ r_thr = 0.5f;
|
|
|
+ }else if (g_encoder.last_delta_cnt <= CONFIG_ENC_DIANOSTIC_MIN_CNT * 6) {
|
|
|
+ r_thr = 0.6f;
|
|
|
+ }else {
|
|
|
+ r_thr = 0.7f;
|
|
|
+ }
|
|
|
+ if (r <= r_thr || r >= (2.0f - r_thr)) {
|
|
|
+ g_encoder.enc_maybe_err = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ g_encoder.last_delta_cnt = delta_cnt;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ g_encoder.enc_maybe_err = false;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
float encoder_get_theta(void) {
|
|
|
if (!g_encoder.b_index_found) {
|
|
|
return g_encoder.pwm_angle;
|
|
|
@@ -154,6 +207,8 @@ float encoder_get_theta(void) {
|
|
|
g_encoder.b_timer_ov = true;
|
|
|
ENC_ClearUpFlags();
|
|
|
}
|
|
|
+
|
|
|
+ encoder_detect_error(cnt);
|
|
|
|
|
|
bool snap_to_zero_vel = encoder_run_pll((float)(cnt));
|
|
|
|
|
|
@@ -171,111 +226,28 @@ float encoder_get_theta(void) {
|
|
|
g_encoder.interpolation = 0.0f;
|
|
|
}
|
|
|
}
|
|
|
- if (g_encoder.cali_angle != INVALID_ANGLE) {
|
|
|
- g_encoder.interpolation = 0.0f;
|
|
|
- }
|
|
|
+
|
|
|
g_encoder.abi_angle = ENC_Pluse_Nr_2_angle((float)cnt + g_encoder.interpolation) * g_encoder.motor_poles + g_encoder.enc_offset;
|
|
|
g_encoder.abi_angle += _eccentricity_compensation(cnt);
|
|
|
rand_angle(g_encoder.abi_angle);
|
|
|
g_encoder.last_cnt = cnt;
|
|
|
g_encoder.last_us = task_get_usecond();
|
|
|
|
|
|
- if (g_encoder.cali_angle != INVALID_ANGLE) {
|
|
|
- encoder_do_offset_calibrate();
|
|
|
- }
|
|
|
g_encoder.position += (g_encoder.est_vel_counts/g_encoder.cpr) * FOC_CTRL_US;
|
|
|
return g_encoder.abi_angle;
|
|
|
}
|
|
|
|
|
|
-float encoder_get_speed(void) {
|
|
|
- return (g_encoder.est_vel_counts/g_encoder.cpr) * 60.0f;
|
|
|
-}
|
|
|
-
|
|
|
-void _encoder_caliberate_init(void) {
|
|
|
- if (g_encoder.encoder_off_map != NULL) {
|
|
|
- return;
|
|
|
- }
|
|
|
- u32 mask = cpu_enter_critical();
|
|
|
- g_encoder.encoder_off_map = (s16 *)os_alloc(g_encoder.cpr * sizeof(s16));
|
|
|
- g_encoder.encoder_off_count = (u8 *)os_alloc(g_encoder.cpr);
|
|
|
-
|
|
|
- for (int i = 0; i < g_encoder.cpr; i++) {
|
|
|
- g_encoder.encoder_off_map[i] = 0;
|
|
|
- g_encoder.encoder_off_count[i] = 0;
|
|
|
- }
|
|
|
- cpu_exit_critical(mask);
|
|
|
-}
|
|
|
-
|
|
|
-void _encoder_caliberate_deinit(void) {
|
|
|
- if (g_encoder.encoder_off_map != NULL) {
|
|
|
- os_free(g_encoder.encoder_off_map);
|
|
|
- os_free(g_encoder.encoder_off_count);
|
|
|
- }
|
|
|
- g_encoder.encoder_off_map = NULL;
|
|
|
- g_encoder.encoder_off_count = NULL;
|
|
|
-}
|
|
|
-
|
|
|
-#define MIN_OFF_COUNT 5
|
|
|
-void encoder_detect_offset(float angle){
|
|
|
-#if 1
|
|
|
- _encoder_caliberate_init();
|
|
|
- g_encoder.cali_angle = angle;
|
|
|
-#else
|
|
|
- plot_2data16((s16)angle, (s16)g_encoder.abi_angle);
|
|
|
-#endif
|
|
|
-}
|
|
|
-
|
|
|
-static void encoder_do_offset_calibrate(void) {
|
|
|
- float delta = (g_encoder.abi_angle - g_encoder.cali_angle);
|
|
|
- if (delta > 200) {
|
|
|
- delta = delta - 360;
|
|
|
- }
|
|
|
- if (delta < -200) {
|
|
|
- delta = delta + 360;
|
|
|
- }
|
|
|
- if (g_encoder.direction == POSITIVE) {
|
|
|
- if ((g_encoder.encoder_off_count[g_encoder.last_cnt] & 0xF) <= MIN_OFF_COUNT) {
|
|
|
- g_encoder.encoder_off_map[g_encoder.last_cnt] += (s16)(delta*100.0f);
|
|
|
- g_encoder.encoder_off_count[g_encoder.last_cnt] += 0x01;
|
|
|
- }
|
|
|
- }else {
|
|
|
- if (((g_encoder.encoder_off_count[g_encoder.last_cnt] >> 4) & 0xF) <= MIN_OFF_COUNT) {
|
|
|
- g_encoder.encoder_off_map[g_encoder.last_cnt] += (s16)(delta*100.0f);
|
|
|
- g_encoder.encoder_off_count[g_encoder.last_cnt] += 0x10;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
-bool encoder_detect_finish(void) {
|
|
|
- u8 off_count = 0;
|
|
|
- for (int i = 0; i < 1024; i++) {
|
|
|
- if (g_encoder.direction == POSITIVE) {
|
|
|
- off_count = g_encoder.encoder_off_count[i] & 0xF;
|
|
|
- }else {
|
|
|
- off_count = (g_encoder.encoder_off_count[i] >> 4)& 0xF;
|
|
|
- }
|
|
|
- if (off_count <= MIN_OFF_COUNT) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
- if (g_encoder.direction == NEGATIVE) {
|
|
|
- g_encoder.cali_angle = INVALID_ANGLE;
|
|
|
- }
|
|
|
- return true;
|
|
|
+void encoder_produce_error(bool error) {
|
|
|
+ g_encoder.produce_error = error;
|
|
|
}
|
|
|
|
|
|
-void encoder_detect_upload(void) {
|
|
|
- _detect_off_finished();//output data to PC tools, and use Matlab do FIR filter
|
|
|
- _encoder_caliberate_deinit();
|
|
|
+bool encoder_may_error(void) {
|
|
|
+ return g_encoder.enc_maybe_err;
|
|
|
}
|
|
|
|
|
|
-static void _detect_off_finished(void) {
|
|
|
- for (int i = 0; i < 1024; i++) {
|
|
|
- float angle_off = g_encoder.encoder_off_map[i] / (((g_encoder.encoder_off_count[i] >> 4)&0xF) + (g_encoder.encoder_off_count[i]&0xF));
|
|
|
- plot_1data16((s16)angle_off);
|
|
|
- delay_ms(30);
|
|
|
- wdog_reload();
|
|
|
- }
|
|
|
+float encoder_get_speed(void) {
|
|
|
+ return (g_encoder.est_vel_counts/g_encoder.cpr) * 60.0f;
|
|
|
}
|
|
|
|
|
|
float encoder_get_vel_count(void) {
|
|
|
@@ -334,12 +306,15 @@ bool encoder_get_cali_error(void) {
|
|
|
}
|
|
|
|
|
|
static void encoder_sync_pwm_abs(void) {
|
|
|
+ u32 mask = cpu_enter_critical();
|
|
|
ENC_COUNT = g_encoder.pwm_count;
|
|
|
g_encoder.last_cnt = g_encoder.pwm_count;
|
|
|
g_encoder.est_pll.observer = (float)g_encoder.pwm_count;
|
|
|
g_encoder.abi_angle = g_encoder.pwm_angle;
|
|
|
g_encoder.b_index_found = true;
|
|
|
+ g_encoder.last_delta_cnt = MAX_S16;
|
|
|
PLL_Reset(&g_encoder.est_pll, (float)_abi_count());
|
|
|
+ cpu_exit_critical(mask);
|
|
|
}
|
|
|
|
|
|
/*I 信号的中断处理,一圈一个中断*/
|
|
|
@@ -386,11 +361,16 @@ void ENC_PWM_Duty_Handler(float t, float d) {
|
|
|
encoder_sync_pwm_abs();
|
|
|
}
|
|
|
pwm_check_count ++;
|
|
|
+#ifdef CONFIG_ENC_ERR_TEST
|
|
|
+ if (!g_encoder.produce_error) {
|
|
|
+ g_encoder.pwm_time_ms = get_tick_ms();
|
|
|
+ }
|
|
|
+#endif
|
|
|
}
|
|
|
static u32 _check_time = 0;
|
|
|
bool ENC_Check_error(void) {
|
|
|
bool error = false;
|
|
|
- if (get_delta_ms(_check_time) > 1000) {
|
|
|
+ if (get_delta_ms(_check_time) > 200) {
|
|
|
if (pwm_check_count == 0) {
|
|
|
error = true;
|
|
|
}
|
|
|
@@ -418,5 +398,5 @@ float encoder_get_abi_angle(void) {
|
|
|
void encoder_log(void) {
|
|
|
sys_debug("pwm %f, abi %f\n", encoder_get_pwm_angle(), encoder_get_abi_angle());
|
|
|
sys_debug("pwm count %d, I count %d\n", g_encoder.pwm_count, abi_I_delta);
|
|
|
- sys_debug("pwm freq %f\n", enc_get_pwm_freq());
|
|
|
+ sys_debug("pwm freq %f, err %d\n", enc_get_pwm_freq(), g_encoder.enc_maybe_err);
|
|
|
}
|