1、硬件介绍:
VL53L3CX是意法半导体新推出的一款激光测距传感器,采用940nm垂直腔面发射激光器(Vertical-Cavity Surface-Emitting Laser,简称VCSEL)发射出激光,激光碰到障碍物后反射回来被VL53L0X接收到,测量激光在空气中的传播时间,进而得到距离。测距范围覆盖了25mm到3000mm,发射的激光对眼睛安全,且完全不可见。
M5StickC PLUS主控采用ESP32-PICO-D4模组,,具备蓝牙4.2与WIFI功能,小巧的机身内部集成了丰富的硬件资源,如红外、RTC、麦克风、LED、IMU、按键、蜂鸣器、PMU等,屏幕尺寸1.14寸、135*240分辨率的TFT屏幕,电池容量达到120mAh。
将VL53L3CX测距模块与M5StickC PLUS主控使用四根线连接起来。其中两条线为电源线,主控为测距模块提供5V电源;另外两条线为I2C接口信号线,将主控与传感器使用I2C协议连接起来。VL53L3CX还有两个管脚:XSHUT脚和GPIO1脚。XSHUT脚,是电源模式控制,如果不需要休眠功能,此脚可以直接接到AVDD上,在这个模块上这个管脚和电源已经短接。脚GPIO1:中断输出。在本项目中这两个管脚都没有使用。
2、开发环境:
软件开发上使用Vscode+platformIO,使用arduino进行开发。调用了官方的M5stack的库。然后额外添加了VL53L3CX的库。
3、软件开发:
ST为VL53L0X专门配备了一套API,直接封装了各种功能比如:初始化/校准、测距开始/停止、精度选择、测距模式选择。用户的应用程序调用API中的函数,然后API通过IIC与VL53L0X中的固件(Firmware)进行通信,固件再操作硬件。
参考着VL53L3CX传感器模块资料,使用库文件中对应的例程,很快就能上手读取数据了。
第一步:初始化I2C接口。这里需要留意M5StickC PLUS的GROVE接口使用的是32、33两个管脚,需要修改I2C协议对应的管脚。
VL53LX sensor_vl53lx_sat(&Wire, -1);
第二步:创建一个VL53LX对象。对象初始化时需要传入两个参数。参数一:I2C协议的对象。用于通讯。参数二:XSHUT电源模式控制管脚,GROVE接口没有多余的控制线,所以这里给-1,不使能。
第三步:初始化VL53L3CX传感器模块。这里使用的是默认参数,对VL53L3CX进行初始化,如需要修改功能参数的,可以在这一步修改。
void setup() { M5.begin(); // Initialize M5StickC Plus. 初始化 M5StickC PLus M5.Lcd.setTextSize(3); // Set font size. 设置字体大小 M5.Lcd.setRotation(3); // Rotate the screen. 将屏幕旋转 // M5.Lcd.print("Hello World"); Wire.begin(32, 33); // sda /scl sensor_vl53lx_sat.begin(); // Configure VL53LX satellite component. sensor_vl53lx_sat.VL53LX_Off(); // Switch off VL53LX satellite component. sensor_vl53lx_sat.InitSensor(0x12); // Initialize VL53LX satellite component. sensor_vl53lx_sat.VL53LX_StartMeasurement(); // Start Measurements xTaskCreate(setDistinct, "setDistinct", 4 * 1024, NULL, 2, NULL); }
第四:当初始化完成后,在FreeRTOS中创建了一个独立任务,专职负责不停地循环读取传感器的值。
//获取激光传感器得到的距离 void setDistinct(void *parameter) { VL53LX_MultiRangingData_t MultiRangingData; VL53LX_MultiRangingData_t *pMultiRangingData = &MultiRangingData; int no_of_object_found = 0, status; while (1) { status = sensor_vl53lx_sat.VL53LX_GetMultiRangingData(pMultiRangingData); no_of_object_found = pMultiRangingData->NumberOfObjectsFound; if (no_of_object_found == 0) //没有测量到距离 distinct[pos] = 0; //测量失败 else if (no_of_object_found == 1) { distinct[pos] = pMultiRangingData->RangeData[0].RangeMilliMeter; } if (status == 0) { status = sensor_vl53lx_sat.VL53LX_ClearInterruptAndStartMeasurement(); } vTaskDelay(50); //任务延时调度 pos = (pos + 1) % 4; } vTaskDelete(NULL); //删除自身函数 }
在主进程中搭建UI界面,用来展示测量数据以及和用户交互。
给按键A添加一个功能,当按键按下后锁定测量的距离值,此时屏幕就固定显示测量的距离。当再次按下A键,解除锁定,屏幕显示当前测量的距离值。
void loop() { uint16_t dist = getDistinct(); M5.update(); Serial.println(dist); if (M5.BtnA.wasReleased()) { // If the button A is pressed. 如果按键 A 被按下 lockstat = !lockstat; } dispDistinct(dist); delay(500); }
数据展示,在1.14寸屏幕上展示当前测量的距离和单位,显示小数点后一位的精度。
//屏幕上显示距离 void dispDistinct(uint16_t dist) { if (lockstat == false) { dispval = dist; } M5.Lcd.setTextSize(4); M5.Lcd.fillScreen(BLACK); M5.Lcd.setCursor(20, 20); M5.Lcd.setTextColor(WHITE); M5.Lcd.printf("%d", dispval / 10); M5.Lcd.setTextSize(2); M5.Lcd.printf(".%d ", dispval % 10); M5.Lcd.setTextSize(4); M5.Lcd.print("CM"); M5.Lcd.setCursor(70, 110); M5.Lcd.setTextColor(RED); M5.Lcd.setTextSize(2); if (lockstat) M5.Lcd.print("Lock"); else M5.Lcd.print("Unlock"); }
4、效果演示:
放置在地面测量屋顶距离。
放置在桌子边缘,测量屋顶距离。
测量桌子边缘到墙的距离,游标卡尺测量为10CM。
5 总结:
读取到VL53L3CX激光测距模块的数据还是挺简单的,但是和预想中的有所不同。预想中因为激光测距使用计算光线从发出到返回所用的时长来计算距离,应该会很精确,毕竟激光在空气中传播速度固定,且激光是直线传播基本没有扩散的问题。想象中的测量结果应该非常稳定、精准。偶有抖动,应该在毫米内的拨动。但是实际结果感觉和超声波测距差不多,也是有较大波动,波动基本都到了1%左右了。在测量2米距离时,波动会在2厘米上下。