Skip to content

Commit a3b4a43

Browse files
wip
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
1 parent 289eafb commit a3b4a43

File tree

7 files changed

+132
-13
lines changed

7 files changed

+132
-13
lines changed

core/frontend/src/components/autopilot/AutopilotManagerUpdater.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,34 @@ export async function fetchFirmwareVehicleType(): Promise<void> {
114114
}
115115
}
116116

117+
export async function fetchExtraArguments(): Promise<void> {
118+
try {
119+
const response = await back_axios({
120+
method: 'get',
121+
url: `${autopilot.API_URL}/extra_arguments`,
122+
timeout: 10000,
123+
})
124+
autopilot.setExtraArguments(response.data)
125+
} catch (error) {
126+
autopilot.setExtraArguments({})
127+
notifier.pushBackError('AUTOPILOT_EXTRA_ARGS_FETCH_FAIL', error)
128+
}
129+
}
130+
131+
export async function fetchProcessStatus(): Promise<void> {
132+
try {
133+
const response = await back_axios({
134+
method: 'get',
135+
url: `${autopilot.API_URL}/process_status`,
136+
timeout: 10000,
137+
})
138+
autopilot.setProcessStatus(response.data)
139+
} catch (error) {
140+
autopilot.setProcessStatus(null)
141+
notifier.pushBackError('AUTOPILOT_PROCESS_STATUS_FETCH_FAIL', error)
142+
}
143+
}
144+
117145
export async function availableFirmwares(vehicleType: Vehicle): Promise<Firmware[]> {
118146
return back_axios({
119147
method: 'get',

core/frontend/src/store/autopilot_manager.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import {
55
import store from '@/store'
66
import {
77
AutopilotEndpoint, FirmwareInfo, FirmwareVehicleType,
8-
FlightController, SerialEndpoint,
8+
FlightController, ProcessStatus, SerialEndpoint,
99
} from '@/types/autopilot'
10+
import { Dictionary } from '@/types/common'
1011

1112
@Module({
1213
dynamic: true,
@@ -37,6 +38,10 @@ class AutopilotManagerStore extends VuexModule {
3738

3839
autopilot_serials: SerialEndpoint[] = []
3940

41+
extra_arguments: Dictionary<string> = {}
42+
43+
process_status: ProcessStatus | null = null
44+
4045
@Mutation
4146
setAutopilotSerialConfigurations(serials: SerialEndpoint[]): void {
4247
this.autopilot_serials = serials
@@ -83,6 +88,16 @@ class AutopilotManagerStore extends VuexModule {
8388
this.available_boards = boards
8489
this.updating_boards = false
8590
}
91+
92+
@Mutation
93+
setExtraArguments(arguments_: Dictionary<string>): void {
94+
this.extra_arguments = arguments_
95+
}
96+
97+
@Mutation
98+
setProcessStatus(process_status: ProcessStatus | null): void {
99+
this.process_status = process_status
100+
}
86101
}
87102

88103
export { AutopilotManagerStore }

core/frontend/src/types/autopilot.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,8 @@ export interface SerialEndpoint {
9898
port: string
9999
endpoint: string
100100
}
101+
102+
export interface ProcessStatus {
103+
running: boolean
104+
exit_code: number | null
105+
}

core/frontend/src/views/Autopilot.vue

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,16 @@
7474
</v-expansion-panel-content>
7575
</v-expansion-panel>
7676
</v-expansion-panels>
77+
<v-expansion-panels v-if="settings.is_pirate_mode && isLinuxFlightController">
78+
<v-expansion-panel>
79+
<v-expansion-panel-header>
80+
Extra Arguments
81+
</v-expansion-panel-header>
82+
<v-expansion-panel-content>
83+
<autopilot-extra-arguments />
84+
</v-expansion-panel-content>
85+
</v-expansion-panel>
86+
</v-expansion-panels>
7787
</v-card-text>
7888
<v-card-actions class="d-flex justify-end align-center flex-wrap">
7989
<v-spacer />
@@ -131,6 +141,7 @@ import Vue from 'vue'
131141
import ArduPilotBanner from '@/assets/img/banners/ArduPilot.svg'
132142
import OpenPilotBanner from '@/assets/img/banners/OpenPilot.svg'
133143
import PX4Banner from '@/assets/img/banners/PX4.svg'
144+
import AutopilotExtraArguments from '@/components/autopilot/AutopilotExtraArguments.vue'
134145
import * as AutopilotManager from '@/components/autopilot/AutopilotManagerUpdater'
135146
import {
136147
fetchAvailableBoards, fetchCurrentBoard, fetchFirmwareInfo, fetchFirmwareVehicleType, fetchVehicleType,
@@ -156,6 +167,7 @@ const notifier = new Notifier(autopilot_service)
156167
export default Vue.extend({
157168
name: 'Autopilot',
158169
components: {
170+
AutopilotExtraArguments,
159171
BoardChangeDialog,
160172
FirmwareManager,
161173
AutopilotSerialConfiguration,

core/services/ardupilot_manager/api/v1/routers/index.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import shutil
44
from functools import wraps
55
from pathlib import Path
6-
from typing import Any, Callable, List, Optional, Tuple
6+
from typing import Any, Callable, Dict, List, Optional, Tuple
77

88
from autopilot_manager import AutoPilotManager
99
from commonwealth.mavlink_comm.exceptions import (
@@ -24,6 +24,7 @@
2424
FlightController,
2525
FlightControllerFlags,
2626
Parameters,
27+
ProcessStatus,
2728
Serial,
2829
SITLFrame,
2930
Vehicle,
@@ -136,6 +137,24 @@ async def set_sitl_frame(frame: SITLFrame) -> Any:
136137
return autopilot.set_sitl_frame(frame)
137138

138139

140+
@index_router_v1.get("/extra_arguments", response_model=Dict[str, str], summary="Get extra ArduPilot arguments.")
141+
@index_to_http_exception
142+
def get_extra_arguments() -> Any:
143+
return autopilot.get_extra_arguments()
144+
145+
146+
@index_router_v1.put("/extra_arguments", status_code=status.HTTP_200_OK, summary="Set extra ArduPilot arguments.")
147+
@index_to_http_exception
148+
def set_extra_arguments(arguments: Dict[str, str] = Body(...)) -> Any:
149+
autopilot.set_extra_arguments(arguments)
150+
151+
152+
@index_router_v1.get("/process_status", response_model=ProcessStatus, summary="Get ArduPilot process status.")
153+
@index_to_http_exception
154+
def get_process_status() -> Any:
155+
return autopilot.get_process_status()
156+
157+
139158
@index_router_v1.get("/firmware_vehicle_type", response_model=str, summary="Get firmware vehicle type.")
140159
@index_to_http_exception
141160
async def get_firmware_vehicle_type() -> Any:

core/services/ardupilot_manager/autopilot_manager.py

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import subprocess
55
import time
66
from copy import deepcopy
7-
from typing import Any, List, Optional, Set
7+
from typing import Any, Dict, List, Optional, Set
88

99
import psutil
1010
from commonwealth.mavlink_comm.VehicleManager import VehicleManager
@@ -30,6 +30,7 @@
3030
Parameters,
3131
Platform,
3232
PlatformType,
33+
ProcessStatus,
3334
Serial,
3435
SITLFrame,
3536
Vehicle,
@@ -151,6 +152,7 @@ async def setup(self) -> None:
151152
self.vehicle_manager = VehicleManager()
152153

153154
self.should_be_running = False
155+
self._last_exit_code: Optional[int] = None
154156
self.remove_old_logs()
155157
self.current_sitl_frame = self.load_sitl_frame()
156158

@@ -189,6 +191,11 @@ def is_running(self) -> bool:
189191
async def auto_restart_ardupilot(self) -> None:
190192
"""Auto-restart Ardupilot when it's not running but was supposed to."""
191193
while True:
194+
if self.ardupilot_subprocess is not None and self.ardupilot_subprocess.poll() is not None:
195+
self._last_exit_code = self.ardupilot_subprocess.returncode
196+
if self._last_exit_code != 0:
197+
logger.warning(f"ArduPilot process exited with code {self._last_exit_code}")
198+
192199
needs_restart = self.should_be_running and not self.is_running()
193200
if needs_restart:
194201
logger.debug("Restarting ardupilot...")
@@ -315,6 +322,7 @@ async def start_linux_board(self, board: LinuxFlightController) -> None:
315322
#
316323
# The first column comes from https://ardupilot.org/dev/docs/sitl-serial-mapping.html
317324

325+
extra_args = self.get_extra_arguments_cmdline()
318326
command_line = (
319327
f"{firmware_path}"
320328
f" -A udp:{master_endpoint.place}:{master_endpoint.argument}"
@@ -323,11 +331,14 @@ async def start_linux_board(self, board: LinuxFlightController) -> None:
323331
f" {self.get_serial_cmdline()}"
324332
f" {self.get_default_params_cmdline(board.platform)}"
325333
)
334+
if extra_args:
335+
command_line += f" {extra_args}"
326336

327337
if self.firmware_has_debug_symbols(firmware_path):
328338
logger.info("Debug symbols found, launching with gdb server...")
329339
command_line = f"gdbserver 0.0.0.0:5555 {command_line}"
330340

341+
self._last_exit_code = None
331342
logger.info(f"Using command line: '{command_line}'")
332343
self.ardupilot_subprocess = subprocess.Popen(
333344
command_line,
@@ -389,6 +400,25 @@ def load_preferred_router(self) -> Optional[str]:
389400
def get_available_routers(self) -> List[str]:
390401
return [router.name() for router in self.mavlink_manager.available_interfaces()]
391402

403+
def get_extra_arguments(self) -> Dict[str, str]:
404+
return self.configuration.get("extra_arguments", {})
405+
406+
def set_extra_arguments(self, arguments: Dict[str, str]) -> None:
407+
self.configuration["extra_arguments"] = arguments
408+
self.settings.save(self.configuration)
409+
410+
def get_extra_arguments_cmdline(self) -> str:
411+
parts = []
412+
for name, value in self.get_extra_arguments().items():
413+
if value:
414+
parts.append(f"{name} {value}")
415+
else:
416+
parts.append(name)
417+
return " ".join(parts)
418+
419+
def get_process_status(self) -> ProcessStatus:
420+
return ProcessStatus(running=self.is_running(), exit_code=self._last_exit_code)
421+
392422
async def start_manual_board(self, board: FlightController) -> None:
393423
self._current_board = board
394424
self.master_endpoint = self.get_manual_board_master_endpoint()
@@ -417,18 +447,23 @@ async def start_sitl(self) -> None:
417447
argument=5760,
418448
protected=True,
419449
)
450+
451+
extra_args = self.get_extra_arguments_cmdline()
452+
command_line = (
453+
f"{firmware_path}"
454+
f" --model {self.current_sitl_frame.value}"
455+
f" --base-port {master_endpoint.argument}"
456+
f" --home -27.563,-48.459,0.0,270.0"
457+
)
458+
if extra_args:
459+
command_line += f" {extra_args}"
460+
420461
# pylint: disable=consider-using-with
462+
self._last_exit_code = None
463+
logger.info(f"Using command line: '{command_line}'")
421464
self.ardupilot_subprocess = subprocess.Popen(
422-
[
423-
firmware_path,
424-
"--model",
425-
self.current_sitl_frame.value,
426-
"--base-port",
427-
str(master_endpoint.argument),
428-
"--home",
429-
"-27.563,-48.459,0.0,270.0",
430-
],
431-
shell=False,
465+
command_line,
466+
shell=True,
432467
encoding="utf-8",
433468
errors="ignore",
434469
cwd=self.settings.firmware_folder,

core/services/ardupilot_manager/typedefs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,8 @@ def valid_endpoint(cls: Any, value: str) -> str:
209209

210210
def __hash__(self) -> int: # make hashable BaseModel subclass
211211
return hash(self.port + self.endpoint)
212+
213+
214+
class ProcessStatus(BaseModel):
215+
running: bool
216+
exit_code: Optional[int] = None

0 commit comments

Comments
 (0)