# 首次应用教程(你好,天空)

本主题介绍如何创建和运行第一个板载应用程序。它涵盖了在 PX4 上开发应用程序所需的所有基本概念和 API。

备注

为简化起见,本节省略了启动/停止功能和命令行参数等更高级的功能。这些在 应用程序/模块模板.

# 先决条件

您需要具备以下条件

源代码 PX4-Autopilot/src/examples/px4_simple_app (打开新窗口) 目录中包含本教程的完整版本,如果遇到问题,可以查看该版本。

  • 重命名(或删除 px4_simple_app 目录。

# 最小化应用

在本节中,我们将创建一个 最小应用 只打印出 你好,天空.这包括一个 C 文件和一个 cmake 定义(告诉工具链如何构建应用程序)。

  1. 创建新目录 PX4-Autopilot/src/examples/px4_simple_app.

  2. 在该目录下创建一个新的 C 文件,文件名为 px4_simple_app.c:

    • 将默认页眉复制到页面顶部。这应该出现在所有贡献文件中!

      /**************************************************************************** * * 版权 (c) 2012-2019 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 并在 飞行回顾 (打开新窗口).

  3. 创建并打开一个新的 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 控制台调用。

    备注

    如果您指定 动态 作为 px4_add_module, a 共享库 而不是 POSIX 平台上的静态库(无需重新编译 PX4 即可加载这些库,并以二进制文件而非源代码的形式与他人共享)。您的应用程序不会成为内建命令,而是会在一个名为 examples__px4_simple_app.px4mod.然后,您可以在运行时使用 动态 指挥: dyn ./examples__px4_simple_app.px4mod

# 构建应用程序/固件

应用程序现已完成。要运行它,首先需要确保它是作为 PX4 的一部分构建的。应用程序会被添加到相应板级的构建/固件中。 cmake 文件:

要将应用程序编译到固件中,请在 cmake 锉刀

例子/px4_simple_app

备注

由于默认情况下固件中包含示例,因此大多数文件中都会有这一行。

使用电路板专用命令构建示例:

  • 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.

下一页将提供一个模板,用于编写具有启动和停止功能的完整应用程序。