feat: allow IMU inversion (#7505)

This commit is contained in:
3djc
2026-07-04 18:33:29 +10:00
committed by GitHub
parent c070ddda4b
commit 057883da83
20 changed files with 124 additions and 3 deletions
@@ -365,6 +365,7 @@ Node convert<GeneralSettings>::encode(const GeneralSettings& rhs)
if (Boards::getCapability(board, Board::HasIMU)) {
node["imuMax"] = rhs.imuMax;
node["imuOffset"] = rhs.imuOffset;
node["imuInvert"] = (rhs.imuInvertX ? 1 : 0) | (rhs.imuInvertY ? 2 : 0);
}
// OneBit sampling (X9D only?)
@@ -714,6 +715,10 @@ bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
node["imuMax"] >> rhs.imuMax;
node["imuOffset"] >> rhs.imuOffset;
int imuInvert = 0;
node["imuInvert"] >> imuInvert;
rhs.imuInvertX = imuInvert & 0x1;
rhs.imuInvertY = imuInvert & 0x2;
// OneBit sampling (X9D only?)
node["uartSampleMode"] >> rhs.uartSampleMode;
@@ -384,6 +384,8 @@ class GeneralSettings {
char registrationId[REGISTRATION_ID_LEN + 1];
int imuMax;
int imuOffset;
bool imuInvertX;
bool imuInvertY;
int uartSampleMode;
int pwrOnSpeed;
+19
View File
@@ -107,6 +107,25 @@ HardwarePanel::HardwarePanel(QWidget * parent, GeneralSettings & generalSettings
addParams();
}
if (Boards::getCapability(board, Board::HasIMU)) {
addSection(tr("IMU"));
addLabel("");
addLabel(tr("Invert"));
addParams();
addLabel(tr("X"));
AutoCheckBox *imuInvertX = new AutoCheckBox(this);
imuInvertX->setField(generalSettings.imuInvertX, this);
params->append(imuInvertX);
addParams();
addLabel(tr("Y"));
AutoCheckBox *imuInvertY = new AutoCheckBox(this);
imuInvertY->setField(generalSettings.imuInvertY, this);
params->append(imuInvertY);
addParams();
}
count = Boards::getCapability(board, Board::Inputs);
if (count > 0) {
+7 -3
View File
@@ -77,11 +77,15 @@ static inline void check_struct()
#endif
#if defined(PCBXLITES)
CHKSIZE(RadioData, 950);
CHKSIZE(RadioData, 951);
#elif defined(RADIO_ST16) || defined(PCBPA01) || defined(RADIO_TX15) || defined(RADIO_T15PRO) || defined(RADIO_TX16SMK3) || defined(RADIO_T22)
CHKSIZE(RadioData, 1181);
CHKSIZE(RadioData, 1182);
#elif defined(COLORLCD)
CHKSIZE(RadioData, 1061);
#if defined(IMU)
CHKSIZE(RadioData, 1062);
#else
CHKSIZE(RadioData, 1061);
#endif
#elif defined(RADIO_GX12)
CHKSIZE(RadioData, 1068);
#else
+1
View File
@@ -1128,6 +1128,7 @@ PACK(struct RadioData {
#if defined(IMU)
NOBACKUP(int8_t imuMax);
NOBACKUP(int8_t imuOffset);
NOBACKUP(uint8_t imuInvert); // user inversion, default off; XORed with hal.h IMU_INVERT_X/Y at apply time (bit0=X, bit1=Y)
#endif
#if defined(COLORLCD)
@@ -25,10 +25,14 @@
#include "choice.h"
#include "edgetx.h"
#include "getset_helpers.h"
#if defined(IMU)
#include "gyro.h"
#endif
#include "hal/adc_driver.h"
#include "hal/switch_driver.h"
#include "layout.h"
#include "static.h"
#include "strhelpers.h"
#include "switches.h"
#include "textedit.h"
@@ -94,6 +98,25 @@ HWSticks::HWSticks(Window* parent) : Window(parent, {0, 0, LV_PCT(100), LV_SIZE_
return std::to_string(value ? 2 << (value - 1) : 0);
});
#endif
#if defined(IMU)
int imuRow = max_sticks;
#if defined(STICK_DEAD_ZONE)
imuRow += 1;
#endif
for (int a = 0; a < 2; a++) {
int row = imuRow + a;
new StaticText(this, {0, S_Y(row) + yo + PAD_MEDIUM, S_LBL_W, 0},
getStringAtIndex(STR_IMU_VSRCRAW, a));
new ToggleSwitch(
this, {S_INV_X, S_Y(row) + yo, S_INV_W, 0},
[=]() -> uint8_t { return (uint8_t)getImuInversion(a); },
[=](int8_t newValue) {
setImuInversion(a, newValue);
SET_DIRTY();
});
}
#endif
}
HWPots::HWPots(Window* parent) :
+44
View File
@@ -102,6 +102,41 @@ static void gyroFilter(etx_imu_data_t* raw)
}
}
// Fixed hardware mounting correction from the target hal.h (X = bit 0, Y = bit 1).
// This accounts for how the chip is physically positioned and is always applied.
static uint8_t imuHwInvertMask()
{
uint8_t mask = 0;
#if defined(IMU_INVERT_X)
mask |= (1 << IMU_AXIS_X);
#endif
#if defined(IMU_INVERT_Y)
mask |= (1 << IMU_AXIS_Y);
#endif
return mask;
}
// User-selectable inversion, stored verbatim and defaulting to off.
bool getImuInversion(uint8_t axis)
{
return (g_eeGeneral.imuInvert >> axis) & 1;
}
void setImuInversion(uint8_t axis, bool value)
{
if (value)
g_eeGeneral.imuInvert |= (1 << axis);
else
g_eeGeneral.imuInvert &= ~(1 << axis);
}
// Effective inversion applied to sensor data: hardware correction XOR user choice.
static bool imuAxisInverted(uint8_t axis)
{
uint8_t effective = g_eeGeneral.imuInvert ^ imuHwInvertMask();
return (effective >> axis) & 1;
}
void gyroStart(imu_read_fn fn)
{
readFn = fn;
@@ -126,6 +161,15 @@ void gyroWakeup()
errors = 0;
if (imuAxisInverted(IMU_AXIS_X)) {
raw.accel_x = -raw.accel_x;
raw.gyro_x = -raw.gyro_x;
}
if (imuAxisInverted(IMU_AXIS_Y)) {
raw.accel_y = -raw.accel_y;
raw.gyro_y = -raw.gyro_y;
}
gyroFilter(&raw);
raw_ax = (int16_t)filteredAccel[0];
+9
View File
@@ -29,6 +29,15 @@
#define IMU_OFFSET_MIN -30
#define IMU_OFFSET_MAX 10
#define IMU_AXIS_X 0
#define IMU_AXIS_Y 1
// User-selectable IMU axis inversion, stored verbatim and defaulting to off.
// The fixed hardware mounting correction (IMU_INVERT_X/Y in the target hal.h) is
// applied on top of this internally, so the user setting is independent of it.
bool getImuInversion(uint8_t axis);
void setImuInversion(uint8_t axis, bool value);
void gyroStart(imu_read_fn fn);
void gyroWakeup();
void gyroSetIMU_X(int16_t offset, int16_t range);
@@ -435,6 +435,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_PADDING( 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -458,6 +458,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "stickDeadZone", 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -458,6 +458,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "stickDeadZone", 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -443,6 +443,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_PADDING( 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -458,6 +458,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "stickDeadZone", 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -458,6 +458,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_PADDING( 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -458,6 +458,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "stickDeadZone", 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -459,6 +459,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_PADDING( 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -434,6 +434,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_PADDING( 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_STRING("selectedTheme", 26),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
@@ -372,6 +372,7 @@ static const struct YamlNode struct_RadioData[] = {
YAML_PADDING( 3 ),
YAML_SIGNED( "imuMax", 8 ),
YAML_SIGNED( "imuOffset", 8 ),
YAML_UNSIGNED( "imuInvert", 8 ),
YAML_SIGNED_CUST( "backlightSrc", 10, r_mixSrcRawEx, w_mixSrcRawEx ),
YAML_SIGNED( "radioGFDisabled", 1 ),
YAML_SIGNED( "radioTrainerDisabled", 1 ),
+2
View File
@@ -402,6 +402,8 @@ SAI1_Block_A: PDM_CLOCK (1 MHz bit-clock output on SAI1_CK1 / PE5, !FLYSKY_GIMBA
// IMU
#define IMU_I2C_BUS I2C_Bus_1
#define IMU_INT_GPIO GPIO_PIN(GPIOG, 13) // PG.13
#define IMU_INVERT_X // X axis mounted reversed (default, user-overridable)
#define IMU_INVERT_Y // Y axis mounted reversed (default, user-overridable)
// IMU_INT_EXTI IRQ
#if !defined(USE_EXTI15_10_IRQ)
+2
View File
@@ -601,6 +601,8 @@ USART6: INTMODULE_USART
#define IMU_I2C_BUS I2C_Bus_2
#define IMU_INT_GPIO GPIO_PIN(GPIOG, 13) // PG.13
#define IMU_INVERT_X // X axis mounted reversed (default, user-overridable)
#define IMU_INVERT_Y // Y axis mounted reversed (default, user-overridable)
#if !defined(USE_EXTI15_10_IRQ)
#define USE_EXTI15_10_IRQ
#define EXTI15_10_IRQ_Priority 6