Pixhawk原生固件PX4之串口读取信息

欢迎交流~ 个人 Gitter 交流平台,点击直达:Gitter


这篇博客纯粹出于对FreeApe这位先行者贡献的复现,也是本人一直想要进行的一项操作。在此还是做一下记录。时代在改变,代码在更新,有些坑先填一填。

说明

本意是采用串口的方式添加一个自定义传感器——超声波。

已知的是超声波模块是通过串口方式发送(Tx)出数据,使用的模块数据发送周期为100ms,数据格式为:

R0034 R0122 R0122 R0046 R0127 R0044 R0044 R0125 R0034 R0037 R0041 R0122 R0122 .....

则可以通过Pixhawk板上的串口来接收(Rx)数据,即将超声波的Tx接口连接到Pixhawk板上的Rx接口。 这个想法就目前来说是非常好并且实施相对最简单的,毕竟PX4源码框架很大,十分复杂,在其原有的基础上改代码需要对这套系统有着很深的理解,所有初学者确实可以采用这种“协同”的方式连入到Pixhawk,可能用一个外部运算能力强的处理器算出姿态或位置或视觉数据经过串口发送到Pixhawk中,怎么把这些数据融合进原生算法那就另说了。

OK,继续主题,Pixhawk板上串口说明如下:

NuttX UARTPixhawk UART
/dev/ttyS0IO DEBUG(RX ONLY)
/dev/ttyS1TELEM1(USART2)
/dev/ttyS2TELEM2(USART3)
/dev/ttyS3GPS(UART4)
/dev/ttyS4N/A(UART5, IO link)
/dev/ttyS5SERIAL5(UART7,NSH Console Only)
/dev/ttyS6SERIAL4(UART8)

测试使用Pixhawk板上TELEM2接口的USART2,对应的Nuttx UART设备文件尾/dev/ttyS2:

pix

对于的各接口线序可以从这里查看,其中Pixhawk接口最左边为Vcc,最右边是GND。

  • TELEM1, TELEM2
PinSignalVolt
1 (red)VCC+5V
2 (blk)TX (OUT)+3.3V
3 (blk)RX (IN)+3.3V
4 (blk)CTS (IN)+3.3V
5 (blk)RTS (OUT)+3.3V
6 (blk)GNDGND
  • GPS
PinSignalVolt
1 (red)VCC+5V
2 (blk)TX (OUT)+3.3V
3 (blk)RX (IN)+3.3V
4 (blk)CAN2 TX+3.3V
5 (blk)CAN2 RX+3.3V
6 (blk)GNDGND
  • SERIAL 4/5
PinSignalVolt
1 (red)VCC+5V
2 (blk)TX (#4)+3.3V
3 (blk)RX (#4)+3.3V
4 (blk)TX (#5)+3.3V
5 (blk)RX (#5)+3.3V
6 (blk)GNDGND

读取数据测试

步骤:

1. Firmware/src/modules中添加一个新的文件夹,命名为rw_uart,并创建C文件rw_uart.c

/* 
 * 串口读取函数
 * rw_uart.c 
 */
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#include <drivers/drv_hrt.h>
#include <string.h>
#include <systemlib/err.h>
#include <systemlib/systemlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

__EXPORT int rw_uart_main(int argc, char *argv[]);

static int uart_init(char * uart_name);
static int set_uart_baudrate(const int fd, unsigned int baud);

int set_uart_baudrate(const int fd, unsigned int baud)
{
    int speed;

    switch (baud) {
        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;
        default:
            warnx("ERR: baudrate: %d\n", baud);
            return -EINVAL;
    }

    struct termios uart_config;

    int termios_state;

    /* 以新的配置填充结构体 */
    /* 设置某个选项,那么就使用"|="运算,
     * 如果关闭某个选项就使用"&="和"~"运算
     * */
    tcgetattr(fd, &uart_config); // 获取终端参数

    /* clear ONLCR flag (which appends a CR for every LF) */
    uart_config.c_oflag &= ~ONLCR;// 将NL转换成CR(回车)-NL后输出。

    /* 无偶校验,一个停止位 */
    uart_config.c_cflag &= ~(CSTOPB | PARENB);// CSTOPB 使用两个停止位,PARENB 表示偶校验

     /* 设置波特率 */
    if ((termios_state = cfsetispeed(&uart_config, speed)) < 0) {
        warnx("ERR: %d (cfsetispeed)\n", termios_state);
        return false;
    }

    if ((termios_state = cfsetospeed(&uart_config, speed)) < 0) {
        warnx("ERR: %d (cfsetospeed)\n", termios_state);
        return false;
    }
    // 设置与终端相关的参数,TCSANOW 立即改变参数
    if ((termios_state = tcsetattr(fd, TCSANOW, &uart_config)) < 0) {
        warnx("ERR: %d (tcsetattr)\n", termios_state);
        return false;
    }

    return true;
}


int uart_init(char * uart_name)
{
    int serial_fd = open(uart_name, O_RDWR | O_NOCTTY);
    /*Linux中,万物皆文件,打开串口设备和打开普通文件一样,使用的是open()系统调用*/
    // 选项 O_NOCTTY 表示不能把本串口当成控制终端,否则用户的键盘输入信息将影响程序的执行
    if (serial_fd < 0) {
        err(1, "failed to open port: %s", uart_name);
        return false;
    }
//    printf("Open the %s\n",serial_fd);
    return serial_fd;
}

int rw_uart_main(int argc, char *argv[])
{
    char data = '0';
    char buffer[4] = "";
    /*
     * TELEM1 : /dev/ttyS1
     * TELEM2 : /dev/ttyS2
     * GPS    : /dev/ttyS3
     * NSH    : /dev/ttyS5
     * SERIAL4: /dev/ttyS6
     * N/A    : /dev/ttyS4
     * IO DEBUG (RX only):/dev/ttyS0
     */
    int uart_read = uart_init("/dev/ttyS2");
    if(false == uart_read)
        return -1;
    if(false == set_uart_baudrate(uart_read,9600)){
        printf("[JXF]set_uart_baudrate is failed\n");
        return -1;
    }
    printf("[JXF]uart init is successful\n");

    while(true){
        read(uart_read,&data,1);
        if(data == 'R'){
            for(int i = 0;i <4;++i){
                read(uart_read,&data,1);
                buffer[i] = data;
                data = '0';
            }
            printf("%s\n",buffer);
        }
    }

    return 0;
}

具体的实现过程请查看irmware/src/drivers/hott/comms.cpp,里面是关于串口的设置,设计到NuttX这个类Unix操作系统的文件系统了,小白有点难啃。

2. rw_uart文件夹中创建CMakeLists.txt文件,并输入以下内容:

set(MODULE_CFLAGS)
px4_add_module(
    MODULE modules__rw_uart
    MAIN rw_uart
    COMPILE_FLAGS
        -Os
    SRCS
        rw_uart.c
    DEPENDS
        platforms__common
    )
# vim: set noet ft=cmake fenc=utf-8 ff=unix : 

3. 注册新添加的应用到NuttShell中。Firmware/cmake/configs/nuttx_px4fmu-v2_default.cmake文件中添加如下内容:

modules/rw_uart

add

4. 编译并上传固件

make px4fmu-v2_default upload

5. 读取测试

  • 查看app
    • 在NSH终端中输入help,在Builtin Apps中出现rw_uart应用。
      nsh
  • 运行rw_uart应用(前提是模块与Pixhawk连接好)

    wire

  • 设置好发送装置
    这里我使用的是秉火STM32开发板的USART1给Pixhawk的TELEM2发送对应的字符串。根据代码,数据的格式要求很严格,不然很可能得不到数据,博主开始设置让串口疯狂的发Rxxxx,结果速度太快是不行的,后来给加了一个延时函数,更新频率设置为20Hz,有时候还是会有乱码出现。各位进行设置的时候需要注意波特率对应,数据格式按要求来。

int main(void)
{   

    /* USARTx config 9600 8-N-1 */
    USARTx_Config();    

    /* 配置SysTick为每10us中断一次 */
    SysTick_Init();

    printf("R1000 ");

  for(;;){
        int i = 1000;
        for(i=1001;i<2000;i++)
        {
            printf("R%d ",i);
            Delay_us(5000); // 5000*10us = 50ms
        }
    }
}
  • 运行rw_uart应用,查看打印数据。
    why

有点不尽人意……

后面一定要改得人性化一点。


                                          By Fantasy

  • 10
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
### 回答1: 原生Android TV固件是指运行原生Android操作系统的电视设备的固件。与传统的定制化操作系统不同,原生Android TV固件基于Google开源的Android操作系统,提供了更纯净的用户体验和更丰富的功能。 原生Android TV固件的优势在于其稳定性和兼容性。由于采用了原生Android操作系统,它能够充分利用Google官方提供的最新更新和安全补丁,保证系统的稳定运行。同时,原生Android TV固件与其他Android设备具有高度的兼容性,可以轻松与各种应用和设备进行连接和交互,提供更广阔的应用选择和功能拓展空间。 此外,原生Android TV固件还提供了丰富的媒体功能和智能化体验。它支持高清视频播放、声音输出和网络连接,可以通过各种应用快速访问流媒体服务和在线视频内容。另外,原生Android TV固件还具有语音控制和智能推荐功能,用户可以通过语音命令轻松控制电视和应用,智能推荐算法也能够根据用户的观看习惯和喜好提供个性化的内容推荐。 然而,原生Android TV固件也有一些限制。由于操作系统的开放性和多样性,某些应用可能不适配或无法在原生Android TV上运行。此外,原生Android TV固件在硬件方面对电视设备的要求较高,低端设备可能无法提供流畅的使用体验。 总体而言,原生Android TV固件是一种值得推荐的选择,它提供了更稳定、兼容和智能化的电视体验,让用户能够享受到更多的媒体和应用内容。 ### 回答2: 原生Android TV固件是指由Google官方开发和维护的操作系统软件,专门为智能电视设备设计的。它采用了与智能手机和平板电脑相似的Android操作系统,并针对大屏幕和遥控器进行了优化。 原生Android TV固件具有以下特点: 1. 用户界面:原生Android TV固件提供了一个简洁、直观的用户界面,用户可以通过遥控器轻松地导航和操作电视。主屏幕上的应用图标和内容推荐帮助用户快速访问他们喜欢的应用和媒体内容。 2. 应用和媒体内容:原生Android TV固件兼容众多电视应用和媒体服务,包括影片、音乐、游戏和社交媒体等。用户可以通过Google Play商店下载和安装各种应用程序,以满足他们的个性化需求。 3. 语音控制:原生Android TV固件支持语音搜索和语音操作,用户可以通过麦克风遥控器或是电视内置的语音识别功能轻松实现语音控制。 4. 联网功能:原生Android TV固件可以通过内置的Wi-Fi或有线网络连接到互联网,用户可以浏览网页、观看在线视频和进行网络游戏等。 5. 兼容性:原生Android TV固件具有良好的兼容性,可与各种电视设备和外部设备(如音频系统、游戏手柄等)配对使用,并通过HDMI接口提供高清视频输出。 总之,原生Android TV固件为用户提供了一个全面的智能电视体验,结合了丰富的应用和媒体内容、简单直观的界面、语音控制和联网功能。它使用户能够轻松访问他们的喜爱内容,并提供了个性化、智能化的娱乐和信息服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值