Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update joystick pipeline architecture and add modifier/shift buttons support #553

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2aebc84
Use intern Vue `capitalize` method when possible
rafaellehmkuhl Dec 1, 2023
15fec30
Rename protocol name from `MAVLink` to `MAVLinkManualControl`
rafaellehmkuhl Dec 1, 2023
c78aaa2
ardupilot: Add vehicle metadata to instances
rafaellehmkuhl Dec 7, 2023
3687527
ardupilot: Stop outputing cryptic Ok messages from `mavlink2rest`
rafaellehmkuhl Dec 7, 2023
5cbfbfd
ardupilot: Add total count of parameters on vehicle to instance
rafaellehmkuhl Dec 7, 2023
e94adc7
vehicle: Output total parameter count together with last parameter
rafaellehmkuhl Dec 7, 2023
a9811bd
joystick-config-view: Pass button-actions correspondency directly to …
rafaellehmkuhl Dec 7, 2023
c36f31c
main-vehicle: Remove ardupilot-specific parameter related code
rafaellehmkuhl Dec 7, 2023
4a6ed85
cockpit-actions: Add dedicated module
rafaellehmkuhl Dec 7, 2023
92a25da
mavlink-manual-control: Add dedicated module
rafaellehmkuhl Dec 7, 2023
dbe2a9d
other-protocols: Add dedicated module
rafaellehmkuhl Dec 7, 2023
4c44150
joystick-protocol: Create modifier keys
rafaellehmkuhl Dec 7, 2023
5b0840c
joystick-protocol: Refactor structure of the joystick interfaces
rafaellehmkuhl Dec 7, 2023
ab39b69
joystick-protocol: Adapt consumers to new structure
rafaellehmkuhl Dec 7, 2023
e509b04
joystick-protocol: Output active joystick actions directly to consumers
rafaellehmkuhl Dec 7, 2023
0bacabf
joystick-protocol: Rename state variables on the store
rafaellehmkuhl Dec 7, 2023
6fd628f
joystick-config-view: Add support for mapping with modifier keys
rafaellehmkuhl Dec 7, 2023
e6837f4
joystick-protocol: Prevent unwanted mapping behaviors from users
rafaellehmkuhl Dec 7, 2023
84fea3b
joystick-config-view: Remove joystick image from mapping modal
rafaellehmkuhl Dec 7, 2023
05c9206
joystick-config-view: Rework input updating modal
rafaellehmkuhl Dec 7, 2023
c804dd5
joystick-config-view: Improve feedback on input remapping
rafaellehmkuhl Dec 7, 2023
a2267c0
joystick-config-view: Use `setTimeout` instead of `nextTick` to reloa…
rafaellehmkuhl Dec 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 13 additions & 3 deletions src/App.vue
Expand Up @@ -148,7 +148,11 @@ import { useRoute } from 'vue-router'

import ConfigurationMenu from '@/components/ConfigurationMenu.vue'
import { coolMissionNames } from '@/libs/funny-name/words'
import { CockpitAction, registerActionCallback, unregisterActionCallback } from '@/libs/joystick/protocols'
import {
availableCockpitActions,
registerActionCallback,
unregisterActionCallback,
} from '@/libs/joystick/protocols/cockpit-actions'
import { useMissionStore } from '@/stores/mission'

import Dialog from './components/Dialog.vue'
Expand All @@ -175,7 +179,10 @@ const routerSection = ref()
const { isFullscreen, toggle: toggleFullscreen } = useFullscreen()

const debouncedToggleFullScreen = useDebounceFn(() => toggleFullscreen(), 10)
const fullScreenCallbackId = registerActionCallback(CockpitAction.TOGGLE_FULL_SCREEN, debouncedToggleFullScreen)
const fullScreenCallbackId = registerActionCallback(
availableCockpitActions.toggle_full_screen,
debouncedToggleFullScreen
)
onBeforeUnmount(() => unregisterActionCallback(fullScreenCallbackId))

const fullScreenToggleIcon = computed(() => (isFullscreen.value ? 'mdi-fullscreen-exit' : 'mdi-overscan'))
Expand Down Expand Up @@ -209,7 +216,10 @@ watch([() => widgetStore.currentView, () => widgetStore.currentView.showBottomBa
showBottomBarNow.value = widgetStore.currentView.showBottomBarOnBoot
})
const debouncedToggleBottomBar = useDebounceFn(() => (showBottomBarNow.value = !showBottomBarNow.value), 25)
const bottomBarToggleCallbackId = registerActionCallback(CockpitAction.TOGGLE_BOTTOM_BAR, debouncedToggleBottomBar)
const bottomBarToggleCallbackId = registerActionCallback(
availableCockpitActions.toggle_bottom_bar,
debouncedToggleBottomBar
)
onBeforeUnmount(() => unregisterActionCallback(bottomBarToggleCallbackId))

// Start datalogging
Expand Down
93 changes: 62 additions & 31 deletions src/assets/joystick-profiles.ts
@@ -1,38 +1,69 @@
import { JoystickModel } from '@/libs/joystick/manager'
import { CockpitAction, MAVLinkAxis } from '@/libs/joystick/protocols'
import { type GamepadToCockpitStdMapping, type ProtocolControllerMapping, JoystickProtocol } from '@/types/joystick'
import { availableCockpitActions } from '@/libs/joystick/protocols/cockpit-actions'
import {
availableMavlinkManualControlButtonFunctions,
mavlinkManualControlAxes,
} from '@/libs/joystick/protocols/mavlink-manual-control'
import { modifierKeyActions, otherAvailableActions } from '@/libs/joystick/protocols/other'
import {
type GamepadToCockpitStdMapping,
type JoystickProtocolActionsMapping,
CockpitModifierKeyOption,
JoystickAxis,
JoystickButton,
} from '@/types/joystick'

// TODO: Adjust mapping for PS5 controller
export const cockpitStandardToProtocols: ProtocolControllerMapping = {
export const cockpitStandardToProtocols: JoystickProtocolActionsMapping = {
name: 'Cockpit Standard Gamepad to Protocols',
axesCorrespondencies: [
{ protocol: JoystickProtocol.MAVLink, value: MAVLinkAxis.Y },
{ protocol: JoystickProtocol.MAVLink, value: MAVLinkAxis.X },
{ protocol: JoystickProtocol.MAVLink, value: MAVLinkAxis.R },
{ protocol: JoystickProtocol.MAVLink, value: MAVLinkAxis.Z },
],
axesMins: [-1000, 1000, -1000, 1000],
axesMaxs: [1000, -1000, 1000, 0],
buttonsCorrespondencies: [
{ protocol: JoystickProtocol.MAVLink, value: 0 },
{ protocol: JoystickProtocol.MAVLink, value: 1 },
{ protocol: JoystickProtocol.MAVLink, value: 2 },
{ protocol: JoystickProtocol.MAVLink, value: 3 },
{ protocol: JoystickProtocol.CockpitAction, value: CockpitAction.GO_TO_PREVIOUS_VIEW },
{ protocol: JoystickProtocol.CockpitAction, value: CockpitAction.GO_TO_NEXT_VIEW },
{ protocol: JoystickProtocol.MAVLink, value: 9 },
{ protocol: JoystickProtocol.MAVLink, value: 10 },
{ protocol: JoystickProtocol.MAVLink, value: 4 },
{ protocol: JoystickProtocol.MAVLink, value: 6 },
{ protocol: JoystickProtocol.MAVLink, value: 7 },
{ protocol: JoystickProtocol.MAVLink, value: 8 },
{ protocol: JoystickProtocol.MAVLink, value: 11 },
{ protocol: JoystickProtocol.MAVLink, value: 12 },
{ protocol: JoystickProtocol.MAVLink, value: 13 },
{ protocol: JoystickProtocol.MAVLink, value: 14 },
{ protocol: JoystickProtocol.MAVLink, value: 5 },
{ protocol: JoystickProtocol.CockpitAction, value: CockpitAction.TOGGLE_FULL_SCREEN },
],
axesCorrespondencies: {
[JoystickAxis.A0]: { action: mavlinkManualControlAxes.axis_y, min: -1000, max: +1000 },
[JoystickAxis.A1]: { action: mavlinkManualControlAxes.axis_x, min: +1000, max: -1000 },
[JoystickAxis.A2]: { action: mavlinkManualControlAxes.axis_r, min: -1000, max: +1000 },
[JoystickAxis.A3]: { action: mavlinkManualControlAxes.axis_z, min: +1000, max: 0 },
},
buttonsCorrespondencies: {
[CockpitModifierKeyOption.regular]: {
[JoystickButton.B0]: { action: availableMavlinkManualControlButtonFunctions['Arm'] },
[JoystickButton.B1]: { action: availableMavlinkManualControlButtonFunctions['Disarm'] },
[JoystickButton.B2]: { action: availableMavlinkManualControlButtonFunctions['Mount tilt up'] },
[JoystickButton.B3]: { action: availableMavlinkManualControlButtonFunctions['Mount tilt down'] },
[JoystickButton.B4]: { action: modifierKeyActions.shift },
[JoystickButton.B5]: { action: otherAvailableActions.no_function },
[JoystickButton.B6]: { action: availableMavlinkManualControlButtonFunctions['Gain inc'] },
[JoystickButton.B7]: { action: availableMavlinkManualControlButtonFunctions['Gain dec'] },
[JoystickButton.B8]: { action: availableMavlinkManualControlButtonFunctions['Lights1 brighter'] },
[JoystickButton.B9]: { action: availableMavlinkManualControlButtonFunctions['Lights1 dimmer'] },
[JoystickButton.B10]: { action: availableCockpitActions.toggle_full_screen },
[JoystickButton.B11]: { action: otherAvailableActions.no_function },
[JoystickButton.B12]: { action: otherAvailableActions.no_function },
[JoystickButton.B13]: { action: otherAvailableActions.no_function },
[JoystickButton.B14]: { action: otherAvailableActions.no_function },
[JoystickButton.B15]: { action: otherAvailableActions.no_function },
[JoystickButton.B16]: { action: otherAvailableActions.no_function },
[JoystickButton.B17]: { action: otherAvailableActions.no_function },
},
[CockpitModifierKeyOption.shift]: {
[JoystickButton.B0]: { action: otherAvailableActions.no_function },
[JoystickButton.B1]: { action: otherAvailableActions.no_function },
[JoystickButton.B2]: { action: otherAvailableActions.no_function },
[JoystickButton.B3]: { action: otherAvailableActions.no_function },
[JoystickButton.B4]: { action: otherAvailableActions.no_function },
[JoystickButton.B5]: { action: otherAvailableActions.no_function },
[JoystickButton.B6]: { action: otherAvailableActions.no_function },
[JoystickButton.B7]: { action: otherAvailableActions.no_function },
[JoystickButton.B8]: { action: otherAvailableActions.no_function },
[JoystickButton.B9]: { action: otherAvailableActions.no_function },
[JoystickButton.B10]: { action: otherAvailableActions.no_function },
[JoystickButton.B11]: { action: otherAvailableActions.no_function },
[JoystickButton.B12]: { action: otherAvailableActions.no_function },
[JoystickButton.B13]: { action: otherAvailableActions.no_function },
[JoystickButton.B14]: { action: otherAvailableActions.no_function },
[JoystickButton.B15]: { action: otherAvailableActions.no_function },
[JoystickButton.B16]: { action: otherAvailableActions.no_function },
[JoystickButton.B17]: { action: otherAvailableActions.no_function },
},
},
}

/**
Expand Down
25 changes: 13 additions & 12 deletions src/components/joysticks/JoystickPS.vue
Expand Up @@ -7,9 +7,13 @@ import { v4 as uuid4 } from 'uuid'
import { computed, onBeforeUnmount, ref, toRefs, watch } from 'vue'

import { JoystickModel } from '@/libs/joystick/manager'
import type { InputWithPrettyName } from '@/libs/joystick/protocols'
import { scale } from '@/libs/utils'
import { type JoystickInput, type ProtocolControllerMapping, JoystickAxis, JoystickButton } from '@/types/joystick'
import {
type JoystickButtonActionCorrespondency,
type JoystickInput,
JoystickAxis,
JoystickButton,
} from '@/types/joystick'
import { InputType } from '@/types/joystick'

const textColor = '#747474'
Expand Down Expand Up @@ -97,8 +101,7 @@ const props = defineProps<{
leftAxisVert?: number // State of the vertical left axis as a floating point number, between -1 and +1
rightAxisHoriz?: number // State of the horizontal right axis as a floating point number, between -1 and +1
rightAxisVert?: number // State of the vertical right axis as a floating point number, between -1 and +1
protocolMapping: ProtocolControllerMapping // Mapping from the Cockpit standard to the protocol functions
buttonLabelCorrespondency: InputWithPrettyName[] // Mapping from the protocol functions to human readable names
buttonsActionsCorrespondency: JoystickButtonActionCorrespondency // Mapping from the Cockpit standard to the protocol functions
}>()

const emit = defineEmits<{
Expand All @@ -109,10 +112,10 @@ const emit = defineEmits<{
const findInputFromPath = (path: string): JoystickInput[] => {
const inputs: JoystickInput[] = []
Object.entries(buttonPath).filter(([, v]) => v === path).forEach((button) => {
inputs.push({ type: InputType.Button, value: button[0] as unknown as JoystickButton })
inputs.push({ type: InputType.Button, id: button[0] as unknown as JoystickButton })
})
Object.entries(axisPath.value).filter(([, v]) => v === path).forEach((axis) => {
inputs.push({ type: InputType.Axis, value: axis[0] as unknown as JoystickAxis })
inputs.push({ type: InputType.Axis, id: axis[0] as unknown as JoystickAxis })
})
return inputs
}
Expand Down Expand Up @@ -194,17 +197,15 @@ watch(
() => updateButtonsState()
)

const buttonLabelCorrespondency = toRefs(props).buttonLabelCorrespondency
const protocolMapping = toRefs(props).protocolMapping
const joystickModel = toRefs(props).model
watch([protocolMapping, buttonLabelCorrespondency], () => updateLabelsState())
const buttonsActionsCorrespondency = toRefs(props).buttonsActionsCorrespondency
watch(buttonsActionsCorrespondency, () => updateLabelsState())

const updateLabelsState = (): void => {
Object.values(JoystickButton).forEach((button) => {
if (isNaN(Number(button))) return
const protocolButton = props.protocolMapping.buttonsCorrespondencies[button as JoystickButton] || undefined
const param = props.buttonLabelCorrespondency.find((btn) => btn.input.protocol === protocolButton.protocol && btn.input.value === protocolButton.value)
const functionName = param === undefined ? `${protocolButton.value} (${protocolButton.protocol})` : param.prettyName
const buttonActionCorrespondency = buttonsActionsCorrespondency.value[button as JoystickButton] || undefined
const functionName = buttonActionCorrespondency === undefined ? 'unassigned' : buttonActionCorrespondency.action.name
if (!svg) return
// @ts-ignore: we already check if button is a number and so if button is a valid index
const labelId = buttonPath[button].replace('path', 'text')
Expand Down