MAVLink Serial sniffer

Long shot, but does anyone have a Python (ideally, but C would work) script that listens for mavlink messages over a serial port and logs them with a timestamp? No need to send anything, just need to listen and log.

You could run a simple mavsdk example (C++) and set export MAVSDK_MESSAGE_DEBUGGING=1 to see all messages coming in and going out.

This would be an example:

#include <cstdint>
#include <future>
#include <mavsdk/mavsdk.h>
#include <iostream>
#include <thread>

using namespace mavsdk;
using namespace std::this_thread;
using namespace std::chrono;

void usage(const std::string& bin_name)
{
    std::cerr << "Usage : " << bin_name << " <connection_url>\n"
              << "Connection URL format should be :\n"
              << " For TCP : tcp://[server_host][:server_port]\n"
              << " For UDP : udp://[bind_host][:bind_port]\n"
              << " For Serial : serial:///path/to/serial/dev[:baudrate]\n"
              << "For example, to connect to the simulator use URL: udp://:14540\n";
}

std::shared_ptr<System> get_system(Mavsdk& mavsdk)
{
    std::cout << "Waiting to discover system...\n";
    auto prom = std::promise<std::shared_ptr<System>>{};
    auto fut = prom.get_future();

    // We wait for new systems to be discovered, once we find one that has an
    // autopilot, we decide to use it.
    mavsdk.subscribe_on_new_system([&mavsdk, &prom]() {
        auto system = mavsdk.systems().back();

        if (system->has_autopilot()) {
            std::cout << "Discovered autopilot\n";

            // Unsubscribe again as we only want to find one system.
            mavsdk.subscribe_on_new_system(nullptr);
            prom.set_value(system);
        }
    });

    // We usually receive heartbeats at 1Hz, therefore we should find a
    // system after around 3 seconds max, surely.
    if (fut.wait_for(seconds(3)) == std::future_status::timeout) {
        std::cerr << "No autopilot found.\n";
        return {};
    }

    // Get discovered system now.
    return fut.get();
}

int main(int argc, char** argv)
{
    if (argc != 2) {
        usage(argv[0]);
        return 1;
    }

    Mavsdk mavsdk;
    ConnectionResult connection_result = mavsdk.add_any_connection(argv[1]);

    if (connection_result != ConnectionResult::Success) {
        std::cerr << "Connection failed: " << connection_result << '\n';
        return 1;
    }

    auto system = get_system(mavsdk);
    if (!system) {
        return 1;
    }

    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    return 0;
}

The CMakeLists.txt would be:


cmake_minimum_required(VERSION 3.10.2)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(sniffer)

add_executable(sniffer
    sniffer.cpp
)

find_package(MAVSDK REQUIRED)

target_link_libraries(sniffer
    MAVSDK::mavsdk
)

if(NOT MSVC)
    add_compile_options(sniffer PRIVATE -Wall -Wextra)
else()
    add_compile_options(sniffer PRIVATE -WX -W2)
endif()

Edit, sorry, I realize this is based on MAVSDK v2 which is not released yet. I changed it for v1 now.

1 Like

FYI: I’ve added an example to MAVSDK with that, however, that one is against v2 which has the additional intercept_ method.
The same method is available for v1, however, it’s part of the MavlinkPassthrough plugin there.

This is great!!

BTW: Is there any interest in providing -lite version of MAV SDK that does not depend on libCURL and friends (I’m aware that some features would not work)? I’m trying to build this quick and dirty on Win based machine and dependency management is a pain.

2 Likes

I have heard of this request before, and I get it, dependencies are a pain. I’ll keep it in mind.

1 Like

It’s coming: Add option to build without cURL by julianoes · Pull Request #1955 · mavlink/MAVSDK · GitHub

It’ll only be in v2 though.

1 Like

Cool! I’ll give it a got tomorrow morning!