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 },
0 commit comments