Correct Method for Querying Sensor Data

Hi,

I’m new to the MAVSDK library, and I’m trying to wrap my head around how to practically use the telemetry data in conjunction with offboard mode. I’m using the Python library.

Based on the examples, I can see that the telemetry data is exposed through an infinite asynchronous generator. This is combersome when trying to query and use multiple different sensors, since the only way I can figure to query the newest value is to do any awkward async for-break block like this:

async for x in drone.telemetry.imu():
    imu = x
    break

The examples show running these async for loops in a separate asyncio task, which I’ve thought about using to update a class-variable in the background, but the values are only updated when my current task yields control (e.g. at a await call), which could cause issues if my control systems requires more frequently updated data. The workaround for that would be littering await asyncio.sleep(0) throughout the code to manually yield control, but that also seems clunky.

Bottom line, I’m curious if the community can provide guidance on the standard/accepted/intended way for retrieving and using the sensor data so I don’t go down a bad path. Thanks!

Good question. I wonder if @JonasVautherin has an answer to this.

I would think that this is exactly it, yes :slight_smile:. Have a separate task for each value that you are interested in, and make it update a shared variable. Then your main code can just read it. You don’t have to worry about concurrency, because everything runs in one thread!

I don’t know what you want to do exactly, but you would not need to await asyncio.sleep(0) every second line. Say you have a coroutine that takes the state of the drone (that you maintain from the async tasks) and does some quick operation. Then when that coroutine starts to work, it can probably finish without having to release control, so you don’t even have to think about breaking it with await asyncio.sleep(0). Now say this coroutine does some long blocking operation. Then this operation should be awaited for, so that it doesn’t block all the tasks. And if you have so many small operations (like a = 3 or a * b - 1) that it ends up being a long-running task, then you can break it with await asyncio.sleep(0). But it’s not like print("hello") should be considerer “slow”. And if you have an infinite blocking loop, then it makes sense to await asyncio.sleep(0) at the end of it.

In the end, asyncio does exactly the same as threading, except that in threading, the system interrupts the functions wherever it wants (so you have to think about mutexes and stuff), and in asyncio, you say when your code may be interrupted, and we trust you on releasing control from time to time. Taking the infinite loop as an example, in threading, it will be interrupted by the system, but in asyncio, you’ll have to give it await points yourself otherwise it will just keep control forever.

Does that help? :sweat_smile:

Thank you! It does.

Im working on creating a wrapper around MAVSDK-Python for control of multiple aircraft and eventually working towards the goal of implementing a minimum snap trajectory controller. So trying to reach down and grab raw sesnor values and use them while setting offboard desired accelerations , velocities and positions… So similar to some implementations in MAVROS but without the ROS

I have been very happy with my design - I have a Python program that talks to MAVSDK to get telemetry updates and then I publish those over zmq so that the other programs in my system can get telemetry updates without having to know about the MAVSDK API. The telemetry program is all asyncio and, coming from a kernel and embedded programming background where I always used real threads, it was at first a bit unnerving to not have to worry about mutexes and locking! But once you get the hang of asyncio it is really quite nice to program with.

In my system, I publish both a single zmq topic per MAVSDK telemetry message and I also aggregate the data from multiple messages using the technique that you and @JonasVautherin talk about where I update global variables for the telemetry data and then publish in one large message from a callback that runs at whatever frequency I need (1Hz, 5Hz, etc…). The callback is also managed by asyncio and every time it runs, it reschedules itself to run again.

Thanks! Very interesting. I hadn’t heard of zmq but am doing some reading on it now. I was looking for a way to publish “actions” from my ground control station to multiple aircraft over digimesh and receive them on a rasp pi companion computer. This may be a good solution.

I have used zmq before, prior to working with MAVSDK and Pixhawk when I was doing development to control DJI drones from a custom ground station. The big benefit of zmq is that it supports a lot of very useful message passing design patterns and is very lightweight. The fact that the zmq team added asyncio support is also a big plus.

In my current project, I am publishing telemetry form both MAVSDK and from AirSim onto a common telemetry bus so that the higher level software can run in both simulation and in real life on a physical vehicle without much change.

Blockquote In my current project, I am publishing telemetry form both MAVSDK and from AirSim onto a common telemetry bus so that the higher level software can run in both simulation and in real life on a physical vehicle without much change.

That seems very similar to what I am doing as well. Do you have public code or notes? Would be interested in keeping tabs on your progress.

That seems very similar to what I am doing as well. Do you have public code or notes? Would be interested in keeping tabs on your progress.

I don’t have anything that I can share publicly right now. I’ll see if I can make some of my work public since I would like to share it with the community.

2 Likes