一、激光雷达简介

笔者使用的激光雷达为亚博智能YDLIDAR SDM15。
YDLIDAR SDM15 激光雷达是一款高性能单点激光雷达(以下简称:SDM15)。本产品基于飞行时间测距原理,并配以相关光学、电学、算法设计,实现高精度激光距离测量,并输出高帧率的点云据。可用于无人机定高、机器人避障、导航等。测量距离为 50mm-15m。

二、接线部分

在这里插入图片描述
从左到右依次为:
黄线:RX : 通信串口的输入口
黑线:GND: 供电接口(负极) 0v
绿线:TX : 通信串口的输出口
红线:VCC: 供电接口(正极) 5V * (低于5v测量的数据不准确,高于5V可能会烧坏激光雷达) *

三、模式

YDLIDAR SDM15 单点激光雷达(以下简称 SDM15)的系统设置了 3 种工作模式:空闲模
式、测距模式、停机模式。
➢ 空闲模式:SDM15 上电时,默认为空闲模式;空闲模式时,SDM15 的测距单元不工作,激
光器不亮。
➢ 测距模式:当 SDM15 进入测距模式时,点亮激光器,实时输出测距数据。
➢ 停机模式:当 SDM15 运行有错时,如测距异常,自检不过等状况,SDM15 会自动关闭测距
单元,并反馈错误代码。

四、系统通信

(一)通信机制

SDM15 是通过串口来和外部设备进行命令和数据的交互。当外部设备发送一个系统命令
至 SDM15,SDM15 解析系统命令,会返回相应的应答报文,并根据命令内容,来切换相应的工
作状态,外部系统根据报文内容,解析报文,便可获取应答数据。

(二)系统命令

外部系统通过发送相关的系统命令,便可设置 SDM15 相应的工作状态,获取相应的数据。SDM15 对外发布的系统命令如下:

命令 描述 模式切换 应答模式
0x60 开启测距 测距模式 持续应答
0x61 停止测距 停机模式 单次应答
0x62 获取版本信息 不切换 单次应答
0x63 雷达自检 不切换 单次应答
0x64 设置输出频率 不切换 单次应答
0x65 设置滤波 不切换 单次应答
0x66 设置串口波特率 不切换 单次应答
0x67 设置输出数据格式 不切换 单次应答
0x68 恢复出厂设置 不切换 单次应答

(三)系统报文

系统报文是系统根据接收的系统命令反馈的应答报文,不同的系统命令,系统报文的应答模式和应答内容也不一样,其中应答模式有三种:无应答、单次应答和持续应答。无应答表示系统不反馈任何报文;单次应答表示系统的报文长度是有限的,应答一次即结束;持续应答表示系统的报文长度是无限长的,需要持续发送数据,如进入测距模式时。单次应答和持续应答的报文采用同一个数据协议,其协议内容为:包头、包类型、数据长度、数据段和校验码,通过串口 16 进制输出。
YDLIDAR SDM15 系统报文数据协议

包头 包类型 数据长度 数据段 校验码
2 Bytes 1 Byte 1 Byte N Bytes 1 Byte

➢ 包头:SDM15 的报文包头标志为 0x55AA;
➢ 包类型:系统命令的类型
➢ 数据长度:表示的是应答数据的长度;
➢ 数据段:不同系统命令下的应答内容,反馈不同的数据内容,其数据格式也不同;
➢ 校验码:校验码(CheckSum),除去校验码以外的其他所有数据的和校验。

SDM15 的数据通信采用的是小端模式,低位在前。

五、编程实验

cube

USART1(与上位机进行通信)
在这里插入图片描述
USART2(与激光雷达进行通信)
在这里插入图片描述
这里波特率设置为460800是因为默认波特率就是460800我没有管他
时钟树
在这里插入图片描述

记得开启外部高速晶振和USART2的全局中断

keil

由于官方给的demo是STM32F103C8T6而且是用标准库写的代码。而我用的是STM32F407ZGT6而且是用HAL库写的,所以没办法直接cv。不过我会保留一部分官方的源码[doge]。
SMD15.c
首先把官方给的SMD15.c和SMD15.h文件整个弄过去,需要修改的部分如下:

delay_ms(200);->HAL_Delay(200);

USART2
官方的USART2的单独封装成.c.h文件,我的usart1和usart2是和到一起的
在usart2初始化函数里要手动开启中断

  HAL_UART_Receive_IT(&huart2, (uint8_t*)&RX_buffer, 1);  //手动开启中断

void USART2_Send_U8(uint8_t Data)
{
	while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
		;
	USART_SendData(USART2, Data);
}

修改为下面的代码

void USART2_Send_U8(uint8_t Data)
{
	HAL_UART_Transmit(&huart2, (uint8_t *)&Data, 1, 1000);	
//	HAL_UART_Transmit(&huart1, (uint8_t *)&Data, 1, 1000);	
	if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_TC) )
	{
		//printf("I have Transmit Data\r\n");
	}
}

HAL库查看usart串口状态的函数是__HAL_UART_GET_FLAG()
串口中断回调函数

void USART2_IRQHandler(void)
{
	if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
	{
		uint8_t Rx2_Temp = USART_ReceiveData(USART2);
		SDM15_Decode(Rx2_Temp);
//		USART2_Send_U8(Rx2_Temp);
	}
}

修改为下面的代码

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART2)
    {
		//printf("%d\r\n",RX_buffer);		
		SDM15_Decode(RX_buffer);
    }		
    HAL_UART_Receive_IT(&huart2, (uint8_t*)&RX_buffer, 1);
}

六、实验结果

在这里插入图片描述

补充

(一)memset

memset 是一个C语言标准库函数,其功能是将一块内存中的每个字节都设置为一个特定的值。该函数通常被用于初始化数据结构中的内存块,例如字符数组、整型数组、结构体等等。
memset 函数的原型如下:
void *memset(void *ptr, int value, size_t num);

  • ptr 是指向要设置的内存块的指针,该内存块的大小至少为 num。
  • value 是要将内存块的每个字节设置为的值,它的取值范围是 0 到 255,通常用十六进制表示,例如 0x00 表示零、0xFF 表示 255 等等。
  • num 是要设置的字节数,即要将 ptr 指向的内存块中的前 num 个字节都设置为 value。
    memset 函数的返回值是指向 ptr 的指针,即返回指向被设置内存块的指针。如果函数调用成功,则返回值与 ptr 相等。
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE 10
int main()
{
  int array[ARRAY_SIZE];
  memset(array, 0, sizeof(int) * ARRAY_SIZE);
  printf("The array contents:\n");
  for (int i = 0; i < ARRAY_SIZE; i++) 
{
    printf("%d ", array[i]);
  }
  printf("\n");
  return 0;
}

在上面的例子中,首先定义了一个整型数组 array,其大小为 ARRAY_SIZE。然后,调用 memset 函数将 array 中的所有元素都设置为零。最后,使用一个循环打印出 array 中的所有元素。
需要注意的是,使用 memset 函数时需要确保 ptr 所指向的内存块大小至少为 num,否则可能会发生内存访问越界等错误。此外,当使用 memset 函数时,value 参数是一个整数类型,而不是字符类型。

(二)前缀 _Bool

前缀 _Bool 是 C99 标准中定义的布尔类型,其取值只能是 0 或 1,分别表示 false 和 true。在 C99 之前,C语言没有内置的布尔类型,通常使用整型变量来模拟布尔类型。但是这种方式并不够安全和直观,因为整数类型的取值范围比布尔类型要大,不易于阅读和维护代码。C99 引入了 _Bool 类型,使得布尔类型的操作更加方便和直观。

(三)strstr()

strstr()是一个C语言函数,用于在一个字符串中查找另一个字符串的第一次出现。它的函数原型为:
char* strstr(const char* str1, const char* str2);
其中,str1表示要查找的字符串,str2表示要在str1中查找的字符串。如果找到了str2在str1中的第一次出现,返回指向该位置的指针;如果没有找到,返回NULL指针。

(四)implicit declaration of function

这个问题其实是很低级的问题,但是经常还是容易发生,翻译下就是西数的隐式说明
有两种情况会产生这种情况
1没有把函数所在的c文件生成.0目 文件
2在西数所在的c文件中定义了,但是没有在与之相关联的.h文件中声明

(五)Over Sampling

在STM32F407微控制器上,USART是一种用于串行通信的外设。在使用CubeMX配置USART时,有一个名为"Over Sampling"的选项。
Over Sampling(过采样)是指在USART的接收端,将输入的数据信号进行多次采样以获得更准确的信号值。在USART中,过采样可以设置为8或16,这表示接收端将对输入信号进行8或16次采样以获得一个符号。
如果过采样设置为8,则USART将对每个输入数据位进行8次采样,以获得每个数据位的最精确的值。过采样值为16时,将对每个数据位进行16次采样。
较高的过采样值可以提供更高的采样精度,但也会增加处理器的负载。在选择过采样值时,应该考虑到所需的精度和处理器的性能。在STM32F407微控制器上,USART是一种用于串行通信的外设。在使用CubeMX配置USART时,有一个名为"Over Sampling"的选项。
Over Sampling(过采样)是指在USART的接收端,将输入的数据信号进行多次采样以获得更准确的信号值。在USART中,过采样可以设置为8或16,这表示接收端将对输入信号进行8或16次采样以获得一个符号。
如果过采样设置为8,则USART将对每个输入数据位进行8次采样,以获得每个数据位的最精确的值。过采样值为16时,将对每个数据位进行16次采样。
较高的过采样值可以提供更高的采样精度,但也会增加处理器的负载。在选择过采样值时,应该考虑到所需的精度和处理器的性能。

在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐