-
Notifications
You must be signed in to change notification settings - Fork 225
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create a drone class to improve interface and documentation
- Loading branch information
1 parent
303e814
commit 7743709
Showing
4 changed files
with
146 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,105 +1,41 @@ | ||
# -*- coding: utf-8 -*- | ||
import aiogrpc | ||
from . import get_event_loop | ||
|
||
|
||
class AsyncPluginManager: | ||
""" | ||
Connects to a running mavsdk server or starts one and manages plugins | ||
:param host: IP address of host running the backend | ||
:param port: Port number | ||
:param secure: Use an SSL Layer (currently not supported) | ||
:param loop: Event loop MAVSDK is running on | ||
Initialize the plugin manager: | ||
>>> manager = AsyncPluginManager(host="127.0.0.1") | ||
There are two (uniform) ways to register a plugin to the backend: | ||
>>> action = Action(manager) | ||
or | ||
>>> action = Action() | ||
>>> action.init_core(manager) | ||
""" | ||
def __init__( | ||
self, | ||
host=None, | ||
port=50051, | ||
secure=False, | ||
loop=None): | ||
@classmethod | ||
async def create(cls, host, port=50051): | ||
|
||
self = AsyncPluginManager() | ||
|
||
self.host, self.port, self.secure = host, port, secure | ||
self.host = host | ||
self.port = port | ||
self.plugins = {} | ||
|
||
if host: | ||
# Connect to the backend when there is a hostname passed | ||
self._connect_backend() | ||
else: | ||
# Spinup a backend | ||
raise NotImplementedError() | ||
await self._connect_backend() | ||
|
||
self._loop = loop or get_event_loop() | ||
return self | ||
|
||
def _connect_backend(self): | ||
async def _connect_backend(self): | ||
""" | ||
Initializes the connection to the running backend | ||
""" | ||
if self.secure: | ||
# For now just allow insecure connections | ||
raise NotImplementedError() | ||
|
||
#: gRPC channel | ||
self._channel = aiogrpc.insecure_channel( | ||
"{}:{}".format(self.host, self.port) | ||
) | ||
|
||
def _spinup_backend(self): | ||
""" | ||
Spinup a backend and connect to it | ||
""" | ||
#: backend is running on localhost | ||
self.host = "127.0.0.1" | ||
# Standart port | ||
self.port = 50051 | ||
# Spinup the backend, not implemented yet | ||
raise NotImplementedError() | ||
# connect to the local running backend | ||
self._connect_backend() | ||
|
||
@property | ||
def loop(self): | ||
""" Event loop """ | ||
return self._loop | ||
print("Waiting for mavsdk_server to be ready...") | ||
await aiogrpc.channel_ready_future(self._channel) | ||
print("Connected to mavsdk_server!") | ||
|
||
@property | ||
def channel(self): | ||
""" | ||
gRPC channel to the backend | ||
""" | ||
return self._channel | ||
|
||
@property | ||
def available_plugins(self): | ||
""" | ||
List of registered plugins | ||
""" | ||
return list(self.plugins.keys()) | ||
|
||
def register_plugin(self, plugin): | ||
""" | ||
Registers a plugin and adds it to the available plugin library | ||
""" | ||
if plugin and plugin not in self.available_plugins: | ||
self.plugins[plugin.name.lower()] = plugin | ||
|
||
def __getattr__(self, name): | ||
""" convenient way to access plugins """ | ||
if name in self.plugins.keys(): | ||
return self.plugins[name] | ||
else: | ||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
from .async_plugin_manager import AsyncPluginManager # NOQA | ||
from .generated import * # NOQA | ||
|
||
from . import bin | ||
|
||
|
||
class Drone: | ||
_core_plugins = [ | ||
"Action", | ||
"Calibration", | ||
"Camera", | ||
"Core", | ||
"Gimbal", | ||
"Info", | ||
"Mission", | ||
"Param", | ||
"Offboard", | ||
"Telemetry" | ||
] | ||
|
||
def __init__(self, mavsdk_server_address=None, port=50051): | ||
self._mavsdk_server_address = mavsdk_server_address | ||
self._port = port | ||
|
||
self._plugins = {} | ||
|
||
async def connect(self, drone_address=None): | ||
if self._mavsdk_server_address is None: | ||
self._mavsdk_server_address = 'localhost' | ||
self._start_mavsdk_server(drone_address) | ||
|
||
await self._init_plugins(self._mavsdk_server_address, self._port) | ||
|
||
async def _init_plugins(self, host, port): | ||
plugin_manager = await AsyncPluginManager.create(host=host, port=port) | ||
|
||
for plugin in self._core_plugins: | ||
self._plugins[plugin.lower()] = globals()[plugin](plugin_manager) | ||
|
||
@property | ||
def action(self) -> Action: | ||
if "action" not in self._plugins: | ||
raise RuntimeError("Action plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["action"] | ||
|
||
@property | ||
def calibration(self) -> Calibration: | ||
if "calibration" not in self._plugins: | ||
raise RuntimeError("Calibration plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["calibration"] | ||
|
||
@property | ||
def camera(self) -> Camera: | ||
if "camera" not in self._plugins: | ||
raise RuntimeError("Camera plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["camera"] | ||
|
||
@property | ||
def core(self) -> Core: | ||
if "core" not in self._plugins: | ||
raise RuntimeError("Core plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["core"] | ||
|
||
@property | ||
def gimbal(self) -> Gimbal: | ||
if "gimbal" not in self._plugins: | ||
raise RuntimeError("Gimbal plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["gimbal"] | ||
|
||
@property | ||
def info(self) -> Info: | ||
if "info" not in self._plugins: | ||
raise RuntimeError("Info plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["info"] | ||
|
||
@property | ||
def mission(self) -> Mission: | ||
if "mission" not in self._plugins: | ||
raise RuntimeError("Mission plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["mission"] | ||
|
||
@property | ||
def param(self) -> Param: | ||
if "param" not in self._plugins: | ||
raise RuntimeError("Param plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["param"] | ||
|
||
@property | ||
def offboard(self) -> Offboard: | ||
if "offboard" not in self._plugins: | ||
raise RuntimeError("Offboard plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["offboard"] | ||
|
||
@property | ||
def telemetry(self) -> Telemetry: | ||
if "telemetry" not in self._plugins: | ||
raise RuntimeError("Telemetry plugin has not been initialized! Did you run `Drone.connect()`?") | ||
return self._plugins["telemetry"] | ||
|
||
@staticmethod | ||
def _start_mavsdk_server(drone_address=None): | ||
""" | ||
Starts the gRPC server in a subprocess, listening on localhost:50051 | ||
""" | ||
import atexit | ||
import os | ||
import subprocess | ||
import sys | ||
|
||
if sys.version_info >= (3, 7): | ||
from importlib.resources import path | ||
else: | ||
from importlib_resources import path | ||
|
||
with path(bin, 'mavsdk_server') as backend: | ||
bin_path_and_args = [os.fspath(backend)] | ||
if drone_address: | ||
bin_path_and_args.append(drone_address) | ||
p = subprocess.Popen(bin_path_and_args, | ||
shell=False, | ||
stdout=subprocess.DEVNULL, | ||
stderr=subprocess.DEVNULL) | ||
|
||
def cleanup(): | ||
p.kill() | ||
|
||
atexit.register(cleanup) |