首页 > 其他分享 >mavlink(四)C库接口使用

mavlink(四)C库接口使用

时间:2023-09-17 10:56:05浏览次数:51  
标签:struct uint8 接口 mavlink packet 使用 msg buf

1. 库文件接口使用

1.1. 原理

编解码流程

发送方发送数据,需要经历组包->格式转换->发包(根据链路类型调用相关发送接口)的过程;
接收方接收数据,需要经历解包->msgId解析->具体消息处理的过程;

1.2. 接口

需要关注的重点是发送数据,接收数据的流程。Mavlink提供了几类接口,简化了应用层收发数据的操作。主要使用的接口如下:

发送相关接口 说明
mavlink_msg_xxx_pack 组包接口,按照协议封装数据,以mavlink_message_t结构对外提供,默认使用通道MAVLINK_COMM_0
mavlink_msg_to_send_bufffer 将mavlink_message_t结构体转换为buf
mavlink_finalize_message 内部组包接口,组除payload之外的其他数据,默认使用通道MAVLINK_COMM_0
mavlink_finalize_message_chan 内部组包接口,组除payload之外的其他数据,可指定通道
mavlink_msg_xxx_encode 组包接口,按照协议封装数据,以mavlink_message_t结构对外提供。源参数都过mavlink_xxx_t结构体提供
mavlink_msg_xxx_encode_chan 组包接口,同mavlink_msg_xxx_encode,但可以指定通道
mavlink_msg_xxx_pack_chan 组包接口,同mavlink_msg_xxx_pack,但可以指定通道
接收相关接口 说明
mavlink_parse_char 解析接收数据,按字节解析
mavlink_msg_xxx_decode 解包接口,将mavlink_message_t转换为mavlink_xxx_t结构体
mavlink_msg_xxx_get_yyy 获取结构体xxx的yyy字段数据

1.3. 结构体

MAVPACKED(
typedef struct __mavlink_message {
    uint16_t checksum;      ///< sent at end of packet
    uint8_t magic;          ///< protocol magic marker
    uint8_t len;            ///< Length of payload
    uint8_t incompat_flags; ///< flags that must be understood
    uint8_t compat_flags;   ///< flags that can be ignored if not understood
    uint8_t seq;            ///< Sequence of packet
    uint8_t sysid;          ///< ID of message sender system/aircraft
    uint8_t compid;         ///< ID of the message sender component
    uint32_t msgid:24;      ///< ID of message in payload
    uint64_t payload64[(MAVLINK_MAX_PAYLOAD_LEN+MAVLINK_NUM_CHECKSUM_BYTES+7)/8];
    uint8_t ck[2];          ///< incoming checksum bytes
    uint8_t signature[MAVLINK_SIGNATURE_BLOCK_LEN];
}) mavlink_message_t;

mavlink_message_t结构体参与组包和解包的过程,作为中间过程参数使用,也是mavlink数据帧格式的体现。结构体成员magic~signature的完全对应帧格式的字段,而checksum成员则作为中间参数,参与解包过程的校验和的计算过程。实际接收和发送的数据帧的校验和,存储在ck中。

typedef struct __mavlink_status {
    uint8_t msg_received;               ///< Number of received messages
    uint8_t buffer_overrun;             ///< Number of buffer overruns
    uint8_t parse_error;                ///< Number of parse errors
    mavlink_parse_state_t parse_state;  ///< Parsing state machine
    uint8_t packet_idx;                 ///< Index in current packet
    uint8_t current_rx_seq;             ///< Sequence number of last packet received
    uint8_t current_tx_seq;             ///< Sequence number of last packet sent
    uint16_t packet_rx_success_count;   ///< Received packets
    uint16_t packet_rx_drop_count;      ///< Number of packet drops
    uint8_t flags;                      ///< MAVLINK_STATUS_FLAG_*
    uint8_t signature_wait;             ///< number of signature bytes left to receive
    struct __mavlink_signing *signing;  ///< optional signing state
    struct __mavlink_signing_streams *signing_streams; ///< global record of stream timestamps
} mavlink_status_t;

mavlink_status_t结构体存储和记录了组包和解包的过程状态量,以及解包成功失败的统计信息。
各字段含义如下:

Element 说明
msg_received 接收状态量,取值为mavlink_framing_t枚举值,可为incomplete/ok/bad_crc/bad_signature
buffer_overrun payload长度溢出的包统计
parse_error 解包错误的包统计
parse_state 解包状态量,控制解包的状态机跳转,取值为mavlink_parse_state_t的枚举值
packet_idx Payload字段的数组下标,解析payload的时候每解析一字节则加1
current_rx_seq 解包时,当前包的seq字段
current_tx_seq 组包时,当前包的seq字段,每次递增1
packet_rx_success_count 解包成功统计值
packet_rx_drop_count 解析失败的包统计(当前1.0.12版本貌似没用上)
flags 标志位,用于标识版本信息,取值为MAVLINK_STATUS_FLAG_*宏
signature_wait 用于记录待接收的签名字段的字节数,初始为13,每收到一个签名字节减1
signing 用于数据签名
signing_streams 用于数据签名

1.4. 程序示例

发送数据帧:

/*Send Heartbeat */
mavlink_msg_heartbeat_pack(1, 200, &msg, MAV_TYPE_HELICOPTER, MAV_AUTOPILOT_GENERIC, MAV_MODE_GUIDED_ARMED, 0, MAV_STATE_ACTIVE);
len = mavlink_msg_to_send_buffer(buf, &msg);
bytes_sent = sendto(sock, buf, len, 0, (struct sockaddr*)&gcAddr, sizeof(struct sockaddr_in));

/* Send Status */
mavlink_msg_sys_status_pack(1, 200, &msg, 0, 0, 0, 500, 11000, -1, -1, 0, 0, 0, 0, 0, 0);
len = mavlink_msg_to_send_buffer(buf, &msg);
bytes_sent = sendto(sock, buf, len, 0, (struct sockaddr*)&gcAddr, sizeof (struct sockaddr_in));

/* Send Local Position */
mavlink_msg_local_position_ned_pack(1, 200, &msg, microsSinceEpoch(), 
                                position[0], position[1], position[2],
                                position[3], position[4], position[5]);
len = mavlink_msg_to_send_buffer(buf, &msg);
bytes_sent = sendto(sock, buf, len, 0, (struct sockaddr*)&gcAddr, sizeof(struct sockaddr_in));

/* Send attitude */
mavlink_msg_attitude_pack(1, 200, &msg, microsSinceEpoch(), 1.2, 1.7, 3.14, 0.01, 0.02, 0.03);
len = mavlink_msg_to_send_buffer(buf, &msg);
bytes_sent = sendto(sock, buf, len, 0, (struct sockaddr*)&gcAddr, sizeof(struct sockaddr_in));

也可以如下:

// heartbeat为mavlink_heartbeat_t类型,外部已经从其他途径获取到该结构体内容,或者自行填充好了该结构体
mavlink_msg_heartbeat_encode(1, 200, &msg, &heartbeat);
len = mavlink_msg_to_send_buffer(buf, &msg);
bytes_sent = sendto(sock, buf, len, 0, (struct sockaddr*)&gcAddr, sizeof(struct sockaddr_in));

接收数据帧:

memset(buf, 0, BUFFER_LENGTH);
recsize = recvfrom(sockS, (void *)buf, BUFFER_LENGTH, 0, (struct sockaddr *)&locAddr, &fromlen);
if (recsize > 0)
{
    // Something received - print out all bytes and parse packet
    mavlink_message_t msg;
    mavlink_status_t status;
    
    printf("Bytes Received: %d\nDatagram: ", (int)recsize);
    for (i = 0; i < recsize; ++i)
    {
        temp = buf[i];
        printf("%02x ", (unsigned char)temp);
        if (mavlink_parse_char(MAVLINK_COMM_0, buf[i], &msg, &status))
        {
            // Packet received
            printf("\nReceived packet: SYS: %d, COMP: %d, LEN: %d, MSG ID: %d\n", msg.sysid, msg.compid, msg.len, msg.msgid);
            switch(msg.msgid)
            {
                case MAVLINK_MSG_ID_HEARTBEAT:
                {
                    mavlink_heartbeat_t heartbeat;
                    mavlink_msg_heartbeat_decode(&msg, &heartbeat);
                    // HanldeHeartbeatMsg(heartbeat);
                    break;
                } 
                default:
                    break;
            }
        }
    }
    printf("\n");    
}

2. 参考链接

MAVLink学习之路05_MAVLink应用编程接口分析

标签:struct,uint8,接口,mavlink,packet,使用,msg,buf
From: https://www.cnblogs.com/hjx168/p/17707938.html

相关文章

  • 11.虚拟桌面基础设施: 使用OpenStack的Horizon模块,创建一个虚拟桌面基础设施,允许用户
    使用OpenStack的Horizon模块创建虚拟桌面基础设施可以让用户访问虚拟桌面环境,这通常使用VNC或其他远程桌面协议来实现。Horizon是OpenStack的Web管理界面,用于管理和监控OpenStack云资源。以下是一个简化的示例,演示如何使用Horizon来构建这样一个虚拟桌面基础设施。注意:为了构建这......
  • 如何使用 jest 测试使用 axios 的 httpClient?
    要使用Jest测试使用axios的httpClient,您可以使用Jest提供的模拟功能来伪造对外部API的请求和响应。下面是一个示例测试的代码:首先,安装所需的依赖:npminstallaxiosaxios-mock-adapterjest--save-dev然后,创建一个名为httpService.test.js的测试文件,编写以下代码:importaxiosfrom......
  • shell命令概述 Shell作用:命令解释器 介于操作系统内核与用户之间,负责解释命令行 获得
    shell命令概述Shell作用:命令解释器介于操作系统内核与用户之间,负责解释命令行获得命令帮助内部命令help命令的“--help”选项使用man命令阅读手册页命令行编辑的几个辅助操作Tab键:自动补齐反斜杠“\”:强制换行快捷键Ctrl+U:清空至行首快捷键Ctrl+K:清空至行尾快捷键Ctr......
  • shell命令概述 Shell作用:命令解释器 介于操作系统内核与用户之间,负责解释命令行 获得
    shell命令概述Shell作用:命令解释器介于操作系统内核与用户之间,负责解释命令行获得命令帮助内部命令help命令的“--help”选项使用man命令阅读手册页命令行编辑的几个辅助操作Tab键:自动补齐反斜杠“\”:强制换行快捷键Ctrl+U:清空至行首快捷键Ctrl+K:清空至行尾快捷键Ctr......
  • shell命令概述 Shell作用:命令解释器 介于操作系统内核与用户之间,负责解释命令行 获得
    shell命令概述Shell作用:命令解释器介于操作系统内核与用户之间,负责解释命令行获得命令帮助内部命令help命令的“--help”选项使用man命令阅读手册页命令行编辑的几个辅助操作Tab键:自动补齐反斜杠“\”:强制换行快捷键Ctrl+U:清空至行首快捷键Ctrl+K:清空至行尾快捷键Ctr......
  • C# Record类使用 注解Attribute JsonConverter
    用Record类的时候,声明成员很方便,但是想要用注解,要用下面这种方式: 和这种方式相同:JsonConverter使用需要创建一个class继承与JsonConverter<T>classJsonDoubleCvt:JsonConverter<double>{publicoverridedoubleRead(refUtf8JsonReaderreader,Typet......
  • vue3探索——pinia高阶使用
    以下是一些Pinia的其他高阶功能:storeToRefs():响应式解构仓库,保证解构出来的数据是响应式的数据。状态持久化:Pinia并没有内置的状态持久化功能,但你可以使用第三方库或自定义插件来实现状态的持久化。例如,你可以使用 localStorage 或 sessionStorage 来将状态保存在客户端......
  • springboot+html使用sql语句能够在控制台输出相关数据信息list,但是输出的list=null(未
    问题描述具体来说,就是,连接上数据库之后,发现查询的sql语句能够正常在控制台输出数据,但是将sql语句的查询结果放到list里面,在控制台输出的list=[null];真的崩溃了!!!之前从来没有遇到过这种情况;尝试了网上的各种方法,也都解决不了,麻木ing~求解!......
  • 合并果子题解-C++ STL priority_queue容器的使用
    说明:本博文关于priority_queue容器的说明来源于www.cnblogs.com/fusiwei/p/11823053.html本人是刚刚接触算法竞赛的萌新,如果有大佬发现了错误,还望指出(真的有人会看本蒟蒻的博文吗)这是我的第一篇博文,更多是作为测试以后会将博客作为笔记记录学习的体会基本概念priority_queu......
  • 抽象与接口
    就是可以不用在父的函数里面写东西,然后继承,但是子类里面一定要重写 创建点interface然后要实现接口就写implement  记住 记住 这个就是接口的一个语法规则,如图就是连续接俩  这边还是复习一下default,如果有新方法,程序员来不及改代码重写,就可以用default,来......