/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* mixer for failsafe operation when FMU is dead */ #include #include #include #include "iofirmware.h" #define ANGLE_SCALE ((int32_t)4500) #define RANGE_SCALE ((int32_t)1000) /* return a RC input value scaled from -4500 to 4500 */ int16_t AP_IOMCU_FW::mix_input_angle(uint8_t channel, uint16_t radio_in) const { const uint16_t &rc_min = mixing.rc_min[channel]; const uint16_t &rc_max = mixing.rc_max[channel]; const uint16_t &rc_trim = mixing.rc_trim[channel]; const uint16_t &reversed = mixing.rc_reversed[channel]; int16_t ret = 0; if (radio_in > rc_trim && rc_max != rc_trim) { ret = (ANGLE_SCALE * (int32_t)(radio_in - rc_trim)) / (int32_t)(rc_max - rc_trim); } else if (radio_in < rc_trim && rc_trim != rc_min) { ret = (ANGLE_SCALE * (int32_t)(radio_in - rc_trim)) / (int32_t)(rc_trim - rc_min); } if (reversed) { ret = -ret; } return ret; } /* return a RC input value scaled from 0 to 1000 */ int16_t AP_IOMCU_FW::mix_input_range(uint8_t channel, uint16_t radio_in) const { const uint16_t &rc_min = mixing.rc_min[channel]; const uint16_t &rc_max = mixing.rc_max[channel]; const uint16_t &reversed = mixing.rc_reversed[channel]; int16_t ret = 0; if (radio_in > rc_max) { ret = RANGE_SCALE; } else if (radio_in < rc_min) { ret = -RANGE_SCALE; } else { ret = (RANGE_SCALE * (int32_t)(radio_in - rc_min)) / (int32_t)(rc_max - rc_min); } if (reversed) { ret = -ret; } return ret; } /* return an output pwm giving an angle for a servo channel */ uint16_t AP_IOMCU_FW::mix_output_angle(uint8_t channel, int16_t angle) const { const uint16_t &srv_min = mixing.servo_min[channel]; const uint16_t &srv_max = mixing.servo_max[channel]; const uint16_t &srv_trim = mixing.servo_trim[channel]; const uint16_t &reversed = mixing.servo_reversed[channel]; if (reversed) { angle = -angle; } angle = constrain_int16(angle, -ANGLE_SCALE, ANGLE_SCALE); if (angle > 0) { return srv_trim + ((int32_t)angle * (int32_t)(srv_max - srv_trim)) / ANGLE_SCALE; } return srv_trim - (-(int32_t)angle * (int32_t)(srv_trim - srv_min)) / ANGLE_SCALE; } /* return an output pwm giving an range for a servo channel */ uint16_t AP_IOMCU_FW::mix_output_range(uint8_t channel, int16_t value) const { const uint16_t &srv_min = mixing.servo_min[channel]; const uint16_t &srv_max = mixing.servo_max[channel]; const uint16_t &reversed = mixing.servo_reversed[channel]; value = constrain_int16(value, 0, RANGE_SCALE); if (reversed) { value = RANGE_SCALE - value; } return srv_min + ((int32_t)value * (int32_t)(srv_max - srv_min)) / RANGE_SCALE; } /* elevon and vtail mixer */ int16_t AP_IOMCU_FW::mix_elevon_vtail(int16_t angle1, int16_t angle2, bool first_output) const { if (first_output) { return (angle2 - angle1) * mixing.mixing_gain / 1000; } return (angle1 + angle2) * mixing.mixing_gain / 1000; } /* run mixer. This is used when FMU is not providing inputs, or when the OVERRIDE_CHAN is high. It allows for manual fixed wing flight */ void AP_IOMCU_FW::run_mixer(void) { int16_t rcin[4] = {0, 0, 0, 0}; int16_t &roll = rcin[0]; int16_t &pitch = rcin[1]; int16_t &throttle = rcin[2]; int16_t &rudder = rcin[3]; // get RC input angles if (rc_input.flags_rc_ok) { for (uint8_t i=0;i<4; i++) { if (mixing.rc_channel[i] > 0 && mixing.rc_channel[i] <= IOMCU_MAX_RC_CHANNELS) { uint8_t chan = mixing.rc_channel[i]-1; if (i == 2 && !mixing.throttle_is_angle) { rcin[i] = mix_input_range(i, rc_input.pwm[chan]); } else { rcin[i] = mix_input_angle(i, rc_input.pwm[chan]); } } } } for (uint8_t i=0; i