基于无人机边沿相关 ------- IBUS、SBUS协议和PPM信号

news2024/11/15 4:12:13

文章目录

  • 一、IBUS协议
  • 二、SBUS协议
  • 三、PPM信号


一、IBUS协议

IBUS(Intelligent Bus)是一种用于电子设备之间通信的协议,采用串行通信方式,允许多设备通过单一数据线通信,较低延迟,支持多主机和从机结构,常用于遥控器与天空端之间,富斯官网已公开协议,协议格式如下可见:
在这里插入图片描述
一共32字节,2 字节帧头+28字节数据位 + 2字节校验位组成

解码如下:

#define IBUS_USER_CHANNELS		10		
#define IBUS_LENGTH				0x20	
#define IBUS_COMMAND40			0x40	
#define IBUS_MAX_CHANNLES		14

uint8_t rx_buffer[32] = {0};
uint16_t channel[IBUS_USER_CHANNELS] = {0};
uint16_t checksum_cal, checksum_ibus;

void IBUS_READ_CHANNEL(uint8_t user_channels)
{
	uint16_t channel_buffer[IBUS_MAX_CHANNLES] = {0};

	if(rx_buffer[0] == IBUS_LENGTH && rx_buffer[1] == IBUS_COMMAND40)
	{
		checksum_cal = 0xffff - rx_buffer[0] - rx_buffer[1];

		for(int i = 0; i < IBUS_MAX_CHANNLES; i++)
		{
			channel_buffer[i] = (uint16_t)(rx_buffer[i * 2 + 3] << 8 | rx_buffer[i * 2 + 2]);
			checksum_cal = checksum_cal - rx_buffer[i * 2 + 3] - rx_buffer[i * 2 + 2];
		}

		checksum_ibus = rx_buffer[31] << 8 | rx_buffer[30];

		if(checksum_cal == checksum_ibus)
		{
			for(int j = 0; j < user_channels; j++)
			{
				channel[j] = channel_buffer[j];
			}
		}
	}

	HAL_UART_Receive_IT(IBUS_UART, rx_buffer, 32);
}

二、SBUS协议

SBUS(Serial Bus)也是一种用于遥控模型、无人机和其他应用程序中的串行通信协议,特别是在飞控系统和遥控设备之间,以实现高效的数据传输。

采用串行通信,单线信号传输,支持最多16个通道的控制,实时性强,可反向兼容PWM,设计考虑冗余性。

协议格式共有25字节数据,由首部(1字节)+ 数据(22字节)+ 标志位(1字节)+ 结束符(1字节)组成

  • 帧头: 0x0F
  • 数据: 22 字节的数据,分别代表16个通道的数据,也即是每个通道的值用了 11 位来表示,22x8/16 = 11,每个通道的取值范围为 0~2047,低位在前、高位在后
  • 标志位: 1字节,高四位从高到低依次表示:
    bit7:CH17数字通道
    bit6:CH16数字通道
    bit5:帧丢失(Frame lost)
    bit4:安全保护(Failsafe):失控保护激活位(0x10)判断飞机是否失控
    bit3~bit0:低四位不用
  • 结束符: 0x00

通道解析:
在这里插入图片描述
解码如下:

#define USART_BUF_SIZE      8       
#define SBUS_DATA_SIZE      25      
struct SBUS_t{
    uint8_t head;                   // 1字节帧头
    uint16_t ch[16];                // 16个通道数据
    uint8_t flag;                   // 1字节标志位
    uint8_t end;                    // 1字节结束
};

uint8_t usart_buf[USART_BUF_SIZE];
uint8_t sbus_rx_head = 0;               // 发现起始字节 0x0F
uint8_t sbus_rx_sta = 0;                // sbus 接收状态,0:未完成,1:已完成一帧接收
uint8_t sbus_rx_index;                  // 接收字节计数
uint8_t sbus_rx_buf[SBUS_DATA_SIZE];    // 接收sbus数据缓冲区

struct SBUS_t sbus;                     // SBUS 结构体实例化


void USART2_IRQHandler(void)                                            //中断函数
{
    uint8_t chr;
    if ((__HAL_UART_GET_FLAG(&UART2_Handler, UART_FLAG_RXNE) != RESET)) // 接收中断
    {
       
        HAL_UART_Receive(&UART2_Handler, &chr, 1, 1000);                // 接收一个字符

        if (sbus_rx_sta == 0)                                           // 接收未完成
        {
            if ((chr == 0x0F) || sbus_rx_head)                          // 找到首字节或已经找到首字节
            {
                sbus_rx_head = 1;                                       // 标明已经找到首字母
                if (sbus_rx_index < SBUS_DATA_SIZE)                     // 未接收到25个字符
                {
                    sbus_rx_buf[sbus_rx_index] = chr;                   // 不断接收
                    sbus_rx_index ++;
                }
                else                                                    // 接收到25个字符了
                {
                    sbus_rx_sta = 1;                                    // 接收完成
                    sbus_rx_head = 0;                                   // 清零,准备下一次接收
                    sbus_rx_index = 0;
                }
            }
        }
    }
    HAL_UART_IRQHandler(&UART2_Handler);
}
   
/* 对SBUS协议数据进行解析                                                      */
/* 实现对S.BUS协议缓存,头部为 0x0F,结尾为 0x00, 中间22Bytes16通道数据,1Byte标志符 */
void SbusParseTask(void *arg)
{
    while (1)
    {
        if(sbus_rx_sta==1)                          // 接收完一帧
        {
           
            NVIC_DisableIRQ(USART2_IRQn);           // 要关闭中断,防止读写混乱
           
            sbus.head = sbus_rx_buf[0];             // 首部
            sbus.flag = sbus_rx_buf[23];            // 标志符
            sbus.end  = sbus_rx_buf[24];            // 结尾

            sbus.ch[0] =((sbus_rx_buf[2]<<8)  + (sbus_rx_buf[1])) & 0x07ff;          
            sbus.ch[1] =((sbus_rx_buf[3]<<5)  + (sbus_rx_buf[2]>>3)) & 0x07ff;
            sbus.ch[2] =((sbus_rx_buf[5]<<10) + (sbus_rx_buf[4]<<2) + (sbus_rx_buf[3]>>6)) & 0x07ff;
            sbus.ch[3] =((sbus_rx_buf[6]<<7)  + (sbus_rx_buf[5]>>1)) & 0x07ff;
            sbus.ch[4] =((sbus_rx_buf[7]<<4)  + (sbus_rx_buf[6]>>4)) & 0x07ff;
            sbus.ch[5] =((sbus_rx_buf[9]<<9)  + (sbus_rx_buf[8]<<1) + (sbus_rx_buf[7]>>7)) & 0x07ff;  
            sbus.ch[6] =((sbus_rx_buf[10]<<6) + (sbus_rx_buf[9]>>2)) & 0x07ff;
            sbus.ch[7] =((sbus_rx_buf[11]<<3) + (sbus_rx_buf[10]>>5)) & 0x07ff;
            sbus.ch[8] =((sbus_rx_buf[13]<<8)  + sbus_rx_buf[12]) & 0x07ff;
            sbus.ch[9] =((sbus_rx_buf[14]<<5)  + (sbus_rx_buf[13]>>3)) & 0x07ff;
            sbus.ch[10]=((sbus_rx_buf[16]<<10) + (sbus_rx_buf[15]<<2) + (sbus_rx_buf[14]>>6)) & 0x07ff;
            sbus.ch[11]=((sbus_rx_buf[17]<<7)  + (sbus_rx_buf[16]>>1)) & 0x07ff;
            sbus.ch[12]=((sbus_rx_buf[18]<<4)  + (sbus_rx_buf[17]>>4)) & 0x07ff;
            sbus.ch[13]=((sbus_rx_buf[20]<<9)  + (sbus_rx_buf[19]<<1) + (sbus_rx_buf[18]>>7)) & 0x07ff;
            sbus.ch[14]=((sbus_rx_buf[21]<<6) + (sbus_rx_buf[20]>>2)) & 0x07ff;
            sbus.ch[15]=((sbus_rx_buf[22]<<3) + (sbus_rx_buf[21]>>5)) & 0x07ff;
           
            delay_ms(500);                          // 先做完延时再开启中断与下一次捕获,否则延时期间中断到来,没有达到预期效果
            NVIC_EnableIRQ(USART2_IRQn);            // 打开串口中断
            sbus_rx_sta = 0;                        // 准备下一次接收   
        }
        else
        {
            delay_ms(500);                          // 免得异常时,到此处使得低优先级任务无法执行
        }
    }
}

三、PPM信号

PPM(Pulse Position Modulation,脉冲位置调制)信号是一种用于传输控制信号的调制方式,尤其在遥控系统中非常常见。PPM信号通过改变脉冲在时间上的位置来代表不同的信息,在遥控模型、无人机和一些工业控制系统中被广泛应用。

采用串行通信,信号频率只有50Hz,略逊于ibus和sbus,对于一些高精度仪器不可用。

这里提一下,PWM表示脉冲宽度调制,也就是高电平维持的时间,而PPM实质上就是将多个通道的PWM放到“一根线”上进行传输,一个完整的PPM信号帧包含了多个通道的PWM值。
在这里插入图片描述
PPM信号一帧数据分为低电平(0.5ms)+高电平(0.5ms-1.5ms),高电平长度与PWM占空比成正比。因为一帧信号最多要2ms,信号周期为20ms,所以理论一次PPM信号可以发送10帧数据,但是由于要确定帧头信号,所以要加入同步帧,真正的PPM信号里面最多有9帧数据帧。

解析方式:①外部中断 ②定时器输入捕获

考虑安全条件下,建议使用定时器输入捕获方式进行解码,具体解码参考如下:

uint16_t PPM_Sample_Cnt=0;
uint32_t PPM_Time=0;
uint16_t PPM_Okay=0;
uint16_t PPM_Databuf[8]={0};   //PPM信号存储
uint8_t TIM2_CH2_CAPTURE_STA=0;

void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_IT_CC2)==!RESET)//捕获中断
	{
		if(TIM2_CH2_CAPTURE_STA&0x01)//符合条件的话说明上次捕获了高电平,那么这次捕获的一定是低电平
		{
			PPM_Time=TIM_GetCapture2(TIM2);
			if(PPM_Time>0)
				PPM_Time++;			
			if(PPM_Okay==1)
			{
				PPM_Databuf[PPM_Sample_Cnt]=PPM_Time;
				PPM_Sample_Cnt++;
				if(PPM_Sample_Cnt>8)
					PPM_Okay=0;
			}
			if(PPM_Time>7000)//识别到帧尾
			{
				PPM_Okay=1;
				PPM_Sample_Cnt=0;
			}    

				TIM_OC2PolarityConfig(TIM2,TIM_ICPolarity_Rising);
				TIM2_CH2_CAPTURE_STA=0;//清掉标志位准备开始下一次上升沿和下降沿检测
		}
			else
			{
				TIM_SetCounter(TIM2,0);//以上为清零            
				TIM2_CH2_CAPTURE_STA|=0x01;//高电平指示被赋值
				TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //当捕获上升沿后改为捕获下降沿
			}        
	}
	
	TIM_ClearITPendingBit(TIM2, TIM_IT_CC2|TIM_IT_Update); //清除中断标志位,一定不要忘,要不然下次进不了中断    
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2071494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis | Django小项目之Mysql数据库和Redis缓存的应用

Django小项目 需求整体架构图技术细节环境配置各文件配置settings.pyurls.pyviews.pyuser_update.html 结果相关代码补充r.hgetall(cacahe_key)new_data {k.decode():v.decode() for k,v in data.items()} 需求 整体架构图 技术细节 环境配置 django-admin startprojrct rmysi…

WIFI 应用层代码

1.0 定义枚举类型 typedef enum {WIFI_COMM_WAIT, // AT 等待命令WIFI_COMM_OK, // AT 命令完成WIFI_COMM_FALL, // AT 命令失败 }WifiCommState_t; 注&#xff1a;该枚举类型的作用是&#xff0c;定义三个成员变量&#xff0c;分别表示AT指令等待发送&#xff0c;AT指令…

unity游戏开发——(细)深入解析 Unity 地形系统:从基础到高级应用

Unity游戏开发 “好读书&#xff0c;不求甚解&#xff1b;每有会意&#xff0c;便欣然忘食。” 本文目录&#xff1a; Unity游戏开发 Unity游戏开发前言深入解析 Unity 地形系统&#xff1a;从基础到高级应用一、初识 Unity 地形系统1. 地形尺寸与分辨率 二、地形编辑工具详解1…

下拉菜单 匹配搜索

操作版本&#xff1a;Excel 2010 下拉菜单 涉及到的函数&#xff1a; INDIRECT函数&#xff1a;返回由文本字符串指定的引用 原文链接 一级下拉菜单 方法一&#xff1a;手动输入 选中要制作下拉菜单的单元格区域&#xff0c;单击【数据】-【数据有效性】-【序列】&#…

15.CentOS7升级内核

升级内核 1.配置镜像源 vim /etc/yum.repos.d/elrepo.repo[elrepo] nameelrepo baseurlhttps://mirrors.aliyun.com/elrepo/archive/kernel/el7/x86_64 gpgcheck0 enabled12.备份 cd /etc/yum.repos.d/ mv local.repo repo.bak/ 3.清缓存 yum clean all 4.升级内核 yum ins…

背部筋膜炎最好的恢复办法

背部筋膜炎是由于寒冷、精神紧张、潮湿或慢性劳损等因素造成的背部肌筋膜和肌组织发生水肿、纤维变性和渗出&#xff0c;其主要症状包括&#xff1a; 1、疼痛&#xff1a;患者通常会出现背部疼痛&#xff0c;这种疼痛在着凉或劳累时可能会加重。晨起时疼痛可能尤为明显&#x…

将两对象(重复属性不替换)合并成一个对象

将这两个对象合并成一个对象 const obj1 {"configType": "all","config": {"a":1} };const obj2 {"target_cluster": "dev-0821","type": "import","config": {"connector…

攻防世界-web题型-4星难度汇总-个人wp

Confusion1 进入页面查看源代码&#xff0c;发现有两个提示 访问第一个源码里面有个 /opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt /opt/salt_b420e8cfb8862548e68459ae1d37a1d5.txt 不过我发现好像是只要访问404页面都有这两个。。。 另外这两个admin和login页面都没用…

如何把照片转换成PDF格式?分享3种好用的PDF转换方法

在数字化的时代中&#xff0c;各种格式的文件已经是我们平时办公中不可或缺的一部分&#xff0c;其中尤其是以图片、PDF这两种文件使用的最多&#xff0c;图片能够更加直观的表现内容&#xff0c;而PDF文档因其稳定性、兼容性等特性&#xff0c;也在办公中有独特的优势&#xf…

Pandas DataFrame的创建方法(Create DataFrame)

pandas是一个第三方数据分析库&#xff0c;其集成了大量的数据模型和分析工具&#xff0c;可以方便的处理和分析各类数据。其中主要对象类型有Series&#xff0c;DataFrame和Index。本文介绍DataFrame对象的基本创建方法。 关于DataFrame的基础用法&#xff0c;可以查看下面的…

随机生成n个字节os.urandom(n)

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 随机生成n个字节 os.urandom(n) [太阳]选择题 下列输出结果中正确的是? import os print("【执行】a os.urandom(2)") a os.urandom(2) print("【显示】a ", a) pri…

【Qt】输入类控件QDail

目录 输入类控件QDail 例子&#xff1a;调整窗口不透明度 输入类控件QDail 使用QDail表示一个旋钮&#xff0c;通过鼠标拖动旋钮可以完成一些相关的属性。 核心属性 属性说明 value 持有的数值. minimum 最⼩值 maximum 最⼤值 singleStep 按下⽅向键的时候改变的步⻓…

【Java数据结构】---二叉树OJ

乐观学习&#xff0c;乐观生活&#xff0c;才能不断前进啊&#xff01;&#xff01;&#xff01; 我的主页&#xff1a;optimistic_chen 我的专栏&#xff1a;c语言 &#xff0c;Java 欢迎大家访问~ 创作不易&#xff0c;大佬们点赞鼓励下吧~ 文章目录 相同的树另一颗树的子树翻…

与copilot 结对编程系列 - log日志重复性检测 - 第4篇 - 网页UI界面

背景 细节可以参考这篇文章: 与copilot 结对编程系列 - log日志重复性检测 - 第1篇 - 总体介绍及效果展示 本文主要将数据库中存储的数据通过网页调用并展示出来, 以下是对详细解释。 web框架选择 当前场景使用 Flask 来展示网页信息. 主要原因如下&#xff1a; 轻量级和易…

如何使用JavaScript获取HTML表单中的值?

在开发中&#xff0c;我们经常需要获取用户在表单中输入的数据&#xff0c;然后进行处理或提交到服务器。今天我们就来聊一聊&#xff0c;如何用JavaScript获取HTML表单中的值。 使用 FormData 构造函数 FormData 是一个非常方便的工具&#xff0c;它可以把表单中的所有数据打包…

C++,std::chrono 详解

文章目录 1. 概述2. 时间点&#xff08;Time Points&#xff09;3. 时间间隔&#xff08;Durations&#xff09;4. 时钟&#xff08;Clocks&#xff09;5. 时间算术6. 时间转换7. 延时参考 1. 概述 std::chrono 是 C11 引入的一个库&#xff0c;用于处理日期和时间。它提供了一…

Unsloth 教程 - 如何微调 Llama-3并导出到 Ollama

本文翻译整理自&#xff1a;&#x1f999; How to Finetune Llama-3 and Export to Ollama https://docs.unsloth.ai/tutorials/how-to-finetune-llama-3-and-export-to-ollama 文章目录 1、什么是Unsloth&#xff1f;2、什么是Ollama&#xff1f;3、安装Unsloth4、选择要微调的…

博弈论总结

公平组合游戏&#xff08;Impartial Game&#xff09;的定义如下&#xff1a; 游戏有两个人参与&#xff0c;二者轮流做出决策&#xff0c;双方均知道游戏的完整信息&#xff1b; 任意一个游戏者在某一确定状态可以作出的决策集合只与当前的状态有关&#xff0c;而与游戏者无关…

pytorch深度学习基础 6(简单的参数估计学习3)

上一篇博客说了如何拟合一条直线ywxb&#xff0c;今天我们现在使用PyTorch进行相同的曲线拟合 拟合y x*x -2x 3 0.1(-1到1的随机值) 曲线 给定x范围&#xff08;0&#xff0c;3&#xff09; 生成数据 import numpy as np import matplotlib.pyplot as plt import torch as t…

小程序学习day13-API Promise化、全局数据共享(状态管理)、分包

44、API Promise化 &#xff08;1&#xff09;基于回调函数的一部API的缺点&#xff1a;小程序官方提供的异步API都是基于回调函数实现的&#xff0c;容易造成回调地狱的问题&#xff0c;代码可读性、可维护性差 &#xff08;2&#xff09;API Promise化概念&#xff1a; 指…