# 首次应用教程(你好,天空)
本主题介绍如何创建和运行第一个板载应用程序。它涵盖了在 PX4 上开发应用程序所需的所有基本概念和 API。
备注
为简化起见,本节省略了启动/停止功能和命令行参数等更高级的功能。这些在 应用程序/模块模板.
# 先决条件
您需要具备以下条件
- PX4 SITL 模拟器 或 a 兼容 PX4 的飞行控制器.
- PX4 开发工具链 的目标。
- 下载 PX4 源代码 来自 Github
源代码 PX4-Autopilot/src/examples/px4_simple_app (打开新窗口) 目录中包含本教程的完整版本,如果遇到问题,可以查看该版本。
- 重命名(或删除 px4_simple_app 目录。
# 最小化应用
在本节中,我们将创建一个 最小应用 只打印出 你好,天空
.这包括一个 C 文件和一个 cmake 定义(告诉工具链如何构建应用程序)。
创建新目录 PX4-Autopilot/src/examples/px4_simple_app.
在该目录下创建一个新的 C 文件,文件名为 px4_simple_app.c:
将默认页眉复制到页面顶部。这应该出现在所有贡献文件中!
/**************************************************************************** * * 版权 (c) 2012-2022 PX4 开发团队。保留所有权利。* 允许在满足以下条件的情况下,以源代码和二进制形式进行再分发和使用,无论修改与否:* * 1.源代码的再分发必须保留上述版权*声明、本条件清单和以下免责声明。* 2.以二进制形式重新发布时,必须在随附的 * 文档和/或其他材料中复制上述版权 * 声明、本条件清单和以下免责声明: * 3.* 未经事先书面许可,不得使用 PX4 或其贡献者的名称 * 为衍生自本软件的产品 * 背书或促销。* 本软件由版权所有者和贡献者*按原样*提供,任何明示或暗示的保证,包括但不*限于适销性和适用于特定用途的暗示保证,一概不予承认。在任何情况下,版权所有者或贡献者均不对任何直接、间接、*附带、特殊、惩戒性或后果性损害(包括*但不限于采购替代商品或服务;*使用、数据或利润损失;或业务中断)承担责任,无论这些损害是如何引起的*以及基于任何责任理论,无论是合同、严格*责任或侵权行为(包括疏忽或其他)引起的*,即使已被告知*可能出现此类损害。* ****************************************************************************/
在默认头下面复制以下代码。所有贡献文件都应包含此代码!
/** * @file px4_simple_app.c * PX4 自动驾驶仪的最小应用示例 * * @author Example User <[email protected]> */ #包括 <px4_platform_common/log.h>; __EXPORT int px4_simple_app_main(int 参数, 烧焦 *参数[]); int px4_simple_app_main(int 参数, 烧焦 *参数[]) { PX4_INFO(你好,天空!";); 返回 好的; }
TIP
主函数必须命名为
<module_name>_main
并从模块中导出,如图所示。TIP
PX4_INFO
相当于printf
用于 PX4 外壳(包括从 px4_platform_common/log.h).有不同的日志级别:PX4_INFO
,PX4_WARN
,PX4_ERR
,PX4_DEBUG
.警告和错误会额外添加到 ULog 并在 飞行回顾 (打开新窗口).
创建并打开一个新的 cmake 定义文件命名为 CMakeLists.txt.复制以下文本:
############################################################################ # # 版权 (c) 2015 PX4 开发团队。保留所有权利。 # # 以源代码和二进制形式再分发和使用,无论有无 #修改,但必须符合以下条件 # 符合要求: # # 1.重新分发源代码必须保留上述版权 # 通知、本条件清单和以下免责声明。 # 2.二进制形式的再分发必须复制上述版权信息。 # 通知、本条件清单和以下免责声明 #随附的文件和/或其他材料 # 分发。 # 3.PX4 名称及其贡献者的姓名均不得 # 用于支持或推广由本软件衍生的产品 # 未经事先书面许可。 # # 本软件由版权所有者和贡献者提供 # "AS" 以及任何明示或暗示的保证,包括但不限于 # 仅限于对适销性和适用性的默示保证 # 对特定用途的免责声明。在任何情况下 # 版权所有者或贡献者对任何直接、间接、间接、间接、间接、间接、间接、间接、间接 #附带的、特殊的、惩戒性的或后果性的损害赔偿(包括 # 包括但不限于采购替代货物或服务;损失 # 使用、数据或利润;或业务中断),无论其原因如何 # 在任何责任理论上,无论是合同、严格的 # 或侵权行为(包括过失或其他)中产生的赔偿责任。 # 使用本软件的任何后果,即使已被告知 # 这种损害的可能性。 # ############################################################################ px4_add_module( MODULE examples__px4_simple_app MAIN px4_simple_app STACK_MAIN 2000 SRCS px4_simple_app.c 取决于 )
px4_add_module()
方法根据模块描述构建静态库。-
单元
块是模块的固件唯一名称(按照惯例,模块名称的前缀是父目录,直到来源
). -
MAIN
块列出了模块的入口点,它将命令注册到 NuttX 中,以便从 PX4 shell 或 SITL 控制台调用。
TIP
px4_add_module()
格式在 PX4-Autopilot/cmake/px4_add_module.cmake (打开新窗口).备注
如果您指定
动态
作为px4_add_module
, a 共享库 而不是 POSIX 平台上的静态库(无需重新编译 PX4 即可加载这些库,并以二进制文件而非源代码的形式与他人共享)。您的应用程序不会成为内建命令,而是会在一个名为examples__px4_simple_app.px4mod
.然后,您可以在运行时使用动态
指挥:dyn ./examples__px4_simple_app.px4mod
-
创建并打开一个新的 Kconfig 定义文件命名为 Kconfig 并定义命名符号(见 Kconfig 命名约定).复制下面的文字:
# 构建应用程序/固件
应用程序现已完成。要运行它,首先需要确保它是作为 PX4 的一部分构建的。应用程序会被添加到相应板级的构建/固件中。 px4board 文件:
- PX4 SITL(模拟器): PX4-Autopilot/boards/px4/sitl/default.px4board (打开新窗口)
- Pixhawk v1/2: PX4-Autopilot/boards/px4/fmu-v2/default.px4board (打开新窗口)
- Pixracer (px4/fmu-v4): PX4-Autopilot/boards/px4/fmu-v4/default.px4board (打开新窗口)
- px4board 其他板的文件可在 PX4-Autopilot/boards/ (打开新窗口)
要将应用程序编译到固件中,请添加相应的 Kconfig 密钥 CONFIG_EXAMPLES_PX4_SIMPLE_APP=y
在 px4board 文件或运行 [boardconfig](../hardware/porting_guide_config.md#px4_menuconfig setup) make px4_fmu-v4_default boardconfig
:
示例 ---> [x] PX4 简单应用程序 ----
备注
由于默认情况下固件中包含示例,因此大多数文件中都会有这一行。
使用电路板专用命令构建示例:
- jMAVSim 模拟器:
make px4_sitl_default jmavsim
- Pixhawk v1/2:
make px4_fmu-v2_default
或仅使 px4_fmu-v2
) - Pixhawk v3:
make px4_fmu-v4_default
- 其他棋盘 构建代码
# 测试应用程序(硬件)
# 将固件上传到电路板
启用上传程序,然后重置电路板:
- Pixhawk v1/2:
使 px4_fmu-v2_default 上传
- Pixhawk v3:
使 px4_fmu-v4_default 上传
在重置电路板之前和最后,它应该会打印一些编译信息:
加载固件 对于 X,X,等待 对于 引导程序...
重置电路板并上传后,就可以打印了:
擦除 : [====================] 100.0% 计划: [====================] 100.0% 验证 : [====================] 100.0% 重新启动。
[100%] 内置目标上传
# 连接控制台
现在连接到 系统控制台 通过串口或 USB。点击 输入 会弹出 shell 提示符:
nsh>;
输入"'help'"并按 ENTER 键
nsh>; 帮助
帮助 使用: 帮助 [-v] [<;cmd>;]
[ df 杀死 mkfifo ps 睡眠
? 回响 ()()()()() pwd 测试
猫 执行 ls mh rm 挂载
CD 出口 mb 挂载 rmdir 未设置
cp 免费的 mkdir mv 设置 我们睡觉
dd 帮助 mkfatfs mw 吁 xd 内置应用程序:
重新启动
敷衍
顶级
..
px4_simple_app
..
sercon serdis
请注意 px4_simple_app
现在是可用命令的一部分。键入 px4_simple_app
和 ENTER 键:
nsh>; px4_simple_app 你好,天空!
现在,应用程序已在系统中正确注册,并可进行扩展,以实际执行有用的任务。
# 测试应用程序(SITL)
如果使用 SITL PX4 控制台 会自动启动(见 构建代码> 首次构建(使用 jMAVSim 模拟器)).与 nsh 控制台 (见上一节),您可以键入 帮助
查看内置应用程序列表。
进入 px4_simple_app
来运行最小应用程序。
pxh>; px4_simple_app INFO [px4_simple_app] 你好,天空!
现在,该应用程序可以扩展到实际执行有用的任务。
# 订阅传感器数据
要做一些有用的事情,应用程序需要订阅输入并发布输出(如电机或伺服命令)。
TIP
PX4 硬件抽象的优势在这里得到了体现!无需以任何方式与传感器驱动程序交互,也无需在电路板或传感器更新时更新应用程序。
应用程序之间的单独信息通道称为 主题.对于本教程,我们感兴趣的是 综合传感器 (打开新窗口) 主题,其中包含整个系统的同步传感器数据。
订阅主题非常简单:
#包括 <uORB/topics/sensor_combined.h>;
..
int 传感器子控制器 = 订阅(ORB_ID(综合传感器));
传感器子控制器
是一个主题句柄,可用于非常高效地执行新数据阻塞等待。当前线程进入休眠状态,一旦有新数据,调度程序就会自动唤醒,在等待过程中不会消耗任何 CPU 周期。为此,我们使用 轮询() (打开新窗口) POSIX 系统调用。
添加 轮询()
的订阅看起来像 (伪代码,下面是完整的实现过程):
#包括 <poll.h>;
#包括 <uORB/topics/sensor_combined.h>;
..
int 传感器子控制器 = 订阅(ORB_ID(综合传感器));
/* 使用这种技术可以等待多个主题,这里只使用一个 */
px4_pollfd_struct_t fds[] = {
{ .fd = 传感器子控制器, .活动 = 波林 },
};
虽然 (真) {
/* 等待传感器更新 1 个文件描述符 1000 毫秒(1 秒) */
int poll_ret = px4_poll(fds, 1, 1000);
..
如果 (fds[0].修订 及样品; 波林) {
/* 获取第一个文件描述符的数据 */
结构 综合传感器 未经加工的;
/* 将传感器原始数据复制到本地缓冲区 */
或复制(ORB_ID(综合传感器), 传感器子控制器, 及样品;未经加工的);
PX4_INFO("Accelerometer:\t%8.4f\t%8.4f\t%8.4f",
(双人)未经加工的.加速度计_m_s2[0],
(双人)未经加工的.加速度计_m_s2[1],
(双人)未经加工的.加速度计_m_s2[2]);
}
}
再次编译应用程序,输入
生产
# 测试 uORB 订阅
最后一步是在 nsh shell 中键入以下内容,将应用程序作为后台进程/任务启动:
px4_simple_app 及样品;
应用程序将在控制台中显示 5 个传感器值,然后退出:
[px4_simple_app] 加速计 0.0483 0.0821 0.0332
[px4_simple_app] 加速计 0.0486 0.0820 0.0336
[px4_simple_app] 加速计 0.0487 0.0819 0.0327
[px4_simple_app] 加速计 0.0482 0.0818 0.0323
[px4_simple_app] 加速计 0.0482 0.0827 0.0331
[px4_simple_app] 加速计 0.0489 0.0804 0.0328
TIP
全面应用模块模板 可用于编写可由命令行控制的后台进程。
# 出版数据
要使用计算出的输出结果,下一步是 发布 结果。下面我们将展示如何发布态度主题。
备注
我们选择了 态度
因为我们知道 多点连接 应用程序会将其转发到地面控制站--提供了一种查看结果的简便方法。
界面非常简单:初始化 结构
要发布的主题,并对该主题进行宣传:
#包括 <uORB/topics/vehicle_attitude.h>;
..
/* 宣传态度主题 */
结构 载具姿态 att;
memset(及样品;att, 0, 尺寸(att));
orb_advert_t att_pub_fd = 广告(ORB_ID(载具姿态), 及样品;att);
在主循环中,只要信息准备就绪,就发布信息:
出版(ORB_ID(载具姿态), att_pub_fd, 及样品;att);
# 完整示例代码
完整示例代码 (打开新窗口) 现在是
/**************************************************************************** * * 版权 (c) 2012-2019 PX4 开发团队。保留所有权利。* 允许在满足以下条件的情况下,以源代码和二进制形式进行再分发和使用,无论修改与否:* * 1.源代码的再分发必须保留上述版权*声明、本条件清单和以下免责声明。* 2.以二进制形式重新发布时,必须在随附的 * 文档和/或其他材料中复制上述版权 * 声明、本条件清单和以下免责声明: * 3.* 未经事先书面许可,不得使用 PX4 或其贡献者的名称 * 为衍生自本软件的产品 * 背书或促销。* 本软件由版权所有者和贡献者*按原样*提供,任何明示或暗示的保证,包括但不*限于适销性和适用于特定用途的暗示保证,一概不予承认。在任何情况下,版权所有者或贡献者均不对任何直接、间接、*附带、特殊、惩戒性或后果性损害(包括*但不限于采购替代商品或服务;*使用、数据或利润损失;或业务中断)承担责任,无论这些损害是如何引起的*以及基于任何责任理论,无论是合同、严格*责任或侵权行为(包括疏忽或其他)引起的*,即使已被告知*可能出现此类损害。* ****************************************************************************/
/** * @file px4_simple_app.c * PX4 自动驾驶仪的最小应用示例 * * @author Example User <[email protected]> */
#包括 <px4_platform_common/px4_config.h>;
#包括 <px4_platform_common/tasks.h>;
#包括 <px4_platform_common/posix.h>;
#包括 <unistd.h>;
#包括 <stdio.h>;
#包括 <poll.h>;
#包括 <string.h>;
#包括 <math.h>;
#包括 <uORB/uORB.h>;
#包括 <uORB/topics/sensor_combined.h>;
#包括 <uORB/topics/vehicle_attitude.h>;
__EXPORT int px4_simple_app_main(int 参数, 烧焦 *参数[]);
int px4_simple_app_main(int 参数, 烧焦 *参数[])
{
PX4_INFO(你好,天空!";);
/* 订阅传感器组合主题 */
int 传感器子控制器 = 订阅(ORB_ID(综合传感器));
/* 将更新速率限制在 5 Hz */
orb_set_interval(传感器子控制器, 200);
/* 宣传态度主题 */
结构 载具姿态 att;
memset(及样品;att, 0, 尺寸(att));
orb_advert_t att_pub = 广告(ORB_ID(载具姿态), 及样品;att);
/* 使用这种技术可以等待多个主题,这里只使用一个 */
px4_pollfd_struct_t fds[] = {
{ .fd = 传感器子控制器, .活动 = 波林 },
/* 这里可以有更多的文件描述符,其形式可以是* { .fd = other_sub_fd, .events = POLLIN }, */
};
int 错误计数器 = 0;
对于 (int i = 0; i <; 5; i++) {
/* 等待传感器更新 1 个文件描述符 1000 毫秒(1 秒) */
int poll_ret = px4_poll(fds, 1, 1000);
/* 处理投票结果 */
如果 (poll_ret == 0) {
/* 这意味着没有一个提供商向我们提供数据 */
PX4_ERR("秒内无数据";);
} 不然 如果 (poll_ret <; 0) {
/* 这太糟糕了--应该是紧急情况 */
如果 (错误计数器 <; 10 || 错误计数器 % 50 == 0) {
/* 使用计数器防止泛洪(并减慢我们的速度) */
PX4_ERR("ERROR return value from poll():%d";, poll_ret);
}
错误计数器++;
} 不然 {
如果 (fds[0].修订 及样品; 波林) {
/* 获取第一个文件描述符的数据 */
结构 综合传感器 未经加工的;
/* 将传感器原始数据复制到本地缓冲区 */
或复制(ORB_ID(综合传感器), 传感器子控制器, 及样品;未经加工的);
PX4_INFO("Accelerometer:\t%8.4f\t%8.4f\t%8.4f",
(双人)未经加工的.加速度计_m_s2[0],
(双人)未经加工的.加速度计_m_s2[1],
(双人)未经加工的.加速度计_m_s2[2]);
/* 以下内容没有任何意义,只是一个示例 */
att.q[0] = 未经加工的.加速度计_m_s2[0];
att.q[1] = 未经加工的.加速度计_m_s2[1];
att.q[2] = 未经加工的.加速度计_m_s2[2];
出版(ORB_ID(载具姿态), att_pub, 及样品;att);
}
/* 这里可能有更多的文件描述符,形式如下:* if (fds[1..n].revents & POLLIN) {}*/
}
}
PX4_INFO(退出;);
返回 0;
}
# 运行完整示例
最后运行应用程序:
px4_simple_app
如果您开始 QGroundControl您可以在实时图 (分析 > MAVLink 检查器 (打开新窗口)).
# 总结
本教程涵盖了开发基本 PX4 自动驾驶应用程序所需的全部内容。请记住,uORB 信息/主题的完整列表是 可在此查阅 (打开新窗口) 并对标头进行详细记录和参考。
更多信息和故障排除/常见陷阱,请点击此处: uORB.
下一页将提供一个模板,用于编写具有启动和停止功能的完整应用程序。