Skip to content

Commit c110bf3

Browse files
committed
joystick: migrate MANUAL_CONTROL axes to data lake
1 parent 0d07fee commit c110bf3

4 files changed

Lines changed: 116 additions & 40 deletions

File tree

src/assets/joystick-profiles.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import { MavType } from '@/libs/connection/m2r/messages/mavlink2rest-enum'
22
import { JoystickModel } from '@/libs/joystick/manager'
33
import { availableCockpitActions } from '@/libs/joystick/protocols/cockpit-actions'
4-
import {
5-
availableMavlinkManualControlButtonFunctions,
6-
mavlinkManualControlAxes,
7-
} from '@/libs/joystick/protocols/mavlink-manual-control'
4+
import { availableMavlinkManualControlButtonFunctions } from '@/libs/joystick/protocols/mavlink-manual-control'
85
import { modifierKeyActions, otherAvailableActions } from '@/libs/joystick/protocols/other'
6+
import { joystickInputAxes } from '@/libs/joystick/protocols/predefined-resources'
97
import { getVehicleModeAction } from '@/libs/vehicle/ardupilot/common'
108
import { RoverMode } from '@/libs/vehicle/ardupilot/types/modes'
119
import { Type as VehicleType } from '@/libs/vehicle/vehicle'
@@ -33,10 +31,10 @@ export const cockpitStandardToProtocols: JoystickProtocolActionsMapping[] = [
3331
name: 'ROV functions mapping',
3432
hash: defaultRovMappingHash,
3533
axesCorrespondencies: {
36-
[JoystickAxis.A0]: { action: mavlinkManualControlAxes.axis_y, min: -1000, max: +1000 },
37-
[JoystickAxis.A1]: { action: mavlinkManualControlAxes.axis_x, min: +1000, max: -1000 },
38-
[JoystickAxis.A2]: { action: mavlinkManualControlAxes.axis_r, min: -1000, max: +1000 },
39-
[JoystickAxis.A3]: { action: mavlinkManualControlAxes.axis_z, min: +1000, max: 0 },
34+
[JoystickAxis.A0]: { action: joystickInputAxes.axis_y, min: -1000, max: +1000 },
35+
[JoystickAxis.A1]: { action: joystickInputAxes.axis_x, min: +1000, max: -1000 },
36+
[JoystickAxis.A2]: { action: joystickInputAxes.axis_r, min: -1000, max: +1000 },
37+
[JoystickAxis.A3]: { action: joystickInputAxes.axis_z, min: +1000, max: 0 },
4038
},
4139
buttonsCorrespondencies: {
4240
[CockpitModifierKeyOption.regular]: {
@@ -85,10 +83,10 @@ export const cockpitStandardToProtocols: JoystickProtocolActionsMapping[] = [
8583
name: 'Boat functions mapping',
8684
hash: defaultBoatMappingHash,
8785
axesCorrespondencies: {
88-
[JoystickAxis.A0]: { action: mavlinkManualControlAxes.axis_y, min: -1000, max: +1000 },
89-
[JoystickAxis.A1]: { action: mavlinkManualControlAxes.axis_x, min: +1000, max: -1000 },
90-
[JoystickAxis.A2]: { action: mavlinkManualControlAxes.axis_r, min: -1000, max: +1000 },
91-
[JoystickAxis.A3]: { action: mavlinkManualControlAxes.axis_z, min: +1000, max: -1000 },
86+
[JoystickAxis.A0]: { action: joystickInputAxes.axis_y, min: -1000, max: +1000 },
87+
[JoystickAxis.A1]: { action: joystickInputAxes.axis_x, min: +1000, max: -1000 },
88+
[JoystickAxis.A2]: { action: joystickInputAxes.axis_r, min: -1000, max: +1000 },
89+
[JoystickAxis.A3]: { action: joystickInputAxes.axis_z, min: +1000, max: -1000 },
9290
},
9391
buttonsCorrespondencies: {
9492
[CockpitModifierKeyOption.regular]: {
@@ -137,10 +135,10 @@ export const cockpitStandardToProtocols: JoystickProtocolActionsMapping[] = [
137135
name: 'MAV functions mapping',
138136
hash: defaultMavMappingHash,
139137
axesCorrespondencies: {
140-
[JoystickAxis.A0]: { action: mavlinkManualControlAxes.axis_r, min: -1000, max: +1000 },
141-
[JoystickAxis.A1]: { action: mavlinkManualControlAxes.axis_z, min: +1000, max: 0 },
142-
[JoystickAxis.A2]: { action: mavlinkManualControlAxes.axis_y, min: -1000, max: +1000 },
143-
[JoystickAxis.A3]: { action: mavlinkManualControlAxes.axis_x, min: +1000, max: -1000 },
138+
[JoystickAxis.A0]: { action: joystickInputAxes.axis_r, min: -1000, max: +1000 },
139+
[JoystickAxis.A1]: { action: joystickInputAxes.axis_z, min: +1000, max: 0 },
140+
[JoystickAxis.A2]: { action: joystickInputAxes.axis_y, min: -1000, max: +1000 },
141+
[JoystickAxis.A3]: { action: joystickInputAxes.axis_x, min: +1000, max: -1000 },
144142
},
145143
buttonsCorrespondencies: {
146144
[CockpitModifierKeyOption.regular]: {

src/libs/joystick/protocols.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,13 @@ import { availableCockpitActions } from './protocols/cockpit-actions'
44
import { availableDataLakeActions } from './protocols/data-lake'
55
import {
66
availableMavlinkManualControlButtonFunctions,
7-
mavlinkManualControlAxes,
7+
migrateMavlinkManualControlAxes,
88
migrateMavlinkManualControlButtons,
99
} from './protocols/mavlink-manual-control'
1010
import { modifierKeyActions, otherAvailableActions } from './protocols/other'
1111

1212
export const allAvailableAxes = (): ProtocolAction[] => {
13-
return [
14-
...Object.values(mavlinkManualControlAxes),
15-
...Object.values(availableDataLakeActions()),
16-
otherAvailableActions.no_function,
17-
]
13+
return [...Object.values(availableDataLakeActions()), otherAvailableActions.no_function]
1814
}
1915

2016
export const allAvailableButtons = (): ProtocolAction[] => {
@@ -30,5 +26,5 @@ export const allAvailableButtons = (): ProtocolAction[] => {
3026
export const performJoystickMappingMigrations = (
3127
mappings: JoystickProtocolActionsMapping[]
3228
): JoystickProtocolActionsMapping[] => {
33-
return migrateMavlinkManualControlButtons(mappings)
29+
return migrateMavlinkManualControlAxes(migrateMavlinkManualControlButtons(mappings))
3430
}

src/libs/joystick/protocols/mavlink-manual-control.ts

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import { capitalize } from 'vue'
66

77
import { useInteractionDialog } from '@/composables/interactionDialog'
8+
import { getDataLakeVariableData } from '@/libs/actions/data-lake'
89
import { sendManualControl } from '@/libs/communication/mavlink'
910
import { modifierKeyActions, otherAvailableActions } from '@/libs/joystick/protocols/other'
10-
import { round, scale } from '@/libs/utils'
11+
import { round } from '@/libs/utils'
1112
import type { ArduPilot } from '@/libs/vehicle/ardupilot/ardupilot'
12-
import { type JoystickProtocolActionsMapping, type JoystickState, type ProtocolAction, CockpitModifierKeyOption, JoystickAxis, JoystickButton, JoystickProtocol } from '@/types/joystick'
13+
import { type JoystickProtocolActionsMapping, type JoystickState, type ProtocolAction, CockpitModifierKeyOption, JoystickButton, JoystickProtocol } from '@/types/joystick'
1314

1415
/**
1516
* Possible axes in the MAVLink `MANUAL_CONTROL` message protocol
@@ -500,21 +501,13 @@ export class MavlinkManualControlManager {
500501
}
501502
}
502503

503-
// Calculate axes values
504-
const xCorrespondency = Object.entries(this.currentActionsMapping.axesCorrespondencies).find((entry) => entry[1].action.protocol === JoystickProtocol.MAVLinkManualControl && entry[1].action.id === mavlinkManualControlAxes.axis_x.id)
505-
const yCorrespondency = Object.entries(this.currentActionsMapping.axesCorrespondencies).find((entry) => entry[1].action.protocol === JoystickProtocol.MAVLinkManualControl && entry[1].action.id === mavlinkManualControlAxes.axis_y.id)
506-
const zCorrespondency = Object.entries(this.currentActionsMapping.axesCorrespondencies).find((entry) => entry[1].action.protocol === JoystickProtocol.MAVLinkManualControl && entry[1].action.id === mavlinkManualControlAxes.axis_z.id)
507-
const rCorrespondency = Object.entries(this.currentActionsMapping.axesCorrespondencies).find((entry) => entry[1].action.protocol === JoystickProtocol.MAVLinkManualControl && entry[1].action.id === mavlinkManualControlAxes.axis_r.id)
508-
const sCorrespondency = Object.entries(this.currentActionsMapping.axesCorrespondencies).find((entry) => entry[1].action.protocol === JoystickProtocol.MAVLinkManualControl && entry[1].action.id === mavlinkManualControlAxes.axis_s.id)
509-
const tCorrespondency = Object.entries(this.currentActionsMapping.axesCorrespondencies).find((entry) => entry[1].action.protocol === JoystickProtocol.MAVLinkManualControl && entry[1].action.id === mavlinkManualControlAxes.axis_t.id)
510-
511-
// Populate MAVLink Manual Control state of axes and buttons
512-
this.manualControlState.x = xCorrespondency === undefined ? 0 : round(scale(this.joystickState.axes[xCorrespondency[0] as unknown as JoystickAxis] ?? 0, -1, 1, xCorrespondency[1].min, xCorrespondency[1].max), 0)
513-
this.manualControlState.y = yCorrespondency === undefined ? 0 : round(scale(this.joystickState.axes[yCorrespondency[0] as unknown as JoystickAxis] ?? 0, -1, 1, yCorrespondency[1].min, yCorrespondency[1].max), 0)
514-
this.manualControlState.z = zCorrespondency === undefined ? 0 : round(scale(this.joystickState.axes[zCorrespondency[0] as unknown as JoystickAxis] ?? 0, -1, 1, zCorrespondency[1].min, zCorrespondency[1].max), 0)
515-
this.manualControlState.r = rCorrespondency === undefined ? 0 : round(scale(this.joystickState.axes[rCorrespondency[0] as unknown as JoystickAxis] ?? 0, -1, 1, rCorrespondency[1].min, rCorrespondency[1].max), 0)
516-
this.manualControlState.s = sCorrespondency === undefined ? 0 : round(scale(this.joystickState.axes[sCorrespondency[0] as unknown as JoystickAxis] ?? 0, -1, 1, sCorrespondency[1].min, sCorrespondency[1].max), 0)
517-
this.manualControlState.t = tCorrespondency === undefined ? 0 : round(scale(this.joystickState.axes[tCorrespondency[0] as unknown as JoystickAxis] ?? 0, -1, 1, tCorrespondency[1].min, tCorrespondency[1].max), 0)
504+
// Read axis values from data lake output variables (scaling is handled by the data-lake protocol handler)
505+
this.manualControlState.x = round(Number(getDataLakeVariableData('joystick/outputs/axis-x') ?? 0), 0)
506+
this.manualControlState.y = round(Number(getDataLakeVariableData('joystick/outputs/axis-y') ?? 0), 0)
507+
this.manualControlState.z = round(Number(getDataLakeVariableData('joystick/outputs/axis-z') ?? 0), 0)
508+
this.manualControlState.r = round(Number(getDataLakeVariableData('joystick/outputs/axis-r') ?? 0), 0)
509+
this.manualControlState.s = round(Number(getDataLakeVariableData('joystick/outputs/axis-s') ?? 0), 0)
510+
this.manualControlState.t = round(Number(getDataLakeVariableData('joystick/outputs/axis-t') ?? 0), 0)
518511
this.manualControlState.buttons = buttons_int
519512
this.manualControlState.buttons2 = buttons2_int
520513
}
@@ -703,3 +696,31 @@ const migrateServoSubButtonsToActuators = (mappings: JoystickProtocolActionsMapp
703696
export const migrateMavlinkManualControlButtons = (mappings: JoystickProtocolActionsMapping[]): JoystickProtocolActionsMapping[] => {
704697
return migrateServoSubButtonsToActuators(mappings)
705698
}
699+
700+
const mavlinkAxisToDataLakeMap: Record<string, { id: string; name: string }> = {
701+
[MAVLinkAxisFunction.X]: { id: 'joystick/inputs/axis-x', name: 'Axis X' },
702+
[MAVLinkAxisFunction.Y]: { id: 'joystick/inputs/axis-y', name: 'Axis Y' },
703+
[MAVLinkAxisFunction.Z]: { id: 'joystick/inputs/axis-z', name: 'Axis Z' },
704+
[MAVLinkAxisFunction.R]: { id: 'joystick/inputs/axis-r', name: 'Axis R' },
705+
[MAVLinkAxisFunction.S]: { id: 'joystick/inputs/axis-s', name: 'Axis S' },
706+
[MAVLinkAxisFunction.T]: { id: 'joystick/inputs/axis-t', name: 'Axis T' },
707+
}
708+
709+
export const migrateMavlinkManualControlAxes = (mappings: JoystickProtocolActionsMapping[]): JoystickProtocolActionsMapping[] => {
710+
const migratedMappings: JoystickProtocolActionsMapping[] = JSON.parse(JSON.stringify(mappings))
711+
migratedMappings.forEach((mapping) => {
712+
Object.entries(mapping.axesCorrespondencies).forEach(([axisIndex, axisConfig]) => {
713+
if (axisConfig.action.protocol === JoystickProtocol.MAVLinkManualControl) {
714+
const replacement = mavlinkAxisToDataLakeMap[axisConfig.action.id]
715+
if (replacement) {
716+
mapping.axesCorrespondencies[axisIndex as unknown as number].action = {
717+
protocol: JoystickProtocol.DataLakeVariable,
718+
id: replacement.id,
719+
name: replacement.name,
720+
}
721+
}
722+
}
723+
})
724+
})
725+
return migratedMappings
726+
}

src/libs/joystick/protocols/predefined-resources.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,42 @@ import { MavCmd, MAVLinkType } from '@/libs/connection/m2r/messages/mavlink2rest
1010
import { getUnindentedString } from '@/libs/utils'
1111
import { customActionTypes } from '@/types/cockpit-actions'
1212

13+
import { DataLakeVariableAction } from './data-lake'
14+
1315
export let mavlinkCameraZoomActionId: string | undefined = undefined
1416
export let mavlinkCameraFocusActionId: string | undefined = undefined
1517

18+
const joystickAxisConfig = [
19+
{ key: 'axis_x' },
20+
{ key: 'axis_y' },
21+
{ key: 'axis_z' },
22+
{ key: 'axis_r' },
23+
{ key: 'axis_s' },
24+
{ key: 'axis_t' },
25+
] as const
26+
27+
const axisInputId = (key: string): string => `joystick/inputs/${key.replace('_', '-')}`
28+
const axisName = (key: string): string =>
29+
key
30+
.split('_')
31+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
32+
.join(' ')
33+
34+
/**
35+
* Pre-built data lake variable actions for joystick axis inputs, used in joystick profile mappings
36+
*/
37+
export const joystickInputAxes: Record<(typeof joystickAxisConfig)[number]['key'], DataLakeVariableAction> =
38+
Object.fromEntries(
39+
joystickAxisConfig.map((axis) => [
40+
axis.key,
41+
new DataLakeVariableAction({
42+
id: axisInputId(axis.key),
43+
name: axisName(axis.key),
44+
type: 'number' as DataLakeVariableType,
45+
}),
46+
])
47+
) as Record<(typeof joystickAxisConfig)[number]['key'], DataLakeVariableAction>
48+
1649
export const setupMavlinkCameraResources = (): void => {
1750
const commonVariableConfig = { type: 'number' as DataLakeVariableType, allowUserToChangeValue: true }
1851
// Initialize camera zoom variables
@@ -126,6 +159,34 @@ export const setupMavlinkCameraResources = (): void => {
126159
}
127160
}
128161

162+
export const setupJoystickAxesResources = (): void => {
163+
const commonVariableConfig = { type: 'number' as DataLakeVariableType, allowUserToChangeValue: true }
164+
165+
for (const axis of joystickAxisConfig) {
166+
const id = axisInputId(axis.key)
167+
const name = axisName(axis.key)
168+
const outputId = id.replace('/inputs/', '/outputs/')
169+
170+
createDataLakeVariable({ id, name, ...commonVariableConfig }, 0)
171+
172+
try {
173+
const existing = getAllTransformingFunctions().find((f) => f.id === outputId)
174+
if (!existing) {
175+
createTransformingFunction(
176+
outputId,
177+
`${name} Output`,
178+
'number',
179+
`{{${id}}}`,
180+
`Output value for MANUAL_CONTROL ${name}.`
181+
)
182+
}
183+
} catch (error) {
184+
console.error(`Error creating transforming function for ${name}:`, error)
185+
}
186+
}
187+
}
188+
129189
export const setupPredefinedLakeAndActionResources = (): void => {
130190
setupMavlinkCameraResources()
191+
setupJoystickAxesResources()
131192
}

0 commit comments

Comments
 (0)