This is the tutorial I would have liked to have had when I started to learn about MAVLink and uORB. I wasted a lot of time learning about these subjects as much as possible. I had to learn on my own, and it took way too much time for me, and now I wish I could have known earlier about all of this information. So from here, it comes this tutorial.
In the beginning, I started from my desire to communicate between a companion computer (in my case NavQ - RDDRONE-8MMNavQ "NavQ") and an FMU unit (in my case, an RDDRONE-FMUK66). Both of them are NXP company products. However, I will present the steps necessary to achieve the proposed goals and the main concepts behind these steps. In this mode, you can apply all these steps without any problem to another FMU (e.g., Pixhawk PX4 Autopilot PIX 2.4.6) or another companion computer (e.g., Raspberry Pi).
Use a custom uORB message and send it as a MAVLink messageThe first part of this tutorial will explain how to use a custom uORB message and send it as a MAVLink message. To accomplish this, please follows the steps:
1. Add a custom uORB video_monitor message in:
msg/video_monitor.msg
- To add a new topic, you need to create a new .msg file in the
msg/
directory, in my case, with the following content:
uint64 timestamp # time since system start (microseconds)
char[11] info # specific info
int32 lat # Latitude in 1E-7 degrees
int32 lon # Longitude in 1E-7 degrees
uint16 no_people # number of identified people
float32 confidence # the highest confidence value for a human recognition
- Second, add the file name to the
msg/CMakeLists.txt
list. Base on this, the needed C/C++ code is automatically generated.
set(msg_files
....
video_monitor.msg
....
)
2. Right now, we will test the new uORBmessage. But first, build the firmware for FMUK66 and upload it to the FMU.
Thelistener
command can be used to listen to the content of a special topic. To test this command, you can tray with (from a QGroundControlMAVLink console):
nsh> listener sensor_accel
and something similar with the following image you will receive:
If you use the listener
command to see the content of the video_monitor topic, you will get the following message:
nsh> listener video_monitor
never published
In this way, you are warned that the topic exists but has never been published before.
To publish a topic, a new program (named inject_VideoMsg.cpp) must be developed and placed into /src/examples/inject_customUORBmsg
folder in the PX4 project.
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/posix.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>
#include <uORB/uORB.h>
#include <uORB/topics/video_monitor.h>
extern "C" __EXPORT int inject_myUORB_main(int argc, char *argv[]);
int inject_myUORB_main(int argc, char *argv[])
{
PX4_INFO("Hello, I am only a test program able to inject VIDEO_MONITOR messages.");
// Declare structure to store data that will be sent
struct video_monitor_s videoMon;
// Clear the structure by filling it with 0s in memory
memset(&videoMon, 0, sizeof(videoMon));
// Create a uORB topic advertisement
orb_advert_t video_monitor_pub = orb_advertise(ORB_ID(video_monitor), &videoMon);
for (int i=0; i<40; i++)
{
char myStr[]={"Salut !!"}; memcpy(videoMon.info, myStr, 9);
videoMon.timestamp = hrt_absolute_time();
videoMon.lat = i;
videoMon.lon = 12345678;
videoMon.no_people = i+5;
videoMon.confidence = 0.369;
orb_publish(ORB_ID(video_monitor), video_monitor_pub, &videoMon);
//sleep for 2s
usleep (2000000);
}
PX4_INFO("inject_myUORB finished!");
return 0;
}
In the same folder place the following CmakeLists.txt file:
px4_add_module(
MODULE examples__inject_customUORBmsg
MAIN inject_myUORB
SRCS
inject_VideoMsg.cpp
DEPENDS
)
To enable the compilation of the previous application into the PX4 firmware create a new line for your application in the boards/nxp/fmuk66-v3/default.cmake file:
px4_add_board (
PLATFORM nuttx
.......
examples
inject_customUORBmsg
.......
)
Executing the inject_myUORBprogram in the background (presented above, which involves compiling it, and compiling the PX4 autopilot) will permit us to run other command-line programs (like the listener
) to check the video_monitor topic:
nsh> inject_myUORB &
inject_myUORB [667:100]
INFO [inject_myUORB] Hello, I am only a test program able to inject VIDEO_MONITOR messages.
nsh> listener video_monitor
TOPIC: video_monitor
video_monitor_s
timestamp: 244441865 (1.819939 seconds ago)
lat: 7
lon: 12345678
confidence: 0.3690
no_people: 12
info: “Salut !!”
To enumerate all existing topics, list the file handles associated with them using:
nsh> ls /obj
But here a short mention, to find your topic, this topic must be previously published at least one time. You can also use the uorb top <message_name>
command to verify, in real-time, that your message was published and to list different other types of information.
3. The next goal is to add a custom MAVLink video_monitor
message placed in:
mavlink/include/mavlink/v2.0/video_monitor/mavlink_msg_video_monitor.h
a. The enums and messages that are generally useful for many flight stacks and ground stations are stored in a file named common.xml, which is managed by the MAVLink project.
b. The dialects are stored in separate XML files, which typically include
(import) common.xml and define just the elements needed for system-specific functionality.
c. When a MAVLink library is generated from a dialect file, the code is created for all messages in both the dialect and any included files (e.g., common.xml), and entries for a particular enum are merged.
d. Steps:
- A messages must be declared between the<messages></messages
>
tags in either common.xml file or in an independent dialectfile. I decide to use the last option. So, create your own dialect named:video_monitor.xml
.
<?xml version="1.0"?>
<mavlink>
<include>common.xml</include>
<dialect>4</dialect>
<messages>
<message id="369" name="VIDEO_MONITOR">
<description>This message send the number of peoples descovered! NavQ => FMU => GroundStation</description>
<field type="uint64_t" name="timestamp">time since system start (microseconds)</field>
<field type="char[11]" name="info">General information (11 characters, null terminated, valid characters are A-Z, 0-9, " " only)</field>
<field type="int32_t" name="lat" units="degE7">Latitude WGS84 (deg * 1E7). If unknown set to INT32_MAX</field>
<field type="int32_t" name="lon" units="degE7">Longitude WGS84 (deg * 1E7). If unknown set to INT32_MAX</field>
<field type="uint16_t" name="no_people">number of identified peoples</field>
<field type="float" name="confidence">I'n not sure for what to using it</field>
</message>
</messages>
</mavlink>
For the <dialect>4</dialect>line, in your specific case, replace the 4 value with the next-largest unused dialect number (based on the other files in the folder: mavlink/message_definitions/v1.0/).
All messages within a particular generated dialect must have a unique ID - <message id="369" name="VIDEO_MONITOR">. But, there are some constrains regarding the ID number. So, the first constrain not allows to create messages with IDs in the "MAVLink 1" range. MAVLink v1 has only has 8 bits messages IDs, and hence can only support messages with IDs on 0 – 255 range. More, the PX4 recommendation is “when creating a new message you should select the next unused ID for your dialect (after the last one defined in your target dialect file)”. In my case, I analyze the common.xml file (placed in mavlink/include/mavlink/v2.0/message_definitions) and there are all the used messaged IDs, reserved ranges etc. – see the following figure. So, I decided tom use ID=369 – a very easy to remember number.
- Place the file under the folder:
mavlink/message_definitions/v1.0/
In my case, I have a HoverGames folder in my home folder where are two other folders:
i.src (here is all the PX4 code), created with:
$ cd~
$ mkdir -p ~/HoverGames/src
$ cd ~/HoverGames/src && git clone --recursive https://github.com/PX4/Firmware.git px4-firmware
ii. mavlink, created with (see https://mavlink.io/en/getting_started/installation.html):
$ cd~
$ sudo apt-get install python3-pip
$ pip3 install --user future
$ cd ~/HoverGames
$ git clone https://github.com/mavlink/mavlink.git --recursive
- Your message needs to be generated as a C-library for MAVLink 2. Once you've installed MAVLink you can do this on the command line using the following commands:
$ cd ~/HoverGames/mavlink
$ python -m pymavlink.tools.mavgen--lang=C --wire-protocol=2.0 --output=generated/include/mavlink/v2.0 message_definitions/v1.0/video_monitor.xml
- For your own use/testing you can just copy the generated headers into PX4-Autopilot/mavlink/include/mavlink/v2.0, in my case:
~/HoverGames/src/px4-firmware/mavlink/include/mavlink/v2.0
But first delete the following folders: common, minimal, and video_monitor(the last one if you previously generated this folder):
$ rm -r ~/HoverGames/src/px4-firmware/mavlink/include/mavlink/v2.0/common
$ rm -r ~/HoverGames/src/px4-firmware/mavlink/include/mavlink/v2.0/minimal
$ rm -r ~/HoverGames/src/px4-firmware/mavlink/include/mavlink/v2.0/video_monitor
So, use the following commands to copy in the right place the files and folders generated at the previous step (Your message needs to be generated as a C-library for MAVLink 2.....):
$ cd ~/HoverGames/mavlink/generated/include/mavlink/v2.0
$ cp -R -v * ~/HoverGames/src/px4-firmware/mavlink/include/mavlink/v2.0
4. This section explains how to use a custom uORB message and send it as a MAVLink message.
In the web tutorial, associated with the PX4 autopilot, it is presented the approach how to change the mavlink_messages.cpp file, placed in my case in src/modules/mavlink/mavlink_messages.cpp (or on the HDD ~/HoverGames/src/px4-firmware/src/modules/mavlink/mavlink_messages.cpp), to deal with all these messages.
But, in the new version of the PX4 autopilot, the trend is to define the class in a header file placed under streams folder: src/modules/mavlink/streams. So, create here the file VIDEO_MONITOR.hpp with the following content:
#ifndef VIDEO_MON_HPP
#define VIDEO_MON_HPP
#include <uORB/topics/video_monitor.h> //placed in: build/nxp_fmuk66-v3_default/uORB/topics
#include <v2.0/video_monitor/mavlink.h>
#include "v2.0/video_monitor/mavlink_msg_video_monitor.h"
class MavlinkStreamVideoMonitor : public MavlinkStream
{
public:
static MavlinkStream *new_instance(Mavlink *mavlink)
{ return new MavlinkStreamVideoMonitor(mavlink); }
// In a member function declaration or definition, override specifier ensures that
// the function is virtual and is overriding a virtual function from a base class.
const char*get_name() const override
{ return MavlinkStreamVideoMonitor::get_name_static(); }
// The constexpr specifier declares that it is possible to
// evaluate the value of the function or variable at compile time.
static constexpr const char *get_name_static()
{ return "VIDEO_MONITOR"; }
uint16_tget_id() override
{ return get_id_static(); }
static constexpr uint16_t get_id_static()
{ return MAVLINK_MSG_ID_VIDEO_MONITOR; }
unsigned get_size() override
{ return MAVLINK_MSG_ID_VIDEO_MONITOR_LEN + MAVLINK_NUM_NON_PAYLOAD_BYTES; }
private:
uORB::Subscription _sub{ORB_ID(video_monitor)};
/* do not allow top copying this class */
MavlinkStreamVideoMonitor(MavlinkStreamVideoMonitor &);
MavlinkStreamVideoMonitor& operator = (const MavlinkStreamVideoMonitor &);
protected:
explicit MavlinkStreamVideoMonitor(Mavlink *mavlink) : MavlinkStream(mavlink)
{}
bool send() override
{
struct video_monitor_s _video_monitor; //make sure video_monitor_s is the
//definition of your uORB topic
if (_sub.update(&_video_monitor))
{
mavlink_video_monitor_t _msg_video_monitor; // mavlink_video_monitor_t is the
// definition of your custom
// MAVLink message
_msg_video_monitor.timestamp = _video_monitor.timestamp;
_msg_video_monitor.lat = _video_monitor.lat;
_msg_video_monitor.lon = _video_monitor.lon;
_msg_video_monitor.no_people = _video_monitor.no_people;
_msg_video_monitor.confidence = _video_monitor.confidence;
for(int i=0; i<11; i++)
_msg_video_monitor.info[i] = _video_monitor.info[i];
mavlink_msg_video_monitor_send_struct(_mavlink->get_channel(),
&_msg_video_monitor);
PX4_WARN("uorb => mavlink - message was sent !!!!");
return true;
}
return false;
}
};
#endif // VIDEO_MON_HPP
Right now, please include in the mavlink_messages.cpp the following code:
....
#include <uORB/topics/video_monitor.h>
....
#include "streams/VIDEO_MONITOR.hpp"
....
static const StreamListItem streams_list[] = {
....
#if defined(VIDEO_MON_HPP)
create_stream_list_item<MavlinkStreamVideoMonitor>(),
#endif // VIDEO_MON_HPP
....
};
5. The mavlink module implements the MAVLink protocol, which can be used on: a Serial link or UDP network connection. It communicates with the system via uORB: some messages are directly handled in the module (e.g., mission protocol), others are published via uORB(e.g., vehicle_command).
There can be multiple independent instances of the MAVLink module, each connected to one serial device or network port.
For the HoverGames drone are three instances of the mavlink module:
In order to check this information, please use:
nsh> mavlink status
Now, make sure to enable the stream from the MavLinkconsole:
nsh> mavlink stream -r 50 -s VIDEO_MONITOR -d /dev/ttyS1
To see if all is ok, print all enabled streams (on instance 2 of the mavlink you will see at the end the VIDEO_MONITOR stream):
nsh> mavlink status streams
6. Now enable the stream at the HoverGames boot process, for example, by adding the following line to the startup script (e.g., /ROMFS/px4fmu_common/init.d/rcS on NuttX. Note that -r
configures the streaming rate and -d
identifies the MAVLink serial channel).
mavlink stream -r 50 -s VIDEO_MONITOR -d /dev/ttyS1
For the UDP channel (not the casefor the HoverGames drone) please use:
mavlink stream -r 50 -s VIDEO_MONITOR -u 14556
7. You have at least two options in order to: (a) check if a uORB message is sent as a MAVLink dialect and (b) to check if all the above-accomplished steps are functional.
In the first approach:
- Use a PX4_WARN call inside the send() function as presented above, at the fourth step.
- Now, arm the HoverGames quadcopter. It is required to arm it to start the logging process – the logging will be stopped when you disarm the quadcopter.
- From a command line, run the inject_myUORB program – developed at the second step.
- Download the last log file.
- Use the following website: https://review.px4.io/for log file plotting and analysis.
- You will see all the logged messages at the bottom of the page, as in the following figure. If you will see the WARNING message "uorb => mavlink - message was sent !!!!" this means that all the code is correctly written and the link between uORB message and the MAVLink message was done correctly.
8. The most challenging approach is developing a Python program (running on the NavQ companion computer, see https://mavlink.io/en/mavgen_python/) to receive the uORB, sent by the inject_myURB application (running on the FMUK66FMU), through MAVLink messages.
Communication between NavQ and FMU (FMUK66) requires:
(a) a serial connection between the two systems, and
(b) some configuration to be done on the FMU side through the QGroundControl. As a direct result, some configurations are needed. So, navigate in QGroundControl to Settings → Parameters→ MAVLink and set the MAV_1_CONFIG to TELEM 2.
The rest of the parameters (MAV_1_FORWARD, MAV_1_MODE, etc.) will appear only after rebooting the FMU. So, press the Tools button (right-up corner) and select Reboot Vehicle. Now you can set these parameters accordingly with the following image:
Also, you'll need to make sure that the settings for SER_TEL2_BAUD (Settings → Parameters → Serial) are like in the next image:
If you want to wait and access a particular type of message when it arrives, you can use the recv_match() method. This method waits for a specific message and intercepts it when it comes. The following example (receiveCustomMavlinkMSG.py
) will also check that the message is valid before using its content.
from pymavlink import mavutil
mavutil.set_dialect("video_monitor")
# create a connection to FMU
hoverGames = mavutil.mavlink_connection("/dev/ttymxc2", baud=921600)
# wait for the heartbeat message to find the system id
hoverGames.wait_heartbeat()
print("Heartbeat from system (system %u component %u)" %(hoverGames.target_system, hoverGames.target_component))
while (True):
msg = hoverGames.recv_match(type='VIDEO_MONITOR', blocking=True)
#check that the message is valid before attempting to use it
if not msg:
print('No message!\n')
continue
if msg.get_type() == "BAD_DATA":
if mavutil.all_printable(msg.data):
sys.stdout.write(msg.data)
sys.stdout.flush()
else:
#Message is valid, so use the attribute
print('Info: %s' % msg.info)
print('Latitude : %d' % msg.lat)
print('Longitude: %d' % msg.lon)
print('No.people: %d' % msg.no_people)
print('Confidence: %f' % msg.confidence)
print('\n')
Send a message over MAVLink and publish it to uORBThe following section explains how to send a message over MAVLink and publish it to uORB!
9. Insert the following include files, in mavlink_receiver.h (you can find it here: src/modules/mavlink):
#include <uORB/topics/video_monitor.h> //placed in:
//build/nxp_fmuk66-v3_default/uORB/topics
#include <v2.0/video_monitor/mavlink.h>
Add a function able to handle all the incoming MAVLink message in the MavlinkReceiver class (class MavlinkReceiver : public ModuleParams) in mavlink_receiver.h:
void handle_message_video_monitor(mavlink_message_t *msg);
Add also an uORB publisher in the MavlinkReceiver class in mavlink_receiver.h:
uORB::Publication<video_monitor_s> _videoMon_pub{ORB_ID(video_monitor)};
You can put any name in the place of _videoMon_pub
, but it will be nice to keep _pub
string in order to respect the PX4 convention.
10. Now it is time to implement the handle_message
_video_monitorfunction in mavlink_receiver.cpp file:
Void MavlinkReceiver::handle_message_video_monitor (mavlink_message_t *msg)
{
mavlink_video_monitor_t videoMon_my;
mavlink_msg_video_monitor_decode(msg, &videoMon_my);
struct video_monitor_s uorb_vm;
memset (&uorb_vm, 0, sizeof(uorb_vm));
uorb_vm.timestamp = hrt_absolute_time();
uorb_vm.lat = videoMon_my.lat;
uorb_vm.lon = videoMon_my.lon;
uorb_vm.confidence = videoMon_my.confidence;
uorb_vm.no_people = videoMon_my.no_people;
for (int i=0; i<11; i++)
uorb_vm.info[i] = videoMon_my.info[i];
_videoMon_pub.publish(uorb_vm);
}
and finally make sure it is called in MavlinkReceiver::handle_message():
MavlinkReceiver::handle_message(mavlink_message_t *msg)
{
switch (msg->msgid) {
....
case MAVLINK_MSG_ID_VIDEO_MONITOR:
handle_message_video_monitor (msg);
break;
....
}
11. The MAVLink, in HoverGames drone, is associated with several different ports and works in a specific stream mode scenario (Normal, Onboard, OSD, etc.) that defines the specific streamed messages able to be sent or received. For all accepted stream mode scenarios, see the following image.
In order for the MAVLinkVIDEO_MONITOR topic to be streamed, add in the mavlink_main.cpp file placed in src/modules/mavlink your topic to the lists of streamed topics. In my case, I added:
configure_stream_local("VIDEO_MONITOR", 10.0f);
to the MAVLINK_MODE_NORMAL and MAVLINK_MODE_ONBOARD.
12. In the header mavlink_bridge_header.h (placed on src/modules/mavlink) change the following line:
#include <v2.0/standard/mavlink.h>
with the header placed on your custom message:
#include <v2.0/video_monitor/mavlink.h>
Without this header replacement, the custom MAVLink messages (like VIDEO_MONITOR) will not arrive as uORB messages!
A Python program able to generate the MAVLink messageThe following will implement a Python program used to generate the MAVLink message. This program will run on the NavQ companion computer. But, for this program to work, several support components are required.
13. Install MAVLink on the NavQ companion computer:
$ cd~
$ sudo apt-get install python3-pip
$ pip3 install --user future
$ git clone https://github.com/mavlink/mavlink.git --recursive
14. Copy the same video_monitor.xml file from the development station (a laptop running Ubuntu in my case) generated at the third step (see above) into the following folder (on the NavQ companion computer): ~/mavlink/message_definitions/v1.0/video_monitor.xml.
15. Generate the Python MAVLink library on NavQ companion computer:
$ cd ~/mavlink
$ python3 -m pymavlink.tools.mavgen --lang=Python --wire-protocol=2.0 --output=generated/my_MAVLinkLib message_definitions/v1.0/video_monitor.xml
As a direct result, a my_MAVKinkLib.py library will be generated in ~/mavlink/generated folder.
16. Install Pymavlink. Pymavlink is a low level and general purposeMAVLink message processing library, written in Python. This library is able to work with MAVLink 1 and MAVLink 2 versions of the protocol and it is used with Python 2.7+ or Python 3.5+.
$ pip3 install pymavlink
Collecting pymavlink
Downloading pymavlink-2.4.14.tar.gz (4.1 MB)
|████████████████████████████████| 4.1 MB 1.3 MB/s
Requirement already satisfied: future in /usr/lib/python3/dist-packages (from pymavlink) (0.18.2)
Collecting lxml
Downloading lxml-4.6.2-cp38-cp38-manylinux2014_aarch64.whl (7.3 MB)
|████████████████████████████████| 7.3 MB 145 kB/s
Building wheels for collected packages: pymavlink
Building wheel for pymavlink (setup.py) ... done
Created wheel for pymavlink: filename=pymavlink-2.4.14-cp38-cp38-linux_aarch64.whl size=4199475 sha256=da42b2cd2e55fb66fc460a54de9b6f79b03ca5e024d6c7b3844849241f91df29
Stored in directory: /home/navq/.cache/pip/wheels/2d/27/ef/9c613a4ce79c9762bb5ff981e4ac49a725a632da1879149f86
Successfully built pymavlink
Installing collected packages: lxml, pymavlink
Successfully installed lxml-4.6.2 pymavlink-2.4.14
17. Now, include the my_MAVKinkLib.py library, generated for your video_monitor dialect, in pymavlink. So, copy the generated my_MAVKinkLib.py dialect file into the appropriate directory of your clone of the mavlink repo (the mavlink folder from the home directory):
- · MAVLink 2: pymavlink/dialects/v20 <== copy here
- · MAVLink 1: pymavlink/dialects/v10
18. Open a command prompt and navigate to the pymavlink directory (~/mavlink/pymavlink).
19. If needed, uninstall previous versions (for example, you had an error in video_monitor.xml message, and you repeat once again step 14):
navq@imx8mmnavq:~/mavlink/pymavlink$ pip3 uninstall pymavlink
20. Install dependencies (if you have not previously installed pymavlink using pip3) - it was done at the 13th step:
navq@imx8mmnavq:~/mavlink/pymavlink$ pip3 install lxml future
21. Run the Python setup program:
navq@imx8mmnavq:~/mavlink/pymavlink$ python3 setup.py install --user
The pymavlink package includes the dialect-specific generated module (video_monitor), which provides low-level functionality to encode and decode messages, and apply and check signatures.
22. Now tray a pymavlink minimal test:
$ python3
>>> import pymavlink
Use pymavlink.__doc__
to show some information about the package
>>> pymavlink.__doc__
Python MAVLink library - see http://www.qgroundcontrol.org/mavlink/start
>>>
To finish python3, in the end, press CTRL+D to exit or use exit().
23. Configure the serial port.
To print all serial characteristics:
$ stty -F /dev/ttymxc2 -a
Configure the serial port on 921600 baud rate:
$ stty -F /dev/ttymxc2 921600
24. In the following, a basic program was developed (on NavQ) to connect to the FMUK66 flight management unit and take some data (getBasicData.py):
from pymavlink import mavutil
import time
# create a connection to FMU
hoverGames = mavutil.mavlink_connection("/dev/ttymxc2", baud=921600)
# Once connected, use 'hoverGames' to get and send messages
# wait for the heartbeat message to find the system id
hoverGames.wait_heartbeat()
print("Received heartbeat message from FMUK66...")
# Get some basic information!
while True:
try:
print(hoverGames.recv_match().to_dict())
except:
pass
time.sleep(1.0)
For some basic knowledge use: https://mavlink.io/en/mavgen_python/. You will also find many beautiful examples here: https://www.ardusub.com/developers/pymavlink.html.
25. In the case, you get the following error:
ModuleNotFoundError: No module named 'serial'
install the serial module:
$ pip3 install pyserial
26. In the end, let's send a custom MAVLink message (video_monitor) from the NavQ computer to the FMU (FMUK66). Please implement the following Python code (in sendCustomMavlinkMSG.py file):
from pymavlink import mavutil
import time
mavutil.set_dialect("video_monitor")
# create a connection to FMU
hoverGames = mavutil.mavlink_connection("/dev/ttymxc2", baud=921600)
# wait for the heartbeat message to find the system id
hoverGames.wait_heartbeat()
print("Heartbeat from system (system %u component %u)" %(hoverGames.target_system, hoverGames.target_component))
counter = 0
#send custom mavlink message
while(True) :
hoverGames.mav.video_monitor_send(
timestamp = int(time.time() * 1e6), # time in microseconds
info = b'Salut!',
lat = counter,
lon = 231234567,
no_people = 6,
confidence = 0.357)
counter += 1
print ("The custom mesage with the number %u was sent it!!!!" %(counter))
time.sleep(1.0)
27. To run the Python program, use:
$ python3 sendCustomMavlinkMSG.py
28. To check if a MAVLinkvideo_monitor dialect was translated into a uORB mesage, you will be required to develop an application that will subscribe to the VIDEO_MONITOR topic (uORB) and it will print the subscribed results. The new program, named test_commCompCom.cpp, was developed and placed into the /src/examples/test_commCompCom
folder, in the PX4 project. The code is the following one:
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/posix.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>
#include <uORB/uORB.h>
#include <uORB/topics/video_monitor.h>
extern "C"__EXPORT intuorb_mavlink_main(int argc, char *argv[]);
int uorb_mavlink_main(int argc, char *argv[])
{
int poll_ret;
int getOut = 1;
PX4_INFO("Hello, I am only a test program able to receive VIDEO_MONITOR messages.");
// Subscirbe to "video_monitor", then set a polling interval of 200ms
int video_sub_fd = orb_subscribe(ORB_ID(video_monitor));
orb_set_interval(video_sub_fd, 200);
// Configure a POSIX POLLIN system to sleep the current
// thread until data appears on the topic
px4_pollfd_struct_t fds_video;
fds_video.fd = video_sub_fd;
fds_video.events = POLLIN;
while (getOut)
{
poll_ret = px4_poll (&fds_video, 1, 2000);
if ( poll_ret == 0 )
{
PX4_ERR ("Got no data within a second !");
}
// If it didn't return 0, we got data!
else
// Double check that the data we recieved was in the
// right format (I think - need to check)
if(fds_video.revents & POLLIN)
{
// declare a video_monitor_s variable to store the data we will receive
struct video_monitor_svideoMon;
// Copy the obtaned data into the struct
orb_copy(ORB_ID(video_monitor), video_sub_fd, &videoMon);
printf ("lat= %d | long= %d | no. people= %d | confidence= %1.3f | %s \n",
videoMon.lat, videoMon.lon, videoMon.no_people,
(double)videoMon.confidence, videoMon.info);
}
}
return 0;
}
In the same folder place the following CmakeLists.txt file:
px4_add_module(
MODULE examples__test_commCompCom
MAIN uorb_mavlink
SRCS
test_commCompCom.cpp
DEPENDS
)
To enable the compilation of the previous application into the PX4 firmware, create a new line for your application in the boards/nxp/fmuk66-v3/default.cmake file:
px4_add_board(
PLATFORM nuttx
...
examples
test_commCompCom
...
)
29. Now, run the Python program (placed on the NavQ onboard computer):
$ python3 sendCustomMavlinkMSG.py
and run the last developed program (placed on the
FMUK66FMU
) from a
QGroundControlMAVLink console:
nsh> uorb_mavlink
All the messages sent from the NavQ onboard computer will be received and presented on the MAVLink console connected to the FMUK66FMU
system
.
- This was a very long and complex tutorial !
- I apologize if any mistakes have snuck in.
- For this writing, I used a lot of documentation from PX4 (for example: this domuent, this document, or this document), information from the forums, and personal experience. Unfortunately, none of these documents are complete, and you need to put other additional information to make them functional.
- I wish you a wonderful life, code as much as possible - but with joy and with God before!
Comments
Please log in or sign up to comment.