Skip to content

Commit 0bb484b

Browse files
frontend: add relay configuration to vehicle setup
1 parent 3d3353e commit 0bb484b

File tree

3 files changed

+162
-22
lines changed

3 files changed

+162
-22
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<template>
2+
<v-card class="mt-4 mb-4">
3+
<v-card-text>
4+
<v-row align="center">
5+
<v-col cols="6">
6+
<span class="text-h6">Relay {{ relay_number }}</span>
7+
</v-col>
8+
<v-col cols="6" class="d-flex justify-end">
9+
<v-btn
10+
v-tooltip="'Turn relay off'"
11+
small
12+
@click="setRelay(0)"
13+
>
14+
<v-icon small left>
15+
mdi-power-off
16+
</v-icon>
17+
Relay Off
18+
</v-btn>
19+
<v-btn
20+
v-tooltip="'Turn relay on'"
21+
small
22+
@click="setRelay(1)"
23+
>
24+
<v-icon small left>
25+
mdi-power
26+
</v-icon>
27+
Relay On
28+
</v-btn>
29+
</v-col>
30+
</v-row>
31+
32+
<v-row align="center">
33+
<v-col cols="6" class="pa0">
34+
<parameter-switch
35+
v-if="inverted_parameter"
36+
:parameter="inverted_parameter"
37+
:off-value="0"
38+
:on-value="1"
39+
label="Invert Output"
40+
/>
41+
</v-col>
42+
<v-col cols="6" class="pa0">
43+
<parameter-switch
44+
v-if="default_parameter"
45+
:parameter="default_parameter"
46+
:off-value="0"
47+
:on-value="1"
48+
label="Startup State"
49+
/>
50+
</v-col>
51+
</v-row>
52+
</v-card-text>
53+
</v-card>
54+
</template>
55+
56+
<script lang="ts">
57+
import Vue from 'vue'
58+
59+
import mavlink2rest from '@/libs/MAVLink2Rest'
60+
import { MavCmd } from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest-enum'
61+
import autopilot_data from '@/store/autopilot'
62+
import Parameter from '@/types/autopilot/parameter'
63+
64+
export default Vue.extend({
65+
name: 'RelaySetup',
66+
props: {
67+
relayParameter: {
68+
type: Object as () => Parameter,
69+
required: true,
70+
},
71+
},
72+
computed: {
73+
relay_number(): number {
74+
return parseInt(this.relayParameter.name.match(/RELAY(\d+)_FUNCTION/)?.[1] ?? '0', 10)
75+
},
76+
inverted_parameter(): Parameter | undefined {
77+
return autopilot_data.parameter(`RELAY${this.relay_number}_INVERTED`)
78+
},
79+
default_parameter(): Parameter | undefined {
80+
return autopilot_data.parameter(`RELAY${this.relay_number}_DEFAULT`)
81+
},
82+
},
83+
methods: {
84+
setRelay(setting: number): void {
85+
// MAV_CMD_DO_SET_RELAY: param1 = relay instance (0-indexed), param2 = setting (0=off, 1=on, 2=toggle)
86+
mavlink2rest.sendCommandLong(
87+
MavCmd.MAV_CMD_DO_SET_RELAY,
88+
this.relay_number - 1, // Convert to 0-indexed relay instance
89+
setting,
90+
)
91+
},
92+
},
93+
})
94+
</script>

core/frontend/src/components/parameter-editor/ServoFunctionGpioEditor.vue

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,34 @@
11
<template>
22
<div class="align-center">
3-
GPIOs can be used for Relays, Leak detection, and other functions not yet supported by this UI.
4-
This servo ({{ servo_number }}) gpio is {{ this_servo_gpio }}.
5-
6-
In use by {{ function_type_using_this_gpio?.name }}
7-
3+
<p>
4+
Some flight controller servo channels are capable of digital (GPIO) functionalities.
5+
Available options include relays, leak detection (input-capable pins only),
6+
and other functions not yet supported by this UI.
7+
</p>
8+
<p>
9+
This servo's GPIO (<strong>{{ this_servo_gpio }}</strong>) is currently in use by
10+
<strong>{{ function_type_using_this_gpio?.name ?? 'nothing' }}</strong>.
11+
</p>
812
<v-row align="end">
9-
<v-col cols="6">
10-
<span style="font-size: 1.0rem;">Change function for this servo's GPIO</span>
11-
</v-col>
12-
<v-col cols="6">
13-
<v-select
14-
v-model="selected_function_type"
15-
:items="options"
16-
item-text="text"
17-
item-value="value"
18-
return-object
19-
hide-details
20-
@change="onChange"
21-
/>
22-
</v-col>
13+
<v-col cols="6">
14+
<span style="font-size: 1.0rem;">GPIO Function:</span>
15+
</v-col>
16+
<v-col cols="6">
17+
<v-select
18+
v-model="selected_function_type"
19+
:items="options"
20+
item-text="text"
21+
item-value="value"
22+
return-object
23+
hide-details
24+
@change="onChange"
25+
/>
26+
</v-col>
2327
</v-row>
24-
28+
<relay-setup
29+
v-if="function_type_using_this_gpio?.name?.includes('RELAY')"
30+
:relay-parameter="function_type_using_this_gpio"
31+
/>
2532
</div>
2633
</template>
2734

core/frontend/src/components/vehiclesetup/PwmSetup.vue

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@
136136
<td v-tooltip="item.name">
137137
{{ convert_servo_name(item.name) }}
138138
</td>
139-
<td>{{ stringToUserFriendlyText(printParam(item)) }}</td>
139+
<td>{{ parameterToUserFriendlyText(item) }}</td>
140140
<td>{{ servo_output[index] }}</td>
141141
</tr>
142142
</tbody>
@@ -156,6 +156,7 @@
156156
<script lang="ts">
157157
import Vue from 'vue'
158158
159+
import { fetchCurrentBoard } from '@/components/autopilot/AutopilotManagerUpdater'
159160
import ServoFunctionEditorDialog from '@/components/parameter-editor/ServoFunctionEditorDialog.vue'
160161
import MotorDetection from '@/components/vehiclesetup/MotorDetection.vue'
161162
import VehicleViewer from '@/components/vehiclesetup/viewers/VehicleViewer.vue'
@@ -376,6 +377,30 @@ export default Vue.extend({
376377
return output
377378
.map((_, i) => data[`servo${i + 1}_raw`])
378379
},
380+
board_name(): string | undefined {
381+
return autopilot.current_board?.name
382+
},
383+
gpio_to_parameter(): Record<number, Parameter> {
384+
return Object.fromEntries(
385+
autopilot_data.parameterRegex('^.*_PIN$')
386+
.map((param) => [param.value, param]),
387+
)
388+
},
389+
servo_to_gpio(): Record<number, number> {
390+
const isNavigator = this.board_name?.includes('Navigator')
391+
return Object.fromEntries(
392+
Array.from({ length: 16 }, (_, i) => {
393+
const servo = i + 1
394+
if (isNavigator) {
395+
return [servo, servo]
396+
}
397+
if (servo <= 8) {
398+
return [servo, servo + 100]
399+
}
400+
return [servo, servo - 9 + 50]
401+
}),
402+
)
403+
},
379404
},
380405
watch: {
381406
is_armed() {
@@ -392,6 +417,8 @@ export default Vue.extend({
392417
mounted() {
393418
this.motor_zeroer_interval = setInterval(this.zero_motors, 300)
394419
this.motor_writer_interval = setInterval(this.write_motors, 100)
420+
fetchCurrentBoard()
421+
395422
mavlink.setMessageRefreshRate({ messageName: 'SERVO_OUTPUT_RAW', refreshRate: 10 })
396423
this.desired_armed_state = this.is_armed
397424
this.installListeners()
@@ -455,13 +482,25 @@ export default Vue.extend({
455482
this.selected_param = param
456483
this.edit_param_dialog = true
457484
},
485+
parameterToUserFriendlyText(param: Parameter): string {
486+
if (param.value === -1) { // GPIO
487+
const servo_number = parseInt(/\d+/g.exec(param.name)?.[0] ?? '0', 10)
488+
const gpio = this.servo_to_gpio[servo_number]
489+
const param_using_this_gpio = this.gpio_to_parameter[gpio]
490+
if (param_using_this_gpio) {
491+
const pretty_name = param_using_this_gpio.name.split('_')[0].toLowerCase().toTitle()
492+
return `GPIO [${pretty_name}]`
493+
}
494+
return `Unknown GPIO ${gpio}`
495+
}
496+
return this.stringToUserFriendlyText(printParam(param))
497+
},
458498
stringToUserFriendlyText(text: string) {
459499
return param_value_map?.[this.vehicle_type ?? '']?.[text] ?? text
460500
},
461501
getParam(param: string): Parameter | undefined {
462502
return autopilot_data.parameter(param)
463503
},
464-
printParam,
465504
zero_motors() {
466505
if (!this.is_manual) {
467506
return

0 commit comments

Comments
 (0)