Understanding MAVLink. Part 2

    In the last part, we examined the basic principles of working with the MAVLink protocol and learned how to exchange messages like HEARTBEAT . In this part, we will look at some other types of messages that are responsible for flight data and try to visualize this data using Qt.

    image


    In MAVLink there are various built-in message types, as well as the ability to add your own . In reality, which data is considered flight, which messages are sent periodically, and which only upon request is the flight controller deciding. MAVLink does not declare which messages should be used; when designing our systems, we decide which messages our software will process and which ones to send. Dialects are provided for various flight controllers.characterized by implementation details: message composition or data, for example, modes. In the root of the header-only C / C ++ library of the MAVLink there are directories corresponding to these dialects: common, ardupilotmega, etc. You can determine which dialect will be used in our examples by specifying the path to the necessary header files in CMake.

    include_directories("3dparty/mavlink_v1/ardupilotmega")
    

    In this part, we will consider some common messages that should be implemented in most flight controllers and ground control stations (GCS) and changing the dialect should not affect the performance of the code. We will take the examples from the last part as a basis, and add handlers for new types of messages, a service, a model and a representation for flight data. I must make a reservation right away that I will not describe the Qt presentation in detail, this is beyond the scope of the article, but all the source code is available on the github . The Vehicle class will act as a model of the domain, which will aggregate flight data for each of the MAVs, and the VehicleService service will allow you to request / create a Vehicle by systemId . The following is a simplified class diagram.

    image

    A message of the ATTITUDE type describes the rotational position of the MAV (drone) relative to its center in space - pitch, roll and yaw angles. Similar to the example with the HEARTBEAT message from the last part, we inherit from the abstract message processing class (AbstractMavLinkHandler), decode the packet and get our data - roll, pitch and yaw angles. From the message we get the systemId of the system that sent our message, and we can compare for which Vehicle it is necessary to update the data.

    Implementation of the processMessage method of the AttitudeHandler class
    void AttitudeHandler::processMessage(constmavlink_message_t& message)
    {
        if (message.msgid != MAVLINK_MSG_ID_ATTITUDE) return;
        Vehicle* vehicle = m_vehicleService->requestVehicle(message.sysid);
        mavlink_attitude_t attitude;
        mavlink_msg_attitude_decode(&message, &attitude);
        vehicle->setAttitude(Attitude(qRadiansToDegrees(attitude.pitch),
                                      qRadiansToDegrees(attitude.roll),
                                      qRadiansToDegrees(attitude.yaw)));
    }
    


    Similarly, we write a packet handler of the VFR_HUD type , in which the parameters are usually grouped, which are usually displayed on the indicator on the windshield . These parameters include MAVLink: airspeed, ground speed, altitude, rate of climb, direction and gas (throttle).

    Implementation of the processMessage method of the VfrHudHandler class
    void VfrHudHandler::processMessage(constmavlink_message_t& message)
    {
        if (message.msgid != MAVLINK_MSG_ID_VFR_HUD) return;
        Vehicle* vehicle = m_vehicleService->requestVehicle(message.sysid);
        mavlink_vfr_hud_t vfrHud;
        mavlink_msg_vfr_hud_decode(&message, &vfrHud);
        vehicle->setTrueAirSpeed(vfrHud.airspeed);
        vehicle->setGroundSpeed(vfrHud.groundspeed);
        vehicle->setBarometricAltitude(vfrHud.alt);
        vehicle->setBarometricClimb(vfrHud.climb);
        vehicle->setHeading(vfrHud.heading);
        vehicle->setThrottle(vfrHud.throttle);
    }
    


    The position of the MAV in space can be determined using a local or global positioning system. This data is transmitted by the protocol in messages of the LOCAL_POSITION and
    GLOBAL_POSITION type, respectively. These packets imply already processed, filtered data. For raw GPS sensor readings, it is necessary to process GPS_RAW and GPS_STATUS packets . To process the position packet, add the PositionHandler handler, and for GPS data packets, add GpsHandler. Handling other commontypes of packages produced on the same principle. The flight controller sends us packets with a certain frequency, which it determines itself, based on settings, data transfer speed or type of communication channel. However, the frequency of sending any data can be requested manually by sending a message MESSAGE_INTERVAL with the identifier of the desired message and the interval in microseconds.

    Message Interval Request Method
    void IntervalHandler::requestMessageFrequency(int messageId, float frequency)
    {
        mavlink_message_t message;
        mavlink_message_interval_t interval;
        interval.message_id = messageId;
        interval.interval_us = ::hzToUs(frequency);
        mavlink_msg_message_interval_encode(m_communicator->systemId(),
                                            m_communicator->componentId(),
                                            &message, &interval);
        m_communicator->sendMessageAllLinks(message);
    }
    


    When we write handlers for all types of packages that interest us, we can fill our model (Vehicle class) with data. When updating data, the model will notify the view using the Qt signal-slot system. In order to redraw the view (or any other action) several times when processing the same package, we will group the data in the model into a structure (class), mirror the contents of the package, or by logical meaning. Since our new types will be used as arguments for Qt signals and slots, they must be registered in the Qt meta-object system using the qRegisterMetaType function . And in order for these data structures to be accessible from the Qt Quick view (QML), we add the Q_GADGET macro to their descriptions . ClassAttitude , for example, will group the pivot position.

    Attitude class header file
    classAttitude
        {Q_GADGET
            Q_PROPERTY(float pitch READ pitch CONSTANT)Q_PROPERTY(float roll READ roll CONSTANT)Q_PROPERTY(float yaw READ yaw CONSTANT)public:
            Attitude(float pitch = 0.0, float roll = 0.0, float yaw = 0.0);
            floatpitch()const;
            floatroll()const;
            floatyaw()const;
            booloperator ==(const Attitude& other);
        private:
            float m_pitch;
            float m_roll;
            float m_yaw;
        };
    


    In QML, I will have two main views - a map and a flight instrument. There is a ready-made component for the map from the Qt Location module, on it we will display MAV icons with a specific position and course, as well as their trajectories. The flight instrument (FD) will have to be drawn by hand, for this task I chose QML Canvas, the result in the picture below.

    image

    Checking can be done on a real flight controller or on the simulator from the previous part, sending new types of packages is already there. In the next article I will try to talk about the commands and the protocol of points (Waypoint Protocol) MAVLink. Thank you for attention!

    Also popular now: