激光測(cè)距在生產(chǎn)生活中有很多應(yīng)用,例如測(cè)距、定位、避障等等。而飛行時(shí)間(ToF)測(cè)距作為激光測(cè)距技術(shù)的一種,因?yàn)槠錅y(cè)量精準(zhǔn)、響應(yīng)快速、低功耗等特點(diǎn),常被用于機(jī)器人、自動(dòng)駕駛汽車(chē)、交通管理中的實(shí)時(shí)對(duì)象檢測(cè),我們手機(jī)的面部檢測(cè)功能,也用到這種技術(shù)。
由瑞科慧聯(lián)(RAK)出品的 ToF 傳感器模塊 WisBlock RAK12014,采用 ST VL53L0X,后者是世界上最小的 ToF 測(cè)距傳感器
本文將介紹一款 ToF 激光測(cè)距傳感器模塊 WisBlock RAK12014,并利用 WisBlock 開(kāi)發(fā)板演示該模塊如何工作。
什么是 ToF 激光測(cè)距傳感器模塊?
ToF 激光測(cè)距傳感器模塊是一種使用激光脈沖來(lái)測(cè)量自身與目標(biāo)物體之間距離的模塊。WisBlock RAK12014 ToF 激光測(cè)距傳感器模塊基于意法半導(dǎo)體 ST VL53L0X 而設(shè)計(jì)。VL53L0X 采用目前市場(chǎng)上最小的封裝,可謂世界上最小的 ToF 測(cè)距傳感器。
WisBlock RAK12014 能提供精確的距離測(cè)量,可測(cè)量 2 米的絕對(duì)距離。其 940nm VCSEL 發(fā)射器(垂直腔面發(fā)射激光器)完全不為人眼所見(jiàn),再加上內(nèi)置的物理紅外濾光片,使其測(cè)距距離更長(zhǎng)、對(duì)環(huán)境光的抗干擾性更強(qiáng)、對(duì)蓋片的光學(xué)串?dāng)_具有更好的穩(wěn)定性。換言之,無(wú)論目標(biāo)反射率如何,該傳感器都能提供精確的距離測(cè)量。上述特點(diǎn)使之能勝任高精度的測(cè)距任務(wù),適用于更多應(yīng)用場(chǎng)景中。
RAK12014 是模塊化的硬件開(kāi)發(fā)平臺(tái) WisBlock 的一款傳感器模塊
RAK12014 模塊規(guī)格與特性:
- 測(cè)量絕對(duì)距離可達(dá) 2 m
- 用于器件控制和數(shù)據(jù)傳輸的I2C接口
- Xshutdown(復(fù)位)和中斷 GPIO
- 電源 2.6~3.5 V
- 尺寸10 x 10 mm
RAK12014 模塊包含一個(gè)兼容 WisBlock 基板傳感器插槽的 24 引腳連接器。通過(guò)該連接器可以將 RAK12014 模塊安裝在 WisBlock 基板(如RAK5005-O)模塊上。該連接器的引腳順序以及引腳定義如下圖所示。
RAK12014 的引腳分布
注意:僅 I2C 相關(guān)引腳、XSHUT(復(fù)位)、INT、3V3_S 以及 GND 連接到了該模塊的連接器上。
RAK12014 典型示例:在 OLED 顯示屏上顯示測(cè)試距離
RAK12014 有一個(gè)很典型的應(yīng)用,能夠很形象地給我們展示 ToF 激光測(cè)距傳感器模塊的特性,即“在 OLED 顯示屏上顯示出測(cè)試的距離”。
在這個(gè)例子中,將 RAK12014 連接到 RAK 5005-O 基板上,通過(guò)核心模塊 RAK4631 驅(qū)動(dòng)它的測(cè)量距離功能,并將其測(cè)量到的距離信息在 OLED 顯示屏上顯示。
讓 RAK12014 實(shí)現(xiàn)“在 OLED 顯示屏上顯示出測(cè)試的距離”應(yīng)用所需的產(chǎn)品配置
以下是實(shí)現(xiàn)這一應(yīng)用的具體步驟:
1、安裝 OLED庫(kù)
要控制 OLED 顯示屏,需要使用到“U8g2”庫(kù)。
2、安裝 ToF 激光測(cè)距傳感器庫(kù)
要控制 ToF 激光測(cè)距傳感器模塊,需要使用“stm32duino_vl53l0x”庫(kù)。
注意:所有的庫(kù)安裝完成之后需要重啟 Arduino IDE,才能使安裝的庫(kù)生效。
3、導(dǎo)入代碼
接著將代碼導(dǎo)入 OLED 顯示屏和 ToF 激光測(cè)距傳感器模塊所需的庫(kù)當(dāng)中,然后定義兩個(gè)名為“u8g2”和“sensor_vl53l0”的對(duì)象。
#include #include // Click to install library: http://librarymanager/All#stm32duino_vl53l0x #include // Click to install library: http://librarymanager/All#u8g2 U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); VL53L0X sensor_vl53l0x(&Wire, WB_IO2);
4、GetDistance()函數(shù)
在 GetDistance() 中,定義一個(gè) report 數(shù)據(jù)。當(dāng)有數(shù)據(jù)的時(shí)候打印出當(dāng)前讀到的數(shù)據(jù)測(cè)量值,當(dāng)沒(méi)有數(shù)據(jù)時(shí)打印如下所示內(nèi)容:
void GetDistance(){ int status; char report[64]; uint32_t distance; u8g2.clearBuffer(); // clear the internal memory u8g2.setFont(u8g2_font_ncenB10_tr); // choose a suitable font // Read Range. status = sensor_vl53l0x.GetDistance(&distance); if (status == VL53L0X_ERROR_NONE) { // Output data. snprintf(report, sizeof(report), "Range: %ld mm", distance); } else { snprintf(report, sizeof(report), "Nothing at all", distance); } Serial.println(report); u8g2.drawStr(15, 30, report); u8g2.sendBuffer(); }
5、setup()函數(shù)
在 setup() 中,ToF 激光測(cè)距傳感器和 OLED 顯示器都會(huì)被初始化。在串口監(jiān)視器上打印一條消息,這樣就能知道 ToF 激光測(cè)距傳感器是否成功找到了。如下所示:
void setup() { int status; pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); pinMode(WB_IO2, OUTPUT); digitalWrite(WB_IO2, HIGH); // Initialize Serial for debug output Serial.begin(115200); time_t serial_timeout = millis(); // On nRF52840 the USB serial is not available immediately while (!Serial) { if ((millis() - serial_timeout) < 5000) { delay(100); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } else { break; } } u8g2.begin(); // Initialize I2C bus. Wire.begin(); // Configure VL53L0X component. sensor_vl53l0x.begin(); // Switch off VL53L0X component. sensor_vl53l0x.VL53L0X_Off(); // Initialize VL53L0X component. status = sensor_vl53l0x.InitSensor(0x52); if(status) { Serial.println("Init sensor_vl53l0x failed..."); } }
6、loop()函數(shù)
在 loop() 中,代碼在 OLED 顯示屏上顯示了主屏幕,而這其實(shí)是在 GetDistance() 函數(shù)中完成的。
void loop() { uint32_t distance; int status; GetDistance(); delay(300); }
7、代碼上傳
完成前面的代碼撰寫(xiě)之后,選擇所使用的開(kāi)發(fā)板 RAK4631,選擇正確的端口之后開(kāi)始代碼上傳燒錄,然后打開(kāi) Arduino IDE 的串口監(jiān)視器。選擇 115200 的波特率,我們就可以看見(jiàn) ToF 激光測(cè)距傳感器模塊的測(cè)距數(shù)據(jù):
8、演示程序
完成以上操作后,一旦 ToF 激光測(cè)距傳感器上方有物體,OLED 顯示屏就會(huì)顯示當(dāng)前物體與傳感器的距離;當(dāng)傳感器上方?jīng)]有物體時(shí),OLED 顯示屏則會(huì)顯示當(dāng)前無(wú)物體,點(diǎn)擊鏈接查看視頻展示了詳細(xì)的演示過(guò)程。
總結(jié)
ToF 激光測(cè)距傳感器模塊可以應(yīng)用的范圍很廣泛,它可以根據(jù)場(chǎng)景的不同調(diào)整距離。另外,所有來(lái)自傳感器的信息都可以直接上傳到云上,便于實(shí)時(shí)調(diào)整。本文主要向大家展示了如何使用 ToF 激光測(cè)距傳感器模塊測(cè)量物體離傳感器的距離。今后再向大家介紹該模塊在我們生活中的更多實(shí)際應(yīng)用。
備注:以下是本次用例的完整代碼,僅大家參考:
/** @file RAK12014_Distance_Detection.ino @author rakwireless.com @brief Distance detection by laser @version 0.1 @date 2021-8-28 @copyright Copyright (c) 2020 **/ #include #include // Click to install library: http://librarymanager/All#stm32duino_vl53l0x #include // Click to install library: http://librarymanager/All#u8g2 U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0); VL53L0X sensor_vl53l0x(&Wire, WB_IO2); void GetDistance(){ int status; char report[64]; uint32_t distance; u8g2.clearBuffer(); // clear the internal memory u8g2.setFont(u8g2_font_ncenB10_tr); // choose a suitable font // Read Range. status = sensor_vl53l0x.GetDistance(&distance); if (status == VL53L0X_ERROR_NONE) { // Output data. snprintf(report, sizeof(report), "Range: %ld mm", distance); } else { snprintf(report, sizeof(report), "Nothing at all", distance); } Serial.println(report); u8g2.drawStr(15, 30, report); u8g2.sendBuffer(); } void setup() { int status; pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); pinMode(WB_IO2, OUTPUT); digitalWrite(WB_IO2, HIGH); // Initialize Serial for debug output Serial.begin(115200); time_t serial_timeout = millis(); // On nRF52840 the USB serial is not available immediately while (!Serial) { if ((millis() - serial_timeout) < 5000) { delay(100); digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); } else { break; } } u8g2.begin(); // Initialize I2C bus. Wire.begin(); // Configure VL53L0X component. sensor_vl53l0x.begin(); // Switch off VL53L0X component. sensor_vl53l0x.VL53L0X_Off(); // Initialize VL53L0X component. status = sensor_vl53l0x.InitSensor(0x52); if(status) { Serial.println("Init sensor_vl53l0x failed..."); } } void loop() { uint32_t distance; int status; GetDistance(); delay(300); }