Telemetry yields outdated values

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.

Hmm are you sure it’s not your code that is not reading the positions fast enough? That would seem more likely to me… Your code has to read the results of the position generator fast enough, otherwise they will accumulate and you will see a delay.

On the contrary. I’m almost sure that it is my code. MavSDK couldn’t operate any drone if this was a normal mode of operation, and it seems to fly a lot of drones successfully.
I’m hoping for a hint on how to read the positions with sufficient speed while performing a computationally intensive function at the same time. The actual solution might have more to do with Python than with MavSDK.

1 Like

When using coroutines, you should never block. So either your “slow” code should release the executor more often, or it should run in a separate thread. I think I mentioned the ThreadPoolExecutor there, not sure if it may help: MAVSDK – Python: easy asyncio | Auterion.