本文主要内容来自于:https://dev.px4.io/en/tutorials/tutorial_hello_sky.html,并对文档中的部分问题进行更正。

本文假设已经建立好开发环境并能正确编译,关于编译过程,可参见本人博客中的[pixhawk笔记]1-编译过程

程序员学习一门语言时第一个例子一般是学习怎么写一个“Hello World”,本文中的简单程序就是类似于该功能,能够让读者搞明白如何实现一个px4程序。

  1. 最小程序
    进入Firmware/src/examples/目录,在px4_simple_app文件夹下面创建px4_simple_app.c文件(该文件已经存在于源码中,为了提高学习效果,建议将其删除,重新写)。
    在其中键入如下代码:

    #include <px4_config.h>
    #include <px4_tasks.h>
    #include <px4_posix.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <poll.h>
    #include <string.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!");
    return OK;
    }

    该代码中有默认头和默认的主函数。  

  2. 在Nuttx系统中注册应用并编译
    为了使该程序能够编译进固件,需要在系统的cmake文件中注册该程序,笔者使用的是pixhawk2,对应的cmake文件是:Firmware/cmake/config/nuttx_px4_fmu-v3_default.cmake,其他平台可以找到对应的cmake文件。
    然后在该文件中config_moule_list代码段加入模块路径:
    examples/px4_simple_app
    笔者发现官方文档有问题,加入.c文件后,还得在px4_simple_app文件夹下面建立CMakeLists.txt文件,否则编译不过去。
    建立CMakeLists.txt并加入如下内容:
    px4_add_module(
    MODULE examples__px4_simple_app
    MAIN px4_simple_app
    STACK_MAIN 2000
    SRCS
    px4_simple_app.c
    DEPENDS
    platforms__common
    )

    然后编译之:

  3. make px4fmu-v3_default

    编译通过后编译并上传

    make px4fmu-v3_default upload
  4. 连接控制台
    Ubuntu下面可以通过screen来连接px4控制台,使用如下命令安装screen:
    sudo apt-get install screen

    然后使用如下命令连接px4控制台:

    screen /dev/ttyXXX BAUDRATE 8N1

    其中,ttyXXX为pixhawk对应的串口设备,如下命令可以列出串口设备列表:

    ls /dev/tty*

    通过插拔pixhawk并对比插拔前后的列表变化,可以确定pixhawk对应的串口设备ID。
    通过对比,本机的pixhawk使用的ttyACM0

    但是笔者这么连接全是乱码……不知何故o(╯□╰)o……

    尝试使用MAVLink shell来连接控制台,先使用pip安装pymavlink和pyserial

    sudo pip install pymavlink pyserial

    GFW的原因,使用pip安装时经常出现连接超时的问题。笔者使用下载安装包离线安装的方法。

    然后使用mavlink shell 来连接:

    ./Tools/mavlink_shell.py /dev/ttyACM0

    连接成功后出现如下界面:


    控制太nsh即为px4代码运行的nuttx操作系统的shell,可在此运行系统内置命令,由于我们已经将写的代码注册到nuttx,所以可以直接运行该应用。键入:px4_simple_app,则出现如下运行界面:

    打印出Hello Sky!的字符串,证明px4_simple_app.c中的代码得到了执行。

  5. 订阅传感器数据
    上面的例子只是为了演示如何写一个px4上运行的应用,为了做一些有用的事情,下面演示如何获得传感器数据并显示出来。
    在px4中,各个应用之间传递的消息称为“主题”(topic),这些消息通过uORB进行传递,当需要传递传感器信息时,我们感兴趣的是 sensor_combined 主题,该主题将整个系统的传感器信息保持同步。
    可以通过如下代码订阅该主题:

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

    得到的sensor_sub_fd是一个主题句柄,使用该句柄可以通过阻塞等待来获得新的传感器数据。 阻塞使该应用开始休眠,知道新数据产生后将该应用唤醒,在等待期间不消耗任何CPU运算。可使用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) */
       px4_poll(fds, , );
    ..
    if (fds[].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[],
    (double)raw.accelerometer_m_s2[],
    (double)raw.accelerometer_m_s2[]);
    }
    }

    注意到上面的代码与源码里给出的有出入,px4_poll无返回值,因为笔者发现网上下载的源码有返回值而没有用,编译时会在gcc中产生错误而编译不通过。所以采用无返回值的形式。

    然后编译,下载,并使用mavlink shell连接,运行px4_simple_app后控制台输出如下:

  6. 发布数据
    上面的例子给出了如何通过uORB获得订阅数据,下面给出如何发布数据。发布的接口比较简单:使用如下代码初始化要发布的内容:
    #include <uORB/topics/vehicle_attitude.h>
    ..
    /* advertise attitude topic */
    struct vehicle_attitude_s att;
    memset(&att, , 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);

    完整代码如下:

        #include <px4_config.h>
    #include <px4_tasks.h>
    #include <px4_posix.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <poll.h>
    #include <string.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!");
    int sensor_sub_fd = orb_subscribe(ORB_ID(sensor_combined));
    orb_set_interval(sensor_sub_fd,);/* limit the update rate to 5 Hz */ struct vehicle_attitude_s att;
    memset(&att,,sizeof(att));
    orb_advert_t att_pub = orb_advertise(ORB_ID(vehicle_attitude),&att); px4_pollfd_struct_t fds[] = {
    {.fd = sensor_sub_fd, .events = POLLIN},
    }; int error_counter = ; for(int i=;i<;i++){
    int poll_ret = px4_poll(fds,,); if(poll_ret == ){
    PX4_ERR("Got no data within a second");
    }else if(poll_ret<){
    if(error_counter< || error_counter % == ){
    PX4_ERR("ERROR return value from poll():%d",poll_ret);
    } error_counter++;
    }else{
    if(fds[].revents & POLLIN){
    struct sensor_combined_s raw;
    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[],
    (double)raw.accelerometer_m_s2[],
    (double)raw.accelerometer_m_s2[]); att.rollspeed = raw.accelerometer_m_s2[];
    att.pitchspeed = raw.accelerometer_m_s2[];
    att.yawspeed = raw.accelerometer_m_s2[]; orb_publish(ORB_ID(vehicle_attitude),att_pub,&att);
    }
    }
    }
    PX4_INFO("exiting");
    return OK;
    }

    笔者注意到使用下载到的默认代码会出现att中没有roll,pitch和yaw的错误,通过查看编译文件夹下面的topics目录中的vehicle_attitude.h头文件,可以看出vehicle_attitude_s结构体中没有roll,pitch和yaw成员。所以笔者将代码中姿态改为角速度,然后编译上传并运行程序。连接地面站,通过控制台运行px4_simple_app,可以看到,其角速率信号会间隔性被发布信息劫持,显示如下:

    可以看出,在运行程序之后,角速率的值间歇性被px4_simple_app劫持,出现-9.8左右的值,因为程序中用加速度的值填充到角速度并进行发布。

[pixhawk笔记]4-如何写一个简单的应用程序的更多相关文章

  1. (原创)如何使用boost.asio写一个简单的通信程序(一)

    boost.asio相信很多人听说过,作为一个跨平台的通信库,它的性能是很出色的,然而它却谈不上好用,里面有很多地方稍不注意就会出错,要正确的用好asio还是需要花一番精力去学习和实践的,本文将通过介 ...

  2. (原创)如何使用boost.asio写一个简单的通信程序(二)

    先说下上一篇文章中提到的保持io_service::run不退出的简单办法.因为只要异步事件队列中有事件,io_service::run就会一直阻塞不退出,所以只要保证异步事件队列中一直有事件就行了, ...

  3. 【Java学习笔记】如何写一个简单的Web Service

    本Guide利用Eclipse以及Ant建立一个简单的Web Service,以演示Web Service的基本开发过程: 1.系统条件: Eclipse Java EE IDE for Web De ...

  4. Python3的tkinter写一个简单的小程序

    一.这个学期开始学习python,但是看了python2和python3,最后还是选择了python3 本着熟悉python的原因,并且也想做一些小程序来增加自己对python的熟练度.所以写了一个简 ...

  5. 用c++写一个简单的计算器程序

    // 050305.cpp : 定义控制台应用程序的入口点.// // 050304.cpp : 定义控制台应用程序的入口点.////四则运算#include "stdafx.h" ...

  6. python3 写一个简单的websocket程序(转)

    原贴:https://segmentfault.com/q/1010000009284816?_ea=1883181 也是找了好久 #! /usr/bin/env python # -*- codin ...

  7. 如何用 Python 写一个简易的抽奖程序

    不知道有多少人是被这个头图骗进来的:) 事情的起因是这样的,上周有同学问小编,看着小编的示例代码敲代码,感觉自己也会写了,如果不看的话,七七八八可能也写的出来,但是一旦自己独立写一段程序,感觉到无从下 ...

  8. Linux系统学习笔记之 1 一个简单的shell程序

    不看笔记,长时间不用自己都忘了,还是得经常看看笔记啊. 一个简单的shell程序 shell结构 1.#!指定执行脚本的shell 2.#注释行 3.命令和控制结构 创建shell程序的步骤 第一步: ...

  9. 用Python写一个简单的Web框架

    一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...

随机推荐

  1. 【R】均值假设检验

    p_value<-function(cdf,x,parament=numeric(0),side=0) { n<-length(parament) p<-switch(n+1, cd ...

  2. ios 页面过长卡顿的情况

    解决方案如下: -webkit-overflow-scrolling: touch;

  3. 一个事半功倍的c#方法 动态注册按钮事件

    前几天在网上看见一个制作计算器的c#程序,其中有一个动态注册按钮事件,觉的很有用.于是实际操作了一哈, 确实比较好. 言归正传,下面就来讲讲怎样动态注册按钮事件. 首先,我们需要设置变量来获取点击一个 ...

  4. IO文件读写

    *b表示二进制模式访问,但是对于Linux或者Unix系统来说这个模式没有任何意义,因为他们把所有文件都看做二进制文件,包括文本文件 一.三种方法读取文件  方法1:open f=open(" ...

  5. 在ubuntu机器上部署php测试环境

    在ubuntu机器上部署php测试环境 一.部署环境 Ubuntu11.10_X86_32,编译安装相应的软件:nginx+mysql+php. 二.软件安装 2.1 软件下载 libiconv-1. ...

  6. Linux下搜索文件find、which、whereis、locate

    Linux下搜索文件find.which.whereis.locate: - which 寻找“执行文件” - -a 将所有可找到的命令均列出,而不仅仅列出第一个找到的命令名称 - whereis 寻 ...

  7. iOS捕获异常,常用的异常处理方法

    本文转载至 http://www.cocoachina.com/ios/20141229/10787.html 前言:在开发APP时,我们通常都会需要捕获异常,防止应用程序突然的崩溃,防止给予用户不友 ...

  8. 【MVC model 验证失效 】【Unexpected token u in JSON at position 0】【jquery-plugin-validation】

    问题描述:mvc model 调用jquery-plugin-validation 实现 前台的数据验证,时报错 Unexpected token u in JSON at position 0 很讨 ...

  9. cocos2d-X学习之主要类介绍:CCDirector

    在cocos2d-x里面,游戏的任何时间,只有一个场景对象实例处于运行状态,该对象可以作为当前游戏内容的整体包对象 Cocos2d-x引擎除了提供了CCDirector,还提供了一个CCDisplay ...

  10. 修改docker时区

    在实际业务场景中,经常碰到启动了一个容器,容器的时区是UTC的导致还需要重新运行: 我们在具体处理时也出现了该显现 业务场景: 数据库系统定时备份脚本, 定时备份脚本按照每天备份, 通过k8s启动容器 ...