Robomaster大疆遥控器DT7&DR16介绍与C型开发板通信教程

文章目录
  • 一、遥控器DT7&DR16介绍
    • 1.DT7&DR16的使用
    • 2.DT7&DR16的连接
    • 3.DBUS协议
  • 二、DR16与C型开发板通信
    • 1.DR16数据帧解析
    • 2.cubemx配置以及串口DMA接收初始化
    • 3.数据帧解码
  • 三、效果展示

一、遥控器DT7&DR16介绍

1.DT7&DR16的使用

需要注意DT7遥控器很不耐摔,天线和拨杆都容易断,切记要保护好

DR16接收机输出的信号为标准的DBUS协议数据,当遥控器与接收机建立连接 后,接收机每隔14ms通过DBUS发送一帧18字节数据。数据内容包括左右两个摇杆的数据,左右上角的两个开关拨杆,以及左侧上方的云台俯仰控制拨轮。

2.DT7&DR16的连接

使用DT7&DR16套件前需要保证接收机和遥控器之间已经成功配对。

DR16上的LED指示灯一般有三种状态:红灯常亮,绿灯闪烁,绿灯常亮,对应的状态如下:

指示灯状态对应状态
红灯常亮未检测到遥控器
绿灯闪烁检测到遥控器,但未配对
绿灯常亮已与遥控器配对

配对方法为开启需要配对的遥控器,靠近正常工作的DR16,长按对频按键5s左右,然后松开,当指示灯常亮绿灯时便代表连接成功。(连接时确保周围没有开启的遥控器,不然会误连)

3.DBUS协议

接收机与接收机之间采用DBUS协议进行通信,信号电平为TTL电平,但是和UART是反相的,需要过一个反相器再输入到单片机的串口上进行接收。但是可以直接连接Robomaster的开发板上专门留给DR16接收机的接口,A板一般是串口1,C板是串口3,直接将接收机上引出的线对应连接即可,接口内置了反相器。DBUS与UART之间电平标准为反相关系,所以不能随意连接到其他串口。

接收时对照着DBUS参数表进行串口的参数设置。

一、DR16与C型开发板通信

1.DR16数据帧解析

我们日常使用中一般使用通道0到3的摇杆和S1,S2两个拨杆开关,摇杆数据为11字节,范围在1684到364,拨杆数据为2字节,范围在3到1。

开关拨杆S1和S2分别位于遥控器左右上角,但摇杆相反,例如通道0位于右摇杆的x轴,通道1位于右摇杆y轴。

2.cubemx配置以及串口DMA接收初始化

根据C板用户手册可知,C板的DBUS接口为UART3,并且波特率为100Kbps。

配置串口3并将波特率配置为100000并开启串口3NVIC.

为串口3添加一个DMA接收通道,并将模式改为轮询(Circular)

在.h文件中定义DBUS串口,预定义的数据缓冲区长度以及控制帧数据长度,以便后面使用。

#define DBUS_MAX_LEN     (50)
#define DBUS_BUFLEN      (18)
#define DBUS_HUART       huart3

定义一个长度为18字节的数组用于存储接收到的遥控器数据。 

uint8_t   dbus_buf[DBUS_BUFLEN];

配置UART以通过DMA接收数据

static int uart_receive_dma_no_it(UART_HandleTypeDef* huart, uint8_t* pData, uint32_t Size)
{//用于接收数据的函数,使用DMA方式来接收UART数据
  uint32_t tmp1 = 0;
  tmp1 = huart->RxState;
	//创建一个临时变量tmp1,并将UART的接收状态赋值给它
	if (tmp1 == HAL_UART_STATE_READY)//判断UART是否处于就绪状态
	{
		if ((pData == NULL) || (Size == 0))
		{
			return HAL_ERROR;
		}

		huart->pRxBuffPtr = pData;
		huart->RxXferSize = Size;
		huart->ErrorCode  = HAL_UART_ERROR_NONE;

		HAL_DMA_Start(huart->hdmarx, (uint32_t)&huart->Instance->DR, (uint32_t)pData, Size);
		//启动DMA接收,源地址为UART数据寄存器,目标地址为接收缓冲区
	
		SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);
		//使能UART的DMA接收功能
		return HAL_OK;
	}
	else
	{
		return HAL_BUSY;
	}
}
void dbus_uart_init(void)//DBUS串口初始化
{
	__HAL_UART_CLEAR_IDLEFLAG(&DBUS_HUART);//用于清除UART的空闲标志,空闲标志指示UART在接收数据时处于空闲状态,通常在接收完成后设置
	//清除这个标志是为了确保后续的接收操作能够正确检测到新的空闲状态
	__HAL_UART_ENABLE_IT(&DBUS_HUART, UART_IT_IDLE);//使能UART的空闲中断,当UART处于空闲状态并且接收缓冲区没有数据时,会触发这个中断
	//使能这个中断后,可以在中断服务例程中处理空闲状态
	uart_receive_dma_no_it(&DBUS_HUART, dbus_buf, DBUS_MAX_LEN);//调用之前的函数,用DMA来接收串口数据
}

配置好DBUS串口初始化函数后,在main函数中调用并初始化。

3.数据帧解码

在.h文件中定义名为rc_info_t的结构体,成员为遥控器数据解码后的内容。

typedef __packed struct
{
  int16_t ch0;
  int16_t ch1;
  int16_t ch2;
  int16_t ch3;
  int16_t roll;
  uint8_t sw1;
  uint8_t sw2;
} rc_info_t;

#define rc_Init   \
{                 \
		0,            \
		0,            \
		0,            \
		0,            \
		0,            \
		0,            \
		0,            \
}

定义以上面结构体为数据类型的变量rc,并赋初值0. 

rc_info_t rc = rc_Init;

遥控器解码数据,并将解码后的真正遥控器值存储到变量rc的结构体成员中。 

void rc_callback_handler(rc_info_t *rc, uint8_t *buff)
{//用于处理接收到的遥控器(rc)数据,将接收到的字节解码
  rc->ch0 = (buff[0] | buff[1] << 8) & 0x07FF;//将buff[0]和buff[1]的值组合为ch0通道的值,并将其限制在11位(通过与0x07FF按位与)
  rc->ch0 -= 1024;//由于数据在364到1684,将解码后的数据减去1024,使其中心值为0
  rc->ch1 = (buff[1] >> 3 | buff[2] << 5) & 0x07FF;
  rc->ch1 -= 1024;
  rc->ch2 = (buff[2] >> 6 | buff[3] << 2 | buff[4] << 10) & 0x07FF;
  rc->ch2 -= 1024;
  rc->ch3 = (buff[4] >> 1 | buff[5] << 7) & 0x07FF;
  rc->ch3 -= 1024;
  rc->roll = (buff[16] | (buff[17] << 8)) & 0x07FF;  //左上角滚轮
  rc->roll -= 1024;

  rc->sw1 = ((buff[5] >> 4) & 0x000C) >> 2;
  rc->sw2 = (buff[5] >> 4) & 0x0003;//sw1和sw2的值分别由相应的位计算得出
	
  if ((abs(rc->ch0) > 660) || \
      (abs(rc->ch1) > 660) || \
      (abs(rc->ch2) > 660) || \
      (abs(rc->ch3) > 660))
	  
  {
    memset(rc, 0, sizeof(rc_info_t));//如果任一通道的绝对值超过660,表示接收到异常数据,则将rc结构体的所有内容清零
  }		
}

 处理DBUS串口接收的数据,并通过空闲中断来解决接收随机长度数据的问题。

uint16_t dma_current_data_counter(DMA_Stream_TypeDef *dma_stream)
{//返回DMA预定义的缓冲区剩余的长度,方便了解传输过程中还有多少数据尚未传输
  return ((uint16_t)(dma_stream->NDTR));
}

static void uart_rx_idle_callback(UART_HandleTypeDef* huart)
{
	__HAL_UART_CLEAR_IDLEFLAG(huart);
	//清除UART的空闲标志,以便下一次接收时能够正确检测到空闲状态
	
	if (huart == &DBUS_HUART)//确保只处理DBUS串口
	{
		__HAL_DMA_DISABLE(huart->hdmarx);//失能DMA接收,防止下一次接收的数据在上一次数据的尾部,而不是全新的数据

		if ((DBUS_MAX_LEN - dma_current_data_counter(huart->hdmarx->Instance)) == DBUS_BUFLEN)
		{//计算当前接收的数据长度,如果接收到的数据长度等于18字节,则调用处理数据函数
			rc_callback_handler(&rc, dbus_buf);	//处理接收的数据并解码
		}
		__HAL_DMA_SET_COUNTER(huart->hdmarx, DBUS_MAX_LEN);//设置DMA接收预定义的缓冲区的长度,以便为下一次接收做好准备
		__HAL_DMA_ENABLE(huart->hdmarx);//重新启用DMA接收,以便继续接收数据
	}
}

使用回调函数来实现串口DMA空闲中断接收。 

void uart_receive_handler(UART_HandleTypeDef *huart)
{//用于检查UART接收状态并在接收到空闲状态时调用相应的回调函数
	if (__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) && //检查UART是否设置了空闲标志,表示UART接收完成并进入空闲状态
			__HAL_UART_GET_IT_SOURCE(huart, UART_IT_IDLE))//检查UART空闲中断是否被使能,只有在中断使能的情况下,才会处理空闲状态
	{
		uart_rx_idle_callback(huart);//调用之前定义的函数,处理接收到的数据
	}
}

 最后在cubemx生成的stm32f4xx_it.c中找到串口3中断服务函数,并调用之前写的回调函数来处理接收的数据。

void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
	uart_receive_handler(&huart3);//调用之前定义的函数,传入DBUS串口的地址,以处理接收事件
  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
  /* USER CODE BEGIN USART3_IRQn 1 */

  /* USER CODE END USART3_IRQn 1 */
}

3、效果展示

当我将遥控器配置为左拨杆中间,右拨杆下,可以看到S1值为3,S2值为2.将左摇杆摇到最左边时可以看到ch2为-660. 

要调用大疆DT7的DBus协议,您需要使用DBus编程接口来与DT7通信。DBus是一种用于进程间通信的系统总线,它是Linux上的一种标准机制。 在使用DBus时,您需要使用如下步骤: 1. 安装DBus库 您需要安装DBus库,例如libdbus-1-dev,以便能够使用DBus API。 2. 创建DBus连接 使用DBus API创建一个DBus连接,并指定要连接的服务名称和对象路径。 3. 发送DBus消息 使用DBus API向DT7发送DBus消息。您需要指定DBus消息的类、目标对象、方法名称以及参数列表。 4. 接收DBus消息 使用DBus API接收DT7返回的DBus消息。 5. 解析DBus消息 使用DBus API解析DBus消息,并从中提取所需的数据。 6. 断开DBus连接 使用DBus API断开与DT7的DBus连接。 这里提供一个简单的示例代码,用于向DT7发送一个DBus消息并接收其返回值: ``` #include <stdio.h> #include <stdlib.h> #include <dbus/dbus.h> int main(int argc, char **argv) { DBusConnection *conn; DBusError err; DBusMessage *msg, *reply; dbus_uint32_t serial = 0; const char *bus_name = "com.dji.dt7"; const char *object_path = "/com/dji/dt7"; const char *interface_name = "com.dji.dt7.Interface"; const char *method_name = "dt7_method"; dbus_bool_t ret; // Initialize error structure dbus_error_init(&err); // Connect to the bus conn = dbus_bus_get(DBUS_BUS_SESSION, &err); if (dbus_error_is_set(&err)) { fprintf(stderr, "Connection Error (%s)\n", err.message); dbus_error_free(&err); return EXIT_FAILURE; } // Request a name on the bus ret = dbus_bus_request_name(conn, bus_name, DBUS_NAME_FLAG_REPLACE_EXISTING, &err); if (dbus_error_is_set(&err)) { fprintf(stderr, "Name Error (%s)\n", err.message); dbus_error_free(&err); return EXIT_FAILURE; } if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) { return EXIT_FAILURE; } // Create a new message msg = dbus_message_new_method_call(bus_name, object_path, interface_name, method_name); if (NULL == msg) { fprintf(stderr, "Message Null\n"); return EXIT_FAILURE; } // Append arguments to the message if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &"Hello, DT7!", DBUS_TYPE_INVALID)) { fprintf(stderr, "Out Of Memory!\n"); return EXIT_FAILURE; } // Send the message and flush the connection if (!dbus_connection_send(conn, msg, &serial)) { fprintf(stderr, "Out Of Memory!\n"); return EXIT_FAILURE; } dbus_connection_flush(conn); // Free the message dbus_message_unref(msg); // Block until we receive a reply dbus_bus_add_match(conn, "type='signal',interface='org.freedesktop.DBus.Properties',member='PropertiesChanged'", &err); dbus_connection_flush(conn); if (dbus_error_is_set(&err)) { fprintf(stderr, "Match Error (%s)\n", err.message); dbus_error_free(&err); return EXIT_FAILURE; } reply = dbus_connection_pop_message(conn); if (NULL == reply) { return EXIT_FAILURE; } // Parse the reply if (!dbus_message_get_args(reply, &err, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) { fprintf(stderr, "Reply Null\n"); return EXIT_FAILURE; } // Print the reply printf("Reply: %s\n", str); // Free the reply and close the connection dbus_message_unref(reply); dbus_connection_close(conn); return EXIT_SUCCESS; } ``` 注意,这个示例只是演示如何使用DBus API向DT7发送DBus消息,并接收其返回值。实际上,DT7的DBus协议非常复杂,您需要根据具体的需求和协议文档编写相应的代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值