[pixhawk筆記]4-如何寫一個簡單的應用程序


 本文主要內容來自於: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, 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]);
        }
    }

    注意到上面的代碼與源碼里給出的有出入,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, 0, 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,200);/* limit the update rate to 5 Hz */
    
        struct vehicle_attitude_s att;
        memset(&att,0,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 = 0;
    
        for(int i=0;i<5;i++){
            int poll_ret = px4_poll(fds,1,1000);
    
            if(poll_ret == 0){
                PX4_ERR("Got no data within a second");
            }else if(poll_ret<0){
                if(error_counter<10 || error_counter % 50 == 0){
                    PX4_ERR("ERROR return value from poll():%d",poll_ret);
                }
    
                error_counter++;
            }else{
                if(fds[0].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[0],
                        (double)raw.accelerometer_m_s2[1],
                        (double)raw.accelerometer_m_s2[2]);
    
                    att.rollspeed = raw.accelerometer_m_s2[0];
                    att.pitchspeed = raw.accelerometer_m_s2[1];
                    att.yawspeed = raw.accelerometer_m_s2[2];
    
                    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左右的值,因為程序中用加速度的值填充到角速度並進行發布。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM