RTL8722DM_MINI + MicroPython + 機器視覺
嗨!如果你還沒有看過之前的演示影片,請點擊上面的影片
計算機視覺雖然已經存在了很長一段時間,但是在微控制器(MCU)上運行機器視覺的應用還是有點不太實際,因為它需要大量的計算,還會消耗大量的電力,因此最好的方法是將與 CV 相關的計算移到更強大的電腦上,例如我們的筆電或云服務器,通過IoT的技術將數據下載到MCU中,讓 MCU來 實時控制傳感器/執行器。
因此這個專案主要有 2 塊組成,
- 機器視覺算法和視頻採集 → PC
- 運行MicroPython, 進行無線數據傳輸和 LED 控制 → RTL8722DM_MINI
接下來我們會聚焦每一個重要的組成部分。
1. 視頻捕捉和運行機器視覺算法
為了實現手勢識別,我選擇了眾所周知的 OpenCV 和 MediaPipe 庫,因為它們都是在 Github 上的開源項目,而且它們都支援Python語言開發——這意味著我們可以使用 Python 來快速實現我們的邏輯並完成原型設計。
我這裏使用的代碼主要來自名為 Murtaza 的 Youtuber,只要在他的網站上註冊帳戶,你就可以免費地獲得他的代碼,但是因為我還沒有獲得開源他的代碼的許可,因此這裏我建議大家可以在點擊觀看他的手部追蹤以及 手勢控制 的影片,從影片中查看他的代碼並了解他是如何實現這些功能的。
當然,我自己也添加並編輯了的原始 Python 腳本,好讓它只運行我需要的任務,並幫助我通過 TCP socket將數據發送到我的 RTL8722DM_MINI上。下面的圖就是在我的 PC 上運行的所有邏輯的流程圖。
程式碼
以下就是完整的代碼。
# Computer Vision related Code partially adopted from https://www.youtube.com/c/MurtazasWorkshopRoboticsandAI/featured
# Credit goes to him for create the module and example
import cv2
import time
import numpy as np
import math
import socket
import mediapipe as mp
########## Module #############
class handDetector():
def __init__(self, mode=False, maxHands=2, detectionCon=0.5, trackCon=0.5):
self.mode = mode
self.maxHands = maxHands
self.detectionCon = detectionCon
self.trackCon = trackCon
self.mpHands = mp.solutions.hands
self.hands = self.mpHands.Hands(self.mode, self.maxHands,
self.detectionCon, self.trackCon)
self.mpDraw = mp.solutions.drawing_utils
def findHands(self, img, draw=True):
imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.results = self.hands.process(imgRGB)
# print(results.multi_hand_landmarks)
if self.results.multi_hand_landmarks:
for handLms in self.results.multi_hand_landmarks:
if draw:
self.mpDraw.draw_landmarks(img, handLms,
self.mpHands.HAND_CONNECTIONS)
return img
def findPosition(self, img, handNo=0, draw=True):
lmList = []
if self.results.multi_hand_landmarks:
myHand = self.results.multi_hand_landmarks[handNo]
for id, lm in enumerate(myHand.landmark):
# print(id, lm)
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
# print(id, cx, cy)
lmList.append( [id, cx, cy])
if draw:
cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
return lmList
############## Variables ##################
wCam, hCam = 640, 480
pTime = 0
minBri = 0
maxBri = 1
briArd =0
############## Declararion ##################
cap = cv2.VideoCapture(0) # default camera is 0, if you have another cam, you can set to 1
cap.set(3, wCam)
cap.set(4, hCam)
detector = handDetector(detectionCon=0.7)
########## Step 1 ###########
# Start a TCP server and bind to port 12345
# Use ipconfig to check the IP address of your PC
s = socket.socket()
print ("Socket successfully created")
port = 12345
s.bind(('', port))
print("socket binded to %s" % (port))
s.listen(5)
print ("socket is listening")
c, addr = s.accept()
print('Got connection from', addr)
######### Step 2 ###############
# Image capture and processing using mediapipe and opencv
while True:
success, img = cap.read()
img = detector.findHands(img)
lmList = detector.findPosition(img, draw=False)
if len(lmList) != 0:
x1, y1 = lmList[4][1], lmList[4][2]
x2, y2 = lmList[8][1], lmList[8][2]
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
cv2.circle(img, (x1, y1), 15, (255, 0, 255), cv2.FILLED)
cv2.circle(img, (x2, y2), 15, (255, 0, 255), cv2.FILLED)
cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 3)
cv2.circle(img, (cx, cy), 15, (255, 0, 255), cv2.FILLED)
length = math.hypot(x2 - x1, y2 - y1)
#print(length)
# Hand range 50 - 300
brightness = np.interp(length, [50, 300], [minBri, maxBri])
briArd = np.around(brightness,2)
#print(briArd, brightness, length)
if length < 50:
cv2.circle(img, (cx, cy), 15, (0, 255, 0), cv2.FILLED)
# Print FPS
cTime = time.time()
fps = 1 / (cTime - pTime)
pTime = cTime
cv2.putText(img, f'FPS: {int(fps)}', (40, 50), cv2.FONT_HERSHEY_COMPLEX,
1, (255, 0, 0), 3)
# Display image
cv2.imshow("Img", img)
cv2.waitKey(1)
# Sending the distance between our thumb and index wirelessly to IoT device
c.sendall(str(briArd).encode())
print("send data success")
print(briArd, str(briArd))
#c.close()
2.運行MicroPython來無線傳輸數據並控制LED亮度
我選擇 MicroPython 的原因是因爲這樣我就不用使用其他編程語言了 所有的開發都可以用Python來完成~
如果有人不瞭解的話 – MicroPython是專為微控制器設計的 Python 3 解釋器,而RTL8722DM_MINI 已經支援 MicroPython。
使用MicroPython,我們就可以控制微控制器上的所有外設,以RTL8722DM_MINI爲例,我們只需13行的Python程式碼就可實現以下的功能,
- 連接到Wi-Fi
- 啟動一個TCP客戶端
- 通過PWM控制LED亮度
(MicroPython 的程式碼在這裡 )
程式碼
import socket
from wireless import WLAN
from machine import PWM
wifi = WLAN(mode = WLAN.STA)
wifi.connect(ssid = "yourNetwork", pswd = "password") # change the ssid and pswd to yours
c = socket.SOCK()
# make sure to check the server IP address and update in the next line of code
c.connect("192.168.0.106", 12345)
p = PWM(pin = "PA_23")
while True:
data = c.recv(512)
f_brightness= float(data[:3])
print(f_brightness)
p.write(f_brightness)
總結
借助 Wi-Fi 和其他無線通訊方式,RTL8722DM_MINI 等支援物聯網的設備可以成為一個 AIoT 專案中不可或缺的一部分。使用 Python 語言,更是可以加速產品原型設計。這也是我在這個專案中感受最深的地方。
其實RTL8722DM_MINI 還有很多其他的有趣的功能還沒有用上,比如Audio Codec、Ultra-Low Power 和BLE5.0,這些功能都很有潛力,可以讓我們用RTL8722DM_MINI來搭建一個強大的多媒體物聯網節點,并且可以部署在外面很長時間。如果有有興趣的朋友,也可以一起來溝通討論,如何來最大化地使用這個開發板