基本上是翻译https://dev.px4.io/master/en/apps/hello_sky.html的内容
本主题解释如何创建和运行第一个板载应用程序。它涵盖了在PX4上开发应用程序所需的所有基本概念和api。
为了简单起见,这里省略了更高级的特性,比如启动/停止功能和命令行参数。这些内容在应用程序/模块模板中介绍。
预备
您需要具备以下条件:
PX4 SITL模拟器或PX4兼容的飞行控制器。
PX4开发工具链。
从Github下载PX4源代码。
源代码固件/src/examples/px4_simple_app目录包含本教程的一个完整版本,如果您遇到了问题,可以查看它。
- 重命名(或删除)px4_simple_app目录。
最小的应用程序
在本节中,我们将创建一个只需打印Hello Sky!的最小应用程序。它由一个C文件和一个cmake定义(它告诉工具链如何构建应用程序)组成。
1.创建一个新的目录Firmware/src/examples/px4_simple_app。
2.在该目录中创建一个名为px4_simple_app.c的新C文件:
- 复制默认页眉到页面的顶部。这应该出现在所有提交的文件中!
/****************************************************************************
*
* Copyright (c) 2012-2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
- 将下面的代码复制到默认标头的下面。这应该出现在所有提交的文件中!
/**
* @file px4_simple_app.c
* Minimal application example for PX4 autopilot
*
* @author Example User <mail@example.com>
*/
#include <px4_platform_common/log.h>
__EXPORT int px4_simple_app_main(int argc, char *argv[]);
int px4_simple_app_main(int argc, char *argv[])
{
PX4_INFO("Hello Sky!");
return OK;
}
main函数必须命名为
<module_name>_main
并从模块中导出(__EXPORT),如上面示。
PX4_INFO
相当于PX4 shell的PX4_INFO
、PX4_WARN
、PX4_ERR
、PX4_DEBUG
。警告和错误被添加到ULog并在飞行检查(Flight Review)中显示。
3.创建并打开一个名为CMakeLists.txt的cmake定义文件。抄送如下
############################################################################
#
# Copyright (c) 2015 PX4 Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name PX4 nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
px4_add_module(
MODULE examples__px4_simple_app
MAIN px4_simple_app
STACK_MAIN 2000
SRCS
px4_simple_app.c
DEPENDS
)
px4_add_module()
从模块描述中构建一个静态库。MAIN
列出了模块的名称——这将命令注册到NuttX,这样就可以从PX4 shell或SITL控制台调用它。
px4_add_module()
格式记录在Firmware/cmake/px4_add_module.cmake中。
如果您将
DYNAMIC
指定为px4_add_module
的选项,那么将创建一个共享库,而不是POSIX平台上的静态库(这些库可以在不需要重新编译PX4的情况下加载,并作为二进制文件而不是源代码共享给其他人)。您的应用程序将不会成为一个内置命令,而是在名为examples__px4_simple_app.px4mod
的单独文件中结束。然后可以在运行时使用dyn
命令加载文件来运行命令:dyn ./ examples剩余的px4_simple_app.px4mod
构建应用程序/固件
应用程序现在已经完成。为了运行它,首先需要确保它是作为PX4的一部分构建的。应用程序被添加到构建/固件在适当的板级cmake文件为您的目标:
- PX4 SITL (Simulator): Firmware/boards/px4/sitl/default.cmake
- Pixhawk v1/2: Firmware/boards/px4/fmu-v2/default.cmake
- Pixracer (px4/fmu-v4): Firmware/boards/px4/fmu-v4/default.cmake
- cmake files for other boards can be found in Firmware/boards/
要将应用程序编译为固件,请在cmake文件的某处为您的应用程序创建一个新行:
examples/px4_simple_app
这行代码已经出现在大多数文件中,因为这些示例默认包含在固件中。
使用特定于板子的命令构建示例:
- jMAVSim Simulator:
make px4_sitl_default jmavsim
- Pixhawk v1/2:
make px4_fmu-v2_default
(or justmake px4_fmu-v2
) - Pixhawk v3:
make px4_fmu-v4_default
- Other boards: Building the Code
测试应用程序(硬件)
上传固件到板子上
打开上传器,然后重置板子:
- Pixhawk v1/2:
make px4_fmu-v2_default upload
- Pixhawk v3:
make px4_fmu-v4_default upload
在重置板子之前,会打印一些消息,最后应该是:
Loaded firmware for X,X, waiting for the bootloader...
一旦板子复位,并上传,它打印:
Erase : [====================] 100.0%
Program: [====================] 100.0%
Verify : [====================] 100.0%
Rebooting.
[100%] Built target upload
连接到控制台
现在通过串口或USB连接到系统控制台(system console)。按回车会弹出shell提示:
默认的没搞出来,可以通过mavlink shell:
-
先安装依赖
sudo pip3 install pymavlink pyserial
-
USB连接的话,在Firmware文件夹下输入:
# For serial port ./Tools/mavlink_shell.py /dev/ttyACM0
可以看到控制台打开了。
使用
mavlink_shell.py -h
获得所有可用参数的描述。
nsh>
Type ''help'' and hit ENTER
nsh> help
help usage: help [-v] [<cmd>]
[ df kill mkfifo ps sleep
? echo losetup mkrd pwd test
cat exec ls mh rm umount
cd exit mb mount rmdir unset
cp free mkdir mv set usleep
dd help mkfatfs mw sh xd
Builtin Apps:px
reboot
perf
top
..
px4_simple_app
..
sercon
serdis
注意,px4_simple_app
现在是可用命令的一部分。输入px4_simple_app
并回车:
nsh> px4_simple_app
Hello Sky!
订阅传感器数据
要做一些有用的事情,应用程序需要订阅输入和发布输出(例如电机或伺服命令)。
PX4硬件抽象的好处在这里发挥了作用!如果板子或传感器更新,没有必要以任何方式与传感器驱动交互,也没有必要更新您的应用程序。
应用程序之间的单个消息通道称为话题(topic)。对于本教程,我们感兴趣的是sensor_combined话题,它保存了整个系统的同步传感器数据。
订阅一个话题很简单:
#include <uORB/topics/sensor_combined.h>
..
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
sensor_sub_fd
是一个话题句柄,可用于非常有效地执行阻塞等待新数据。当前线程进入睡眠状态,一旦有新数据可用,调度程序就会自动唤醒该线程,在等待时不消耗任何CPU周期。为此,我们使用poll() POSIX系统调用。
将poll()添加到订阅中类似于(伪代码,请参阅下面的完整实现):
#include <poll.h>
#include <uORB/topics/sensor_combined.h>
..
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
/* one could wait for multiple topics with this technique, just using one here */
px4_pollfd_struct_t fds[] = {
{ .fd = sensor_sub_fd, .events = POLLIN },
};
while (true) {
/* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
int poll_ret = px4_poll(fds, 1, 1000);
..
if (fds[0].revents & POLLIN) {
/* obtained data for the first file descriptor */
struct sensor_combined_s raw;
/* copy sensors raw data into local buffer */
orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
PX4_INFO("Accelerometer:\t%8.4f\t%8.4f\t%8.4f",
(double)raw.accelerometer_m_s2[0],
(double)raw.accelerometer_m_s2[1],
(double)raw.accelerometer_m_s2[2]);
}
}
重新编译app,输入:
make
测试uORB订阅
最后一步是通过在nsh shell中输入以下命令来启动你的应用程序作为后台进程/任务:
px4_simple_app &
您的应用程序将在控制台显示5个传感器值,然后退出:
[px4_simple_app] Accelerometer: 0.0483 0.0821 0.0332
[px4_simple_app] Accelerometer: 0.0486 0.0820 0.0336
[px4_simple_app] Accelerometer: 0.0487 0.0819 0.0327
[px4_simple_app] Accelerometer: 0.0482 0.0818 0.0323
[px4_simple_app] Accelerometer: 0.0482 0.0827 0.0331
[px4_simple_app] Accelerometer: 0.0489 0.0804 0.0328
整个应用程序的模块模板可以用来编写后台进程,可以从命令行控制。
发布数据
要使用计算出的输出,下一步是发布结果。下面我们展示如何发布attitude话题。
我们选择了attitude ,因为我们知道mavlink应用程序会将它转发到地面控制站——这提供了一种查看结果的简单方法。
这个接口非常简单:初始化要发布的主题的结构并发布主题:
#include <uORB/topics/vehicle_attitude.h>
..
/* advertise attitude topic */
struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att));
orb_advert_t att_pub_fd = orb_advertise(ORB_ID(vehicle_attitude), &att);
在主循环中,当它准备好时发布信息:
orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);
完整的示例代码
/****************************************************************************
*
* Copyright (c) 2012-2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* @file px4_simple_app.c
* Minimal application example for PX4 autopilot
*
* @author Example User <mail@example.com>
*/
#include <px4_platform_common/px4_config.h>
#include <px4_platform_common/tasks.h>
#include <px4_platform_common/posix.h>
#include <unistd.h>
#include <stdio.h>
#include <poll.h>
#include <string.h>
#include <math.h>
#include <uORB/uORB.h>
#include <uORB/topics/sensor_combined.h>
#include <uORB/topics/vehicle_attitude.h>
__EXPORT int px4_simple_app_main(int argc, char *argv[]);
int px4_simple_app_main(int argc, char *argv[])
{
PX4_INFO("Hello Sky!");
/* subscribe to sensor_combined topic */
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
/* limit the update rate to 5 Hz */
orb_set_interval(sensor_sub_fd, 200);
/* advertise attitude topic */
struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att));
orb_advert_t att_pub = orb_advertise(ORB_ID(vehicle_attitude), &att);
/* one could wait for multiple topics with this technique, just using one here */
px4_pollfd_struct_t fds[] = {
{ .fd = sensor_sub_fd, .events = POLLIN },
/* there could be more file descriptors here, in the form like:
* { .fd = other_sub_fd, .events = POLLIN },
*/
};
int error_counter = 0;
for (int i = 0; i < 5; i++) {
/* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
int poll_ret = px4_poll(fds, 1, 1000);
/* handle the poll result */
if (poll_ret == 0) {
/* this means none of our providers is giving us data */
PX4_ERR("Got no data within a second");
} else if (poll_ret < 0) {
/* this is seriously bad - should be an emergency */
if (error_counter < 10 || error_counter % 50 == 0) {
/* use a counter to prevent flooding (and slowing us down) */
PX4_ERR("ERROR return value from poll(): %d", poll_ret);
}
error_counter++;
} else {
if (fds[0].revents & POLLIN) {
/* obtained data for the first file descriptor */
struct sensor_combined_s raw;
/* copy sensors raw data into local buffer */
orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
PX4_INFO("Accelerometer:\t%8.4f\t%8.4f\t%8.4f",
(double)raw.accelerometer_m_s2[0],
(double)raw.accelerometer_m_s2[1],
(double)raw.accelerometer_m_s2[2]);
/* set att and publish this information for other apps
the following does not have any meaning, it's just an example
*/
att.q[0] = raw.accelerometer_m_s2[0];
att.q[1] = raw.accelerometer_m_s2[1];
att.q[2] = raw.accelerometer_m_s2[2];
orb_publish(ORB_ID(vehicle_attitude), att_pub, &att);
}
/* there could be more file descriptors here, in the form like:
* if (fds[1..n].revents & POLLIN) {}
*/
}
}
PX4_INFO("exiting");
return 0;
}
运行完整的示例
最后运行你的应用程序:
px4_simple_app
如果您启动QGroundControl,您可以在实时图中检查传感器值(分析> MAVLink Inspector)。
总结
本教程介绍了开发基本的PX4自动驾驶仪应用程序所需的所有内容(available here)。这里提供了uORB消息/主题的完整列表,并且头文件都有很好的文档记录,可以作为参考。
更多信息和故障排除/常见缺陷可以在这里找到:uORB。