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

creating "safe mode" #2888

Merged
merged 5 commits into from
Sep 17, 2024
Merged
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
17 changes: 17 additions & 0 deletions core/frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@
color="white"
@click="drawer = true"
/>
<v-card
v-if="!safe_mode"
v-tooltip="'Some functionality is not available while the vehicle is armed'"
class="d-flex align-center warning justify-center mr-5"
height="40"
>
<v-icon class="ml-3">
mdi-alert-outline
</v-icon>
<v-card-title>
Armed
</v-card-title>
</v-card>
<draggable v-model="selected_widgets" class="d-flex align-center justify-center">
<component
:is="getWidget(widget_name)"
Expand Down Expand Up @@ -387,6 +400,7 @@ import NotificationTrayButton from './components/notifications/TrayButton.vue'
import WifiTrayMenu from './components/wifi/WifiTrayMenu.vue'
import WifiUpdater from './components/wifi/WifiUpdater.vue'
import menus, { menuItem } from './menus'
import autopilot_data from './store/autopilot'
import Cpu from './widgets/Cpu.vue'
import Disk from './widgets/Disk.vue'

Expand Down Expand Up @@ -458,6 +472,9 @@ export default Vue.extend({
app_bar_style(): string {
return settings.is_dark_theme ? 'dark-background-glass' : 'light-background-glass'
},
safe_mode(): boolean {
return autopilot_data.is_safe
},
wifi_connected(): boolean {
return wifi.current_network != null
},
Expand Down
43 changes: 43 additions & 0 deletions core/frontend/src/components/common/NotSafeOverlay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<template>
<v-overlay
v-if="!is_safe"
:absolute="true"
:opacity="0.85"
>
<div class="d-flex flex-column justify-center align-center">
<p class="text-center">
This feature is disabled because the vehicle is armed.
</p>
<v-btn
class="ml-auto mr-auto"
color="warning"
@click="override()"
>
I know what I'm doing, let me through
</v-btn>
</div>
</v-overlay>
</template>

<script lang="ts">
import autopilot_data from '@/store/autopilot'

export default {
name: 'NotSafeOverlay',
data() {
return {
user_override: false,
}
},
computed: {
is_safe(): boolean {
return autopilot_data.is_safe || this.user_override
},
},
methods: {
override() {
this.user_override = true
},
},
}
</script>
3 changes: 2 additions & 1 deletion core/frontend/src/components/health/HealthTrayMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
import Vue from 'vue'

import mavlink2rest from '@/libs/MAVLink2Rest'
import { MavType } from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest-enum'
import { MavModeFlag, MavType } from '@/libs/MAVLink2Rest/mavlink2rest-ts/messages/mavlink2rest-enum'
import autopilot_data from '@/store/autopilot'
import mavlink from '@/store/mavlink'
import system_information from '@/store/system-information'
Expand Down Expand Up @@ -212,6 +212,7 @@ export default Vue.extend({
}
autopilot_data.setSystemId(message?.header.system_id)
autopilot_data.setAutopilotType(message?.message.autopilot.type)
autopilot_data.setVehicleArmed(Boolean(message?.message.base_mode.bits & MavModeFlag.MAV_MODE_FLAG_SAFETY_ARMED))
this.last_heartbeat_date = new Date()
}).setFrequency(0)
},
Expand Down
12 changes: 12 additions & 0 deletions core/frontend/src/store/autopilot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class AutopilotStore extends VuexModule {

system_id = 1

verhicle_armed = false

get parameter() {
return (name: string): Parameter | undefined => this.parameters.find((parameter) => parameter.name === name)
}
Expand All @@ -53,6 +55,11 @@ class AutopilotStore extends VuexModule {
)
}

get is_safe() {
// We can potentially check for external things here
return !this.verhicle_armed
}

Comment on lines +58 to +62
Copy link
Member

Choose a reason for hiding this comment

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

why is this not calling the backend instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

This will give us feedback at 1hz, I don't want yet another thing polling the backends at 1hz for no reason...
I can add to the comment "such as ardupilotManager's /safe endpoint"

Copy link
Member

Choose a reason for hiding this comment

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

So why we have the safe endpoint in the backend ?

Copy link
Member

Choose a reason for hiding this comment

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

hmm, so why was the backend endpoint added?

Copy link
Member Author

Choose a reason for hiding this comment

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

for subsequent backend-based validations, such in ardupilot_manager.py and whatever else

@Mutation
reset(): void {
this.parameters = []
Expand Down Expand Up @@ -100,6 +107,11 @@ class AutopilotStore extends VuexModule {
this.parameters_total = count
this.finished_loading = this.parameters_loaded >= this.parameters_total && this.metadata_loaded
}

@Mutation
setVehicleArmed(armed: boolean): void {
this.verhicle_armed = armed
}
}

export { AutopilotStore }
Expand Down
2 changes: 2 additions & 0 deletions core/frontend/src/views/Autopilot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</v-row>
<br>
</div>
<not-safe-overlay />
<v-expansion-panels>
<v-expansion-panel>
<v-expansion-panel-header>
Expand Down Expand Up @@ -129,6 +130,7 @@ export default Vue.extend({
BoardChangeDialog,
FirmwareManager,
AutopilotSerialConfiguration,
NotSafeOverlay,
},
data() {
return {
Expand Down
1 change: 1 addition & 0 deletions core/frontend/src/views/ExtensionManagerView.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<v-container fluid>
<not-safe-overlay />
<pull-progress
:progress="pull_output"
:show="show_pull_output"
Expand Down
2 changes: 2 additions & 0 deletions core/frontend/src/views/NetworkTestView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<v-card
height="100%"
>
<not-safe-overlay />
<v-tabs
v-model="page_selected"
centered
Expand Down Expand Up @@ -46,6 +47,7 @@ export default Vue.extend({
components: {
InternetSpeedTest,
NetworkSpeedTest,
NotSafeOverlay,
},
data() {
return {
Expand Down
2 changes: 2 additions & 0 deletions core/frontend/src/views/VersionChooser.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<v-container>
<not-safe-overlay />
<version-chooser />
</v-container>
</template>
Expand All @@ -13,6 +14,7 @@ export default Vue.extend({
name: 'VersionChooserView',
components: {
VersionChooser,
NotSafeOverlay,
},
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,9 @@ async def disarm_vehicle(self) -> None:
await self.mavlink2rest.send_mavlink_message(disarm_message)
if await self.is_vehicle_armed():
raise VehicleDisarmFail("Failed to disarm vehicle. Please try a manual disarm.")

async def vehicle_is_safe(self) -> bool:
"""Check if vehicle is safe to arm.
This might eventually be enhanced to check for other conditions.
"""
return not await self.is_vehicle_armed()
10 changes: 10 additions & 0 deletions core/services/ardupilot_manager/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,16 @@ async def available_boards() -> Any:
return await autopilot.available_boards(True)


@app.get("/safe")
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't make more sense to move to "armed" ? Safe is to abstracted, and armed is a common term.

Copy link
Member

Choose a reason for hiding this comment

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

@patrickelectric I think safe can abstract more than just arm, in case we want to check for other things..?

Copy link
Member

Choose a reason for hiding this comment

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

any idea of other things that the backend of ardupilot_manager may know ?
It would be nice to have a comment about that.

Copy link
Member Author

Choose a reason for hiding this comment

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

if there's a flashing operation in progress, for example, I'll add comments and/or more checking

Copy link
Member Author

Choose a reason for hiding this comment

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

comment added, I'll leave the actual blocking checks to after @JoaoMario109 's refactor is done

@version(1, 0)
async def safe() -> bool:
"""
Checks if the vehicle is in a condition where it is safe to perform dangerous operations on it,
Such as firmware flashing, parameter loading, rebooting, networking changes, etc.
"""
return bool(autopilot.vehicle_manager.vehicle_is_safe())


app = VersionedFastAPI(app, version="1.0.0", prefix_format="/v{major}.{minor}", enable_latest=True)


Expand Down
Loading