I’m writing an autonomous landing algorithm with MavSDK and Python that detects aruco markers, using OpenCV.
After connecting to the drone and getting a position estimation, I start a async task that continuously fetches the current position of the drone:
class PX4Drone:
def __init__(self):
self.drone = System()
await self.drone.connect(system_address=connection_string_complete)
async for state in self.drone.core.connection_state():
if state.is_connected:
print("Drone connected")
await self.sendToServer("Drone connected")
break
print("Trying to get a position estimate")
async for terrain_info in self.drone.telemetry.home():
self.absolute_altitude = terrain_info.absolute_altitude_m
print("Home coordinates are " + str(terrain_info.latitude_deg) + ", " + str(terrain_info.longitude_deg))
print("ASML altitude at home position is " + str(self.absolute_altitude))
break
# Start telemetry
executor = concurrent.futures.ThreadPoolExecutor()
await loop.run_in_executor(executor, long_sync_fun)
asyncio.ensure_future(self.status_battery())
async def status_position(self):
print("Position future started")
async for position in self.drone.telemetry.position():
self.telemetry_position = position
...
Now I do some flying. using actions like land
or goto_position
, while the future I started keeps delivering positions as they come. Later, I approach the landing pad and call the method for precision landing:
async def handleAction_PreciseLanding(self):
self.precisionLanding = PrecisionLanding(self.drone);
await self.precisionLanding.land(action)
Image acquisition, as well as searching an image for markers are performed by computationally expensive synchronous methods. This during the landing, the frequency of positions received by the position future goes down to maybe 3 per second. Even worse is, that MavSDK seems to queue up these positions that are acquired faster that I can read them out, and when the position future finally queries a position again, it was taken seconds or minutes ago.
What would be a way to deal with this? My current approach would be running the position task in a separate process by creating the following class:
import asyncio
import logging
from multiprocessing import Process
class PX4DroneTelemetry(object):
def __init__(self, drone):
self.logger = logging.getLogger()
self.process_pool = []
self.drone = drone
async def run_telemetry(self):
asyncio.ensure_future(self.status_position())
def exec_async_method(self):
asyncio.run(self.run_telemetry())
def run(self):
process = Process(target=self.exec_async_method, args=())
self.process_pool.append(process)
process.start()
async def status_position(self):
self.logger.info("Position future started")
async for position in self.drone.telemetry.position():
self.telemetry_position = position
and calling it like this
PX4DroneTelemetry(self.drone).run()
However, this seems to block execution entirely, as soon as the drone object is accesses. If it’s not obvious by now, I’m not an experienced Python programmer, maybe the problem is easy to spot.
p.s. Of course, my code is more complex than shown in these examples. I tried to cut out the parts that I considered relevant to this question. If you miss anything, let me know.