Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
>
<SplashScreen v-if="interfaceStore.showSplashScreen" />
</Transition>
<JoystickWizard v-if="interfaceStore.isJoystickWizardVisible" />
</template>

<script setup lang="ts">
Expand All @@ -151,6 +152,7 @@ import { computed, onBeforeMount, onBeforeUnmount, onMounted, ref, watch } from

import ActionDiscoveryModal from '@/components/ActionDiscoveryModal.vue'
import GlassModal from '@/components/GlassModal.vue'
import JoystickWizard from '@/components/joysticks/JoystickWizard.vue'
import SkullAnimation from '@/components/SkullAnimation.vue'
import SnackbarContainer from '@/components/SnackbarContainer.vue'
import Tutorial from '@/components/Tutorial.vue'
Expand Down
2 changes: 2 additions & 0 deletions src/components/GlassModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,8 @@ watch(
max-height: 100vh;
border: 1px solid #cbcbcb33;
box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.3), 0px 8px 12px 6px rgba(0, 0, 0, 0.15);
top: 50%;
transform: translateY(-50%);
z-index: 100;
}
</style>
1,427 changes: 1,427 additions & 0 deletions src/components/joysticks/JoystickWizard.vue

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions src/libs/joystick/configuration-wizard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { v4 as uuid4 } from 'uuid'

import {
JoystickAxisActionCorrespondency,
JoystickButtonActionCorrespondency,
JoystickProtocol,
JoystickProtocolActionsMapping,
} from '@/types/joystick'

/**
* Standard axis profile using Blue Robotics recommended default mappings for ROV controllers.
*/
export const axisConfigMapROV: JoystickAxisActionCorrespondency = {
3: {
action: { id: 'axis_z', name: 'Axis Z', protocol: JoystickProtocol.MAVLinkManualControl },
min: 1000,
max: 0,
},
4: {
action: { id: 'axis_y', name: 'Axis Y', protocol: JoystickProtocol.MAVLinkManualControl },
min: -1000,
max: 1000,
},
5: {
action: { id: 'axis_x', name: 'Axis X', protocol: JoystickProtocol.MAVLinkManualControl },
min: 1000,
max: -1000,
},
6: {
action: { id: 'axis_r', name: 'Axis R', protocol: JoystickProtocol.MAVLinkManualControl },
min: -1000,
max: 1000,
},
}

/**
* Standard button profile using Blue Robotics recommended default mappings for ROV controllers.
*/
export const buttonConfigMapROV: JoystickButtonActionCorrespondency = {
7: { action: { id: 'no_function', name: 'Shift (modifier)', protocol: JoystickProtocol.Other } },
9: { action: { id: 'servo_1_max_momentary', name: 'Gripper Open', protocol: JoystickProtocol.MAVLinkManualControl } },
10: {
action: { id: 'servo_1_min_momentary', name: 'Gripper Close', protocol: JoystickProtocol.MAVLinkManualControl },
},
12: { action: { id: 'camera-zoom-increase', name: 'Camera Zoom In', protocol: JoystickProtocol.CockpitAction } },
13: { action: { id: 'camera-zoom-decrease', name: 'Camera Zoom Out', protocol: JoystickProtocol.CockpitAction } },
14: { action: { id: 'camera-focus-increase', name: 'Camera Focus Near', protocol: JoystickProtocol.CockpitAction } },
15: { action: { id: 'camera-focus-decrease', name: 'Camera Focus Far', protocol: JoystickProtocol.CockpitAction } },
16: { action: { id: 'btn_auto_focus', name: 'Auto Focus', protocol: JoystickProtocol.CockpitAction } },
17: { action: { id: 'btn_auto_wb', name: 'Auto White Balance', protocol: JoystickProtocol.CockpitAction } },
18: { action: { id: 'gain_inc', name: 'Pilot Gain +', protocol: JoystickProtocol.MAVLinkManualControl } },
19: { action: { id: 'gain_dec', name: 'Pilot Gain –', protocol: JoystickProtocol.MAVLinkManualControl } },
20: { action: { id: 'Arm', name: 'Arm', protocol: JoystickProtocol.MAVLinkManualControl } },
21: { action: { id: 'Disarm', name: 'Disarm', protocol: JoystickProtocol.MAVLinkManualControl } },
22: { action: { id: 'mount_tilt_up', name: 'Camera Tilt Up', protocol: JoystickProtocol.MAVLinkManualControl } },
23: { action: { id: 'mount_tilt_down', name: 'Camera Tilt Down', protocol: JoystickProtocol.MAVLinkManualControl } },
24: { action: { id: 'mount_center', name: 'Camera Tilt Center', protocol: JoystickProtocol.MAVLinkManualControl } },
25: { action: { id: 'lights1_brighter', name: 'Lights Brighter', protocol: JoystickProtocol.MAVLinkManualControl } },
26: { action: { id: 'lights1_dimmer', name: 'Lights Dimmer', protocol: JoystickProtocol.MAVLinkManualControl } },
27: { action: { id: 'trim_pitch_inc', name: 'Trim Pitch Forward', protocol: JoystickProtocol.MAVLinkManualControl } },
28: {
action: { id: 'trim_pitch_dec', name: 'Trim Pitch Backward', protocol: JoystickProtocol.MAVLinkManualControl },
},
29: { action: { id: 'trim_roll_inc', name: 'Trim Roll Right', protocol: JoystickProtocol.MAVLinkManualControl } },
30: { action: { id: 'trim_roll_dec', name: 'Trim Roll Left', protocol: JoystickProtocol.MAVLinkManualControl } },
31: { action: { id: 'mode_manual', name: 'Manual Mode', protocol: JoystickProtocol.MAVLinkManualControl } },
32: { action: { id: 'mode_depth_hold', name: 'Depth-hold Mode', protocol: JoystickProtocol.MAVLinkManualControl } },
33: { action: { id: 'mode_stabilize', name: 'Stabilize Mode', protocol: JoystickProtocol.MAVLinkManualControl } },
34: { action: { id: 'input_hold_set', name: 'Toggle Input Hold', protocol: JoystickProtocol.MAVLinkManualControl } },
35: {
action: { id: 'roll_pitch_toggle', name: 'Roll & Pitch Toggle', protocol: JoystickProtocol.MAVLinkManualControl },
},
Comment on lines +10 to +72
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't those the same we have in joystick-profiles.ts? If there were changes in the recommended mapping, we should update and consume from there, so we don't have to maintain two codebases.

}

/**
* Basic blank mapping to be used as a starting point in the joystick configuration wizard.
*/
export const blankWizardMapping: JoystickProtocolActionsMapping = {
name: 'Wizard Functions mapping',
hash: uuid4(),
axesCorrespondencies: {} as JoystickProtocolActionsMapping['axesCorrespondencies'],
buttonsCorrespondencies: {
regular: {},
shift: {},
},
}
1 change: 1 addition & 0 deletions src/stores/appInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const useAppInterfaceStore = defineStore('responsive', {
currentSubMenuComponentName: ref<SubMenuComponentName | null>(null),
isGlassModalAlwaysOnTop: false,
isTutorialVisible: false,
isJoystickWizardVisible: false,
userHasSeenTutorial: useBlueOsStorage('cockpit-has-seen-tutorial', false),
configPanelVisible: false,
showSplashScreen: true,
Expand Down
13 changes: 13 additions & 0 deletions src/stores/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,18 @@ export const useControllerStore = defineStore('controller', () => {
reader.readAsText(e.target.files[0])
}

const mergeFunctionsMapping = (mapping: JoystickProtocolActionsMapping): void => {
const existingIndex = protocolMappings.value.findIndex((m) => m.hash === mapping.hash || m.name === mapping.name)

if (existingIndex !== -1) {
protocolMappings.value[existingIndex] = mapping
protocolMappingIndex.value = existingIndex
} else {
protocolMappings.value.push(mapping)
protocolMappingIndex.value = protocolMappings.value.length - 1
}
}

// Add hash on mappings that don't have it - TODO: Remove for 1.0.0 release
Object.values(protocolMappings.value).forEach((mapping) => {
if (mapping.hash !== undefined) return
Expand Down Expand Up @@ -563,5 +575,6 @@ export const useControllerStore = defineStore('controller', () => {
currentMainJoystick,
disabledJoysticks,
checkForOtherManualControlSources,
mergeFunctionsMapping,
}
})
45 changes: 36 additions & 9 deletions src/views/ConfigurationJoystickView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<template #title>Joystick configuration </template>
<template #content>
<div
:class="interfaceStore.isOnSmallScreen ? 'max-w-[88vw] max-h-[95vh]' : 'max-w-[880px] max-h-[80vh]'"
:class="interfaceStore.isOnSmallScreen ? 'max-w-[88vw] max-h-[95vh]' : 'max-w-[910px] max-h-[80vh]'"
class="overflow-y-auto"
>
<div
Expand Down Expand Up @@ -44,8 +44,8 @@
</div>
</template>
<template #content>
<div class="flex flex-col items-center h-[280px] overflow-auto">
<div class="flex flex-col items-center">
<div class="flex flex-col items-center h-[225px] overflow-visible">
<div class="flex flex-col w-full items-center">
<div
v-if="
controllerStore.availableButtonActions.every((b) => b.protocol === JoystickProtocol.CockpitAction)
Expand Down Expand Up @@ -79,22 +79,23 @@
class="scale-[85%] -mb-4"
/>
</div>
<div class="flex w-full justify-center mb-2">
<div class="w-full overflow-x-auto overflow-y-hidden px-2 whitespace-nowrap">
<div
v-for="functionMapping in controllerStore.protocolMappings"
:key="functionMapping.name"
class="relative mx-2"
class="relative inline-block align-top mx-1"
>
<!-- Container for active profile -->
<div
v-if="activeProfileName === functionMapping.name"
class="flex flex-col items-center bg-[#FFFFFF15] rounded-lg p-2 border border-[#FFFFFF30]"
>
<v-btn
class="text-md bg-[#FFFFFF23]"
class="text-md bg-[#FFFFFF23] px-2"
size="small"
:class="{
'bg-[#FFFFFF43]': selectedProfile.name === functionMapping.name,
'text-sm': interfaceStore.isOnSmallScreen,
'text-xs': interfaceStore.isOnSmallScreen,
}"
@click="selectProfile(functionMapping)"
>
Expand All @@ -106,7 +107,7 @@
<!-- Regular profile button -->
<div v-else class="relative mt-2">
<v-btn
class="text-md bg-[#FFFFFF23] px-6"
class="text-[12px] bg-[#FFFFFF23] px-2"
:class="{
'bg-[#FFFFFF43]': selectedProfile.name === functionMapping.name,
'text-sm': interfaceStore.isOnSmallScreen,
Expand All @@ -121,7 +122,7 @@
v-if="selectedProfile.name === functionMapping.name && isSelectedProfileDifferentFromActive"
icon
size="x-small"
class="absolute top-3 -right-3 text-white bg-[#51565B] rounded-full"
class="absolute top-3 -right-2 text-white bg-[#51565B] rounded-full"
@click.stop="switchToSelectedProfile"
>
<v-icon size="14">mdi-swap-horizontal</v-icon>
Expand Down Expand Up @@ -215,6 +216,17 @@
class="-mt-2"
@update:model-value="toggleJoystickEnabling(joystick.model)"
/>
<div v-if="showWizardButton" class="absolute right-0 mb-2">
<v-btn
variant="elevated"
size="small"
class="bg-[#FFFFFF22] text-white pt-[2px] pl-4"
prepend-icon="mdi-gamepad-up"
@click="interfaceStore.isJoystickWizardVisible = true"
>
Joystick config wizard
</v-btn>
</div>
</div>
<div
v-if="showJoystickLayout"
Expand Down Expand Up @@ -268,6 +280,17 @@
class="-mt-2 -mb-1"
@update:model-value="toggleJoystickEnabling(joystick.model)"
/>
<div v-if="showWizardButton" class="absolute right-0 mb-2">
<v-btn
variant="elevated"
size="small"
class="bg-[#FFFFFF22] text-white pt-[2px] pl-4"
prepend-icon="mdi-gamepad-up"
@click="interfaceStore.isJoystickWizardVisible = true"
>
Joystick config wizard
</v-btn>
</div>
</div>
<p class="text-start text-sm font-bold w-[93%] mb-1">Axes</p>
<v-data-table
Expand Down Expand Up @@ -763,6 +786,10 @@ const throttledButtonStates = ref<Record<number, number | undefined>>({})
const lastButtonUpdateTime = ref(0)
const buttonUpdateThrottleMs = 30

const showWizardButton = computed(() => {
return vehicleType === 'MAV_TYPE_SUBMARINE'
})

// Optimized shallow watcher instead of deep watcher
let buttonUpdateScheduled = false
watch(
Expand Down
Loading