背景
最近買的一堆傳感器到貨了,先來把玩一下超聲波測距傳感器。超聲波傳感器一般用于機器人,小車的避障,物體的測距,液位檢測,停車檢測等領域。
知識回顧
開始之前我們先復習一下高中的物理知識。
通過上圖的原理圖,又已知聲波速度,這里取 340 m/s (空氣中的音速在1個標準大氣壓和15℃的條件下約為340m/s)。
那么,我們通過記錄發射時間和接收時間,計算出間隔,然后距離根據(聲波速度 * 時間間隔)/ 2 就可以得到。
模塊介紹
我使用這個模塊是寬壓的 3.3v -5 v,探測距離:2cm-450cm,有2cm的超近盲區。精度0.3cm。
使用的方式也很簡單,一個控制口發出一個10US以上的高電平,就可以在接收口等待高電平輸出。一有輸出就記錄一個開始時間,當此口變為低電平時再記錄一個結束時間,他們的間隔時間就為此次測距的時間,根據公式便可算出距離。
接線測試
在這里我用的 Jetson TX2 開發版套件測試,針腳使用的 38,和40。
38腳連 Trig ,設為輸出模式;40 腳連 Echo,設為輸入模式。
其上還連接了 I2C 設備,一個SSD1306 OLED 顯示屏,作為后續的距離展示,更詳細的介紹可以看我之前的文章《使用.Net驅動Jetson Nano的OLED顯示屏》。
上圖因為沒找到 TX2 的圖片所以用的 Nano。樹莓派,Nano 和 TX2 的物理引腳功能一樣,只是 PCM 編碼和 GPIO 的編號是不一樣的,代碼有的情況下需要調整,后續會講到。
接好線,我們先快速用 Python 驗證下原理。
import RPi.GPIO as GPIO
import timeTRIG_PIN = 38
ECHO_PIN = 40def main():GPIO.setmode(GPIO.BOARD)GPIO.setup(TRIG_PIN, GPIO.OUT)GPIO.setup(ECHO_PIN, GPIO.IN)print("Demo running. Press CTRL+C to exit.")try:while True:time.sleep(1)distance = StartModule()print("Distance: {}cm".format(distance))finally:GPIO.cleanup()def StartModule():# 發送 trig 信號,持續 10us 的方波脈沖GPIO.output(TRIG_PIN,GPIO.HIGH)# 單位為 s ,10us 需轉換time.sleep(0.00001)GPIO.output(TRIG_PIN,GPIO.LOW)#等待低電平結束,記錄時間while GPIO.input(ECHO_PIN) == GPIO.LOW:passpulse_s = time.time()#等待高電平結束,再次記錄時間while GPIO.input(ECHO_PIN) == GPIO.HIGH:passpulse_e = time.time()# 測得距離(單位:m) = (pulse_end - pulse_start) * 聲波速度 / 2 return round((pulse_e - pulse_s) * 17000,2)if __name__ == '__main__':main()
.NET 實現
.NET IoT 庫由兩個 NuGet 包組成:
?System.Device.Gpio?Iot.Device.Bindings
System.Device.Gpio
?支持使用各種協議來與低級別硬件引腳交互,以控制設備。我編寫的?Sang.IoT.SSD1306
?就使用了這個庫。
Iot.Device.Bindings
?提供了各種常用的設備綁定,當然里面其實也是有 SSD13xx 的,如果不是想了解原理,可以不用重復造輪子,先前往支持的設備文檔[1]里面查詢。
1.新建項目
dotnet new console -o ultrasonic
2.進入項目目錄
cd ultrasonic
3.安裝依賴庫
dotnet add package Iot.Device.Bindings
4.修改代碼
using System;
using System.Device.Gpio;
using System.Threading;
using Iot.Device.Hcsr04;
Console.WriteLine("Test sensor. Press Ctrl+C to end.");
// 此處注意 使用的是TX2設備,其他設備需查閱轉換
int TRIG_GPIO = 394; //Pin 38
int ECHO_GPIO = 393; //Pin 40using var controller = new GpioController();
using var sensor = new Hcsr04(controller,TRIG_GPIO,ECHO_GPIO);while (true)
{if(sensor.TryGetDistance(out _)){Console.WriteLine($"Distance: {sensor.Distance}");}Thread.Sleep(1000);
}
5.運行測試
dotnet run
以上便是 .NET 中的實現,如果你想驗證下驅動原理,可以自行嘗試用 .NET 編碼實現。
這里需要注意的是,傳入的 triggerPin 和 echoPin 是所用設備的 GPIO 編號,不是物理的針腳號,需要查閱資料獲取。
針對本案例,使用的 38 和 40針腳,在樹莓派中 GPIO 編號分別是 20和21,在 Jetson Nano 中分別是 77和78 ,在 Jetson TX2 中分別是 394和393。
接入顯示屏
基于以上代碼,我們引入包Sang.IoT.SSD1306
。
dotnet add package Sang.IoT.SSD1306
修改代碼
using System;
using System.Device.Gpio;
using System.Threading;
using Iot.Device.Hcsr04;using Sang.IoT.SSD1306;
using SkiaSharp;Console.WriteLine("Test sensor. Press Ctrl+C to end.");// 此處注意 使用的是TX2設備,其他設備需查閱轉換
int TRIG_GPIO = 394; //Pin 38
int ECHO_GPIO = 393; //Pin 40using var controller = new GpioController();
using var sensor = new Hcsr04(controller,TRIG_GPIO,ECHO_GPIO);// 顯示準備
using var oled = new SSD1306_128_64(1);SKPaint paint = new SKPaint() { Color = new SKColor(255, 255, 255),StrokeWidth = 1,TextSize = 13,Style = SKPaintStyle.Fill,
};oled.Begin();
oled.Clear();while (true)
{if(sensor.TryGetDistance(out _)){Console.WriteLine($"Distance: {sensor.Distance}");// OLED 顯示using(var bitmap = new SKBitmap(128, 64, true)){SKCanvas canvas = new SKCanvas(bitmap);paint.TextSize = 13;canvas.DrawText(DateTime.Now.ToString(), 0, 13, paint);paint.TextSize = 30;canvas.DrawText(sensor.Distance.ToString(), 0, 50, paint);oled.Image(bitmap.Encode(SKEncodedImageFormat.Png, 100).ToArray());}oled.Display();}Thread.Sleep(1000);
}
最終效果如下:
References
[1]
?支持的設備文檔:?https://github.com/dotnet/iot/blob/main/src/devices/README.md