You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
231 lines
6.0 KiB
231 lines
6.0 KiB
/* |
|
per-motor compass compensation |
|
*/ |
|
|
|
#include "AP_Compass.h" |
|
#include <GCS_MAVLink/GCS.h> |
|
#include <SRV_Channel/SRV_Channel.h> |
|
|
|
extern const AP_HAL::HAL &hal; |
|
|
|
const AP_Param::GroupInfo Compass_PerMotor::var_info[] = { |
|
// @Param: _EN |
|
// @DisplayName: per-motor compass correction enable |
|
// @Description: This enables per-motor compass corrections |
|
// @Values: 0:Disabled,1:Enabled |
|
// @User: Advanced |
|
AP_GROUPINFO_FLAGS("_EN", 1, Compass_PerMotor, enable, 0, AP_PARAM_FLAG_ENABLE), |
|
|
|
// @Param: _EXP |
|
// @DisplayName: per-motor exponential correction |
|
// @Description: This is the exponential correction for the power output of the motor for per-motor compass correction |
|
// @Range: 0 2 |
|
// @Increment: 0.01 |
|
// @User: Advanced |
|
AP_GROUPINFO("_EXP", 2, Compass_PerMotor, expo, 0.65), |
|
|
|
// @Param: 1_X |
|
// @DisplayName: Compass per-motor1 X |
|
// @Description: Compensation for X axis of motor1 |
|
// @User: Advanced |
|
|
|
// @Param: 1_Y |
|
// @DisplayName: Compass per-motor1 Y |
|
// @Description: Compensation for Y axis of motor1 |
|
// @User: Advanced |
|
|
|
// @Param: 1_Z |
|
// @DisplayName: Compass per-motor1 Z |
|
// @Description: Compensation for Z axis of motor1 |
|
// @User: Advanced |
|
AP_GROUPINFO("1", 3, Compass_PerMotor, compensation[0], 0), |
|
|
|
// @Param: 2_X |
|
// @DisplayName: Compass per-motor2 X |
|
// @Description: Compensation for X axis of motor2 |
|
// @User: Advanced |
|
|
|
// @Param: 2_Y |
|
// @DisplayName: Compass per-motor2 Y |
|
// @Description: Compensation for Y axis of motor2 |
|
// @User: Advanced |
|
|
|
// @Param: 2_Z |
|
// @DisplayName: Compass per-motor2 Z |
|
// @Description: Compensation for Z axis of motor2 |
|
// @User: Advanced |
|
AP_GROUPINFO("2", 4, Compass_PerMotor, compensation[1], 0), |
|
|
|
// @Param: 3_X |
|
// @DisplayName: Compass per-motor3 X |
|
// @Description: Compensation for X axis of motor3 |
|
// @User: Advanced |
|
|
|
// @Param: 3_Y |
|
// @DisplayName: Compass per-motor3 Y |
|
// @Description: Compensation for Y axis of motor3 |
|
// @User: Advanced |
|
|
|
// @Param: 3_Z |
|
// @DisplayName: Compass per-motor3 Z |
|
// @Description: Compensation for Z axis of motor3 |
|
// @User: Advanced |
|
AP_GROUPINFO("3", 5, Compass_PerMotor, compensation[2], 0), |
|
|
|
// @Param: 4_X |
|
// @DisplayName: Compass per-motor4 X |
|
// @Description: Compensation for X axis of motor4 |
|
// @User: Advanced |
|
|
|
// @Param: 4_Y |
|
// @DisplayName: Compass per-motor4 Y |
|
// @Description: Compensation for Y axis of motor4 |
|
// @User: Advanced |
|
|
|
// @Param: 4_Z |
|
// @DisplayName: Compass per-motor4 Z |
|
// @Description: Compensation for Z axis of motor4 |
|
// @User: Advanced |
|
AP_GROUPINFO("4", 6, Compass_PerMotor, compensation[3], 0), |
|
|
|
AP_GROUPEND |
|
}; |
|
|
|
// constructor |
|
Compass_PerMotor::Compass_PerMotor(Compass &_compass) : |
|
compass(_compass) |
|
{ |
|
AP_Param::setup_object_defaults(this, var_info); |
|
} |
|
|
|
// return current scaled motor output |
|
float Compass_PerMotor::scaled_output(uint8_t motor) |
|
{ |
|
if (!have_motor_map) { |
|
if (SRV_Channels::find_channel(SRV_Channel::k_motor1, motor_map[0]) && |
|
SRV_Channels::find_channel(SRV_Channel::k_motor2, motor_map[1]) && |
|
SRV_Channels::find_channel(SRV_Channel::k_motor3, motor_map[2]) && |
|
SRV_Channels::find_channel(SRV_Channel::k_motor4, motor_map[3])) { |
|
have_motor_map = true; |
|
} |
|
} |
|
if (!have_motor_map) { |
|
return 0; |
|
} |
|
|
|
// this currently assumes first 4 channels. |
|
uint16_t pwm = hal.rcout->read_last_sent(motor_map[motor]); |
|
|
|
// get 0 to 1 motor demand |
|
float output = (hal.rcout->scale_esc_to_unity(pwm)+1) * 0.5f; |
|
|
|
if (output <= 0) { |
|
return 0; |
|
} |
|
|
|
// scale for voltage |
|
output *= voltage; |
|
|
|
// apply expo correction |
|
output = powf(output, expo); |
|
return output; |
|
} |
|
|
|
// per-motor calibration update |
|
void Compass_PerMotor::calibration_start(void) |
|
{ |
|
for (uint8_t i=0; i<4; i++) { |
|
field_sum[i].zero(); |
|
output_sum[i] = 0; |
|
count[i] = 0; |
|
start_ms[i] = 0; |
|
} |
|
|
|
// we need to ensure we get current data by throwing away several |
|
// samples. The offsets may have just changed from an offset |
|
// calibration |
|
for (uint8_t i=0; i<4; i++) { |
|
compass.read(); |
|
hal.scheduler->delay(50); |
|
} |
|
|
|
base_field = compass.get_field(0); |
|
running = true; |
|
} |
|
|
|
// per-motor calibration update |
|
void Compass_PerMotor::calibration_update(void) |
|
{ |
|
uint32_t now = AP_HAL::millis(); |
|
|
|
// accumulate per-motor sums |
|
for (uint8_t i=0; i<4; i++) { |
|
float output = scaled_output(i); |
|
|
|
if (output <= 0) { |
|
// motor is off |
|
start_ms[i] = 0; |
|
continue; |
|
} |
|
if (start_ms[i] == 0) { |
|
start_ms[i] = now; |
|
} |
|
if (now - start_ms[i] < 500) { |
|
// motor must run for 0.5s to settle |
|
continue; |
|
} |
|
|
|
// accumulate a sample |
|
field_sum[i] += compass.get_field(0); |
|
output_sum[i] += output; |
|
count[i]++; |
|
} |
|
} |
|
|
|
// calculate per-motor calibration values |
|
void Compass_PerMotor::calibration_end(void) |
|
{ |
|
for (uint8_t i=0; i<4; i++) { |
|
if (count[i] == 0) { |
|
continue; |
|
} |
|
|
|
// calculate effective output |
|
float output = output_sum[i] / count[i]; |
|
|
|
// calculate amount that field changed from base field |
|
Vector3f field_change = base_field - (field_sum[i] / count[i]); |
|
if (output <= 0) { |
|
continue; |
|
} |
|
|
|
Vector3f c = field_change / output; |
|
compensation[i].set_and_save(c); |
|
} |
|
|
|
// enable per-motor compensation |
|
enable.set_and_save(1); |
|
|
|
running = false; |
|
} |
|
|
|
/* |
|
calculate total offset for per-motor compensation |
|
*/ |
|
void Compass_PerMotor::compensate(Vector3f &offset) |
|
{ |
|
offset.zero(); |
|
|
|
if (running) { |
|
// don't compensate while calibrating |
|
return; |
|
} |
|
|
|
for (uint8_t i=0; i<4; i++) { |
|
float output = scaled_output(i); |
|
|
|
const Vector3f &c = compensation[i].get(); |
|
|
|
offset += c * output; |
|
} |
|
}
|
|
|