Improved flux linkage measurement

This commit is contained in:
Benjamin Vedder 2020-04-16 09:12:08 +02:00
parent ccb2fd3f7f
commit 6f7c40b4e1
7 changed files with 106 additions and 22 deletions

View File

@ -19,6 +19,7 @@
* Added hall_analyze terminal command.
* Motor temperature filtering bug fix.
* Inductance measurement scaling fix.
* Better flux linkage measurement.
=== FW 4.02 ===
* Position PID fix (most notable on multiturn encoders).

View File

@ -1580,9 +1580,14 @@ static THD_FUNCTION(blocking_thread, arg) {
inductance = buffer_get_float32(data, 1e8, &ind);
}
float linkage;
float linkage, linkage_undriven, undriven_samples;
bool res = conf_general_measure_flux_linkage_openloop(current, duty,
erpm_per_sec, resistance, inductance, &linkage);
erpm_per_sec, resistance, inductance,
&linkage, &linkage_undriven, &undriven_samples);
if (undriven_samples > 60) {
linkage = linkage_undriven;
}
if (!res) {
linkage = 0.0;

View File

@ -789,11 +789,18 @@ uint8_t conf_general_calculate_deadtime(float deadtime_ns, float core_clock_freq
* @param linkage
* The calculated flux linkage.
*
* @param linkage_undriven
* Flux linkage measured while the motor was undriven.
*
* @param undriven_samples
* Number of flux linkage samples while the motor was undriven.
*
* @return
* True for success, false otherwise.
*/
bool conf_general_measure_flux_linkage_openloop(float current, float duty,
float erpm_per_sec, float res, float ind, float *linkage) {
float erpm_per_sec, float res, float ind, float *linkage,
float *linkage_undriven, float *undriven_samples) {
bool result = false;
mc_configuration *mcconf = mempools_alloc_mcconf();
@ -901,7 +908,7 @@ bool conf_general_measure_flux_linkage_openloop(float current, float duty,
float id_avg = 0.0;
float samples2 = 0.0;
for (int i = 0;i < 30000;i++) {
for (int i = 0;i < 10000;i++) {
vq_avg += mcpwm_foc_get_vq();
vd_avg += mcpwm_foc_get_vd();
iq_avg += mcpwm_foc_get_iq();
@ -915,14 +922,40 @@ bool conf_general_measure_flux_linkage_openloop(float current, float duty,
iq_avg /= samples2;
id_avg /= samples2;
(void)ind;
*linkage = (sqrtf(SQ(vq_avg) + SQ(vd_avg)) - res *
sqrtf(SQ(iq_avg) + SQ(id_avg))) / (rpm_now * ((2.0 * M_PI) / 60.0));
float rad_s = rpm_now * ((2.0 * M_PI) / 60.0);
float v_mag = sqrtf(SQ(vq_avg) + SQ(vd_avg));
float i_mag = sqrtf(SQ(iq_avg) + SQ(id_avg));
*linkage = (v_mag - (2.0 / 3.0) * res * i_mag) / rad_s - (2.0 / 3.0) * i_mag * ind;
// float rad_s = rpm_now * ((2.0 * M_PI) / 60.0);
// float v_mag = sqrtf(SQ(vq_avg) + SQ(vd_avg));
// float i_mag = sqrtf(SQ(iq_avg) + SQ(id_avg));
// *linkage = (v_mag - res * i_mag) / rad_s - i_mag * ind;
mcconf->foc_motor_r = res;
mcconf->foc_motor_l = ind;
mcconf->foc_motor_flux_linkage = *linkage;
mcconf->foc_observer_gain = 0.5e3 / SQ(*linkage);
mc_interface_set_configuration(mcconf);
chThdSleepMilliseconds(500);
mcpwm_foc_set_current(0.0);
chThdSleepMilliseconds(5);
float linkage_sum = 0.0;
float linkage_samples = 0.0;
for (int i = 0;i < 20000;i++) {
float rad_s_now = mcpwm_foc_get_rpm_faster() * ((2.0 * M_PI) / 60.0);
if (fabsf(mcpwm_foc_get_duty_cycle_now()) < 0.01) {
break;
}
linkage_sum += mcpwm_foc_get_vq() / rad_s_now;
linkage_samples += 1.0;
chThdSleep(1);
}
*undriven_samples = linkage_samples;
if (linkage_samples > 0) {
*linkage_undriven = linkage_sum / linkage_samples;
} else {
*linkage_undriven = 0.0;
}
result = true;
}
@ -1238,13 +1271,23 @@ static void measure_flux_linkage_task(void *arg) {
measure_flux_linkage_arg_t *args = (measure_flux_linkage_arg_t*)arg;
mc_interface_select_motor_thread(args->motor);
float linkage, linkage_undriven, undriven_samples;
args->result = conf_general_measure_flux_linkage_openloop(
args->current,
args->duty,
args->erpm_per_sec,
args->res,
args->ind,
&args->linkage);
&linkage,
&linkage_undriven,
&undriven_samples);
if (undriven_samples > 60) {
args->linkage = linkage_undriven;
} else {
args->linkage = linkage;
}
}
typedef struct {
@ -1420,7 +1463,14 @@ int conf_general_detect_apply_all_foc(float max_power_loss,
#endif
float lambda = 0.0;
int res = conf_general_measure_flux_linkage_openloop(i_max / 2.5, 0.3, 1800, r, l, &lambda);
float lambda_undriven = 0.0;
float lambda_undriven_samples = 0.0;
int res = conf_general_measure_flux_linkage_openloop(i_max / 2.5, 0.3, 1800, r, l,
&lambda, &lambda_undriven, &lambda_undriven_samples);
if (lambda_undriven_samples > 60) {
lambda = lambda_undriven;
}
#ifdef HW_HAS_DUAL_MOTORS
worker_wait();

View File

@ -24,7 +24,7 @@
#define FW_VERSION_MAJOR 5
#define FW_VERSION_MINOR 00
// Set to 0 for building a release and iterate during beta test builds
#define FW_TEST_VERSION_NUMBER 3
#define FW_TEST_VERSION_NUMBER 4
#include "datatypes.h"
@ -72,8 +72,8 @@
// Mark3 version of HW60 with power switch and separate NRF UART.
//#define HW60_IS_MK3
#define HW_SOURCE "hw_60.c"
#define HW_HEADER "hw_60.h"
//#define HW_SOURCE "hw_60.c"
//#define HW_HEADER "hw_60.h"
//#define HW_SOURCE "hw_r2.c"
//#define HW_HEADER "hw_r2.h"
@ -121,8 +121,8 @@
//#define HW_SOURCE "hw_binar_v1.c"
//#define HW_HEADER "hw_binar_v1.h"
//#define HW_SOURCE "hw_hd.c"
//#define HW_HEADER "hw_hd.h"
#define HW_SOURCE "hw_hd.c"
#define HW_HEADER "hw_hd.h"
//#define HW_SOURCE "hw_a200s_v2.c"
//#define HW_HEADER "hw_a200s_v2.h"
@ -306,7 +306,8 @@ bool conf_general_measure_flux_linkage(float current, float duty,
float min_erpm, float res, float *linkage);
uint8_t conf_general_calculate_deadtime(float deadtime_ns, float core_clock_freq);
bool conf_general_measure_flux_linkage_openloop(float current, float duty,
float erpm_per_sec, float res, float ind, float *linkage);
float erpm_per_sec, float res, float ind, float *linkage,
float *linkage_undriven, float *undriven_samples);
int conf_general_autodetect_apply_sensors_foc(float current,
bool store_mcconf_on_success, bool send_mcconf_on_success);
void conf_general_calc_apply_foc_cc_kp_ki_gain(mc_configuration *mcconf, float tc);

View File

@ -127,6 +127,7 @@ typedef struct {
float m_gamma_now;
bool m_using_encoder;
float m_speed_est_fast;
float m_speed_est_faster;
int m_curr_samples;
int m_curr_sum[3];
int m_curr_ofs[3];
@ -1141,6 +1142,20 @@ float mcpwm_foc_get_rpm(void) {
// return motor_now()->m_speed_est_fast / ((2.0 * M_PI) / 60.0);
}
/**
* Same as above, but uses the fast and noisier estimator.
*/
float mcpwm_foc_get_rpm_fast(void) {
return motor_now()->m_speed_est_fast / ((2.0 * M_PI) / 60.0);
}
/**
* Same as above, but uses the faster and noisier estimator.
*/
float mcpwm_foc_get_rpm_faster(void) {
return motor_now()->m_speed_est_faster / ((2.0 * M_PI) / 60.0);
}
/**
* Get the motor current. The sign of this value will
* represent whether the motor is drawing (positive) or generating
@ -2686,6 +2701,10 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) {
UTILS_LP_FAST(motor_now->m_speed_est_fast, diff / dt, 0.01);
UTILS_NAN_ZERO(motor_now->m_speed_est_fast);
UTILS_LP_FAST(motor_now->m_speed_est_faster, diff / dt, 0.2);
UTILS_NAN_ZERO(motor_now->m_speed_est_faster);
motor_now->m_phase_before_speed_est = motor_now->m_motor_state.phase;
}

View File

@ -52,6 +52,8 @@ float mcpwm_foc_get_pid_pos_now(void);
float mcpwm_foc_get_switching_frequency_now(void);
float mcpwm_foc_get_sampling_frequency_now(void);
float mcpwm_foc_get_rpm(void);
float mcpwm_foc_get_rpm_fast(void);
float mcpwm_foc_get_rpm_faster(void);
float mcpwm_foc_get_tot_current(void);
float mcpwm_foc_get_tot_current_filtered(void);
float mcpwm_foc_get_abs_motor_current(void);

View File

@ -469,9 +469,15 @@ void terminal_process_string(char *str) {
if (current > 0.0 && current <= mc_interface_get_configuration()->l_current_max &&
erpm_per_sec > 0.0 && duty > 0.02 && res >= 0.0 && ind >= 0.0) {
float linkage;
conf_general_measure_flux_linkage_openloop(current, duty, erpm_per_sec, res, ind, &linkage);
commands_printf("Flux linkage: %.7f\n", (double)linkage);
float linkage, linkage_undriven, undriven_samples;
commands_printf("Measuring flux linkage...");
conf_general_measure_flux_linkage_openloop(current, duty, erpm_per_sec, res, ind,
&linkage, &linkage_undriven, &undriven_samples);
commands_printf(
"Flux linkage : %.7f\n"
"Flux Linkage (undriven) : %.7f\n"
"Undriven samples : %.1f\n",
(double)linkage, (double)linkage_undriven, (double)undriven_samples);
} else {
commands_printf("Invalid argument(s).\n");
}