PX4 QGC透明串口轉(zhuǎn)發(fā)三--自定義uORB消息實(shí)現(xiàn),實(shí)現(xiàn)PX4模塊間數(shù)據(jù)傳遞

3. 自定義uORB消息實(shí)現(xiàn),實(shí)現(xiàn)PX4模塊間數(shù)據(jù)傳遞

uORB官方說明

設(shè)計(jì)構(gòu)想

QGC <--mavlink(數(shù)傳)--> PX4(mavlink守護(hù)進(jìn)程) <--uORB--> raw_serial_rtx <--UART--> device
  • 上一節(jié)實(shí)現(xiàn)了 QGC <--mavlink(數(shù)傳)--> PX4(mavlink守護(hù)進(jìn)程)
  • 本節(jié)實(shí)現(xiàn) PX4(mavlink守護(hù)進(jìn)程) <--uORB--> raw_serial_rtx飞傀,從而打通整個數(shù)據(jù)鏈路
  • 技術(shù)點(diǎn):uORB消息的定義朴摊,發(fā)布和訂閱
  • 未加說明下文中文件路徑均以PX4-Framework項(xiàng)目根路徑作為起始路徑的相對路徑。

3.1 自定義uORB消息

  • 依據(jù)上節(jié)自定義的mavlink消息,參考 msg/qshell_req.msg千扔,在msg目錄創(chuàng)建raw_serial_rx.msgraw_serial_tx.msg憎妙。為什么要創(chuàng)建兩個库正,主要考慮,以后還想在其他模塊重用厘唾,避免混淆
  • msg/raw_serial_rx.msg,對應(yīng)串口接收
uint64 timestamp        # time since system start (microseconds)
uint8 dev               # which port received data, define in Mavlink enum RSRTX_OPT_DEV_ENUM
uint8 len               # pakage length
uint8[250] data         # payload
uint8 MAX_LEN = 250     # max length of payload
  • msg/raw_serial_tx.msg,對應(yīng)串口發(fā)送
uint64 timestamp        # time since system start (microseconds)
uint8 dev               # which port data send to, define in Mavlink enum RSRTX_OPT_DEV_ENUM
uint8 len               # pakage length
uint8[250] data         # payload
uint8 MAX_LEN = 250     # max length of payload
  • msg/CMakeLists.txt 添加消息
#...
set(msg_files
#...
    raw_serial_rx.msg
    raw_serial_tx.msg
    )
#...
  • 編譯一遍 make px4_fmu-v2_default
  • build/px4_fmu-v2_default/uORB/topics下會出現(xiàn)兩個頭文件,在消息定義時timestamp必選诀诊,字段賦值會自動生成常量
uORBMSG.png

3.2 uORB消息的提出/發(fā)布/訂閱/讀取 流程(advertise/public/subscribe/copy)

  • 簡單把uORB的流程梳理一下,以便閱讀后面實(shí)際代碼
  • 提出/發(fā)布必須在同一線程阅嘶,如果提出失敗属瓣,需要再次提出,貿(mào)然發(fā)布會導(dǎo)致系統(tǒng)宕機(jī)重啟
  • 訂閱/讀取必須在同一線程
/*消息發(fā)送線程---------------------------------------------------*/
//1.提出消息讯柔,一次就夠
struct raw_serial_tx_s tx_pkg = {};
orb_advert_t _raw_serial_tx_pub{nullptr};
_raw_serial_tx_pub = orb_advertise(ORB_ID(raw_serial_tx),&tx_pkg);

//2.發(fā)布消息抡蛙,可發(fā)布多次,_raw_serial_tx_pub不可為空魂迄,否者會出現(xiàn)系統(tǒng)宕機(jī)
tx_pkg.timestamp = hrt_absolute_time();
tx_pkg.dev = mavpkg.dev;
tx_pkg.len = mavpkg.len;
memcpy(tx_pkg.data,mavpkg.data,mavpkg.len);
orb_publish(ORB_ID(raw_serial_tx), _raw_serial_tx_pub, &tx_pkg);

/*開新線程接收消息--------------------------------------------------*/
//3.訂閱
int raw_serial_rx_sub = orb_subscribe(ORB_ID(raw_serial_rx));

//4.消息讀取循環(huán)
px4_pollfd_struct_t fds[1];
fds[0].fd = raw_serial_rx_sub;
fds[0].events = POLLIN;
while (true)
    {
        //阻塞等待10ms
        int ret = px4_poll(fds, 1, 10);
        if (ret < 0) {
            break;
        } if(ret==0){
            continue;
        }
        bool updated;
        // 檢查消息更新 
        orb_check(raw_serial_rx_sub, &updated);
        if (updated) {
            orb_copy(ORB_ID(raw_serial_rx), raw_serial_rx_sub, &rxpkg);
            ...
        }
    }

3.3 Mavlink端實(shí)際代碼

  • src/modules/mavlink/mavlink_raw_serial_rtx.h
#pragma once
#include "mavlink_bridge_header.h"
#include <drivers/drv_hrt.h>

#include <uORB/uORB.h>
#include <uORB/topics/raw_serial_rx.h>
#include <uORB/topics/raw_serial_tx.h>

class Mavlink;

class MavlinkRawSerialRTX
{
public:
    explicit MavlinkRawSerialRTX(Mavlink *mavlink);
    ~MavlinkRawSerialRTX();
    void handle_message(const mavlink_message_t *msg);
private:
    int sendData(uint8_t dev,uint8_t len,uint8_t * data );
    MavlinkRawSerialRTX(MavlinkRawSerialRTX &);
    MavlinkRawSerialRTX &operator = (const MavlinkRawSerialRTX &);
    Mavlink *_mavlink;

    orb_advert_t _raw_serial_tx_pub{nullptr};
    void pubUorbTx(mavlink_rtx_gcs2uav_t mavpkg);

    void startRXThread(void);
    static void * start_helper(void *instance);
    void rx_check_update_thread(void);

};

  • src/modules/mavlink/mavlink_raw_serial_rtx.cpp
#include <stdio.h>
#include "mavlink_raw_serial_rtx.h"
#include "mavlink_main.h"

MavlinkRawSerialRTX::MavlinkRawSerialRTX(Mavlink *mavlink) :
    _mavlink(mavlink)
{
    //開始rx的uORB訂閱
    startRXThread();
}

MavlinkRawSerialRTX::~MavlinkRawSerialRTX()
{

}

//接收地面站消息
void
MavlinkRawSerialRTX::handle_message(const mavlink_message_t *msg)
{
    //接收消息
    switch (msg->msgid){
        case MAVLINK_MSG_ID_RTX_GCS2UAV:{
            mavlink_rtx_gcs2uav_t mavpkg ;
            mavlink_msg_rtx_gcs2uav_decode(msg,&mavpkg);

            struct raw_serial_tx_s tx_pkg = {};
            tx_pkg.timestamp = hrt_absolute_time();
            tx_pkg.dev = mavpkg.dev;
            tx_pkg.len = mavpkg.len;
            memcpy(tx_pkg.data,mavpkg.data,mavpkg.len);

            if(_raw_serial_tx_pub==nullptr){//如果一開始沒有提出advert或者沒有成功
                _raw_serial_tx_pub = orb_advertise(ORB_ID(raw_serial_tx),&tx_pkg);
            }
            if(_raw_serial_tx_pub!=nullptr){//發(fā)布uORB消息
                orb_publish(ORB_ID(raw_serial_tx), _raw_serial_tx_pub, &tx_pkg);
            }

        }
        default:
            break;
    }
}

//向地面站直接發(fā)送消息
int
MavlinkRawSerialRTX::sendData(uint8_t dev,uint8_t len,uint8_t * data ){
    if(len>sizeof(mavlink_rtx_uav2gcs_t::data) || _mavlink==nullptr )
        return -1;

    mavlink_rtx_uav2gcs_t pkg;
    pkg.dev = dev;
    pkg.len = len;
    memcpy(pkg.data,data,len);

    mavlink_msg_rtx_uav2gcs_send_struct(_mavlink->get_channel(),&pkg);

    return 0;
}



//開啟一個線程接收raw_serial_rx消息
void MavlinkRawSerialRTX::startRXThread(){
    pthread_t _receive_thread {};
    pthread_attr_t rxsubloop_attr;
    pthread_attr_init(&rxsubloop_attr);

    struct sched_param param;
    (void)pthread_attr_getschedparam(&rxsubloop_attr, &param);
    //優(yōu)先級放到最低吧粗截,以免影響飛控核心功能
    param.sched_priority = SCHED_PRIORITY_MIN;
    (void)pthread_attr_setschedparam(&rxsubloop_attr, &param);

    pthread_attr_setstacksize(&rxsubloop_attr, PX4_STACK_ADJUSTED(2840));
    pthread_create(&_receive_thread, &rxsubloop_attr, MavlinkRawSerialRTX::start_helper, (void *)this);

    pthread_attr_destroy(&rxsubloop_attr);
}

//開線程要用到的工具函數(shù),必須是靜態(tài)的
void * MavlinkRawSerialRTX::start_helper(void *instance){
    ((MavlinkRawSerialRTX *) instance)->rx_check_update_thread();
    return  nullptr;
}

//線程接收訂閱raw_serial_rx消息
void  MavlinkRawSerialRTX::rx_check_update_thread(){
    //設(shè)置線程名
    char thread_name[30];
    sprintf(thread_name, "mavlink_serial_rx_if%d", _mavlink->get_instance_id());
    px4_prctl(PR_SET_NAME, thread_name, px4_getpid());

    int raw_serial_rx_sub = orb_subscribe(ORB_ID(raw_serial_rx));
    struct raw_serial_rx_s rxpkg;

    px4_pollfd_struct_t fds[1];
    fds[0].fd = raw_serial_rx_sub;
    fds[0].events = POLLIN;
    //和mavlink一起停止
    while (!_mavlink->_task_should_exit)
    {
        //阻塞等待10ms
        int ret = px4_poll(fds, 1, 10);

        if (ret < 0) {
            break;
        } if(ret==0){
            continue;
        }

        bool updated;

        /* 檢查消息更新 */
        orb_check(raw_serial_rx_sub, &updated);

        if (updated) {//如果更新了就取數(shù)據(jù),并使用mavlink發(fā)送

            orb_copy(ORB_ID(raw_serial_rx), raw_serial_rx_sub, &rxpkg);
            //mavlink 發(fā)給地面站
            sendData(rxpkg.dev,rxpkg.len,rxpkg.data);
        }
    }

}

3.4 串口端實(shí)際代碼

  • 代碼結(jié)構(gòu)和第一章有所區(qū)別捣炬,可同時啟動多個守護(hù)進(jìn)程熊昌,相互間不干擾,通過消息中的dev字段區(qū)別到底時那個串口發(fā)送/接收湿酸。
  • src/modules/raw_serial_rtx/raw_serial_rtx_main.h
#pragma once

#include <pthread.h>
#include <stdbool.h>
#include <containers/List.hpp>
#include <parameters/param.h>
#include <px4_cli.h>
#include <px4_getopt.h>
#include <px4_module.h>
#include <px4_module_params.h>
#include <px4_posix.h>
#include <termios.h>
#include <errno.h>
#include <drivers/drv_hrt.h>

#include <uORB/uORB.h>
#include <uORB/topics/raw_serial_rx.h>
#include <uORB/topics/raw_serial_tx.h>


//直接從mavlink消息定義處復(fù)制過來婿屹,想直接使用rsrtx.h,好像還需要其他依賴
#ifndef HAVE_ENUM_RSRTX_OPT_DEV_ENUM
#define HAVE_ENUM_RSRTX_OPT_DEV_ENUM
typedef enum RSRTX_OPT_DEV_ENUM
{
   DEV_TTYS0=0, /* /dev/ttyS0 | */
   DEV_TTYS1=1, /* /dev/ttyS1 | */
   DEV_TTYS2=2, /* /dev/ttyS2 | */
   DEV_TTYS3=3, /* /dev/ttyS3 | */
   DEV_TTYS4=4, /* /dev/ttyS4 | */
   DEV_TTYS5=5, /* /dev/ttyS5 | */
   DEV_TTYS6=6, /* /dev/ttyS6 | */
   RSRTX_OPT_DEV_ENUM_ENUM_END=7, /*  | */
} RSRTX_OPT_DEV_ENUM;
#endif

#define MAX_SERIAL_SIZE 250

namespace raw_serial_rtx{

class RawSerialRTX : public ModuleParams
{

public:
    RawSerialRTX(int baudrate ,int datarate,const char* device_name , int uart_fd);
    ~RawSerialRTX();
    static void usage();
    static int start(int argc,char *argv[]);
    static int getSpeedCodeFormBuadrate(int baud);
    static int openUART(const char * uart_name,int baud,int speed);
    static uint8_t getOptDevEnumByName(const char * uart_name);

private:
    int _baudrate;
    int _datarate;
    const char* _device_name ;
    int _uart_fd;
    uint8_t _opt_dev;
    orb_advert_t _raw_serial_rx_pub{nullptr};

    void readUartLoop();
    void pubUorbRx(uint8_t *buf,int len);
    void startTXThread(void);
    static void * start_helper(void *instance);
    void tx_check_update_thread(void);
};
}
  • src/modules/raw_serial_rtx/raw_serial_rtx_main.cpp
#include <string.h>
#include "raw_serial_rtx_main.h"

#define MAX_DATA_RATE                  10000000        ///< max data rate in bytes/s
#define MAIN_LOOP_DELAY                10000           ///< 100 Hz @ 1000 bytes/s data rate

using namespace raw_serial_rtx;

extern "C" __EXPORT int raw_serial_rtx_main(int argc, char *argv[]);

bool thread_should_exit = true;

/**----------------------------------------------------**/
//C代碼
/**----------------------------------------------------**/
 void RawSerialRTX::usage(){

    PRINT_MODULE_DESCRIPTION(
        R"DESCR_STR(
### Description

transport raw serial data via Mavlink

### Examples
start raw_serial_rtx on ttyS6 serial with baudrate 57600 and maximum sending rate of 2500B/s:
$ raw_serial_rtx start -d /dev/ttyS6 -b 57600 -r 2500

)DESCR_STR");

    PRINT_MODULE_USAGE_NAME("raw_serial_rtx", "communication");
    PRINT_MODULE_USAGE_COMMAND_DESCR("start", "Start instance");
    PRINT_MODULE_USAGE_PARAM_STRING('d', "/dev/ttyS1", "<file:dev>", "Select Serial Device", true);
    PRINT_MODULE_USAGE_PARAM_INT('b', 57600, 9600, 3000000, "Baudrate (can also be p:<param_name>)", true);
    PRINT_MODULE_USAGE_PARAM_INT('r', 0, 10, 10000000, "Maximum sending data rate in B/s (if 0, use baudrate / 20)", true);
    PRINT_MODULE_USAGE_COMMAND_DESCR("stop", "Stop instances");
    PRINT_MODULE_USAGE_COMMAND_DESCR("status", "Print status for instance");
}
//入口函數(shù)
int raw_serial_rtx_main(int argc, char *argv[]){
if (argc < 2) {
        RawSerialRTX::usage();
        return 1;
    }

    if (!strcmp(argv[1], "start")) {

        px4_task_spawn_cmd("raw_serial_rtx_1",
                         SCHED_DEFAULT,
                         SCHED_PRIORITY_MIN,
                         3000,
                         RawSerialRTX::start,
                         (char *const *)argv);

    //RawSerialRTX::start(argc,argv);

    }else if (!strcmp(argv[1], "stop")) {

        thread_should_exit = true;

    }else if (!strcmp(argv[1], "status")) {
        if(thread_should_exit){
            PX4_INFO("task is not running");
        } else {
            PX4_INFO("task is running");
        }

    }else {
        RawSerialRTX::usage();
        return 1;
    }

    return 0;
}

/*C++ 代碼*/

/* 打開串口 */
int RawSerialRTX::openUART(const char * uart_name,int baud,int speed){
    int uart_fd = ::open(uart_name, O_RDWR | O_NOCTTY | O_NONBLOCK);

    if(uart_fd < 0){
        PX4_ERR("can't open device : %s ",uart_name);
        return PX4_ERROR;
    }

    struct termios uart_config;
    int termios_state;

    /* Initialize the uart config */
    if ((termios_state = tcgetattr(uart_fd, &uart_config)) < 0) {
        PX4_ERR("ERR GET CONF %s: %d\n", uart_name, termios_state);
        ::close(uart_fd);
        return PX4_ERROR;
    }

    /* Clear ONLCR flag (which appends a CR for every LF) */
    uart_config.c_oflag &= ~ONLCR;

    /* Set baud rate */
    if (cfsetispeed(&uart_config, speed) < 0 || cfsetospeed(&uart_config, speed) < 0) {
        PX4_ERR("ERR SET BAUD %s: %d\n", uart_name, termios_state);
        ::close(uart_fd);
        return PX4_ERROR;
    }
    /* Set UART conf */
    if ((termios_state = tcsetattr(uart_fd, TCSANOW, &uart_config)) < 0) {
        PX4_WARN("ERR SET CONF %s\n", uart_name);
        ::close(uart_fd);
        return PX4_ERROR;
    }

    return uart_fd;
}

/* process baud rate */
int RawSerialRTX::getSpeedCodeFormBuadrate(int baud){
#ifndef B460800
#define B460800 460800
#endif
#ifndef B500000
#define B500000 500000
#endif
#ifndef B921600
#define B921600 921600
#endif
#ifndef B1000000
#define B1000000 1000000
#endif
    int speed;
    switch (baud) {
    case 0:      speed = B0;      break;
    case 50:     speed = B50;     break;
    case 75:     speed = B75;     break;
    case 110:    speed = B110;    break;
    case 134:    speed = B134;    break;
    case 150:    speed = B150;    break;
    case 200:    speed = B200;    break;
    case 300:    speed = B300;    break;
    case 600:    speed = B600;    break;
    case 1200:   speed = B1200;   break;
    case 1800:   speed = B1800;   break;
    case 2400:   speed = B2400;   break;
    case 4800:   speed = B4800;   break;
    case 9600:   speed = B9600;   break;
    case 19200:  speed = B19200;  break;
    case 38400:  speed = B38400;  break;
    case 57600:  speed = B57600;  break;
    case 115200: speed = B115200; break;
    case 230400: speed = B230400; break;
    case 460800: speed = B460800; break;
    case 500000: speed = B500000; break;
    case 921600: speed = B921600; break;
    case 1000000: speed = B1000000; break;
#ifdef B1500000
    case 1500000: speed = B1500000; break;
#endif
#ifdef B2000000
    case 2000000: speed = B2000000; break;
#endif
#ifdef B3000000
    case 3000000: speed = B3000000; break;
#endif
    default:
        PX4_ERR("Unsupported baudrate: %d\n\tsupported examples:\n\t9600, 19200, 38400, 57600\t\n115200\n230400\n460800\n500000\n921600\n1000000\n",
            baud);
        return -EINVAL;
    }
    return speed;
}

//通過設(shè)備名獲取串口的枚舉值,沒有返回RSRTX_OPT_DEV_ENUM::RSRTX_OPT_DEV_ENUM_ENUM_END
uint8_t RawSerialRTX::getOptDevEnumByName(const char* device_name){
    if(!strcasecmp(device_name,"/dev/ttyS0")){
        return RSRTX_OPT_DEV_ENUM::DEV_TTYS0;
    } else if(!strcasecmp(device_name,"/dev/ttyS1")){
        return RSRTX_OPT_DEV_ENUM::DEV_TTYS1;
    } else if(!strcasecmp(device_name,"/dev/ttyS2")){
        return RSRTX_OPT_DEV_ENUM::DEV_TTYS2;
    } else if(!strcasecmp(device_name,"/dev/ttyS3")){
        return RSRTX_OPT_DEV_ENUM::DEV_TTYS3;
    } else if(!strcasecmp(device_name,"/dev/ttyS4")){
        return RSRTX_OPT_DEV_ENUM::DEV_TTYS4;
    } else if(!strcasecmp(device_name,"/dev/ttyS5")){
        return RSRTX_OPT_DEV_ENUM::DEV_TTYS5;
    } else if(!strcasecmp(device_name,"/dev/ttyS6")){
        return RSRTX_OPT_DEV_ENUM::DEV_TTYS6;
    }
    return RSRTX_OPT_DEV_ENUM::RSRTX_OPT_DEV_ENUM_ENUM_END;
}

/**
 * 任務(wù)啟動函數(shù)
 */
int RawSerialRTX::start(int argc,char *argv[]){
    int baudrate = 57600;
    int datarate = 0;
    const char* device_name = nullptr;

        int uart_fd = -1;

    bool err_flag = false;
    int myoptind = 1;
    const char *myoptarg = nullptr;
    int ch;

    //解析命令
    while ((ch = px4_getopt(argc, argv, "b:r:d:n:u:o:m:t:c:fwxz", &myoptind, &myoptarg)) != EOF) {
        switch (ch) {
        case 'b':
            if (px4_get_parameter_value(myoptarg, baudrate) != 0) {
                PX4_ERR("baudrate parsing failed");
                err_flag = true;
            }

            if (baudrate < 9600 || baudrate > 3000000) {
                PX4_ERR("invalid baud rate '%s'", myoptarg);
                err_flag = true;
            }

            break;

        case 'r':

            if (px4_get_parameter_value(myoptarg, datarate) != 0) {
                PX4_ERR("datarate parsing failed");
                err_flag = true;
            }

            if (datarate > MAX_DATA_RATE) {
                PX4_ERR("invalid data rate '%s'", myoptarg);
                err_flag = true;
            }

            break;

        case 'd':
            device_name = myoptarg;
            break;

        default:
            err_flag = true;
            break;
        }
    }


    if(device_name==nullptr){
        PX4_ERR("serial device name must be setted.");
        err_flag = true;
    }

    uint8_t opt_dev_enum =getOptDevEnumByName(device_name);

    if(opt_dev_enum==RSRTX_OPT_DEV_ENUM::RSRTX_OPT_DEV_ENUM_ENUM_END){
        PX4_ERR("device name is name a serial port");
        err_flag = true;
    }

    int speedcode = RawSerialRTX::getSpeedCodeFormBuadrate(baudrate);
    if(speedcode == -EINVAL){
        err_flag = true;
    }

    if (err_flag ) {
        usage();
        return PX4_ERROR;
    }

    if (datarate == 0) {
        /* convert bits to bytes and use 1/2 of bandwidth by default */
        datarate = baudrate / 20;
    }

    if (datarate > MAX_DATA_RATE) {
        datarate = MAX_DATA_RATE;
    }

    PX4_INFO("data rate: %d B/s on %s @ %dB",datarate, device_name, baudrate);
    fflush(stdout);
    uart_fd = openUART(device_name,baudrate,speedcode);

    if(uart_fd < 0){
        return PX4_ERROR;
    }

    thread_should_exit = false;

    RawSerialRTX  *instance = new RawSerialRTX(baudrate,datarate,device_name,uart_fd);

    //開uORB訂閱線程
    instance->startTXThread();
    //循環(huán)不會退出推溃,除非thread_should_exit===true;
    instance->readUartLoop();
    //uartEcho(uart_fd,baudrate);
    //readUartLoop(uart_fd,baudrate,opt_dev_enum);
    delete instance;

    ::close(uart_fd);

    return PX4_OK;
}

RawSerialRTX::RawSerialRTX(int baudrate ,int datarate,const char* device_name , int uart_fd):
ModuleParams(nullptr),
_baudrate(baudrate),
_datarate(datarate),
_device_name(device_name),
_uart_fd(uart_fd)
{
    _opt_dev = getOptDevEnumByName(device_name);
}

RawSerialRTX::~RawSerialRTX(){

}

//讀取數(shù)據(jù)循環(huán),發(fā)布raw_serial_rx uORB消息
void RawSerialRTX::readUartLoop(){
    if(_uart_fd<0) return;

    //設(shè)置線程名
    char thread_name[64];
    sprintf(thread_name, "raw_serial_rtx:%s", _device_name);
    px4_prctl(PR_SET_NAME, thread_name, px4_getpid());

    struct raw_serial_rx_s rx_pkg = {};
    int chmin = 20;
    uint8_t buf[MAX_SERIAL_SIZE];
    int nread = 0;
    int tread = 0;
    const unsigned sleeptime = chmin * 1000000 / (_baudrate / 10);

    while(!thread_should_exit){

        nread = 0;
        tread = 0;
        //使用非阻塞讀取  O_NONBLOCK
        //一直讀取知道緩存讀滿或者外部數(shù)據(jù)發(fā)送結(jié)束
        while(nread<MAX_SERIAL_SIZE){
            tread = read(_uart_fd, buf+nread, MAX_SERIAL_SIZE-nread);
            if(tread>0) nread+=tread;
            else break;
            px4_usleep(sleeptime);
        }
        if(nread>0){

            rx_pkg.timestamp = hrt_absolute_time();
            rx_pkg.dev = _opt_dev;
            rx_pkg.len = nread;
            memcpy(rx_pkg.data,buf,nread);
            if(_raw_serial_rx_pub==nullptr){//如果一開始沒有提出advert或者沒有成功
                _raw_serial_rx_pub = orb_advertise(ORB_ID(raw_serial_rx),&rx_pkg);
            }
            if(_raw_serial_rx_pub!=nullptr){ //成功advertise之后才能發(fā)布昂利,不然系統(tǒng)會宕機(jī)
                orb_publish(ORB_ID(raw_serial_rx), _raw_serial_rx_pub, &rx_pkg);
            }
        }

        //數(shù)據(jù)接受完畢或者沒有數(shù)據(jù)時,以免過度使用占用cpu
        if(tread<1) px4_usleep(sleeptime);
    }


}


//開啟一個線程接收raw_serial_rx消息
void RawSerialRTX::startTXThread(){
    pthread_t _receive_thread {};
    pthread_attr_t txsubloop_attr;
    pthread_attr_init(&txsubloop_attr);

    struct sched_param param;
    (void)pthread_attr_getschedparam(&txsubloop_attr, &param);
    param.sched_priority = SCHED_PRIORITY_MIN;
    (void)pthread_attr_setschedparam(&txsubloop_attr, &param);

    pthread_attr_setstacksize(&txsubloop_attr, PX4_STACK_ADJUSTED(2840));
    pthread_create(&_receive_thread, &txsubloop_attr, RawSerialRTX::start_helper, (void *)this);

    pthread_attr_destroy(&txsubloop_attr);
}

//開線程要用到的工具函數(shù),必須是靜態(tài)的
void * RawSerialRTX::start_helper(void *instance){
    ((RawSerialRTX *) instance)->tx_check_update_thread();
    return  nullptr;
}

//線程接收訂閱raw_serial_tx消息
void  RawSerialRTX::tx_check_update_thread(){
    //設(shè)置線程名
    char thread_name[64];
    sprintf(thread_name, "raw_serial_tx:%s", _device_name);
    px4_prctl(PR_SET_NAME, thread_name, px4_getpid());

    int raw_serial_tx_sub = orb_subscribe(ORB_ID(raw_serial_tx));

    struct raw_serial_rx_s txpkg;

    px4_pollfd_struct_t fds[1];
    fds[0].fd = raw_serial_tx_sub;
    fds[0].events = POLLIN;

    while (!thread_should_exit)
    {
        //阻塞等待10ms
        int ret = px4_poll(fds, 1, 10);
        if (ret < 0) {
            break;
        } if(ret==0){
            continue;
        }

        bool updated;
        // 檢查消息更新
        orb_check(raw_serial_tx_sub, &updated);
        if (updated) {//如果更新了就取數(shù)據(jù)铁坎,并使用mavlink發(fā)送

            orb_copy(ORB_ID(raw_serial_tx), raw_serial_tx_sub, &txpkg);
            if(txpkg.dev==_opt_dev){
            ::write(_uart_fd, txpkg.data, txpkg.len);
            }
        }
    }
}

3.5 簡單測試

  • 涉及到mavlink蜂奸,在調(diào)試過程中最好使用Serial 5連USB轉(zhuǎn)UART,操作NSH硬萍,如果mavlink起不來扩所,QGC里也就看不見了,PX4調(diào)試說明
  • NSH top命令查看活動進(jìn)程,用綠線標(biāo)出朴乖,我們產(chǎn)生的進(jìn)程祖屏。兩個mavlink_serial_rx_ifx,接收串口守護(hù)進(jìn)程發(fā)送的rx消息,分別在USB和TELEM1上的兩個mavlink守護(hù)進(jìn)程上產(chǎn)生寒砖;raw_serial_rtx:/dev/ttyS6,ttyS6上的串口守護(hù)進(jìn)程赐劣,產(chǎn)生raw_serial_tx:/dev/ttyS6,接收mavlink守護(hù)進(jìn)程上收到的串口發(fā)送消息哩都。
FTOP.png
  • QGC 發(fā)送接收消息
FQGC.png
  • 串口收發(fā)
FUART.png
  • 串口收發(fā)短接魁兼,USB連接QGC,收發(fā)來回30+ms
FQECHOU.png
  • 串口收發(fā)短接,sik數(shù)傳@57600連接QGC咐汞,收發(fā)來回270+ms
FQECHOT.png

至此QGC PX4串口轉(zhuǎn)發(fā)全部功能實(shí)現(xiàn)完畢盖呼,感謝圍觀

傳送門: PX4 QGC透明串口轉(zhuǎn)發(fā)

1. PX4串口讀寫
2.自定義Mavlink消息實(shí)現(xiàn)QGC和PX4 mavlink守護(hù)進(jìn)程通信
3.自定義uORB消息實(shí)現(xiàn),實(shí)現(xiàn)PX4模塊間數(shù)據(jù)傳遞

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載化撕,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者几晤。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市植阴,隨后出現(xiàn)的幾起案子蟹瘾,更是在濱河造成了極大的恐慌,老刑警劉巖掠手,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件憾朴,死亡現(xiàn)場離奇詭異,居然都是意外死亡喷鸽,警方通過查閱死者的電腦和手機(jī)众雷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來做祝,“玉大人砾省,你說我怎么就攤上這事』旎保” “怎么了编兄?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纵隔。 經(jīng)常有香客問我翻诉,道長,這世上最難降的妖魔是什么捌刮? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮舒岸,結(jié)果婚禮上绅作,老公的妹妹穿的比我還像新娘。我一直安慰自己蛾派,他們只是感情好俄认,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著洪乍,像睡著了一般眯杏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上壳澳,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天岂贩,我揣著相機(jī)與錄音,去河邊找鬼巷波。 笑死萎津,一個胖子當(dāng)著我的面吹牛卸伞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播锉屈,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼荤傲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了颈渊?” 一聲冷哼從身側(cè)響起遂黍,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俊嗽,沒想到半個月后雾家,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乌询,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年榜贴,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妹田。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡唬党,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鬼佣,到底是詐尸還是另有隱情驶拱,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布晶衷,位于F島的核電站蓝纲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏晌纫。R本人自食惡果不足惜税迷,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锹漱。 院中可真熱鬧箭养,春花似錦、人聲如沸哥牍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗅辣。三九已至撼泛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澡谭,已是汗流浹背愿题。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抠忘。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓撩炊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親崎脉。 傳聞我的和親對象是個殘疾皇子拧咳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容