HLK-LD116S-24G 物联网毫米波传感器模块,可用于监测小范围 内的运动目标,不受温湿度、气流、灰尘、 噪声、光线明暗等环境影响,用于安防/智能家居等室内场景非常合适。
我家有个乌龟缸,养了唐僧师徒五龟(包括白龙龟)。乌龟运动比较慢,平时都喜欢趴着不动,所以我想试试,用咱们的毫米波传感器来检测乌龟的移动,并自动拍照。
结合我手头的地平线旭日X3派,以及USB摄像头,做了下面一个简单的应用场景:
毫米波雷达传感器部分细节如下:
参考旭日X3派的引脚图,进行接线:
HLK-LD116S-24G使用5V供电,数字信号输出连接到GPIO3口上即可。
在旭日X3派板子上,有一个状态LED,连接到了GPIO26上。在后面的程序中,如果检测到了移动物体,则点亮该LED。
为了方便测试,参考网上的资料,使用PyQT5编程,读取摄像头数据并进行显示,并结合毫米波雷达传感器的信号数据,检测到移动信号,就自动拍照。
最终具体的程序如下:
from PyQt5 import QtWidgets
from PyQt5.QtGui import QImage, QPixmap
import sys, cv2, threading, random
from datetime import datetime
import time
import gpiod
# 根据具体板卡的LED灯和来啊连接修改使用的Chip和Line
LED_LINE_OFFSET = 26
RADAR_LINE_OFFSET = 3
CAMERA_DEVICE_INDEX = 0
chip0 = gpiod.Chip("0", gpiod.Chip.OPEN_BY_NUMBER)
led = chip0.get_line(LED_LINE_OFFSET)
led.request(consumer="LED", type=gpiod.LINE_REQ_DIR_OUT, default_vals=[0])
led.set_value(0)
radar = chip0.get_line(RADAR_LINE_OFFSET)
radar.request(consumer="BUTTON", type=gpiod.LINE_REQ_DIR_IN)
app = QtWidgets.QApplication(sys.argv)
window_w, window_h = 640, 530 # 設定視窗長寬
scale = 480/640 # 影片高度的比例
Form = QtWidgets.QWidget()
Form.setWindowTitle('USB摄像头')
Form.resize(window_w, window_h)
# 視窗尺寸改變時的動作
def windowResize(self):
global window_w, window_h, scale
window_w = Form.width() # 取得視窗寬度
window_h = Form.height() # 取得視窗高度
label.setGeometry(0,0,window_w,int(window_w*scale)) # 設定 QLabel 尺寸
btn1.setGeometry(10,window_h-40,70,30) # 設定按鈕位置
btn2.setGeometry(80,window_h-40,200,30) # 設定按鈕位置
btn3.setGeometry(window_w-210,window_h-40,200,30) # 設定按鈕位置
Form.resizeEvent = windowResize # 視窗尺寸改變時觸發
ocv = True # 啟用 OpenCV 的參考變數,預設 True
# 關閉視窗時的動作
def closeOpenCV(self):
global ocv, output
ocv = False # 關閉視窗後,設定成 False
try:
output.release() # 關閉視窗後,釋放儲存影片的資源
except:
pass # 如果沒有按下錄製影片按鈕,就略過
Form.closeEvent = closeOpenCV # 視窗關閉時觸發
label = QtWidgets.QLabel(Form)
label.setGeometry(0,0,window_w,int(window_w*scale)) # 設定 QLabel 位置和尺寸
# 存檔時使用名稱的函式
def rename():
# return str(random.random()*10).replace('.','')
return datetime.now().strftime('%Y%m%d_%H%M%S')
photo= False # 按下拍照紐時的參考變數,預設 False
# 按下拍照扭的動作
def takePhoto():
global photo
photo = True # 變數設定為 True
btn1 = QtWidgets.QPushButton(Form)
btn1.setGeometry(10,window_h-40,70,30) # 設定拍照鈕的位置和尺寸
btn1.setText('拍照')
btn1.clicked.connect(takePhoto) # 按下按鈕觸發拍照
fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 設定存檔影片格式
recorderType = False # 設定是否處於錄影狀態,預設 False
# 按下錄影按鈕的動作
def recordVideo():
global recorderType, output
if recorderType == False:
# 如果按下按鈕時沒有在錄影
# 設定錄影的檔案
output = cv2.VideoWriter(f'videos/{rename()}.mp4', fourcc, 20.0, (window_w,int(window_w*scale)))
recorderType = True # 改為 True 表示正在錄影
btn2.setGeometry(80,window_h-40,200,30) # 因為內容文字變多,改變尺寸
btn2.setText('录像中,点击停止保存')
else:
# 如果按下按鈕時正在錄影
output.release() # 釋放檔案資源
recorderType = False # 改為 False 表示停止錄影
btn2.setGeometry(80,window_h-40,70,30) # 改變尺寸
btn2.setText('录像')
btn2 = QtWidgets.QPushButton(Form)
btn2.setGeometry(80,window_h-40,70,30) # 設錄影照鈕的位置和尺寸
btn2.setText('录像')
btn2.clicked.connect(recordVideo) # 按下按鈕觸發錄影或停止錄影
def opencv():
global window_w, window_h, scale, photo, output, recorderType
cap = cv2.VideoCapture(CAMERA_DEVICE_INDEX)
if not cap.isOpened():
print("Cannot open camera")
exit()
while ocv:
ret, frame = cap.read() # 讀取影格
if not ret:
print("Cannot receive frame")
break
frame = cv2.resize(frame, (window_w, int(window_w*scale))) # 改變尺寸符合視窗
if photo == True:
photo = False # 按下拍照鈕時,會先設定 True,觸發後再設回 False
name = rename() # 重新命名檔案
cv2.imwrite(f'photos/{name}.jpg', frame) # 儲存圖片
if recorderType == True:
output.write(frame) # 按下錄影時,將檔案儲存到 output
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 改為 RGB
height, width, channel = frame.shape
bytesPerline = channel * width
img = QImage(frame, width, height, bytesPerline, QImage.Format_RGB888)
label.setPixmap(QPixmap.fromImage(img)) # 顯示圖片
video = threading.Thread(target=opencv) # 將 OpenCV 的部分放入 threading 裡執行
video.start()
btn3 = QtWidgets.QPushButton(Form)
btn3.setGeometry(window_w-210,window_h-40,200,30) # 設定拍照鈕的位置和尺寸
btn3.setText('雷达:检测中。。。')
def radar_check():
global photo
# value_prev = 0
count = 0
while True:
val = 1 if radar.get_value() else 0
if val == 1:
count = count + 1
else:
count = 0
# if val != value_prev:
# print("RADAR %d" % val)
# value_prev = val
print("RADAR:%d count:%d " % (val, count), end="")
if count >= 3:
btn3.setText('雷达:检测到移动物体')
if count == 3:
print("检测到移动物体,拍照")
photo = True
else:
print("检测到移动物体")
elif count >= 1:
btn3.setText('雷达:可能有移动物体')
print("可能有移动物体")
else:
btn3.setText('雷达:检测中。。。')
print("检测中...")
led.set_value(radar.get_value())
time.sleep(1)
radar_th = threading.Thread(target=radar_check) # 將 OpenCV 的部分放入 threading 裡執行
radar_th.start()
Form.show()
sys.exit(app.exec_())
上述代码运行后,显示的界面如下:
同时命令行输出如下:
如果检测到物体移动,则整体显示如下:
如果连续3秒检测到物体移动,则会自动进行拍照:
上述代码毫米雷达波传感器部分的关键代码如下:
代码中的逻辑为:
当检测到移动物体时,先给出可能状态,当连续3秒3次都检测到时,则确定有移动物体,并进行拍照,如果一直检测到,则不用一直拍照。
在实际使用时,发现,发现HLK-LD116S-24G对于乌龟这样较小的个体的运动,基本无法检测出来。
但是,如果我打开了乌龟缸的水泵,水面出现波动后,则很快检测到了移动。
并成功拍下照片:
虽然对于个体较小的物体移动无法检测,但检测猫狗等动物或者人体,则没有任何问题,因为用手晃动时,也能检测到。
经过测试,对于门窗的开合,或者一个包的移动,或者一个盒子的移动,都能检测到。
所以,HLK-LD116S-24G如果用于安防或者智能家居的场合,还是非常合适非常适用的。
补充说明:
地平线旭日X3派本身可以读取摄像头数据,做物体移动检测,但需要实时计算。如果结合毫米波雷达,则能有效的减小计算量,按需计算。