123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /*
- 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;
- }
- }
|