一、激光雷达简介
笔者使用的激光雷达为亚博智能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次采样。
较高的过采样值可以提供更高的采样精度,但也会增加处理器的负载。在选择过采样值时,应该考虑到所需的精度和处理器的性能。