Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
66c1bda98This file is pinned to the selected release. Download the original to open it in your design tool.
#ifndef _ESPFC_MODEL_CONFIG_H_
#define _ESPFC_MODEL_CONFIG_H_
#include "Target/Target.h"
#include <EscDriver.h>
#include "Utils/Filter.h"
#include "Hal/BusDevice.hpp"
#include "Device/GyroDevice.hpp"
#include "Device/MagDevice.hpp"
#include "Device/BaroDevice.hpp"
#include "Device/Input/InputPPM.hpp"
#include "Output/Mixers.h"
#include "Control/Pid.h"
namespace Espfc {
enum GyroDlpf {
GYRO_DLPF_256 = 0x00,
GYRO_DLPF_188 = 0x01,
GYRO_DLPF_98 = 0x02,
GYRO_DLPF_42 = 0x03,
GYRO_DLPF_20 = 0x04,
GYRO_DLPF_10 = 0x05,
GYRO_DLPF_5 = 0x06,
GYRO_DLPF_EX = 0x07,
};
enum SensorAlign {
ALIGN_DEFAULT = 0,
ALIGN_CW0_DEG = 1,
ALIGN_CW90_DEG = 2,
ALIGN_CW180_DEG = 3,
ALIGN_CW270_DEG = 4,
ALIGN_CW0_DEG_FLIP = 5,
ALIGN_CW90_DEG_FLIP = 6,
ALIGN_CW180_DEG_FLIP = 7,
ALIGN_CW270_DEG_FLIP = 8,
ALIGN_CUSTOM = 9,
};
enum FusionMode {
FUSION_NONE,
FUSION_MADGWICK,
FUSION_MAHONY,
FUSION_RTQF,
FUSION_MAX,
};
struct FusionConfig
{
int8_t mode = FUSION_MAHONY;
uint8_t gain = 50;
uint8_t gainI = 5;
uint8_t useMag = 0;
static const char * getModeName(FusionMode mode)
{
if(mode >= FUSION_MAX) return "?";
return getModeNames()[mode];
}
static const char ** getModeNames()
{
static const char* modeChoices[] = { "NONE", "MADGWICK", "MAHONY", "RTQF", NULL };
return modeChoices;
}
};
enum FlightMode {
MODE_ARMED,
MODE_AIRMODE,
MODE_ANGLE,
MODE_ALTHOLD,
MODE_BUZZER,
MODE_FAILSAFE,
MODE_BLACKBOX,
MODE_BLACKBOX_ERASE,
MODE_COUNT,
};
enum ScalerDimension {
ACT_INNER_P = 1 << 0, // 1
ACT_INNER_I = 1 << 1, // 2
ACT_INNER_D = 1 << 2, // 4
ACT_INNER_F = 1 << 3, // 8
ACT_OUTER_P = 1 << 4, // 16
ACT_OUTER_I = 1 << 5, // 32
ACT_OUTER_D = 1 << 6, // 64
ACT_OUTER_F = 1 << 7, // 128
ACT_AXIS_ROLL = 1 << 8, // 256
ACT_AXIS_PITCH = 1 << 9, // 512
ACT_AXIS_YAW = 1 << 10, // 1024
ACT_AXIS_THRUST = 1 << 11, // 2048
ACT_GYRO_THRUST = 1 << 12, // 4096
};
constexpr size_t SCALER_COUNT = 3;
struct ScalerConfig {
uint32_t dimension = 0;
int16_t minScale = 20;
int16_t maxScale = 400;
int8_t channel = 0;
};
enum DebugMode {
DEBUG_NONE,
DEBUG_CYCLETIME,
DEBUG_BATTERY,
DEBUG_GYRO_FILTERED,
DEBUG_ACCELEROMETER,
DEBUG_PIDLOOP,
DEBUG_RC_INTERPOLATION,
DEBUG_ANGLERATE,
DEBUG_ESC_SENSOR,
DEBUG_SCHEDULER,
DEBUG_STACK,
DEBUG_ESC_SENSOR_RPM,
DEBUG_ESC_SENSOR_TMP,
DEBUG_ALTITUDE,
DEBUG_FFT,
DEBUG_FFT_TIME,
DEBUG_FFT_FREQ,
DEBUG_RX_FRSKY_SPI,
DEBUG_RX_SFHSS_SPI,
DEBUG_GYRO_RAW,
DEBUG_MULTI_GYRO_RAW,
DEBUG_MULTI_GYRO_DIFF,
DEBUG_MAX7456_SIGNAL,
DEBUG_MAX7456_SPICLOCK,
DEBUG_SBUS,
DEBUG_FPORT,
DEBUG_RANGEFINDER,
DEBUG_RANGEFINDER_QUALITY,
DEBUG_OPTICALFLOW,
DEBUG_LIDAR_TF,
DEBUG_ADC_INTERNAL,
DEBUG_RUNAWAY_TAKEOFF,
DEBUG_SDIO,
DEBUG_CURRENT_SENSOR,
DEBUG_USB,
DEBUG_SMARTAUDIO,
DEBUG_RTH,
DEBUG_ITERM_RELAX,
DEBUG_ACRO_TRAINER,
DEBUG_RC_SMOOTHING,
DEBUG_RX_SIGNAL_LOSS,
DEBUG_RC_SMOOTHING_RATE,
DEBUG_ANTI_GRAVITY,
DEBUG_DYN_LPF,
DEBUG_RX_SPEKTRUM_SPI,
DEBUG_DSHOT_RPM_TELEMETRY,
DEBUG_RPM_FILTER,
DEBUG_D_MAX,
DEBUG_AC_CORRECTION,
DEBUG_AC_ERROR,
DEBUG_MULTI_GYRO_SCALED,
DEBUG_DSHOT_RPM_ERRORS,
DEBUG_CRSF_LINK_STATISTICS_UPLINK,
DEBUG_CRSF_LINK_STATISTICS_PWR,
DEBUG_CRSF_LINK_STATISTICS_DOWN,
DEBUG_BARO,
DEBUG_AUTOPILOT_ALTITUDE,
DEBUG_DYN_IDLE,
DEBUG_FEEDFORWARD_LIMIT,
DEBUG_FEEDFORWARD,
DEBUG_BLACKBOX_OUTPUT,
DEBUG_GYRO_SAMPLE,
DEBUG_RX_TIMING,
DEBUG_D_LPF,
DEBUG_VTX_TRAMP,
DEBUG_GHST,
DEBUG_GHST_MSP,
DEBUG_SCHEDULER_DETERMINISM,
DEBUG_TIMING_ACCURACY,
DEBUG_RX_EXPRESSLRS_SPI,
DEBUG_RX_EXPRESSLRS_PHASELOCK,
DEBUG_RX_STATE_TIME,
DEBUG_GPS_RESCUE_VELOCITY,
DEBUG_GPS_RESCUE_HEADING,
DEBUG_GPS_RESCUE_TRACKING,
DEBUG_GPS_CONNECTION,
DEBUG_ATTITUDE,
DEBUG_VTX_MSP,
DEBUG_GPS_DOP,
DEBUG_FAILSAFE,
DEBUG_GYRO_CALIBRATION,
DEBUG_ANGLE_MODE,
DEBUG_ANGLE_TARGET,
DEBUG_CURRENT_ANGLE,
DEBUG_DSHOT_TELEMETRY_COUNTS,
DEBUG_RPM_LIMIT,
DEBUG_RC_STATS,
DEBUG_MAG_CALIB,
DEBUG_MAG_TASK_RATE,
DEBUG_EZLANDING,
DEBUG_TPA,
DEBUG_S_TERM,
DEBUG_SPA,
DEBUG_TASK,
DEBUG_GIMBAL,
DEBUG_WING_SETPOINT,
DEBUG_CHIRP,
DEBUG_FLASH_TEST_PRBS,
DEBUG_MAVLINK_TELEMETRY,
DEBUG_AUTOPILOT_PID,
DEBUG_POSITION_NAV,
DEBUG_AUTOPILOT_STOP,
DEBUG_PITOT,
DEBUG_COUNT,
};
enum Axis {
AXIS_ROLL, // x
AXIS_PITCH, // y
AXIS_YAW, // z
AXIS_THRUST, // throttle channel index
AXIS_AUX_1,
AXIS_AUX_2,
AXIS_AUX_3,
AXIS_AUX_4,
AXIS_AUX_5,
AXIS_AUX_6,
AXIS_AUX_7,
AXIS_AUX_8,
AXIS_AUX_9,
AXIS_AUX_10,
AXIS_AUX_11,
AXIS_AUX_12,
AXIS_COUNT,
AXIS_COUNT_RP = AXIS_YAW, // RP axis count
AXIS_COUNT_RPY = AXIS_THRUST, // RPY axis count
AXIS_COUNT_RPYT = AXIS_AUX_1, // RPYT axis count
};
enum Feature {
FEATURE_RX_PPM = 1 << 0,
FEATURE_RX_SERIAL = 1 << 3,
FEATURE_MOTOR_STOP = 1 << 4,
FEATURE_SOFTSERIAL = 1 << 6,
FEATURE_GPS = 1 << 7,
FEATURE_TELEMETRY = 1 << 10,
FEATURE_AIRMODE = 1 << 22,
FEATURE_RX_SPI = 1 << 25,
// FEATURE_DYNAMIC_FILTER = 1 << 29, (removed)
};
constexpr size_t MODEL_NAME_LEN = 16;
constexpr size_t INPUT_CHANNELS = AXIS_COUNT;
constexpr size_t OUTPUT_CHANNELS = ESC_CHANNEL_COUNT;
static_assert(ESC_CHANNEL_COUNT == ESPFC_OUTPUT_COUNT, "ESC_CHANNEL_COUNT and ESPFC_OUTPUT_COUNT must be equal");
constexpr size_t RPM_FILTER_MOTOR_MAX = 4;
constexpr size_t RPM_FILTER_HARMONICS_COUNT = 3;
enum SerialSpeed
{
SERIAL_SPEED_NONE = 0,
SERIAL_SPEED_9600 = 9600,
SERIAL_SPEED_19200 = 19200,
SERIAL_SPEED_38400 = 38400,
SERIAL_SPEED_57600 = 57600,
SERIAL_SPEED_115200 = 115200,
SERIAL_SPEED_230400 = 230400,
SERIAL_SPEED_250000 = 250000,
SERIAL_SPEED_400000 = 400000,
SERIAL_SPEED_460800 = 460800,
SERIAL_SPEED_500000 = 500000,
SERIAL_SPEED_921600 = 921600,
SERIAL_SPEED_1000000 = 1000000,
SERIAL_SPEED_1500000 = 1500000,
SERIAL_SPEED_2000000 = 2000000,
SERIAL_SPEED_2470000 = 2470000,
};
enum SerialPortId
{
SERIAL_ID_NONE = -1,
SERIAL_ID_UART_1 = 0,
SERIAL_ID_UART_2,
SERIAL_ID_UART_3,
SERIAL_ID_UART_4,
SERIAL_ID_UART_5,
SERIAL_ID_UART_6,
SERIAL_ID_UART_7,
SERIAL_ID_UART_8,
SERIAL_ID_LPUART_1,
SERIAL_ID_USB_VCP = 20,
SERIAL_ID_SOFTSERIAL_1 = 30,
SERIAL_ID_SOFTSERIAL_2,
SERIAL_ID_MAX = SERIAL_ID_SOFTSERIAL_2,
};
enum SerialFunction
{
SERIAL_FUNCTION_NONE = 0,
SERIAL_FUNCTION_MSP = (1 << 0), // 1
SERIAL_FUNCTION_GPS = (1 << 1), // 2
SERIAL_FUNCTION_TELEMETRY_FRSKY = (1 << 2), // 4
SERIAL_FUNCTION_TELEMETRY_HOTT = (1 << 3), // 8
SERIAL_FUNCTION_TELEMETRY_LTM = (1 << 4), // 16
SERIAL_FUNCTION_TELEMETRY_SMARTPORT = (1 << 5), // 32
SERIAL_FUNCTION_RX_SERIAL = (1 << 6), // 64
SERIAL_FUNCTION_BLACKBOX = (1 << 7), // 128
SERIAL_FUNCTION_TELEMETRY_MAVLINK = (1 << 9), // 512
SERIAL_FUNCTION_ESC_SENSOR = (1 << 10), // 1024
SERIAL_FUNCTION_VTX_SMARTAUDIO = (1 << 11), // 2048
SERIAL_FUNCTION_TELEMETRY_IBUS = (1 << 12), // 4096
SERIAL_FUNCTION_VTX_TRAMP = (1 << 13), // 8192
SERIAL_FUNCTION_RCDEVICE = (1 << 14), // 16384
SERIAL_FUNCTION_LIDAR_TF = (1 << 15), // 32768
SERIAL_FUNCTION_FRSKY_OSD = (1 << 16), // 65536
};
enum SerialRXProvider
{
SERIALRX_SPEKTRUM1024 = 0,
SERIALRX_SPEKTRUM2048 = 1,
SERIALRX_SBUS = 2,
SERIALRX_SUMD = 3,
SERIALRX_SUMH = 4,
SERIALRX_XBUS_MODE_B = 5,
SERIALRX_XBUS_MODE_B_RJ01 = 6,
SERIALRX_IBUS = 7,
SERIALRX_JETIEXBUS = 8,
SERIALRX_CRSF = 9,
SERIALRX_SRXL = 10,
SERIALRX_TARGET_CUSTOM = 11,
SERIALRX_FPORT = 12,
};
enum SerialPort
{
#ifdef ESPFC_SERIAL_USB
SERIAL_USB,
#endif
#ifdef ESPFC_SERIAL_0
SERIAL_UART_0,
#endif
#ifdef ESPFC_SERIAL_1
SERIAL_UART_1,
#endif
#ifdef ESPFC_SERIAL_2
SERIAL_UART_2,
#endif
#ifdef ESPFC_SERIAL_SOFT_0
SERIAL_SOFT_0,
#endif
SERIAL_UART_COUNT
};
enum PinFunction {
#ifdef ESPFC_INPUT
PIN_INPUT_RX,
#endif
PIN_OUTPUT_0,
PIN_OUTPUT_1,
PIN_OUTPUT_2,
PIN_OUTPUT_3,
#if ESPFC_OUTPUT_COUNT > 4
PIN_OUTPUT_4,
#endif
#if ESPFC_OUTPUT_COUNT > 5
PIN_OUTPUT_5,
#endif
#if ESPFC_OUTPUT_COUNT > 6
PIN_OUTPUT_6,
#endif
#if ESPFC_OUTPUT_COUNT > 7
PIN_OUTPUT_7,
#endif
PIN_BUTTON,
PIN_BUZZER,
PIN_LED_BLINK,
#ifdef ESPFC_SERIAL_0
PIN_SERIAL_0_TX,
PIN_SERIAL_0_RX,
#endif
#ifdef ESPFC_SERIAL_1
PIN_SERIAL_1_TX,
PIN_SERIAL_1_RX,
#endif
#ifdef ESPFC_SERIAL_2
PIN_SERIAL_2_TX,
PIN_SERIAL_2_RX,
#endif
#ifdef ESPFC_I2C_0
PIN_I2C_0_SCL,
PIN_I2C_0_SDA,
#endif
#ifdef ESPFC_ADC_VBAT
PIN_INPUT_ADC_VBAT,
#endif
#ifdef ESPFC_ADC_IBAT
PIN_INPUT_ADC_IBAT,
#endif
#ifdef ESPFC_SPI_0
PIN_SPI_0_SCK,
PIN_SPI_0_MOSI,
PIN_SPI_0_MISO,
#endif
#ifdef ESPFC_SPI_0
PIN_SPI_CS0,
PIN_SPI_CS1,
PIN_SPI_CS2,
#endif
PIN_COUNT,
};
constexpr size_t ACTUATOR_CONDITIONS = 8;
struct ActuatorCondition
{
uint8_t id = 0;
uint8_t ch = AXIS_AUX_1;
int16_t min = 900;
int16_t max = 900;
uint8_t logicMode = 0;
uint8_t linkId = 0;
};
struct SerialPortConfig
{
int8_t id;
int32_t functionMask;
int32_t baud;
int32_t blackboxBaud;
};
constexpr size_t BUZZER_MAX_EVENTS = 8;
enum BuzzerEvent {
BUZZER_SILENCE = 0, // Silence, see beeperSilence()
BUZZER_GYRO_CALIBRATED,
BUZZER_RX_LOST, // Beeps when TX is turned off or signal lost (repeat until TX is okay)
BUZZER_RX_LOST_LANDING, // Beeps SOS when armed and TX is turned off or signal lost (autolanding/autodisarm)
BUZZER_DISARMING, // Beep when disarming the board
BUZZER_ARMING, // Beep when arming the board
BUZZER_ARMING_GPS_FIX, // Beep a special tone when arming the board and GPS has fix
BUZZER_BAT_CRIT_LOW, // Longer warning beeps when battery is critically low (repeats)
BUZZER_BAT_LOW, // Warning beeps when battery is getting low (repeats)
BUZZER_GPS_STATUS, // FIXME **** Disable beeper when connected to USB ****
BUZZER_RX_SET, // Beeps when aux channel is set for beep or beep sequence how many satellites has found if GPS enabled
BUZZER_ACC_CALIBRATION, // ACC inflight calibration completed confirmation
BUZZER_ACC_CALIBRATION_FAIL, // ACC inflight calibration failed
BUZZER_READY_BEEP, // Ring a tone when GPS is locked and ready
BUZZER_MULTI_BEEPS, // Internal value used by 'beeperConfirmationBeeps()'.
BUZZER_DISARM_REPEAT, // Beeps sounded while stick held in disarm position
BUZZER_ARMED, // Warning beeps when board is armed (repeats until board is disarmed or throttle is increased)
BUZZER_SYSTEM_INIT, // Initialisation beeps when board is powered on
BUZZER_USB, // Some boards have beeper powered USB connected
BUZZER_BLACKBOX_ERASE, // Beep when blackbox erase completes
BUZZER_CRASH_FLIP_MODE, // Crash flip mode is active
BUZZER_CAM_CONNECTION_OPEN, // When the 5 key simulation stated
BUZZER_CAM_CONNECTION_CLOSE, // When the 5 key simulation stop
BUZZER_ALL, // Turn ON or OFF all beeper conditions
BUZZER_PREFERENCE, // Save preferred beeper configuration
// BUZZER_ALL and BUZZER_PREFERENCE must remain at the bottom of this enum
};
struct BuzzerConfig
{
int8_t inverted = true;
int32_t beeperMask;
};
enum PidIndex {
FC_PID_ROLL,
FC_PID_PITCH,
FC_PID_YAW,
FC_PID_LEVEL,
FC_PID_MAG,
FC_PID_ALT,
FC_PID_VEL,
FC_PID_POS,
FC_PID_POSR,
FC_PID_NAVR,
FC_PID_ITEM_COUNT,
};
enum BlacboxLogField { // no more than 32, sync with flightLogFieldSelect_e
BLACKBOX_FIELD_PID = 0,
BLACKBOX_FIELD_RC_COMMANDS,
BLACKBOX_FIELD_SETPOINT,
BLACKBOX_FIELD_BATTERY,
BLACKBOX_FIELD_MAG,
BLACKBOX_FIELD_ALTITUDE,
BLACKBOX_FIELD_RSSI,
BLACKBOX_FIELD_GYRO,
BLACKBOX_FIELD_ATTITUDE,
BLACKBOX_FIELD_ACC,
BLACKBOX_FIELD_DEBUG_LOG,
BLACKBOX_FIELD_MOTOR,
BLACKBOX_FIELD_GPS,
BLACKBOX_FIELD_RPM,
BLACKBOX_FIELD_GYROUNFILT,
BLACKBOX_FIELD_SERVO,
BLACKBOX_FIELD_PITOT,
BLACKBOX_FIELD_COUNT,
};
enum BlackboxLogDevice {
BLACKBOX_DEV_NONE = 0,
BLACKBOX_DEV_FLASH = 1,
BLACKBOX_DEV_SDCARD = 2,
BLACKBOX_DEV_SERIAL = 3,
};
struct PidConfig
{
uint8_t P;
uint8_t I;
uint8_t D;
int16_t F;
};
struct InputChannelConfig
{
int16_t min = 1000;
int16_t neutral = 1500;
int16_t max = 2000;
int8_t map = 0;
int8_t fsMode = 0;
int16_t fsValue = 1500;
};
struct InputConfig
{
int8_t ppmMode = PPM_MODE_NORMAL;
uint8_t serialRxProvider = SERIALRX_SBUS;
int16_t minCheck = 1050;
int16_t maxCheck = 1900;
int16_t minRc = 885;
int16_t midRc = 1500;
int16_t maxRc = 2115;
int8_t deadband = 3;
int8_t airModeActivateThreshold = 40;
bool filterEnable = true;
int8_t filterAutoFactor = 50; // RPY factor
int8_t filterAutoThrottleFactor = 50; // Throttle factor
FilterConfig filter{FILTER_PT3, 0}; // autoFactor if freq=0
FilterConfig filterThrottle{FILTER_PT3, 0}; // autoFactor if freq=0
FilterConfig filterDerivative{FILTER_PT3, 0}; // autoFactor if freq=0
uint8_t expo[3] = { 0, 0, 0 };
uint8_t rate[3] = { 20, 20, 30 };
uint8_t superRate[3] = { 40, 40, 36 };
int16_t rateLimit[3] = { 1998, 1998, 1998 };
int8_t rateType = 3;
uint8_t rssiChannel = 0;
InputChannelConfig channel[INPUT_CHANNELS];
};
struct OutputChannelConfig
{
int16_t min = 1000;
int16_t neutral = 1500;
int16_t max = 2000;
bool reverse = false;
bool servo = false;
};
struct OutputConfig
{
int8_t protocol = ESC_PROTOCOL_DISABLED;
int8_t async = false;
int8_t dshotTelemetry = false;
int8_t motorPoles = 14;
int16_t rate = 480;
int16_t servoRate = 0;
int16_t minCommand = 1000;
int16_t maxThrottle = 2000;
int16_t motorIdle = 550;
int8_t throttleLimitType = 0;
int8_t throttleLimitPercent = 100;
int8_t motorLimit = 100;
OutputChannelConfig channel[ESPFC_OUTPUT_COUNT];
};
enum DisarmReason {
DISARM_REASON_ARMING_DISABLED = 0,
DISARM_REASON_FAILSAFE = 1,
DISARM_REASON_THROTTLE_TIMEOUT = 2,
DISARM_REASON_STICKS = 3,
DISARM_REASON_SWITCH = 4,
DISARM_REASON_CRASH_PROTECTION = 5,
DISARM_REASON_RUNAWAY_TAKEOFF = 6,
DISARM_REASON_GPS_RESCUE = 7,
DISARM_REASON_SERIAL_COMMAND = 8,
DISARM_REASON_SYSTEM = 255,
};
enum ArmingDisabledFlags {
ARMING_DISABLED_NO_GYRO = (1 << 0),
ARMING_DISABLED_FAILSAFE = (1 << 1),
ARMING_DISABLED_RX_FAILSAFE = (1 << 2),
ARMING_DISABLED_BAD_RX_RECOVERY = (1 << 3),
ARMING_DISABLED_BOXFAILSAFE = (1 << 4),
ARMING_DISABLED_RUNAWAY_TAKEOFF = (1 << 5),
ARMING_DISABLED_CRASH_DETECTED = (1 << 6),
ARMING_DISABLED_THROTTLE = (1 << 7),
ARMING_DISABLED_ANGLE = (1 << 8),
ARMING_DISABLED_BOOT_GRACE_TIME = (1 << 9),
ARMING_DISABLED_NOPREARM = (1 << 10),
ARMING_DISABLED_LOAD = (1 << 11),
ARMING_DISABLED_CALIBRATING = (1 << 12),
ARMING_DISABLED_CLI = (1 << 13),
ARMING_DISABLED_CMS_MENU = (1 << 14),
ARMING_DISABLED_BST = (1 << 15),
ARMING_DISABLED_MSP = (1 << 16),
ARMING_DISABLED_PARALYZE = (1 << 17),
ARMING_DISABLED_GPS = (1 << 18),
ARMING_DISABLED_RESC = (1 << 19),
ARMING_DISABLED_RPMFILTER = (1 << 20),
ARMING_DISABLED_REBOOT_REQUIRED = (1 << 21),
ARMING_DISABLED_DSHOT_BITBANG = (1 << 22),
ARMING_DISABLED_ACC_CALIBRATION = (1 << 23),
ARMING_DISABLED_MOTOR_PROTOCOL = (1 << 24),
ARMING_DISABLED_CRASHFLIP = (1 << 25),
ARMING_DISABLED_ALTHOLD = (1 << 26),
ARMING_DISABLED_POSHOLD = (1 << 27),
ARMING_DISABLED_AUTOPILOT = (1 << 28),
ARMING_DISABLED_ARM_SWITCH = (1 << 29), // Needs to be the last element, since it's always activated if one of the others is active when arming
};
static constexpr size_t ARMING_DISABLED_FLAGS_COUNT = 30;
struct WirelessConfig
{
static constexpr size_t MAX_LEN = 32;
int16_t port = 1111;
char ssid[MAX_LEN + 1];
char pass[MAX_LEN + 1];
};
struct FailsafeConfig
{
uint8_t delay = 4;
uint8_t killSwitch = 0;
};
struct BlackboxConfig
{
int8_t dev = 0;
int16_t pDenom = 1; // loop / 2
int32_t fieldsMask = 0xffff;
int8_t mode = 0;
};
struct DebugConfig
{
int8_t mode = DEBUG_NONE;
uint8_t axis = 1;
};
struct RpmFilterConfig
{
uint8_t harmonics = 3;
uint8_t minFreq = 100;
int16_t q = 500;
uint8_t freqLpf = 150;
uint8_t weights[RPM_FILTER_HARMONICS_COUNT] = {100, 100, 100};
uint8_t fade = 30;
};
enum VBatSource : int8_t
{
VBAT_SOURCE_NONE = 0,
VBAT_SOURCE_ADC = 1
};
struct VBatConfig
{
int16_t cellWarning = 350;
uint8_t scale = 100;
uint8_t resDiv = 10;
uint8_t resMult = 1;
int8_t source = VBAT_SOURCE_NONE;
};
enum IBatSource : int8_t
{
IBAT_SOURCE_NONE = 0,
IBAT_SOURCE_ADC = 1
};
struct IBatConfig
{
int8_t source = IBAT_SOURCE_NONE;
int16_t scale = 100;
int16_t offset = 0;
};
struct GyroConfig
{
int8_t bus = Hal::BUS_AUTO;
int8_t dev = GYRO_AUTO;
int8_t dlpf = GYRO_DLPF_256;
int8_t align = ALIGN_DEFAULT;
int16_t bias[3] = { 0, 0, 0 };
FilterConfig filter{FILTER_PT1, 150};
FilterConfig filter2{FILTER_PT1, 400};
FilterConfig dynLpfFilter{FILTER_PT1, 400, 150};
FilterConfig filter3{FILTER_FO, 150};
FilterConfig notch1Filter{FILTER_NOTCH, 0, 0};
FilterConfig notch2Filter{FILTER_NOTCH, 0, 0};
DynamicFilterConfig dynamicFilter;
RpmFilterConfig rpmFilter;
};
static constexpr size_t GYRO_FUSION_LPF_DIV = 3;
struct AccelConfig
{
int8_t bus = Hal::BUS_AUTO;
int8_t dev = GYRO_AUTO;
int16_t bias[3] = { 0, 0, 0 };
int16_t trim[2] = { 0, 0 };
FilterConfig filter{FILTER_BIQUAD, 15};
};
struct BaroConfig
{
int8_t bus = Hal::BUS_AUTO;
int8_t dev = BARO_NONE;
FilterConfig filter{FILTER_BIQUAD, 3};
};
struct MagConfig
{
int8_t bus = Hal::BUS_AUTO;
int8_t dev = MAG_NONE;
int8_t align = ALIGN_DEFAULT;
int16_t offset[3] = { 0, 0, 0 };
int16_t scale[3] = { 1000, 1000, 1000 };
FilterConfig filter{FILTER_BIQUAD, 10};
int16_t declination = 0;
};
struct YawConfig
{
FilterConfig filter{FILTER_PT1, 90};
};
struct DtermConfig
{
FilterConfig filter{FILTER_PT1, 75};
FilterConfig filter2{FILTER_PT1, 150};
FilterConfig dynLpfFilter{FILTER_PT1, 150, 75};
FilterConfig notchFilter{FILTER_NOTCH, 0, 0};
};
struct ItermConfig
{
int8_t limit = 30;
int8_t relax = ITERM_RELAX_RP;
int8_t relaxCutoff = 15;
bool lowThrottleZeroIterm = true;
};
struct LevelConfig
{
FilterConfig ptermFilter{FILTER_PT1, 90};
int8_t angleLimit = 55;
int16_t rateLimit = 300;
};
struct AltHoldConfig
{
uint8_t itermCenter = 50;
uint8_t itermRange = 50;
uint8_t baroTau = 20; // tau = time constant in seconds / 10
};
struct MixerConfiguration
{
int8_t type = FC_MIXER_QUADX;
bool yawReverse = 0;
};
struct ControllerConfig
{
int8_t tpaMode = 0;
int8_t tpaScale = 10;
int16_t tpaBreakpoint = 1650;
};
struct VtxConfig
{
uint8_t channel = 0x8;
uint8_t band = 0x1;
uint8_t power = 0;
uint8_t lowPowerDisarm = 0;
};
struct GpsConfig
{
uint8_t minSats = 8;
uint8_t setHomeOnce = 1;
// GNSS Constellation Configuration (M10 multi-band support)
uint8_t gnssMode = 0; // 0=Auto, 1=GPS only, 2=GPS+GLO, 3=GPS+GAL, 4=GPS+BDS, 5=All
uint8_t enableDualBand = 1; // Enable L1+L5 dual-band on M10 (0=L1 only, 1=Auto/M10 dual-band)
uint8_t enableGPS = 1; // Enable GPS constellation
uint8_t enableGLONASS = 0; // Enable GLONASS constellation
uint8_t enableGalileo = 1; // Enable Galileo constellation
uint8_t enableBeiDou = 0; // Enable BeiDou constellation
uint8_t enableQZSS = 1; // Enable QZSS (Asia-Pacific)
uint8_t enableSBAS = 1; // Enable SBAS (WAAS/EGNOS)
};
struct LedConfig
{
uint8_t invert = 0;
int8_t type = 0;
};
struct ArmingConfig
{
uint8_t smallAngle = 25;
};
enum SimplifiedTuningMode: uint8_t
{
SIMPLIFIED_TUNING_OFF = 0,
SIMPLIFIED_TUNING_RP = FC_PID_PITCH, // roll + pitch
SIMPLIFIED_TUNING_RPY = FC_PID_YAW, // roll + pitch + yaw
};
// Betaflight simplified-tuning slider baselines and limits
static constexpr int SIMPLIFIED_PID_GAIN_MAX = 250;
static constexpr int SIMPLIFIED_F_GAIN_MAX = 2000;
static constexpr int SIMPLIFIED_DYN_LPF_MAX_HZ = 500;
static constexpr int SIMPLIFIED_LPF_MAX_HZ = 500;
static constexpr int SIMPLIFIED_GYRO_LPF1_DYN_MIN_HZ = 150;
static constexpr int SIMPLIFIED_GYRO_LPF1_DYN_MAX_HZ = 400;
static constexpr int SIMPLIFIED_GYRO_LPF2_HZ = 400;
static constexpr int SIMPLIFIED_DTERM_LPF1_DYN_MIN_HZ = 75;
static constexpr int SIMPLIFIED_DTERM_LPF1_DYN_MAX_HZ = 150;
static constexpr int SIMPLIFIED_DTERM_LPF2_HZ = 150;
struct SimplifiedTuningConfig
{
int8_t pidsMode = SIMPLIFIED_TUNING_RPY;
uint8_t masterMultiplier = 100;
uint8_t rollPitchRatio = 100;
uint8_t iGain = 100;
uint8_t dGain = 80;
uint8_t piGain = 100;
uint8_t dMaxGain = 0; // unused, ESP-FC has no D-Max
uint8_t ffGain = 80;
uint8_t pitchPiGain = 100;
uint8_t dtermFilter = 1;
uint8_t dtermFilterMultiplier = 100;
uint8_t gyroFilter = 1;
uint8_t gyroFilterMultiplier = 100;
};
// persistent data
class ModelConfig
{
public:
// inputs and sensors
GyroConfig gyro;
AccelConfig accel;
BaroConfig baro;
MagConfig mag;
InputConfig input;
FailsafeConfig failsafe;
FusionConfig fusion;
VBatConfig vbat;
IBatConfig ibat;
VtxConfig vtx;
GpsConfig gps;
ArmingConfig arming;
ActuatorCondition conditions[ACTUATOR_CONDITIONS];
ScalerConfig scaler[SCALER_COUNT];
// pid controller
PidConfig pid[FC_PID_ITEM_COUNT] = {
[FC_PID_ROLL] = { .P = 45, .I = 80, .D = 24, .F = 88 }, // ROLL
[FC_PID_PITCH] = { .P = 47, .I = 84, .D = 27, .F = 92 }, // PITCH
[FC_PID_YAW] = { .P = 45, .I = 80, .D = 0, .F = 88 }, // YAW
[FC_PID_LEVEL] = { .P = 45, .I = 0, .D = 0, .F = 0 }, // ANGLE/LEVEL
[FC_PID_MAG] = { .P = 0, .I = 0, .D = 0, .F = 0 }, // MAG
[FC_PID_ALT] = { .P = 0, .I = 0, .D = 0, .F = 0 }, // ALTHOLD POS
[FC_PID_VEL] = { .P = 80, .I = 60, .D = 40, .F = 20 }, // ALTHOLD VEL
[FC_PID_POS] = { .P = 0, .I = 0, .D = 0, .F = 0 }, // POSHOLD_P * 100, POSHOLD_I * 100,
[FC_PID_POSR] = { .P = 0, .I = 0, .D = 0, .F = 0 }, // POSHOLD_RATE_P * 10, POSHOLD_RATE_I * 100, POSHOLD_RATE_D * 1000,
[FC_PID_NAVR] = { .P = 0, .I = 0, .D = 0, .F = 0 }, // NAV_P * 10, NAV_I * 100, NAV_D * 1000
};
YawConfig yaw;
LevelConfig level;
DtermConfig dterm;
ItermConfig iterm;
AltHoldConfig altHold;
ControllerConfig controller;
SimplifiedTuningConfig simplifiedTuning;
// hardware
int8_t pin[PIN_COUNT] = {
#ifdef ESPFC_INPUT
[PIN_INPUT_RX] = ESPFC_INPUT_PIN,
#endif
[PIN_OUTPUT_0] = ESPFC_OUTPUT_0,
[PIN_OUTPUT_1] = ESPFC_OUTPUT_1,
[PIN_OUTPUT_2] = ESPFC_OUTPUT_2,
[PIN_OUTPUT_3] = ESPFC_OUTPUT_3,
#if ESPFC_OUTPUT_COUNT > 4
[PIN_OUTPUT_4] = ESPFC_OUTPUT_4,
#endif
#if ESPFC_OUTPUT_COUNT > 5
[PIN_OUTPUT_5] = ESPFC_OUTPUT_5,
#endif
#if ESPFC_OUTPUT_COUNT > 6
[PIN_OUTPUT_6] = ESPFC_OUTPUT_6,
#endif
#if ESPFC_OUTPUT_COUNT > 7
[PIN_OUTPUT_7] = ESPFC_OUTPUT_7,
#endif
[PIN_BUTTON] = ESPFC_BUTTON_PIN,
[PIN_BUZZER] = ESPFC_BUZZER_PIN,
[PIN_LED_BLINK] = ESPFC_LED_PIN,
#ifdef ESPFC_SERIAL_0
[PIN_SERIAL_0_TX] = ESPFC_SERIAL_0_TX,
[PIN_SERIAL_0_RX] = ESPFC_SERIAL_0_RX,
#endif
#ifdef ESPFC_SERIAL_1
[PIN_SERIAL_1_TX] = ESPFC_SERIAL_1_TX,
[PIN_SERIAL_1_RX] = ESPFC_SERIAL_1_RX,
#endif
#ifdef ESPFC_SERIAL_2
[PIN_SERIAL_2_TX] = ESPFC_SERIAL_2_TX,
[PIN_SERIAL_2_RX] = ESPFC_SERIAL_2_RX,
#endif
#ifdef ESPFC_I2C_0
[PIN_I2C_0_SCL] = ESPFC_I2C_0_SCL,
[PIN_I2C_0_SDA] = ESPFC_I2C_0_SDA,
#endif
#ifdef ESPFC_ADC_VBAT
[PIN_INPUT_ADC_VBAT] = ESPFC_ADC_VBAT_PIN,
#endif
#ifdef ESPFC_ADC_IBAT
[PIN_INPUT_ADC_IBAT] = ESPFC_ADC_IBAT_PIN,
#endif
#ifdef ESPFC_SPI_0
[PIN_SPI_0_SCK] = ESPFC_SPI_0_SCK,
[PIN_SPI_0_MOSI] = ESPFC_SPI_0_MOSI,
[PIN_SPI_0_MISO] = ESPFC_SPI_0_MISO,
[PIN_SPI_CS0] = ESPFC_SPI_CS_GYRO,
[PIN_SPI_CS1] = ESPFC_SPI_CS_BARO,
[PIN_SPI_CS2] = -1,
#endif
};
SerialPortConfig serial[SERIAL_UART_COUNT] = {
#ifdef ESPFC_SERIAL_USB
[SERIAL_USB] = { .id = SERIAL_ID_USB_VCP, .functionMask = ESPFC_SERIAL_USB_FN, .baud = SERIAL_SPEED_115200, .blackboxBaud = SERIAL_SPEED_NONE },
#endif
#ifdef ESPFC_SERIAL_0
[SERIAL_UART_0] = { .id = SERIAL_ID_UART_1, .functionMask = ESPFC_SERIAL_0_FN, .baud = ESPFC_SERIAL_0_BAUD, .blackboxBaud = ESPFC_SERIAL_0_BBAUD },
#endif
#ifdef ESPFC_SERIAL_1
[SERIAL_UART_1] = { .id = SERIAL_ID_UART_2, .functionMask = ESPFC_SERIAL_1_FN, .baud = ESPFC_SERIAL_1_BAUD, .blackboxBaud = ESPFC_SERIAL_1_BBAUD },
#endif
#ifdef ESPFC_SERIAL_2
[SERIAL_UART_2] = { .id = SERIAL_ID_UART_3, .functionMask = ESPFC_SERIAL_2_FN, .baud = ESPFC_SERIAL_2_BAUD, .blackboxBaud = ESPFC_SERIAL_2_BBAUD },
#endif
#ifdef ESPFC_SERIAL_SOFT_0
[SERIAL_SOFT_0] = { .id = SERIAL_ID_SOFTSERIAL_1, .functionMask = ESPFC_SERIAL_SOFT_0_FN, .baud = SERIAL_SPEED_115200, .blackboxBaud = SERIAL_SPEED_NONE },
#endif
};
LedConfig led;
BuzzerConfig buzzer;
WirelessConfig wireless;
// mixer and outputs
int8_t customMixerCount = 0;
MixerEntry customMixes[MIXER_RULE_MAX];
MixerConfiguration mixer;
OutputConfig output;
BlackboxConfig blackbox;
DebugConfig debug;
// not classified yet
int16_t i2cSpeed = 800;
int8_t loopSync = 8; // MPU 1000Hz
int8_t mixerSync = 1;
int32_t featureMask = ESPFC_FEATURE_MASK;
bool telemetry = 0;
int32_t telemetryInterval = 1000;
uint8_t rescueConfigDelay = 30;
int16_t boardAlignment[3] = {0, 0, 0};
char modelName[MODEL_NAME_LEN + 1];
ModelConfig()
{
for(size_t i = 0; i < INPUT_CHANNELS; i++)
{
input.channel[i].map = i;
input.channel[i].neutral = input.midRc;
input.channel[i].fsMode = i <= AXIS_THRUST ? 0 : 1; // auto, hold, set
input.channel[i].fsValue = i != AXIS_THRUST ? input.midRc : 1000;
}
// swap yaw and throttle for AETR
input.channel[2].map = 3; // replace input 2 with rx channel 3, yaw
input.channel[3].map = 2; // replace input 3 with rx channel 2, throttle
// PID controller config (BF default)
//pid[FC_PID_ROLL] = { .P = 42, .I = 85, .D = 30, .F = 90 };
//pid[FC_PID_PITCH] = { .P = 46, .I = 90, .D = 32, .F = 95 };
//pid[FC_PID_YAW] = { .P = 45, .I = 90, .D = 0, .F = 90 };
//pid[FC_PID_LEVEL] = { .P = 55, .I = 0, .D = 0, .F = 0 };
wireless.ssid[0] = 0;
wireless.pass[0] = 0;
modelName[0] = 0;
// only local development settings
devPreset();
}
void devPreset()
{
#ifdef ESPFC_DEV_PRESET_BLACKBOX_SERIAL
blackbox.dev = BLACKBOX_DEV_SERIAL; // serial
debug.mode = DEBUG_GYRO_SAMPLE;
serial[ESPFC_DEV_PRESET_BLACKBOX_SERIAL].functionMask |= SERIAL_FUNCTION_BLACKBOX;
serial[ESPFC_DEV_PRESET_BLACKBOX_SERIAL].blackboxBaud = SERIAL_SPEED_250000;
serial[ESPFC_DEV_PRESET_BLACKBOX_SERIAL].baud = SERIAL_SPEED_250000;
#endif
#ifdef ESPFC_DEV_PRESET_BLACKBOX_FLASH
blackbox.dev = BLACKBOX_DEV_FLASH; // flash
debug.mode = DEBUG_GYRO_SAMPLE;
blackbox.pDenom = 1; // 500Hz
#endif
#ifdef ESPFC_DEV_PRESET_MODES
conditions[0].id = MODE_ARMED;
conditions[0].ch = AXIS_AUX_1 + 0; // aux1
conditions[0].min = 1300;
conditions[0].max = 2100;
conditions[0].logicMode = 0;
conditions[0].linkId = 0;
conditions[1].id = MODE_AIRMODE;
conditions[1].ch = AXIS_AUX_1 + 0; // aux1
conditions[1].min = 1300;
conditions[1].max = 2100;
conditions[1].logicMode = 0;
conditions[1].linkId = 0;
conditions[2].id = MODE_ANGLE;
conditions[2].ch = AXIS_AUX_1 + 1; // aux2
conditions[2].min = 1300;
conditions[2].max = 2100;
conditions[2].logicMode = 0;
conditions[2].linkId = 0;
conditions[3].id = MODE_ALTHOLD;
conditions[3].ch = AXIS_AUX_1 + 1; // aux2
conditions[3].min = 1700;
conditions[3].max = 2100;
conditions[3].logicMode = 0;
conditions[3].linkId = 0;
#endif
#ifdef ESPFC_DEV_PRESET_SCALER
scaler[0].dimension = (ACT_INNER_P | ACT_AXIS_ROLL | ACT_AXIS_PITCH);
scaler[0].channel = AXIS_AUX_1 + 1;
scaler[1].dimension = (ACT_INNER_I | ACT_AXIS_ROLL | ACT_AXIS_PITCH);
scaler[1].channel = AXIS_AUX_1 + 2;
scaler[2].dimension = (ACT_INNER_D | ACT_AXIS_ROLL | ACT_AXIS_PITCH);
scaler[2].channel = AXIS_AUX_1 + 3;
#endif
#ifdef ESPFC_DEV_PRESET_DSHOT
output.protocol = ESC_PROTOCOL_DSHOT300;
#endif
#ifdef ESPFC_DEV_PRESET_BRUSHED
output.protocol = ESC_PROTOCOL_BRUSHED;
output.async = true;
output.rate = 3000;
#endif
}
void brobot()
{
mixer.type = FC_MIXER_GIMBAL;
pin[PIN_OUTPUT_0] = 14; // D5 // ROBOT
pin[PIN_OUTPUT_1] = 12; // D6 // ROBOT
pin[PIN_OUTPUT_2] = 15; // D8 // ROBOT
pin[PIN_OUTPUT_3] = 0; // D3 // ROBOT
//fusionMode = FUSION_SIMPLE; // ROBOT
//fusionMode = FUSION_COMPLEMENTARY; // ROBOT
//accelFilter.freq = 30; // ROBOT
iterm.lowThrottleZeroIterm = false; // ROBOT
iterm.limit = 10; // ROBOT
level.angleLimit = 10; // deg // ROBOT
output.protocol = ESC_PROTOCOL_PWM; // ROBOT
output.rate = 100; // ROBOT
output.async = true; // ROBOT
output.channel[0].servo = true; // ROBOT
output.channel[1].servo = true; // ROBOT
output.channel[0].reverse = true; // ROBOT
scaler[0].dimension = (ACT_INNER_P | ACT_AXIS_PITCH); // ROBOT
//scaler[1].dimension = (ACT_INNER_P | ACT_AXIS_YAW); // ROBOT
scaler[1].dimension = (ACT_INNER_I | ACT_AXIS_PITCH); // ROBOT
scaler[2].dimension = (ACT_INNER_D | ACT_AXIS_PITCH); // ROBOT
}
};
}
#endif