【分享帖】北京理工大学DreamChaser战队-遥控&键鼠控制总结
大家好,由于想要获取补报步兵射击对抗和工程攀岛取弹的报名资格,故分享一下遥控&键鼠控制的心得,欢迎大家评论交流~~
遥控通信总结
一、概述
在逛论坛的时候发现还没有同学对遥控部分内容做过比较详细的整理,因此在这里做一个遥控器&键鼠的通讯和控制上的总结,主要包括硬件、通讯格式、解码和一些小tips,便于以后的同学学习,本人也是第一年参加比赛,欢迎各路大神在下方留言补充纠正~
二、硬件&通信介绍
RM比赛中各个参赛队伍使用的都是大疆官方提供的遥控器套装,包括遥控器和接收机,接收机上共三个引脚:VCC,GND,DBUS(数据通道),首次使用需要进行遥控器和接收机配对,在两者都上电的情况下短按接收机上的对频按键即可(位于指示灯旁边)。在官方更新了遥控器的固件版本之后,遥控器上手轮也已经开放。
遥控器通讯采用的是2.4GHz频段的DBUS通讯协议(这里不对DBUS进行过多阐释了,有兴趣的同学可以自行学习),接收机工作电压为4-8.4V,输出信号满足TTL电平,但是为负逻辑,因此接收机和单片机之间需要加反相器来获得正确的数据(官方开发板的USART1接口已经集成)。
接收机的数据发送周期为14ms,每次发送18字节数据,和单片机通过串口通信,通信参数如下:

1.jpg



2.jpg



三、解码
遥控器的数据每一帧为18个字节,采用串口接收,每个字节都用CPU处理效率较低,因此考虑使用DMA,串口中断使能IDLE(线路空闲),当一帧数据接收完毕之后触发串口中断,调用DMA进行接收。官方手册提供了基于标准库的串口&DMA配置以及解码函数,在这里只贴出中断服务函数(HAL库)以及解码函数,串口和DMA略去。
代码实现(如果要使用请提前定义相关变量):
1.中断服务函数
voidRemotreCtl_Data_Receive(void)
{
uint32_t rx_data_len = 0;
if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)!=RESET)) //判断一帧数据是否接收完成
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1); //清空IDLE标志位
(void)USART1->SR; //清空SR寄存器
(void)USART1->DR; //清空DR寄存器
__HAL_DMA_CLEAR_FLAG(&hdma_usart1_rx,DMA_FLAG_TCIF2_6); //清除DMA传输完成标注
HAL_UART_DMAStop(&huart1); //停止DMA接收
rx_data_len=BSP_USART1_DMA_RX_BUF_LEN-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//数据量
HAL_UART_Receive_DMA(&huart1,USART1_DMA_RX_BUF, BSP_USART1_DMA_RX_BUF_LEN); //读数据
if(rx_data_len== 18) //如果数据量正确,则进行解码
{
RC_DataHandle(USART1_DMA_RX_BUF);
}
}
}
2.解码函数
voidRC_DataHandle(uint8_t *pData)
{
if(pData == NULL)
{
return;
}
/*pData[0]为ch0的低8位,Data[1]的第三位为ch0的高三位*/
RemoteCtrlData.remote.ch0 =((uint16_t)pData[0] | (uint16_t)pData[1] << 8) & 0x07FF;
/*pData[1]的高5位为ch1的低五位,pData[2]的低6位为ch1的高6位*/
RemoteCtrlData.remote.ch1 = ((uint16_t)pData[1] >> 3 |(uint16_t)pData[2] << 5) & 0x07FF;
/*pData[2]的高2位为ch3的低二位,pData[3]为ch3的3~10位,pData[4]的最低位为ch3的最高位*/
RemoteCtrlData.remote.ch2 = ((uint16_t)pData[2] >> 6 |(uint16_t)pData[3] << 2 | (uint16_t)pData[4] << 10) & 0x07FF;
/*pData[4]的高7位为ch4的低7位,pData[5]的低4位为ch4的高4位*/
RemoteCtrlData.remote.ch3 = ((uint16_t)pData[4] >> 1 |(uint16_t)pData[5] << 7) & 0x07FF
/*pData[5]的高8位为S1*/
RemoteCtrlData.remote.s1 = ((pData[5] >> 6) &0x03);
/*pData[5]的6、7位为s2*/
RemoteCtrlData.remote.s2 = ((pData[5] >> 4) &0x03);
/*pData[6]和pData[7]鼠标x方向*/
RemoteCtrlData.mouse.x = ((int16_t)pData[6] |(int16_t)pData[7] << 8);
/*pData[8]和pData[9]为鼠标Y方向*/
RemoteCtrlData.mouse.y = ((int16_t)pData[8] | (int16_t)pData[9] << 8);
/*pData[10]和pData[11]为鼠标Z方向*/
RemoteCtrlData.mouse.z = ((int16_t)pData[10] | (int16_t)pData[11] << 8);
/*pData[12]为鼠标左键*/
RemoteCtrlData.mouse.press_l = pData[12];
/*pData[13] 为鼠标右键*/
RemoteCtrlData.mouse.press_r = pData[13];
/*pData[14]和pData[15]为键盘*/
RemoteCtrlData.key.v = ((int16_t)pData[14]) |((int16_t)pData[15] << 8);
}
四、键鼠控制的小tips
键鼠控制和遥控器有所不同,接收机发送频率较高,按键存在延时,按下一个键该键值会被置高一段时间,并且在中断中不能通过延时来解决该问题。

3.jpg

按下按键之前

4.jpg

短暂按下按键之后
基本上短按都会持续 7~14次接收周期, 所以如果想要用按键做模式切换的话,至少需要延时20个接收周期,也就是在第一次接收到这个键之后20次接收中断中不再对这个键进行解码,因为模式切换通常来说不会在短时间内进行,所以我建议1S之内都不对这个按键进行解码,从而实现可靠模式切换。

2019年1月30日
北京理工大学
RM战队电控组整理


遥控&amp;键鼠控制总结.pdf

关联专栏
电控开源专栏
电控开源专栏
请问这篇文章对你有用吗?
【分享帖】北京理工大学DreamChaser战队-遥控&键鼠控制总结
所有评论
暂无更多
暂无更多
关于作者
BITDreamChaser
BITDreamChaser
0 关注Ta
0 文章
0 经验值
0 获赞
关联专栏
电控开源专栏
电控开源专栏