1 激光雷达工作原理
大多数激光雷达采用光学三角测距技术,配合精密光学视觉采集处理机构,进行高频测距,每次测量过程中,激光雷达发射经过调制的红外激光信号,该激光信号经目标物体漫反射后被激光雷达的光学视觉采集系统接收,再由激光雷达内部处理器实时数据分析,计算出目标物体到雷达的距离以及当前的夹角,最后通过通讯接口输出到外部设备。
购买链接:https://item.taobao.com/item.htm?spm=a1z09.2.0.0.4b202e8dE6nkNG&id=572130646200&_u=m1m2a10q521f
雷达是旋转测量一周,扫描得到周围一圈均匀分布点的信息(点的角度和距离)。SDK就是接收解析数据,得到每一圈点的信息。一圈360°被平均分为16帧上报扫描信息帧,所以得到16 帧的每帧起始角度分别是0°、22.5°、45°、67.5°、90°…270°、292.5°、315、337.5°、360°。16 帧数据加起来是完整一圈,一圈的总点数=16*每帧的点数;每帧的总点数根据扫描信息帧计算距离个数可以得到(距离个数=总点数)。每帧数据点的信息(角度和距离):一帧中第N 个点的距离是扫描信息帧中N 距离值,那一帧中第N 个点距离对应的角度=此帧起始角度+(N-1)*22.5/(每帧的总点数),这样就得到一帧点的角度和距离。
2 激光雷达通讯
实验使用的激光雷达的接口以及通讯方式如下,采用TTL串口通讯方式将数据输出到外部设备中去。
通讯帧结构
通讯帧由帧头、帧长度、协议类型、命令字、参数长度、参数、校验码组成,
主要用于外部设备和激光雷达之间的通讯,测量信息和故障信息的上传。
帧头: 固定为0xAA;
帧长度:是通讯帧的长度,帧长度计算是从帧头开始,到校验位前一字节(16 位无符号数, 低位在前,高位在后);
协议版本: 当前协议版本号(8 位无符号数);
命令字:命令字占1 Byte;
Bit7: 通讯错误标志;
Bit6: 通讯方向标志:0:主机---> 雷达; 1: 雷达---> 主机;
Bit0 ~ Bit5: 是命令标识符;
参数长度:通讯帧中参数的长度(16 位无符号数, 低位在前,高位在后);
参数:命令的有效数据;
校验位:是从帧头开始到校验位前一字节的异或。(16 位无符号数,低位前,高位在后);
举例:
AA 0A 00 04 56 03 00 01 CC 03 E1 01
AA:帧头标识。
0A 00:帧长度为0x000A(即10)字节(不包含校验位)
04:协议版本
56:通讯方向(0x40)+命令字(0x16)
03 00:有效数据长度0x0003
01:故障代码失速异常
CC 03:雷达转速0x03CC(972),即972*0.01(分辨率) = 9.72r/s
E1 01:校验码为0x01E1=(AA+0A+…+CC+03)
3 MDK程序开发
制作了一个demo程序,使用USART1和激光雷达进行数据通讯,使用USART2作为打印串口,扫描一圈有512个数据点,打印第20到第50个数据点的角度和距离。
3.1 main.c编写
int main(void)
{
uint16_t i=0;
uint16_t N=20;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
USART1_Init(230400);
USART2_Init(115200);
Lidarscaninfo_Init();
SetLidarWorkMode(_8K_SCAN_MODE);
printf("one circle point num:%d\n",lidarscaninfo.OneCriclePointNum);
printf("one circle point num:%d\n",lidarscaninfo.OneCriclePointNum);
while(1)
{
ProcessUartRxData();
if(lidarscaninfo.Result == LIDAR_GRAB_SUCESS)
{
lidarscaninfo.Result=LIDAR_GRAB_ING;
printf("Point: \t\t\t Angle\t\t\t Distance\t\t\n");
for(N=20;N<51;N++)
{
printf("%d\t\t\t %5.2f\t\t\t %5.2f\t\t\n",
N,
lidarscaninfo.OneCriclePoint[N].Angle,
lidarscaninfo.OneCriclePoint[N].Distance);
if(N==50)
{
printf("Point: \t\t\t Angle\t\t\t Distance\t\t\n");
N=20;
ProcessUartRxData();
}
}
}
}
}
/*设置雷达工作模式*/
void SetLidarWorkMode(uint8_t workmode)
{
uint8_t i=0;
uint16_t Len=0;
T_PROTOCOL Preq;
Preq.Header=FRAME_HEAD;
Preq.Len=7+1;
Preq.ProtoVer=PROTO_VER;
Preq.CmdId=PC_TO_LD|CMD_SET_WORK_MODE;
Preq.ParamLen=1;
Len = Preq.Len+2;
Big2LittleEndian_u16(Preq.Len);
Big2LittleEndian_u16(Preq.ParamLen);
memcpy(TxBuffer.Buff,&Preq,7);
TxBuffer.Buff[7]=workmode;
Preq.CheckSum=Calc_Pack_Checksum(TxBuffer.Buff,&TxBuffer.Buff[7],Len);
TxBuffer.Buff[8]=Preq.CheckSum&0xFF;
TxBuffer.Buff[9]=Preq.CheckSum>>8;
for(i=0;i<Len;i++)
{
USART_SendData(USART1,TxBuffer.Buff[i]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //µÈ´ý·¢ËÍÍê
}
}
3.2 USART配置
/*初始化数据传送串口1*/
void USART1_Init(int baud)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_DeInit(USART1);
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
USART_Cmd(USART1, ENABLE);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
USART_ClearITPendingBit(USART1, USART_IT_IDLE);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void USART1_IRQHandler(void)
{
volatile u8 Temp;
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) != RESET)
{
UartReceive(USART1->DR);
USART_ClearFlag(USART1,USART_FLAG_RXNE);
}
if(USART_GetFlagStatus(USART1,USART_FLAG_IDLE) != RESET)
{
RxDataComplete();
USART_ClearFlag(USART1,USART_FLAG_IDLE);
}
Temp = USART1->SR;
Temp = USART1->DR;
}
void RxDataComplete(void)
{
if((RxBuffer.Rdy == 0)&&(RxBuffer.Len > 0))
{
if(RxBuffer.Len > 3)
RxBuffer.Rdy = 1;
else
RxBuffer.Len = 0;
}
}
void UartReceive(u8 data)
{
if(RxBuffer.Rdy == 0)
{
RxBuffer.Buff[RxBuffer.Len++] = data;
if(RxBuffer.Len >= sizeof(RxBuffer.Buff))
RxBuffer.Rdy = 1;
}
}
/*初始化打印串口2*/
void USART2_Init( int baud2)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_DeInit(USART2);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); //³õʼ»¯NVIC¼Ä´æÆ÷
USART_InitStructure.USART_BaudRate = baud2;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
USART_Cmd(USART2, ENABLE);
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
USART_ClearITPendingBit(USART2, USART_IT_IDLE);
}
int fputc(int ch, FILE *f)
{
USART_SendData(USART2, (uint8_t) ch);
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
return (ch);
}
4实验结果分析
由于拿着激光雷达不停晃动,打印出的数据有些混乱,甚至有部分错误,暂时就不去处理了,读者理解即可,这里也只是演示一下就行了。
(谢谢大家,欢迎关注指正)