PX4源码开发人员文档二Hello Sky.docx
《PX4源码开发人员文档二Hello Sky.docx》由会员分享,可在线阅读,更多相关《PX4源码开发人员文档二Hello Sky.docx(12页珍藏版)》请在冰点文库上搜索。
![PX4源码开发人员文档二Hello Sky.docx](https://file1.bingdoc.com/fileroot1/2023-5/10/f54b1dce-488f-499c-89fe-aa279c9622b4/f54b1dce-488f-499c-89fe-aa279c9622b41.gif)
PX4源码开发人员文档二HelloSky
前提
∙ 用UART1连接PX4FMU和计算机
∙ 安装PX4Toolchain
∙ 注册Github账户
Step1:
准备源码文件
为了方便管理代码,可以使用GIT版本控制系统,在GitHub上fork和更新源码。
不注册GitHub的话,可以在PX4console中输入下面的命令:
1.git clone
更新thegitsubmodules,在PX4console上输入:
1.cd Firmware
2.git submodule init
3.git submodule update
文件准本完成,编译操作系统,输入:
1.make archives
当submodules或者NuttX 配置改变,重新编译。
在Firmware/src/examples/ 新建目录px4_simple_app,在目录中新建文件module.mk并添加如下内容:
1.MODULE_COMMAND = px4_simple_app
2.SRCS = px4_simple_app.c
Step2:
最小程序
在px4_simple_app目录下创建px4_simple_app.c文件。
遵循PX4CodingStyle 编辑如下代码:
1./**
2. * @file px4_simple_app.c
3. * Minimal application example for PX4 autopilot.
4. */
5.
6.#include
7.#include
8.#include
9.
10.__EXPORT int px4_simple_app_main(int argc, char *argv[]);
11.
12.int px4_simple_app_main(int argc, char *argv[])
13.{
14. printf("Hello Sky!
\n");
15. return OK;
16.}
Step3:
在NuttShell中注册应用并build
完成了应用并可以运行,但是没有在NuttShell命令中注册。
为将应用编译到固件当中,将其填加到需要build的模块中。
该配置位于:
Firmware/makefiles/nuttx/config_px4fmu-v2_default.mk
在上面的文件中的任意位置,为应用创建一行:
1.MODULES += examples/px4_simple_app
然后编译,并清除已经build的应用:
1.make clean
2.make px4fmu-v2_default -j4
如果没有注册新的app,只需要对新增的builds执行下述命令:
1.make px4fmu-v2_default -j4
Step4:
加载应用并测试
使能uploader然后重置电路板:
1.make upload px4fmu-v2_default -j4
在重置电路板之前显示如下一系列信息:
1.Generating /Users/user/src/Firmware/Images/px4fmu.px4
2.Loaded firmware for 5,0, waiting for the bootloader...
电路板充值并上载后,打印:
1.Found board 5,0 on /dev/tty.usbmodem1
2.erase...
3.program...
4.verify...
5.done, rebooting.
运行px4Toolchain 下的TeraTerm,运行File/Newconnection,选择飞控所在的串口,点击OK。
按回车,出现nsh>.
在NSH连接的情况下,切换到shell.如果没有看到输出,敲击Enter键,会得到NSH提示;
或者也可以,使用QGroundControl进行NuttShell(NSH),使用Mini-USB连接Pixhawk,按照下图进行。
点击QGroundControl上的终端输出,并敲击Enter键。
1.nsh>
输入 help,并敲击Enter键:
1.nsh> help
2. help usage:
help [-v] []
3.
4. [ df kill mkfifo ps sleep
5. ?
echo losetup mkrd pwd test
6. cat exec ls mh rm umount
7. cd exit mb mount rmdir unset
8. cp free mkdir mv set usleep
9. dd help mkfatfs mw sh xd
10.
11.Builtin Apps:
12. reboot
13. perf
14. top
15. ..
16. px4_simple_app
17. ..
18. sercon
19. serdis
px4_simple_app 现在成为可用的指令。
输入px4_simple_app并敲击Enter键:
1.nsh> px4_simple_app
2.Hello Sky!
Step5:
订阅传感器数据
为了做有用的事情,应用需要订阅subscribe输入并发布publish输出(e.g.电机或伺服指令).PX4平台真正的硬件抽象(true hardwareabstraction)开始有用——不需要与传感器驱动以任何方式相互作用,并且电路板或者传感器升级后不需要升级。
PX4中应用间独立的消息通道被称作topics.在这里,感兴趣的是 sensor_combined topic,其调用整个系统的同步传感器数据。
订阅到topic非常快和干净:
1.#include
2...
3.int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
sensor_sub_fd 是一个文件描述符,非常高效的执行一块等待新的数据的数据块。
当前的进程进入休眠,当有新的数据可用时,由调度程序自动地唤醒,在等待的时候,不占用任何CPU周期。
为实现这点,使用poll(),调用POSIXsystem。
将poll() 添加到subscription看上去像:
1.#include
2.#include
3...
4.int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
5.
6./* one could wait for multiple topics with this technique, just using one here */
7.struct pollfd fds[] = {
8. { .fd = sensor_sub_fd, .events = POLLIN },
9.};
10.
11.while (true) {
12. /* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
13. int poll_ret = poll(fds, 1, 1000);
14...
15. if (fds[0].revents & POLLIN) {
16. /* obtained data for the first file descriptor */
17. struct sensor_combined_s raw;
18. /* copy sensors raw data into local buffer */
19. orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
20. printf("[px4_simple_app] Accelerometer:
\t%8.4f\t%8.4f\t%8.4f\n",
21. (double)raw.accelerometer_m_s2[0],
22. (double)raw.accelerometer_m_s2[1],
23. (double)raw.accelerometer_m_s2[2]);
24. }
25.}
px4_simple_app 的完整代码如下:
1./**
2. * @file px4_simple_app.c
3. * Minimal application example for PX4 autopilot
4. *
5. * @author Example User
6. */
7.
8.#include
9.#include
10.#include
11.#include
12.
13.#include
14.#include
15.
16.__EXPORT int px4_simple_app_main(int argc, char *argv[]);
17.
18.int px4_simple_app_main(int argc, char *argv[])
19.{
20. printf("Hello Sky!
\n");
21.
22. /* subscribe to sensor_combined topic */
23. int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
24.
25. /* one could wait for multiple topics with this technique, just using one here */
26. struct pollfd fds[] = {
27. { .fd = sensor_sub_fd, .events = POLLIN },
28. /* there could be more file descriptors here, in the form like:
29. * { .fd = other_sub_fd, .events = POLLIN },
30. */
31. };
32.
33. int error_counter = 0;
34.
35. while (true) {
36. /* wait for sensor update of 1 file descriptor for 1000 ms (1 second) */
37. int poll_ret = poll(fds, 1, 1000);
38.
39. /* handle the poll result */
40. if (poll_ret == 0) {
41. /* this means none of our providers is giving us data */
42. printf("[px4_simple_app] Got no data within a second\n");
43. } else if (poll_ret < 0) {
44. /* this is seriously bad - should be an emergency */
45. if (error_counter < 10 || error_counter % 50 == 0) {
46. /* use a counter to prevent flooding (and slowing us down) */
47. printf("[px4_simple_app] ERROR return value from poll():
%d\n"
48. , poll_ret);
49. }
50. error_counter++;
51. } else {
52.
53. if (fds[0].revents & POLLIN) {
54. /* obtained data for the first file descriptor */
55. struct sensor_combined_s raw;
56. /* copy sensors raw data into local buffer */
57. orb_copy(ORB_ID(sensor_combined), sensor_sub_fd, &raw);
58. printf("[px4_simple_app] Accelerometer:
\t%8.4f\t%8.4f\t%8.4f\n",
59. (double)raw.accelerometer_m_s2[0],
60. (double)raw.accelerometer_m_s2[1],
61. (double)raw.accelerometer_m_s2[2]);
62. }
63. /* there could be more file descriptors here, in the form like:
64. * if (fds[1..n].revents & POLLIN) {}
65. */
66. }
67. }
68.
69. return 0;
70.}
编译app,通过下面的指令:
1.make
测试uORB订阅
运行更新后的程序。
UORBapp可能已经在运行,但是重新运行一次也没关系,所以执行:
1.uorb start
目标请求中间人已经被激活,可以启动传感器:
1.sh /etc/init.d/rc.sensors
最后一步是启动应用,但是为什么语法不同?
1.px4_simple_app &
不同是,uorb和传感器应用作为后台程序运行Daemon(computing)。
这就允许在不失去对NuttShell控制的情况下,启动/停止其。
假如忘了在行末输入&,应用将会将现在传感器的值铺满显示屏:
1.[px4_simple_app] Accelerometer:
0.0483 0.0821 0.0332
2.[px4_simple_app] Accelerometer:
0.0486 0.0820 0.0336
3.[px4_simple_app] Accelerometer:
0.0487 0.0819 0.0327
4.[px4_simple_app] Accelerometer:
0.0482 0.0818 0.0323
5.[px4_simple_app] Accelerometer:
0.0482 0.0827 0.0331
6.[px4_simple_app] Accelerometer:
0.0489 0.0804 0.0328
由于不是后台程序,没有办法将其停止,只能让其运行,或者通过发起下面的命令重启自驾仪:
1.reboot
或者按压PX4FMU上的resetbutton.如何将应用变为后台程序可以参考thistutorial 。
Step6:
速率受限的订阅
上一步最后一步是屏幕上铺满传感器数据。
通常并不需要数据以最高速率刷新,试图保持最高速率,通常会使整个系统变慢。
API接口非常简单:
1.orb_set_interval(int handle, unsigned interval);
限制topic到1Hz,只需添加:
1.orb_set_interval(sensor_sub_fd, 1000);
到示例代码这行的下面(在line55附近):
1./* subscribe to sensor_combined topic */
2.int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
屏幕将会以1Hz的速率方便的打印传感器数据。
Step7:
发布数据
为了使用计算得到的输出,下一步是发布结果。
假如我们使用了一个topic,mavlink app通过该topic转发到地面站,我们甚至可以查看结果。
出于这个目的,来拦截姿态topic。
接口非常简单,初始化topic结构,并通告(advertise)topic。
1.#include
2...
3./* advertise attitude topic */
4.struct vehicle_attitude_s att;
5.memset(&att, 0, sizeof(att));
6.orb_advert_t att_pub_fd = orb_advertise(ORB_ID(vehicle_attitude), &att);
在主循环中,当其准备好后,发布信息:
1.orb_publish(ORB_ID(vehicle_attitude), att_pub_fd, &att);
修改后的完整示例代码为:
1./**
2. * @file px4_simple_app.c
3. * Minimal application example for PX4 autopilot
4. */
5.