Skip to content

Commit 459f080

Browse files
committed
feat: Implement Multi-Gyro support for API 1.47+
- Ported multi-gyro support logic from PR #4490 to Vue implementation. - Updated 'FC.SENSOR_ALIGNMENT' in 'src/js/fc.js' to support gyro arrays. - Updated 'MSPHelper' to read/write multiple gyros for API >= 1.47. - Added dynamic 'GYRO Alignment' UI in 'ConfigurationTab.vue' for API >= 1.47. - Preserved legacy UI for older firmware versions. - Fixed UI visibility logic and updated localization.
1 parent 1a2b529 commit 459f080

File tree

3 files changed

+214
-11
lines changed

3 files changed

+214
-11
lines changed

src/components/tabs/ConfigurationTab.vue

Lines changed: 184 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,114 @@
298298
</div>
299299
</div>
300300

301-
<!-- GYRO ALIGNMENT (Complex) -->
301+
<!-- NEW MULTI-GYRO ALIGNMENT (API 1.47+) -->
302+
<div class="gui_box grey" v-if="showMultiGyro">
303+
<div class="gui_box_titlebar">
304+
<div class="spacer_box_title">{{ $t("configurationGyroAlignment") }}</div>
305+
<div class="helpicon cf_tip" :title="$t('configurationGyroAlignmentHelp')"></div>
306+
</div>
307+
<div class="spacer_box">
308+
<div
309+
v-for="gyro in gyroList"
310+
:key="gyro.index"
311+
class="gyro-row"
312+
style="margin-bottom: 10px; border-bottom: 1px solid #111; padding-bottom: 10px"
313+
>
314+
<div class="grid-row col2">
315+
<div class="col-span-1">
316+
<!-- Gyro Enable Toggle -->
317+
<div class="select">
318+
<div>
319+
<input
320+
type="checkbox"
321+
class="toggle"
322+
:id="'gyro-enable-' + gyro.index"
323+
:checked="gyro.enabled"
324+
@change="toggleGyro(gyro.index, $event.target.checked)"
325+
/>
326+
</div>
327+
<span class="freelabel"
328+
>{{ $t("sensorStatusGyroShort") }} {{ gyro.index + 1 }}</span
329+
>
330+
</div>
331+
</div>
332+
<div class="col-span-1">
333+
<!-- Alignment Dropdown -->
334+
<div class="select">
335+
<select
336+
:value="gyro.align"
337+
@change="updateGyroAlign(gyro.index, parseInt($event.target.value))"
338+
>
339+
<option :value="0">
340+
{{ $t("configurationSensorAlignmentDefaultOption") }}
341+
</option>
342+
<option
343+
v-for="(align, idx) in sensorAlignments"
344+
:key="idx"
345+
:value="idx + 1"
346+
>
347+
{{ align }}
348+
</option>
349+
</select>
350+
<span>{{ $t("configurationSensorAlignment") }}</span>
351+
</div>
352+
353+
<!-- Custom Alignment Inputs -->
354+
<div class="sensor_align_content" v-if="gyro.align === 9">
355+
<div class="sensor_align_inputs">
356+
<div class="alignicon roll"></div>
357+
<label>
358+
<input
359+
type="number"
360+
v-model.number="gyro.roll"
361+
step="0.1"
362+
min="-180"
363+
max="360"
364+
@change="
365+
sensorAlignment.gyro_align_roll[gyro.index] = gyro.roll
366+
"
367+
/>
368+
<span>{{ $t("configurationGyroAlignmentRoll") }}</span>
369+
</label>
370+
</div>
371+
<div class="sensor_align_inputs">
372+
<div class="alignicon pitch"></div>
373+
<label>
374+
<input
375+
type="number"
376+
v-model.number="gyro.pitch"
377+
step="0.1"
378+
min="-180"
379+
max="360"
380+
@change="
381+
sensorAlignment.gyro_align_pitch[gyro.index] = gyro.pitch
382+
"
383+
/>
384+
<span>{{ $t("configurationGyroAlignmentPitch") }}</span>
385+
</label>
386+
</div>
387+
<div class="sensor_align_inputs">
388+
<div class="alignicon yaw"></div>
389+
<label>
390+
<input
391+
type="number"
392+
v-model.number="gyro.yaw"
393+
step="0.1"
394+
min="-180"
395+
max="360"
396+
@change="sensorAlignment.gyro_align_yaw[gyro.index] = gyro.yaw"
397+
/>
398+
<span>{{ $t("configurationGyroAlignmentYaw") }}</span>
399+
</label>
400+
</div>
401+
</div>
402+
</div>
403+
</div>
404+
</div>
405+
</div>
406+
</div>
407+
408+
<!-- GYRO ALIGNMENT (Legacy) -->
302409
<div class="gui_box grey" v-if="showSensorAlignment">
303410
<div class="gui_box_titlebar">
304411
<div class="spacer_box_title">{{ $t("configurationActiveImu") }}</div>
@@ -770,21 +877,68 @@ export default defineComponent({
770877
gyro_2_align_roll: 0,
771878
gyro_2_align_pitch: 0,
772879
gyro_2_align_yaw: 0,
880+
881+
gyro_align: [], // API 1.47+
882+
gyro_enable_mask: 0, // API 1.47+
883+
gyro_align_roll: [], // API 1.47+
884+
gyro_align_pitch: [], // API 1.47+
885+
gyro_align_yaw: [], // API 1.47+
773886
});
774887
775888
const magDeclination = ref(0);
776889
const showGyroCalOnFirstArm = ref(false);
777890
const showAutoDisarmDelay = ref(false);
778891
const hasSecondGyro = ref(false);
779892
const hasDualGyros = ref(false);
780-
const showGyroToUse = computed(() => {
781-
return true; // Active IMU selection (or display) is relevant for all supported versions
893+
const showMultiGyro = ref(false); // API 1.47+ multi-gyro UI
894+
895+
const gyroList = computed(() => {
896+
if (!showMultiGyro.value || !sensorAlignment.gyro_align) return [];
897+
898+
// Assume 8 gyros possible (or match array length)
899+
const gyros = [];
900+
for (let i = 0; i < 8; i++) {
901+
// If the array doesn't have data for this index, break or skip
902+
// Ideally this array is populated with 8 elements in loadConfig
903+
if (sensorAlignment.gyro_align[i] === undefined) continue;
904+
905+
gyros.push({
906+
index: i,
907+
enabled: bit_check(sensorAlignment.gyro_enable_mask, i),
908+
align: sensorAlignment.gyro_align[i],
909+
roll: sensorAlignment.gyro_align_roll[i],
910+
pitch: sensorAlignment.gyro_align_pitch[i],
911+
yaw: sensorAlignment.gyro_align_yaw[i],
912+
});
913+
}
914+
return gyros;
782915
});
916+
917+
const toggleGyro = (index, enabled) => {
918+
if (enabled) {
919+
sensorAlignment.gyro_enable_mask = bit_set(sensorAlignment.gyro_enable_mask, index);
920+
} else {
921+
sensorAlignment.gyro_enable_mask = bit_clear(sensorAlignment.gyro_enable_mask, index);
922+
}
923+
};
924+
925+
const updateGyroAlign = (index, value) => {
926+
// Vue reactivity caveat with arrays:
927+
// sensorAlignment.gyro_align[index] = value;
928+
// Should verify if this triggers update, if not we might need to splice or recreate array
929+
if (sensorAlignment.gyro_align) {
930+
sensorAlignment.gyro_align[index] = value;
931+
}
932+
};
933+
783934
const showGyro1Align = ref(false);
784935
const showGyro2Align = ref(false);
785936
const showMagAlign = ref(false);
786937
const showMagDeclination = ref(false);
787938
const showRangefinder = ref(false);
939+
const showGyroToUse = computed(() => {
940+
return semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_47);
941+
});
788942
const showOpticalFlow = ref(false);
789943
790944
// This section contains gyro alignment dropdowns (API < 1.47) and mag alignment (API >= 1.47)
@@ -1120,6 +1274,11 @@ export default defineComponent({
11201274
sensorAlignment.gyro_2_align_roll = FC.SENSOR_ALIGNMENT.gyro_2_align_roll;
11211275
sensorAlignment.gyro_2_align_pitch = FC.SENSOR_ALIGNMENT.gyro_2_align_pitch;
11221276
sensorAlignment.gyro_2_align_yaw = FC.SENSOR_ALIGNMENT.gyro_2_align_yaw;
1277+
sensorAlignment.gyro_align = FC.SENSOR_ALIGNMENT.gyro_align || [];
1278+
sensorAlignment.gyro_enable_mask = FC.SENSOR_ALIGNMENT.gyro_enable_mask || 0;
1279+
sensorAlignment.gyro_align_roll = FC.SENSOR_ALIGNMENT.gyro_align_roll || [];
1280+
sensorAlignment.gyro_align_pitch = FC.SENSOR_ALIGNMENT.gyro_align_pitch || [];
1281+
sensorAlignment.gyro_align_yaw = FC.SENSOR_ALIGNMENT.gyro_align_yaw || [];
11231282
11241283
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47)) {
11251284
sensorAlignment.mag_align_roll = FC.SENSOR_ALIGNMENT.mag_align_roll || 0;
@@ -1140,12 +1299,15 @@ export default defineComponent({
11401299
11411300
// Gyro alignment dropdowns are only available for API < 1.47
11421301
// In API 1.47+, the firmware uses gyro_enable_mask instead of individual gyro alignments
1302+
// In API 1.47+, the firmware uses gyro_enable_mask instead of individual gyro alignments
11431303
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_47)) {
11441304
showGyro1Align.value = true;
11451305
showGyro2Align.value = hasSecondGyro.value;
1306+
showMultiGyro.value = false;
11461307
} else {
11471308
showGyro1Align.value = false;
11481309
showGyro2Align.value = false;
1310+
showMultiGyro.value = true;
11491311
}
11501312
11511313
// Mag Declination & Alignment
@@ -1251,12 +1413,21 @@ export default defineComponent({
12511413
FC.SENSOR_ALIGNMENT.gyro_2_align = sensorAlignment.gyro_2_align;
12521414
FC.SENSOR_ALIGNMENT.align_mag = sensorAlignment.align_mag;
12531415
1254-
FC.SENSOR_ALIGNMENT.gyro_1_align_roll = sensorAlignment.gyro_1_align_roll;
1255-
FC.SENSOR_ALIGNMENT.gyro_1_align_pitch = sensorAlignment.gyro_1_align_pitch;
1256-
FC.SENSOR_ALIGNMENT.gyro_1_align_yaw = sensorAlignment.gyro_1_align_yaw;
1257-
FC.SENSOR_ALIGNMENT.gyro_2_align_roll = sensorAlignment.gyro_2_align_roll;
1258-
FC.SENSOR_ALIGNMENT.gyro_2_align_pitch = sensorAlignment.gyro_2_align_pitch;
1259-
FC.SENSOR_ALIGNMENT.gyro_2_align_yaw = sensorAlignment.gyro_2_align_yaw;
1416+
if (semver.lt(FC.CONFIG.apiVersion, API_VERSION_1_47)) {
1417+
FC.SENSOR_ALIGNMENT.gyro_1_align_roll = sensorAlignment.gyro_1_align_roll;
1418+
FC.SENSOR_ALIGNMENT.gyro_1_align_pitch = sensorAlignment.gyro_1_align_pitch;
1419+
FC.SENSOR_ALIGNMENT.gyro_1_align_yaw = sensorAlignment.gyro_1_align_yaw;
1420+
FC.SENSOR_ALIGNMENT.gyro_2_align_roll = sensorAlignment.gyro_2_align_roll;
1421+
FC.SENSOR_ALIGNMENT.gyro_2_align_pitch = sensorAlignment.gyro_2_align_pitch;
1422+
FC.SENSOR_ALIGNMENT.gyro_2_align_yaw = sensorAlignment.gyro_2_align_yaw;
1423+
} else {
1424+
// API 1.47+ Multi-Gyro
1425+
FC.SENSOR_ALIGNMENT.gyro_enable_mask = sensorAlignment.gyro_enable_mask;
1426+
FC.SENSOR_ALIGNMENT.gyro_align = sensorAlignment.gyro_align;
1427+
FC.SENSOR_ALIGNMENT.gyro_align_roll = sensorAlignment.gyro_align_roll;
1428+
FC.SENSOR_ALIGNMENT.gyro_align_pitch = sensorAlignment.gyro_align_pitch;
1429+
FC.SENSOR_ALIGNMENT.gyro_align_yaw = sensorAlignment.gyro_align_yaw;
1430+
}
12601431
12611432
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47)) {
12621433
FC.SENSOR_ALIGNMENT.mag_align_roll = sensorAlignment.mag_align_roll;
@@ -1394,6 +1565,10 @@ export default defineComponent({
13941565
showGyroToUse,
13951566
opticalFlowTypesList,
13961567
sensorAlignments,
1568+
showMultiGyro,
1569+
gyroList,
1570+
toggleGyro,
1571+
updateGyroAlign,
13971572
saveConfig,
13981573
};
13991574
},

src/js/fc.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ const FC = {
479479
align_mag: 0,
480480
gyro_detection_flags: 0,
481481
gyro_to_use: 0,
482-
gyro_enable_mask: 0,
482+
483483
gyro_1_align: 0,
484484
gyro_2_align: 0,
485485
gyro_1_align_roll: 0,
@@ -488,6 +488,11 @@ const FC = {
488488
gyro_2_align_roll: 0,
489489
gyro_2_align_pitch: 0,
490490
gyro_2_align_yaw: 0,
491+
gyro_align: [], // API 1.47+
492+
gyro_enable_mask: 0, // API 1.47+
493+
gyro_align_roll: [], // API 1.47+
494+
gyro_align_pitch: [], // API 1.47+
495+
gyro_align_yaw: [], // API 1.47+
491496
mag_align_roll: 0,
492497
mag_align_pitch: 0,
493498
mag_align_yaw: 0,

src/js/msp/MSPHelper.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,20 @@ MspHelper.prototype.process_data = function (dataHandler) {
641641
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47)) {
642642
FC.SENSOR_ALIGNMENT.gyro_enable_mask = data.readU8();
643643

644+
// Initialize arrays
645+
FC.SENSOR_ALIGNMENT.gyro_align = [];
646+
FC.SENSOR_ALIGNMENT.gyro_align_roll = [];
647+
FC.SENSOR_ALIGNMENT.gyro_align_pitch = [];
648+
FC.SENSOR_ALIGNMENT.gyro_align_yaw = [];
649+
650+
// Read 8 gyros
651+
for (let i = 0; i < 8; i++) {
652+
FC.SENSOR_ALIGNMENT.gyro_align.push(data.readU8());
653+
FC.SENSOR_ALIGNMENT.gyro_align_roll.push(data.read16() / 10);
654+
FC.SENSOR_ALIGNMENT.gyro_align_pitch.push(data.read16() / 10);
655+
FC.SENSOR_ALIGNMENT.gyro_align_yaw.push(data.read16() / 10);
656+
}
657+
644658
// Read Mag alignment if data remains
645659
if (data.byteLength - data.offset >= 6) {
646660
FC.SENSOR_ALIGNMENT.mag_align_roll = data.read16() / 10;
@@ -2126,8 +2140,17 @@ MspHelper.prototype.crunch = function (code, modifierCode = undefined) {
21262140
.push8(FC.SENSOR_ALIGNMENT.align_mag);
21272141

21282142
if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_47)) {
2143+
buffer.push8(FC.SENSOR_ALIGNMENT.gyro_enable_mask);
2144+
2145+
for (let i = 0; i < 8; i++) {
2146+
buffer
2147+
.push8(FC.SENSOR_ALIGNMENT.gyro_align[i])
2148+
.push16(FC.SENSOR_ALIGNMENT.gyro_align_roll[i] * 10)
2149+
.push16(FC.SENSOR_ALIGNMENT.gyro_align_pitch[i] * 10)
2150+
.push16(FC.SENSOR_ALIGNMENT.gyro_align_yaw[i] * 10);
2151+
}
2152+
21292153
buffer
2130-
.push8(FC.SENSOR_ALIGNMENT.gyro_enable_mask) // replacing gyro_to_use
21312154
.push16(FC.SENSOR_ALIGNMENT.mag_align_roll * 10)
21322155
.push16(FC.SENSOR_ALIGNMENT.mag_align_pitch * 10)
21332156
.push16(FC.SENSOR_ALIGNMENT.mag_align_yaw * 10);

0 commit comments

Comments
 (0)