# 搭建你的第一个应用（Hello Shy）

## 系统必备组件

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

## 最小的应用程序

1. 新建如下文件夹： Firmware/src/examples/px4_simple_app
2. 在该目录中新建一个名为 px4_simple_app.c 的 C 文件：

3. 将下面的默认头部注释复制到文件页面的顶部， 该注释应出现在所有贡献的文件中！

c /** *

• 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.
1. 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.
1. 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.
• **/ 
4. 将下面的代码复制到头部注释的下方， This should be present in all contributed files!

c /**

• @file px4_simple_app.c
• Minimal application example for PX4 autopilot
• @author Example User mail@example.com */

# include

__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; } 

主函数必须跟上述代码一样以 <module_name>_main 的形式进行命名并完成从模块中导出。

PX4_INFO is the equivalent of printf for the PX4 shell (included from px4_platform_common/log.h). 有以下不同的日志级别： PX4_INFOPX4_WARNPX4_ERRPX4_DEBUG。 其中警告和错误会被额外添加到 ULog 中，且还会在 Flight Review 中显示。

5. 创建并打开一个名为 CMakeLists.txt 的新的 cmake 定义文件。 复制下面的文本：

 ############################################################################
#
#
# 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.
#
############################################################################
MODULE examples__px4_simple_app
MAIN px4_simple_app
STACK_MAIN 2000
SRCS
px4_simple_app.c
DEPENDS
)


px4_add_module() 方法从模块描述生成静态库。 MAIN 块列出了模块的名称 — 该名称将会作为 NuttX 的注册命令以便可以从 PX4 命令行或 SITL 控制台调用该命令。

The px4_add_module() format is documented in Firmware/cmake/px4_add_module.cmake.

If you specify DYNAMIC as an option to px4_add_module, a shared library is created instead of a static library on POSIX platforms (these can be loaded without having to recompile PX4, and shared to others as binaries rather than source code). Your app will not become a builtin command, but ends up in a separate file called examples__px4_simple_app.px4mod. You can then run your command by loading the file at runtime using the dyn command: dyn ./examples__px4_simple_app.px4mod

## 编译应用程序/固件

examples/px4_simple_app


• jMAVSim 仿真器：make px4_sitl_default jmavsim
• Pixhawk v1/2：make px4_fmu-v2_default（或只用 make px4_fmu-v2
• Pixhawk v3：make px4_fmu-v4_default
• 其他飞控板：构建代码

## 测试应用（硬件）

### 将固件上传至飞控板

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



### 连接至控制台

nsh>


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:
reboot
perf
top
..
px4_simple_app
..
sercon
serdis


nsh> px4_simple_app
Hello Sky!


## 测试应用（SITL）

pxh> px4_simple_app
INFO  [px4_simple_app] Hello Sky!


## 订阅传感器数据

PX4 对硬件层进行抽象化的好处在这里发挥了作用！ 我们在构建应用程序时无需直接与传感器驱动进行任何的交互，且即便对飞控板或者传感器硬件进行更新后也不需要对你的应用程序进行任何更新。

#include <uORB/topics/sensor_combined.h>
..
int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));


sensor_sub_fd 是一个 topic 句柄（handle），它可以高效地执行阻断以等待新数据。 待新数据抵达后调度程序会自动将当前进程从休眠中唤醒，线程在等待期间不会占用任何 CPU 周期。 为了实现这一功能，我们使用了 POSIX 系统调用函数 poll()

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]);
}
}


make


### 测试 uORB 消息订阅

px4_simple_app &


[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


## 发布数据

#include <uORB/topics/vehicle_attitude.h>
..
struct vehicle_attitude_s att;
memset(&att, 0, sizeof(att));


orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);


## 完整的示例代码

/****************************************************************************
*

*
* 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/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);

struct vehicle_attitude_s att;
memset(&att, 0, sizeof(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


If you start QGroundControl, you can check the sensor values in the real time plot (Analyze > MAVLink Inspector).