1. PPT自动切换模块简介
本模块利用北醒公司两台TFmini Plus、Arduino DUE板、一个低功率红外激光指向灯、两个LED指示灯、一个单向开关、一个双向开关和连接线结合设计。
系统作用:通过检测人的手势,操作PPT的上一页、下一页切换。
2. 试验设备及接线
2.1 实验设备
-
Benewake TFmini Plus 标品
TFmini Plus(如图2.1所示),详细参数见TFmini Plus使用说明;
本模块用来检测人的手势,当手或者手臂扫过时,测距状态发生改变。
-
Arduino DUE板
本模块使用DUE板检测雷达1和雷达2的测距状态,并利用自带的USB通信实现HID功能。
Arduino DUE板(如图2.2所示),详细介绍和学习,请参考以下两个网站:
中文社区:http://www.arduino.cn/;
英文官网:http://www.arduino.cc/。
-
激光指示灯
如图2.3所示,为红外激光指示灯,用来指示雷达的工作方向和大致区域。
具体说明参考:https://m.tb.cn/h.eml6WNY?sm=032032
-
LED灯
如图2.4所示,为LED灯,用来指示模块功能状态:绿灯为功能开启,红灯为功能关闭。
-
单向开关
如图2.5所示,为单向开关,用来控制红外激光指示灯的打开和关闭。
-
双向开关
- 电脑
如图2.7所示,作为该系统的上位机,用来编写程序并上传到DUE板,并为模块供电。 - 连接线
如图2.8所示,为杜邦线和USB数据线。
杜邦线——用于TFmini Plus与UNO板连接;
USB数据线——用于DUE板与电脑连接、供电。
2.2 接线
如图2.9所示,为PPT切换模块的接线图,接线需要注意一下几个方面:
(1) TFmini Plus供电电压为5V,直接连接Arduino DUE板的5V和GND,其他雷达需查阅产品规格书,确保供电正常;
(2) 雷达1(RX,TX)连接DUE板的(TX3,RX3); 雷达2(RX,TX)连接DUE板的(TX1,RX1);
(3) 功能指示灯连接23,25引脚,通过检测开关状态,对应功能指示灯的关闭和打开。当功能打开时,绿灯亮起;功能关闭时,红灯亮起;
3. PPT切换原理及注意事项
- 注意事项
(1) TFmini Plus的采样率最大为1000,手臂挥动速度不应太大;
(2) 手臂挥动速度不应过小,即触发时间符合正常操作;
(3) 可以实现人一般速度走过,不触发PPT切换。 - 程序流程图
4. 系统程序编写
#include <Keyboard.h>
/****************************************************************
定义引脚功能,控制引脚为27,29,显示引脚为23,25
*****************************************************************/
#define ON 23
#define OFF 25
#define LED_ON 27
#define LED_OFF 29
char left = KEY_LEFT_ARROW;
char right = KEY_RIGHT_ARROW;
const int HEADER=0x59;//数据包帧头
/****************************************************************
定义模块功能初始状态参数
*****************************************************************/
bool receiveok1=false;
bool receiveok2=false;
bool status_complete1=false;
bool status_complete2=true;
/****************************************************************
变量DELAY可以控制模块的延迟时间,用以滤除人行走带来的误操作
*****************************************************************/
int DELAY=180;
int distance1=0;
int distance2=0;
int DISTANCE1=1200;
int DISTANCE2=1200;
int threshold=0;
unsigned long tim[2]={0};
int period=0;
/****************************************************************
声明函数,雷达数据获取函数和采集环境距离阈值函数
*****************************************************************/
int TFminione(void);
int TFminitwo(void);
int lidar_average(void);
/****************************************************************
引脚功能定义,初始化;
串口初始化;
采集周边环境,确定模块工作阈值;
*****************************************************************/
void setup()
{
pinMode(ON,INPUT);
pinMode(OFF,INPUT);
pinMode(LED_ON,OUTPUT);
pinMode(LED_OFF,OUTPUT);
digitalWrite(ON,HIGH);
digitalWrite(OFF,HIGH);
digitalWrite(LED_ON,LOW);
digitalWrite(LED_OFF,LOW);
Serial1.begin(115200);//设置TFmini1与arduino的串口波特率
Serial2.begin(115200);//设置TFmini2与arduino的串口波特率
Serial3.begin(115200);//设置电脑与arduino的串口波特率
int threshold1=lidar_average();
threshold=threshold1-100;
Serial3.print("threshold=");
Serial3.println(threshold);
}
/****************************************************************
首先,判断功能开关状态;
然后,对雷达测距状态进行判断;
如果满足判断条件,执行对应操作;
*****************************************************************/
void loop()
{
if(digitalRead(ON)==LOW)//控制开关打开
{
digitalWrite(ON,HIGH);
digitalWrite(LED_OFF,LOW);
digitalWrite(LED_ON,HIGH);
Keyboard.begin();
receiveok1=false;
receiveok2=false;
distance1 = TFminione();
distance2 = TFminitwo();
if(receiveok1 & receiveok2)
{
if(DISTANCE1>threshold & distance1<=threshold & distance2>threshold)
{
tim[0]=millis();
DISTANCE1=distance1;
DISTANCE2=distance2;
while(true)
{
receiveok1=false;
receiveok2=false;
distance1 = TFminione();
distance2 = TFminitwo();
if(receiveok1 & receiveok2)
{
tim[1]=millis();
period=tim[1]-tim[0];
if(DISTANCE2>threshold & distance2<=threshold )
{
DISTANCE1=distance1;
DISTANCE2=distance2;
while(true)
{
receiveok1=false;
receiveok2=false;
distance1 = TFminione();
distance2 = TFminitwo();
if(receiveok1 & receiveok2)
{
tim[1]=millis();
period=tim[1]-tim[0];
if(distance2>threshold & distance1>threshold )
{
tim[1]=millis();
period=tim[1]-tim[0];
if(period<DELAY)
{
Keyboard.write(right);
status_complete1=true;
break;
}
else
{
status_complete1=true;
break;
}
}
else if(period>DELAY)
{
status_complete1=true;
break;
}
else
{
DISTANCE1=distance1;
DISTANCE2=distance2;
}
}
}
}
else if(status_complete1)
{
status_complete1=false;
break;
}
else if(period>DELAY)
{
break;
}
else
{
DISTANCE1=distance1;
DISTANCE2=distance2;
}
}
}
}
else if(DISTANCE2>threshold & distance2<=threshold & distance1>threshold)
{
tim[0]=millis();
DISTANCE1=distance1;
DISTANCE2=distance2;
while(true)
{
receiveok1=false;
receiveok2=false;
distance1 = TFminione();
distance2 = TFminitwo();
if(receiveok1 & receiveok2)
{
tim[1]=millis();
period=tim[1]-tim[0];
if(DISTANCE1>threshold & distance1<=threshold )
{
DISTANCE1=distance1;
DISTANCE2=distance2;
while(true)
{
receiveok1=false;
receiveok2=false;
distance1 = TFminione();
distance2 = TFminitwo();
if(receiveok1 & receiveok2)
{
tim[1]=millis();
period=tim[1]-tim[0];
if(distance1>threshold & distance2>threshold )
{
tim[1]=millis();
period=tim[1]-tim[0];
if(period<DELAY)
{
Keyboard.write(left);
status_complete2=true;
break;
}
else
{
status_complete2=true;
break;
}
}
else if(period>DELAY)
{
status_complete2=true;
break;
}
else
{
DISTANCE1=distance1;
DISTANCE2=distance2;
}
}
}
}
else if(status_complete2)
{
status_complete2=false;
break;
}
else if(period>DELAY)
{
break;
}
else
{
DISTANCE1=distance1;
DISTANCE2=distance2;
}
}
}
}
else
{
DISTANCE1=distance1;
DISTANCE2=distance2;
}
Keyboard.end();
}
}
else if(digitalRead(OFF)==LOW)
{
digitalWrite(OFF,HIGH);
digitalWrite(LED_OFF,HIGH);
digitalWrite(LED_ON,LOW);
}
else
{
delay(1);
}
}
/****************************************************************
雷达1采集环境距离函数
*****************************************************************/
int TFminione(void)
{
int dist=0;//雷达实测距离值
int check;//校验数值存放
int uart[9]={0};//存放雷达测量的数据
int i=0;
if (Serial1.available())//查看串口是否有数据输入
{
if(Serial1.read()==HEADER)//判断数据包帧头0x59
{
uart[0]=HEADER;
if(Serial1.read()==HEADER)//判断数据包帧头0x59
{
uart[1]=HEADER;
for(i=2;i<9;i++)//存储数据到数组
{
uart[i]=Serial1.read();
}
check=uart[0]+uart[1]+uart[2]+uart[3]+uart[4]+uart[5]+uart[6]+uart[7];
if(uart[8]==(check&0xff))//按照协议对收到的数据进行校验
{
dist=uart[2]+uart[3]*256;//计算距离值
receiveok1=true;
return(dist);
}
}
}
}
else
{
delay(1);
}
}
/****************************************************************
雷达2采集环境距离函数
*****************************************************************/
int TFminitwo(void)
{
int dist=0;//雷达实测距离值
int check;//校验数值存放
int uart[9]={0};//存放雷达测量的数据
int i=0;
if (Serial2.available())//查看串口是否有数据输入
{
if(Serial2.read()==HEADER)//判断数据包帧头0x59
{
uart[0]=HEADER;
if(Serial2.read()==HEADER)//判断数据包帧头0x59
{
uart[1]=HEADER;
for(i=2;i<9;i++)//存储数据到数组
{
uart[i]=Serial2.read();
}
check=uart[0]+uart[1]+uart[2]+uart[3]+uart[4]+uart[5]+uart[6]+uart[7];
if(uart[8]==(check&0xff))//按照协议对收到的数据进行校验
{
dist=uart[2]+uart[3]*256;//计算距离值
receiveok2=true;
return(dist);
}
}
}
}
else
{
delay(1);
}
}
int lidar_average(void)
{
int i=0;
int sum=0;
int average=0;
int temp[100]={0};
while(true)
{
distance1=TFminione();
if(receiveok1)
{
temp[i]=distance1;
Serial3.println(distance1);
i++;
if(i>=100)
{
for(i=0;i<100;i++)
{
sum+=temp[i];
}
average=sum/100;
Serial3.print("average=");
Serial3.print(average);
Serial3.print('\t');
i=0;
sum=0;
return(average);
delay(1);
break;
}
}
receiveok1=false;
}
}
5. 使用说明
- 模块上电;
- 系统自适应实际场景,采集距离信息,设定模块工作阈值;
- 打开PPT切换功能开关;
- 打开激光指示灯,大致调整模块工作区域,然后关闭激光指示灯;
- 手掌或者手臂通过模块,从上到下或者从下到上,依次经过两个雷达,当离开工作区域后,PPT进行切换(上一页或者下一页);
- 重复步骤4;
- 模块断电。
- 实际结构图
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)