TOF测距(双冗余设计,串口模式)

        

目录

TOF介绍

 TOF工作模式

modbus数据格式

​TOF寄存器及示例 

双模块补偿测距

源码例程(部分)

注意


        好久没更新了,今天给大家分享一下近期在用的TOF模块的相关原理及使用方法。话不多说,直接进入正题。

TOF介绍

        TOF模块也分很多种类,在这里我使用的是TOF200F这一款。不同型号的有效测量距离不尽相同,其他的配置、测距原理都大同小异。如果有用到的话,可以根据需要购买适合自己使用的模块。下面是各类模块的选型表,因为工作需要,需要测量30cm以上的距离,又想要高精度,所以就用了TOF200F。 

 TOF工作模式

        TOF模块同时支持IIC和串口+modbus配置,用户可以利用提供的协议,自行配置其内部寄存器。也可以通过厂家提供的上位机直接赋值(简单粗暴!!!),相关资料可以点这里

modbus数据格式

TOF寄存器及示例 

        以上这些按照规格书上的配置就行,没什么好说的。我使用的是串口模式(主要是讨懒,但是当节点多的时候串口模式就不太行了!!!可以考虑转485或者使用iic模式)。

双模块补偿测距

        接下来说点有用的,在使用过TOF模块后不难发现:测距过程中存在盲区且随着测量距离的增加,偏角也会越来越大(准确的说是越来越宽)。当测量的距离足够远时,距离之间的变化是非常小的,哪怕障碍物移动了很长一截距离;另外,TOF测距其实就是利用光线反射实现测距的功能,众所周知,光线是散射的,TOF模块发射出的红外线不可能是成直线传播的,类似于手电筒,光线成“椎体”发出,那么垂直于发射区的障碍物的距离很有可能和“锥体”上的某些点的距离是相同的(斜边大于直边)。说的比较抽象,直接上图吧(算不算得上一个灵魂画手???)。

         现在要测量TOF到A点的距离,假设为20cm,那么有没有可能在TOF发射的这个锥形范围内还存在着20cm的B点呢?肯定是有的,并且外围的那个环形上的点到TOF的距离都是20cm。因为在测量的时候大多是测量的垂直距离,但是光线传播的时候是会发散的。不垂直的时候遇到障碍物一样会反射回来,然后计算出一个值,而这个值是有可能和你想要测得那个距离是一样的,这就造成了干扰!

        假如现在需要你做一个项目:你的手指在一个固定区域内点亮led1,在另外一个固定区域内点亮led2,你应该怎么办?垂直测量一个区域的距离肯定没有问题,但问题是你在伸出或者收回手指的时候,很有可能让模块捕获到了一个反射光,而最后计算出的结果也点亮了灯,但却不在你预先确定的区域内。这个时候就可以使用双模块测距,对于同一片区域,模块1会测得一个距离范围,模块2也可以测得一个范围(每个点都对应两个距离值),如果检测到手指到两个模块的距离都在预先确定好的范围内,就说明它很有可能就在那个区域内(不能保证100%,只是通过增加限制条件增大了手指在设定区域内的概率),如果想要更高的识别率的话,可以再多加一些模块,直接形成对射光幕,也可以通过滤波的方法减少杂波的影响(如:连续测距十次,取平均值,观察平均值是否在合理范围内)。

源码例程(部分)

我采用的是主从机通信,所以在这里并没有实现什么现象,只是给从机发了数据,哈哈。

#include "senser.h"
#include "delay.h"

uint16_t Time;
unsigned int test1; //debug测试
unsigned int test2;
extern unsigned char ucRxFinish1; //完成标志位
extern unsigned char ucRxFinish2;
extern unsigned char usart2_ucRxData[100]; //数据缓冲区
extern unsigned char usart3_ucRxData[100];
extern unsigned char CMD_1[8];
extern unsigned char CMD_2[8];

void Delay(void)
{
	unsigned int i=0;
	while(++i<1000);
}

void GetData(void)
{
	unsigned int uiData1;
	unsigned int uiData2;
	USART2_Send(CMD_1,8);
	USART3_Send(CMD_2,8);
	Time=0;
	while((Time<100)&&((ucRxFinish1==0)||(ucRxFinish2==0)))
	{
		Delay();
	}
	if(ucRxFinish1 && ucRxFinish2)
	{
		uiData1=usart2_ucRxData[3]<<8|usart2_ucRxData[4];
		uiData2=usart3_ucRxData[3]<<8|usart3_ucRxData[4];
		test1=uiData1;
		test2=uiData2;
		if((uiData1>=265 && uiData1<=325) && (uiData2>=173 && uiData2<=203))
		{
			USART1_SendByte('1');				
		}
		else if((uiData1>=302 && uiData1<=325) && (uiData2>=249 && uiData2<=265))
		{
			USART1_SendByte('2');			
		}
		else if((uiData1>=329 && uiData1<=345) && (uiData2>=280 && uiData2<=292))
		{
			USART1_SendByte('3');		
		}
		else if((uiData1>=350 && uiData1<=360) && (uiData2>=296 && uiData2<=303))
		{
			USART1_SendByte('4');
		}
		else
			USART1_SendByte('0');
//		printf("Sensor%d Distance:%d\r\n",usart2_ucRxData[0],uiData1);		
//		printf("Sensor%d Distance:%d\r\n",usart3_ucRxData[0],uiData2);	
	}
	ucRxFinish1=0;
	ucRxFinish2=0;
}

 对应的两个模块的配置函数如下,使用的是usart2和usart3(两个都是一样的,只贴一个吧)

#include "sys.h"
#include "usart2.h"	
#include "stm32f10x.h"
        
void USART2_Init(u32 bound){
    //GPIO端口设置
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能USART2,GPIOA时钟
 	USART_DeInit(USART2);  //复位串口2
	//USART2_TX   PA.2
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.9
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
   
    //USART2_RX	  PA.3
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10

   //Usart2 NVIC 配置

	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置
	USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	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_Cmd(USART2, ENABLE);                    //使能串口 

}


unsigned char ucRxFinish1=0;
static unsigned char ucCnt=0,ucLen=0;
unsigned char usart2_ucRxData[100];
void USART2_IRQHandler(void)                	
{
	unsigned char temp=0;
	u16 C=0;

	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  
		{
		  temp=USART_ReceiveData(USART2);
			
			if(ucCnt==0)
				usart2_ucRxData[ucCnt++]=temp;
			else if((ucCnt==1)&(temp==0x03))
				usart2_ucRxData[ucCnt++]=temp;
			else if(ucCnt==2)
			{
				usart2_ucRxData[ucCnt++]=temp;
				ucLen=usart2_ucRxData[2];
			}
			else if((ucCnt>2)&(ucCnt<=(ucLen+4)))
				usart2_ucRxData[ucCnt++]=temp;
			if(ucCnt==(ucLen+5))
			{  
				C=ModbusCRC(usart2_ucRxData,ucLen+3);
				if(C==((usart2_ucRxData[ucLen+3]<<8)|usart2_ucRxData[ucLen+4]))
				{
					ucRxFinish1=1;	
					ucCnt=0;ucLen=0;
				}			
				else 
				{
					ucCnt=0;
					ucLen=0;
				}				
			}
			
		}
	  USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}   		 
 
	

void USART2_Send(unsigned char *data,uint8_t ucLen)
{
	uint8_t i;
	USART_ClearFlag(USART2,USART_FLAG_TC);
	for(i=0;i<ucLen;i++)
	{
		USART_SendData(USART2,*(data+i));
		while(USART_GetFlagStatus(USART2,USART_FLAG_TC) == RESET);
	}
}

uint16_t ModbusCRC(uint8_t *ptr,uint16_t ucLen)//CRC校验
{
	uint8_t i;
	uint16_t j,crc=0xffff;
	
	i=i;	
	
	for(int n=0;n<ucLen;n++)
	{
		crc=ptr[n]^crc;
		for(int i=0;i<8;i++)
		if(crc&0x01)
		{
			crc=crc>>1;
			crc=crc^0xa001;
		}
		else
		{
			crc=crc>>1;	
		}		
	}

	j=crc>>8;
	j=j|(crc<<8);
	return j;

}

注意

        最好不要拿TOF模块去测量到透明物体的距离,障碍物反射光的能力越强,测距效果越好。如果想要在结构上去除干扰,可以考虑把模块四周用黑色物体遮挡起来,这样就减小了光的散射面(理论上是这样,还没有尝试!)。另外,每个模块对应的散射角度是固定的,那么偏移距离也是可以计算出来的,如下图

  如果错误,欢迎提出!

  

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈大本事er

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值