Copter: add current based compass compensation

This commit is contained in:
Randy Mackay 2013-03-03 23:02:36 +09:00
parent b8d492b504
commit cb84ec9d9b
7 changed files with 112 additions and 37 deletions

View File

@ -1079,6 +1079,11 @@ static void medium_loop()
case 0: case 0:
medium_loopCounter++; medium_loopCounter++;
// read battery before compass because it may be used for motor interference compensation
if (g.battery_monitoring != 0) {
read_battery();
}
#if HIL_MODE != HIL_MODE_ATTITUDE // don't execute in HIL mode #if HIL_MODE != HIL_MODE_ATTITUDE // don't execute in HIL mode
if(g.compass_enabled) { if(g.compass_enabled) {
if (compass.read()) { if (compass.read()) {
@ -1154,10 +1159,6 @@ static void medium_loop()
case 4: case 4:
medium_loopCounter = 0; medium_loopCounter = 0;
if (g.battery_monitoring != 0) {
read_battery();
}
// Accel trims = hold > 2 seconds // Accel trims = hold > 2 seconds
// Throttle cruise = switch less than 1 second // Throttle cruise = switch less than 1 second
// -------------------------------------------- // --------------------------------------------
@ -1327,6 +1328,7 @@ static void super_slow_loop()
Log_Write_Data(DATA_AP_STATE, ap.value); Log_Write_Data(DATA_AP_STATE, ap.value);
} }
// log battery info to the dataflash
if (g.log_bitmask & MASK_LOG_CURRENT && motors.armed()) if (g.log_bitmask & MASK_LOG_CURRENT && motors.armed())
Log_Write_Current(); Log_Write_Current();

View File

@ -208,7 +208,7 @@ static NOINLINE void send_extended_status1(mavlink_channel_t chan, uint16_t pack
battery_current = current_amps1 * 100; battery_current = current_amps1 * 100;
} }
if (g.battery_monitoring == 3) { if (g.battery_monitoring == BATT_MONITOR_VOLTAGE_ONLY) {
/*setting a out-of-range value. /*setting a out-of-range value.
* It informs to external devices that * It informs to external devices that
* it cannot be calculated properly just by voltage*/ * it cannot be calculated properly just by voltage*/

View File

@ -82,7 +82,7 @@ const AP_Param::Info var_info[] PROGMEM = {
// @Description: Controls enabling monitoring of the battery's voltage and current // @Description: Controls enabling monitoring of the battery's voltage and current
// @Values: 0:Disabled,3:Voltage Only,4:Voltage and Current // @Values: 0:Disabled,3:Voltage Only,4:Voltage and Current
// @User: Standard // @User: Standard
GSCALAR(battery_monitoring, "BATT_MONITOR", DISABLED), GSCALAR(battery_monitoring, "BATT_MONITOR", BATT_MONITOR_DISABLED),
// @Param: FS_BATT_ENABLE // @Param: FS_BATT_ENABLE
// @DisplayName: Battery Failsafe Enable // @DisplayName: Battery Failsafe Enable

View File

@ -350,6 +350,10 @@ enum gcs_severity {
#define BATTERY_VOLTAGE(x) (x->voltage_average()*g.volt_div_ratio) #define BATTERY_VOLTAGE(x) (x->voltage_average()*g.volt_div_ratio)
#define CURRENT_AMPS(x) (x->voltage_average()-CURR_AMPS_OFFSET)*g.curr_amp_per_volt #define CURRENT_AMPS(x) (x->voltage_average()-CURR_AMPS_OFFSET)*g.curr_amp_per_volt
#define BATT_MONITOR_DISABLED 0
#define BATT_MONITOR_VOLTAGE_ONLY 3
#define BATT_MONITOR_VOLTAGE_AND_CURRENT 4
/* ************************************************************** */ /* ************************************************************** */
/* Expansion PIN's that people can use for various things. */ /* Expansion PIN's that people can use for various things. */

View File

@ -111,23 +111,26 @@ static void read_battery(void)
{ {
static uint8_t low_battery_counter = 0; static uint8_t low_battery_counter = 0;
if(g.battery_monitoring == 0) { if(g.battery_monitoring == BATT_MONITOR_DISABLED) {
battery_voltage1 = 0; battery_voltage1 = 0;
return; return;
} }
if(g.battery_monitoring == 3 || g.battery_monitoring == 4) { if(g.battery_monitoring == BATT_MONITOR_VOLTAGE_ONLY || g.battery_monitoring == BATT_MONITOR_VOLTAGE_AND_CURRENT) {
batt_volt_analog_source->set_pin(g.battery_volt_pin); batt_volt_analog_source->set_pin(g.battery_volt_pin);
battery_voltage1 = BATTERY_VOLTAGE(batt_volt_analog_source); battery_voltage1 = BATTERY_VOLTAGE(batt_volt_analog_source);
} }
if(g.battery_monitoring == 4) { if(g.battery_monitoring == BATT_MONITOR_VOLTAGE_AND_CURRENT) {
batt_curr_analog_source->set_pin(g.battery_curr_pin); batt_curr_analog_source->set_pin(g.battery_curr_pin);
current_amps1 = CURRENT_AMPS(batt_curr_analog_source); current_amps1 = CURRENT_AMPS(batt_curr_analog_source);
current_total1 += current_amps1 * 0.02778f; // called at 100ms on average, .0002778 is 1/3600 (conversion to hours) current_total1 += current_amps1 * 0.02778f; // called at 100ms on average, .0002778 is 1/3600 (conversion to hours)
// update compass with current value
compass.set_current(current_amps1);
} }
// check for low voltage or current if the low voltage check hasn't already been triggered // check for low voltage or current if the low voltage check hasn't already been triggered
if (!ap.low_battery && ( battery_voltage1 < g.low_voltage || (g.battery_monitoring == 4 && current_total1 > g.pack_capacity))) { if (!ap.low_battery && ( battery_voltage1 < g.low_voltage || (g.battery_monitoring == BATT_MONITOR_VOLTAGE_AND_CURRENT && current_total1 > g.pack_capacity))) {
low_battery_counter++; low_battery_counter++;
if( low_battery_counter >= BATTERY_FS_COUNTER ) { if( low_battery_counter >= BATTERY_FS_COUNTER ) {
low_battery_counter = BATTERY_FS_COUNTER; // ensure counter does not overflow low_battery_counter = BATTERY_FS_COUNTER; // ensure counter does not overflow

View File

@ -463,13 +463,32 @@ setup_compass(uint8_t argc, const Menu::arg *argv)
static int8_t static int8_t
setup_compassmot(uint8_t argc, const Menu::arg *argv) setup_compassmot(uint8_t argc, const Menu::arg *argv)
{ {
int8_t comp_type; // throttle or current based compensation
Vector3f compass_base; // compass vector when throttle is zero Vector3f compass_base; // compass vector when throttle is zero
Vector3f motor_impact; // impact of motors on compass vector Vector3f motor_impact; // impact of motors on compass vector
Vector3f motor_impact_scaled; // impact of motors on compass vector scaled with throttle Vector3f motor_impact_scaled; // impact of motors on compass vector scaled with throttle
Vector3f motor_compensation; // final compensation to be stored to eeprom Vector3f motor_compensation; // final compensation to be stored to eeprom
float throttle_pct; // throttle as a percentage 0.0 ~ 1.0 float throttle_pct; // throttle as a percentage 0.0 ~ 1.0
uint32_t last_run_time; uint32_t last_run_time;
uint8_t print_counter = 0; uint8_t print_counter = 49;
bool updated = false; // have we updated the compensation vector at least once
// default compensation type to use current if possible
if( g.battery_monitoring == BATT_MONITOR_VOLTAGE_AND_CURRENT ) {
comp_type = AP_COMPASS_MOT_COMP_CURRENT;
}else{
comp_type = AP_COMPASS_MOT_COMP_THROTTLE;
}
// check if user wants throttle compensation
if( !strcmp_P(argv[1].str, PSTR("t")) || !strcmp_P(argv[1].str, PSTR("T")) ) {
comp_type = AP_COMPASS_MOT_COMP_THROTTLE;
}
// check if user wants current compensation
if( !strcmp_P(argv[1].str, PSTR("c")) || !strcmp_P(argv[1].str, PSTR("C")) ) {
comp_type = AP_COMPASS_MOT_COMP_CURRENT;
}
// check compass is enabled // check compass is enabled
if( !g.compass_enabled ) { if( !g.compass_enabled ) {
@ -477,30 +496,39 @@ setup_compassmot(uint8_t argc, const Menu::arg *argv)
return 0; return 0;
} }
// check if we have a current monitor
if( comp_type == AP_COMPASS_MOT_COMP_CURRENT && g.battery_monitoring != BATT_MONITOR_VOLTAGE_AND_CURRENT ) {
cliSerial->print_P(PSTR("current monitor disabled, exiting"));
return 0;
}
// initialise compass // initialise compass
init_compass(); init_compass();
// set motor compensation to zero // disable motor compensation
compass.motor_compensation_type(AP_COMPASS_MOT_COMP_DISABLED);
compass.set_motor_compensation(Vector3f(0,0,0)); compass.set_motor_compensation(Vector3f(0,0,0));
// print warning that motors will spin // print warning that motors will spin
cliSerial->print_P(PSTR("This setup records the impact on the compass of spinning up the motors. The motors will spin!\n"));
// ask user to raise throttle // ask user to raise throttle
cliSerial->print_P(PSTR("Hold throttle low, then raise as high as possible (without taking off) for 10 sec.\n"));
// inform how to stop test // inform how to stop test
cliSerial->print_P(PSTR("At any time you may press any key to exit.\n")); cliSerial->print_P(PSTR("This setup records the impact on the compass of spinning up the motors. The motors will spin!\nHold throttle low, then raise as high as safely possible for 10 sec.\nAt any time you may press any key to exit.\nmeasuring compass vs "));
// wait 1 second for user to read message // inform what type of compensation we are attempting
delay(2000); if( comp_type == AP_COMPASS_MOT_COMP_CURRENT ) {
cliSerial->print_P(PSTR("CURRENT\n"));
}else{
cliSerial->print_P(PSTR("THROTTLE\n"));
}
// clear out user input
while( cliSerial->available() ) { while( cliSerial->available() ) {
cliSerial->read(); cliSerial->read();
} }
// disable throttle failsafe // disable throttle and battery failsafe
g.failsafe_throttle = FS_THR_DISABLED; g.failsafe_throttle = FS_THR_DISABLED;
g.failsafe_battery_enabled = false;
// read radio // read radio
read_radio(); read_radio();
@ -561,6 +589,9 @@ setup_compassmot(uint8_t argc, const Menu::arg *argv)
// read some compass values // read some compass values
compass.read(); compass.read();
// read current
read_battery();
// calculate scaling for throttle // calculate scaling for throttle
throttle_pct = (float)g.rc_3.control_in / 1000.0f; throttle_pct = (float)g.rc_3.control_in / 1000.0f;
throttle_pct = constrain(throttle_pct,0.0f,1.0f); throttle_pct = constrain(throttle_pct,0.0f,1.0f);
@ -574,22 +605,36 @@ setup_compassmot(uint8_t argc, const Menu::arg *argv)
// causing printing to happen as soon as throttle is lifted // causing printing to happen as soon as throttle is lifted
print_counter = 49; print_counter = 49;
}else{ }else{
// calculate diff from compass base and scale with throttle // calculate diff from compass base and scale with throttle
motor_impact.x = compass.mag_x - compass_base.x; motor_impact.x = compass.mag_x - compass_base.x;
motor_impact.y = compass.mag_y - compass_base.y; motor_impact.y = compass.mag_y - compass_base.y;
motor_impact.z = compass.mag_z - compass_base.z; motor_impact.z = compass.mag_z - compass_base.z;
// scale by throttle // throttle based compensation
motor_impact_scaled = motor_impact / throttle_pct; if( comp_type == AP_COMPASS_MOT_COMP_THROTTLE ) {
// scale by throttle
motor_impact_scaled = motor_impact / throttle_pct;
// adjust the motor compensation to negate the impact // adjust the motor compensation to negate the impact
motor_compensation = motor_compensation * 0.99f - motor_impact_scaled * 0.01f; motor_compensation = motor_compensation * 0.99f - motor_impact_scaled * 0.01f;
updated = true;
}else{
// current based compensation if more than 3amps being drawn
motor_impact_scaled = motor_impact / current_amps1;
// adjust the motor compensation to negate the impact if drawing over 3amps
if( current_amps1 >= 3.0f ) {
motor_compensation = motor_compensation * 0.99f - motor_impact_scaled * 0.01f;
updated = true;
}
}
// display output at 1hz if throttle is above zero // display output at 1hz if throttle is above zero
print_counter++; print_counter++;
if(print_counter >= 50) { if(print_counter >= 50) {
print_counter = 0; print_counter = 0;
cliSerial->printf_P(PSTR("thr:%d mot x:%4.1f\ty:%4.1f\tz:%4.1f\tcomp x:%4.1f\ty:%4.1f\tz:%4.1f\n"),(int)g.rc_3.control_in, (float)motor_impact.x, (float)motor_impact.y, (float)motor_impact.z, (float)motor_compensation.x, (float)motor_compensation.y, (float)motor_compensation.z); cliSerial->printf_P(PSTR("thr:%d cur:%4.2f mot x:%4.1f y:%4.1f z:%4.1f comp x:%4.2f y:%4.2f z:%4.2f\n"),(int)g.rc_3.control_in, (float)current_amps1, (float)motor_impact.x, (float)motor_impact.y, (float)motor_impact.z, (float)motor_compensation.x, (float)motor_compensation.y, (float)motor_compensation.z);
} }
} }
}else{ }else{
@ -607,9 +652,19 @@ setup_compassmot(uint8_t argc, const Menu::arg *argv)
cliSerial->read(); cliSerial->read();
} }
// print one more time so the last thing printed matches what appears in the report_compass
cliSerial->printf_P(PSTR("thr:%d cur:%4.2f mot x:%4.1f y:%4.1f z:%4.1f comp x:%4.2f y:%4.2f z:%4.2f\n"),(int)g.rc_3.control_in, (float)current_amps1, (float)motor_impact.x, (float)motor_impact.y, (float)motor_impact.z, (float)motor_compensation.x, (float)motor_compensation.y, (float)motor_compensation.z);
// set and save motor compensation // set and save motor compensation
compass.set_motor_compensation(motor_compensation); if( updated ) {
compass.save_motor_compensation(); compass.motor_compensation_type(comp_type);
compass.set_motor_compensation(motor_compensation);
compass.save_motor_compensation();
}else{
// compensation vector never updated, report failure
cliSerial->printf_P(PSTR("Failed! Compensation disabled. Did you forget to raise the throttle high enough?"));
compass.motor_compensation_type(AP_COMPASS_MOT_COMP_DISABLED);
}
// display new motor offsets and save // display new motor offsets and save
report_compass(); report_compass();
@ -946,9 +1001,9 @@ static void report_batt_monitor()
{ {
cliSerial->printf_P(PSTR("\nBatt Mon:\n")); cliSerial->printf_P(PSTR("\nBatt Mon:\n"));
print_divider(); print_divider();
if(g.battery_monitoring == 0) print_enabled(false); if(g.battery_monitoring == BATT_MONITOR_DISABLED) print_enabled(false);
if(g.battery_monitoring == 3) cliSerial->printf_P(PSTR("volts")); if(g.battery_monitoring == BATT_MONITOR_VOLTAGE_ONLY) cliSerial->printf_P(PSTR("volts"));
if(g.battery_monitoring == 4) cliSerial->printf_P(PSTR("volts and cur")); if(g.battery_monitoring == BATT_MONITOR_VOLTAGE_AND_CURRENT) cliSerial->printf_P(PSTR("volts and cur"));
print_blanks(2); print_blanks(2);
} }
@ -1044,11 +1099,22 @@ static void report_compass()
offsets.z); offsets.z);
// motor compensation // motor compensation
Vector3f motor_compensation = compass.get_motor_compensation(); cliSerial->print_P(PSTR("Motor Comp: "));
cliSerial->printf_P(PSTR("Mot comp: %4.0f, %4.0f, %4.0f\n"), if( compass.motor_compensation_type() == AP_COMPASS_MOT_COMP_DISABLED ) {
motor_compensation.x, cliSerial->print_P(PSTR("Off\n"));
motor_compensation.y, }else{
motor_compensation.z); if( compass.motor_compensation_type() == AP_COMPASS_MOT_COMP_THROTTLE ) {
cliSerial->print_P(PSTR("Throttle"));
}
if( compass.motor_compensation_type() == AP_COMPASS_MOT_COMP_CURRENT ) {
cliSerial->print_P(PSTR("Current"));
}
Vector3f motor_compensation = compass.get_motor_compensation();
cliSerial->printf_P(PSTR("\nComp Vec: %4.2f, %4.2f, %4.2f\n"),
motor_compensation.x,
motor_compensation.y,
motor_compensation.z);
}
print_blanks(1); print_blanks(1);
} }

View File

@ -680,7 +680,7 @@ test_battery(uint8_t argc, const Menu::arg *argv)
delay(100); delay(100);
read_radio(); read_radio();
read_battery(); read_battery();
if (g.battery_monitoring == 3) { if (g.battery_monitoring == BATT_MONITOR_VOLTAGE_ONLY) {
cliSerial->printf_P(PSTR("V: %4.4f\n"), cliSerial->printf_P(PSTR("V: %4.4f\n"),
battery_voltage1, battery_voltage1,
current_amps1, current_amps1,