📜 ⬆️ ⬇️

We understand in MAVLink. Part 2

In the last part, we discussed 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 with Qt.

image


In MAVLink there are various built-in message types, as well as the ability to add your own . In fact, what data to consider flight, which messages are sent periodically, and which only on request decides the flight controller. MAVLink does not declare which messages must be used; we ourselves decide when designing our systems which messages our software will process and which messages will be sent. For various flight controllers, dialects are provided that differ in implementation details: the composition of messages or data, for example, modes. In the root header-only MAVLink C / C ++ libraries have 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 look at some common messages that should be implemented in most flight controllers and ground control stations (GCS) and the dialect change should not affect the performance of the code. We take the examples from the last part as a basis, and add handlers of new types of messages, service, model and presentation for flight data. At once I will make a reservation that I will not describe Qt-representation in detail, it is beyond the scope of the article, but all the source code is available on github . The Vehicle class will act as a domain model, which will aggregate flight data for each of the MAVs, and the VehicleService service will allow you to query / create a Vehicle by systemId . Below is a simplified class diagram.

image

A message like ATTITUDE describes the rotational position of the MAV (drone) relative to its center in space - the pitch, roll and yaw angles. Like 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 match for which Vehicle it is necessary to update the data.

Implementing the AttitudeHandler class processMessage Method
 void AttitudeHandler::processMessage(const mavlink_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 will write a VFR_HUD type packet handler, in which the parameters usually displayed on the indicator on the windshield are grouped together. MAVLink attributes to these parameters: air speed, ground speed, height above sea level, rate of climb, direction and gas (throttle).

Implementing the processMessage method of the VfrHudHandler class
 void VfrHudHandler::processMessage(const mavlink_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 type LOCAL_POSITION and
GLOBAL_POSITION 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 handle a position package, add a PositionHandler handler, and for GPS data packets, add GpsHandler. Handling of other common types of packages is done according to the same principle. The flight controller sends us packets at a certain frequency, which it determines itself, based on the settings, data transfer rate or type of communication channel. However, the frequency of sending any data can be requested manually by sending a MESSAGE_INTERVAL message with the identifier of the desired message and an interval in microseconds.

Message Intermission 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 we are interested in, 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 not redraw the presentation (or any other action) several times while processing the same packet, we group the data in the model into a structure (class), mirror the contents of the packet, or by logical meaning. Since our new types will be used as arguments to Qt's signals and slots, they must be registered in Qt's meta-object system using the qRegisterMetaType function. And in order for these data structures to be accessible from the view on Qt Quick (QML), we will add the Q_GADGET macro to their descriptions. The Attitude class, for example, will group a turning position.

Attitude Class Header
  class Attitude { 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); float pitch() const; float roll() const; float yaw() const; bool operator ==(const Attitude& other); private: float m_pitch; float m_roll; float m_yaw; }; 


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

image

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

Source: https://habr.com/ru/post/312592/


All Articles