器視覺(jué)開(kāi)發(fā)指南:從顏色識(shí)別到STM32通信實(shí)戰(zhàn))
1. 項(xiàng)目概述為什么選擇OpenMV構(gòu)建機(jī)器視覺(jué)應(yīng)用如果你正在尋找一種能快速將“眼睛”和“大腦”賦予嵌入式設(shè)備的方法OpenMV絕對(duì)是一個(gè)繞不開(kāi)的名字。它不是一個(gè)簡(jiǎn)單的攝像頭模塊而是一個(gè)集成了圖像傳感器、處理器和一套完整開(kāi)發(fā)環(huán)境的機(jī)器視覺(jué)微控制器。簡(jiǎn)單來(lái)說(shuō)OpenMV讓你能用Python更準(zhǔn)確地說(shuō)是MicroPython來(lái)編寫(xiě)視覺(jué)算法直接在一塊郵票大小的板子上完成圖像采集、處理、分析和決策而無(wú)需依賴上位機(jī)或強(qiáng)大的計(jì)算平臺(tái)。這解決了嵌入式開(kāi)發(fā)者在實(shí)現(xiàn)人臉檢測(cè)、顏色追蹤、二維碼識(shí)別等功能時(shí)面臨的算法移植復(fù)雜、開(kāi)發(fā)周期漫長(zhǎng)的核心痛點(diǎn)。我最初接觸OpenMV是為了做一個(gè)自動(dòng)分揀小車(chē)的項(xiàng)目需要實(shí)時(shí)識(shí)別不同顏色的積木塊。當(dāng)時(shí)如果從零開(kāi)始用STM32驅(qū)動(dòng)攝像頭、編寫(xiě)圖像處理庫(kù)工作量巨大且調(diào)試?yán)щy。OpenMV的出現(xiàn)讓我在幾天內(nèi)就搭建出了可用的顏色識(shí)別原型其開(kāi)發(fā)效率的提升是顛覆性的。它特別適合創(chuàng)客、學(xué)生、產(chǎn)品原型開(kāi)發(fā)者以及需要在資源受限的嵌入式環(huán)境中集成視覺(jué)功能的工程師。無(wú)論你是想做一個(gè)能追蹤光點(diǎn)的智能小車(chē)一個(gè)能識(shí)別特定標(biāo)簽的自動(dòng)門(mén)禁還是一個(gè)簡(jiǎn)單的產(chǎn)品瑕疵檢測(cè)裝置OpenMV都能提供一個(gè)極佳的起點(diǎn)。2. OpenMV核心架構(gòu)與硬件選型解析2.1 硬件平臺(tái)不只是STM32很多人一提到OpenMV就聯(lián)想到STM32這沒(méi)錯(cuò)但不夠全面。OpenMV項(xiàng)目的核心是開(kāi)源的硬件設(shè)計(jì)和固件其官方主流型號(hào)如OpenMV Cam H7、M7等確實(shí)基于意法半導(dǎo)體的STM32系列微控制器特別是搭載Arm Cortex-M7內(nèi)核的型號(hào)主頻可達(dá)數(shù)百M(fèi)Hz并配備了硬件FPU和大量RAM為圖像處理提供了必要的算力基礎(chǔ)。然而OpenMV的生態(tài)正在擴(kuò)展。除了官方的STM32平臺(tái)其MicroPython固件和機(jī)器視覺(jué)庫(kù)sensor,image,find_blobs等模塊經(jīng)過(guò)適配也可以運(yùn)行在其他支持MicroPython的硬件上例如樂(lè)鑫的ESP32系列。雖然ESP32的CPU性能可能不及高端STM32但其集成的Wi-Fi和藍(lán)牙功能為需要無(wú)線傳輸圖像或識(shí)別結(jié)果的場(chǎng)景提供了另一種選擇。此外像嘉楠科技的K210這類(lèi)帶硬件AI加速器的邊緣計(jì)算芯片也與OpenMV有結(jié)合案例用于運(yùn)行更復(fù)雜的神經(jīng)網(wǎng)絡(luò)模型。注意對(duì)于初學(xué)者或希望獲得最穩(wěn)定、最完整支持的開(kāi)發(fā)者我強(qiáng)烈建議從官方OpenMV Cam H7開(kāi)始。它的軟硬件兼容性最好社區(qū)資源最豐富能避免大量底層驅(qū)動(dòng)和兼容性問(wèn)題。2.2 軟件生態(tài)MicroPython帶來(lái)的效率革命OpenMV最大的魅力在于其軟件層。它運(yùn)行的是經(jīng)過(guò)深度定制的MicroPython解釋器。這意味著你可以通過(guò)串口或USB連接打開(kāi)一個(gè)交互式的Python REPL讀取-求值-打印循環(huán)實(shí)時(shí)執(zhí)行命令、調(diào)試代碼就像在電腦上使用Python一樣直觀。這種即時(shí)反饋的開(kāi)發(fā)體驗(yàn)對(duì)于視覺(jué)算法的調(diào)試和參數(shù)調(diào)優(yōu)至關(guān)重要。OpenMV IDE是這個(gè)生態(tài)中的重要一環(huán)。它不僅僅是一個(gè)代碼編輯器更集成了固件燒錄、串口終端、幀緩沖區(qū)查看器、直方圖工具、圖像編輯器等強(qiáng)大功能。你可以直接在IDE里看到攝像頭捕捉的實(shí)時(shí)畫(huà)面運(yùn)行腳本后觀察識(shí)別框甚至保存一幀圖像下來(lái)進(jìn)行離線分析。這種高度集成的環(huán)境將圖像采集、處理、顯示和調(diào)試的鏈路完全打通極大降低了開(kāi)發(fā)門(mén)檻。其核心的機(jī)器視覺(jué)庫(kù)是經(jīng)過(guò)高度優(yōu)化的雖然用MicroPython調(diào)用但底層關(guān)鍵函數(shù)如圖像二值化、色彩空間轉(zhuǎn)換、卷積運(yùn)算大多是用C語(yǔ)言實(shí)現(xiàn)并編譯成機(jī)器碼的保證了執(zhí)行效率。你調(diào)用的img.find_blobs()或img.find_qrcodes()等方法背后都是高效的本地代碼在運(yùn)行。3. 從零搭建你的第一個(gè)機(jī)器視覺(jué)應(yīng)用3.1 開(kāi)發(fā)環(huán)境搭建與“Hello World”第一步是準(zhǔn)備好你的硬件一塊OpenMV Cam以H7為例、一根Micro-USB數(shù)據(jù)線。軟件方面去OpenMV官網(wǎng)下載對(duì)應(yīng)你操作系統(tǒng)的OpenMV IDE。安裝過(guò)程非常簡(jiǎn)單一路下一步即可。連接攝像頭打開(kāi)IDE。首次連接時(shí)IDE可能會(huì)提示更新固件。務(wù)必確保固件版本與IDE版本匹配這是避免很多詭異問(wèn)題的前提。更新固件通常通過(guò)IDE內(nèi)置的“燒錄固件”工具完成選擇最新穩(wěn)定版過(guò)程全自動(dòng)。環(huán)境就緒后我們來(lái)寫(xiě)一個(gè)最簡(jiǎn)單的“Hello World”——實(shí)時(shí)顯示攝像頭畫(huà)面。在IDE中新建一個(gè)腳本main.py輸入以下代碼import sensor, image, time # 初始化攝像頭傳感器 sensor.reset() # 重置傳感器 sensor.set_pixformat(sensor.RGB565) # 設(shè)置像素格式為RGB565彩色 sensor.set_framesize(sensor.QVGA) # 設(shè)置幀大小為QVGA (320x240) sensor.skip_frames(time 2000) # 等待設(shè)置生效跳過(guò)一些幀 clock time.clock() # 創(chuàng)建一個(gè)時(shí)鐘對(duì)象來(lái)跟蹤FPS while(True): clock.tick() # 更新FPS時(shí)鐘 img sensor.snapshot() # 從攝像頭抓取一幀圖像 print(clock.fps()) # 在串口終端打印幀率點(diǎn)擊IDE左下角的“運(yùn)行”按鈕綠色三角形。如果一切正常你會(huì)在IDE右側(cè)的“幀緩沖區(qū)”窗口看到實(shí)時(shí)視頻流并在下方的“串口終端”看到不斷刷新的幀率FPS數(shù)據(jù)。這個(gè)簡(jiǎn)單的流程驗(yàn)證了硬件連接、驅(qū)動(dòng)、基礎(chǔ)圖像采集的完整性是后續(xù)所有復(fù)雜應(yīng)用的基礎(chǔ)。3.2 核心視覺(jué)算法實(shí)戰(zhàn)顏色塊識(shí)別與追蹤顏色識(shí)別是OpenMV最經(jīng)典、最實(shí)用的功能之一。其核心是利用find_blobs函數(shù)在圖像中尋找符合特定顏色閾值的連通區(qū)域Blob。下面我們實(shí)現(xiàn)一個(gè)識(shí)別并框出紅色色塊的功能。import sensor, image, time # 顏色跟蹤閾值 (L Min, L Max, A Min, A Max, B Min, B Max) # 在LAB色彩空間下紅色通常表現(xiàn)為A分量值很高。 # 閾值需要根據(jù)實(shí)際燈光環(huán)境和目標(biāo)顏色進(jìn)行調(diào)整 red_threshold (30, 70, 40, 80, 10, 70) sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(time 2000) sensor.set_auto_gain(False) # 關(guān)閉自動(dòng)增益為了顏色穩(wěn)定 sensor.set_auto_whitebal(False) # 關(guān)閉自動(dòng)白平衡為了顏色穩(wěn)定 clock time.clock() while(True): clock.tick() img sensor.snapshot() # 在圖像中尋找所有色塊 blobs img.find_blobs([red_threshold], pixels_threshold100, area_threshold100, mergeTrue) if blobs: # 找到最大的色塊 largest_blob max(blobs, keylambda b: b.pixels()) # 在圖像上繪制一個(gè)矩形框出色塊 img.draw_rectangle(largest_blob.rect(), color(255,0,0)) # 在框的中心畫(huà)一個(gè)十字 img.draw_cross(largest_blob.cx(), largest_blob.cy(), color(0,255,0)) # 打印色塊的中心坐標(biāo)和大小 print(中心坐標(biāo): [%d, %d], 像素面積: %d % (largest_blob.cx(), largest_blob.cy(), largest_blob.pixels())) print(clock.fps())關(guān)鍵參數(shù)解析與調(diào)參心得色彩空間與閾值OpenMV默認(rèn)使用LAB色彩空間進(jìn)行顏色追蹤。L代表亮度A代表紅綠色譜B代表黃藍(lán)色譜。設(shè)定閾值(L_min, L_max, A_min, A_max, B_min, B_max)就是定義了一個(gè)LAB立方體只有落在這個(gè)立方體內(nèi)的像素才會(huì)被選中。如何確定閾值最實(shí)用的方法是使用OpenMV IDE自帶的“工具 - 機(jī)器視覺(jué) - 閾值編輯器”。在這個(gè)工具里你可以實(shí)時(shí)調(diào)整六個(gè)滑塊觀察圖像中哪些部分被高亮白色直到目標(biāo)物體被完整選出而背景盡可能為黑色。然后將得到的閾值填入代碼。pixels_threshold與area_threshold這兩個(gè)參數(shù)用于過(guò)濾噪聲。pixels_threshold指一個(gè)色塊至少需要有多少個(gè)像素點(diǎn)才被認(rèn)可area_threshold指色塊的外接矩形面積至少需要多大。它們能有效過(guò)濾掉圖像中的小噪點(diǎn)。我的經(jīng)驗(yàn)是先從較小的值如50開(kāi)始如果發(fā)現(xiàn)很多小噪點(diǎn)被誤識(shí)別再逐步調(diào)大。mergeTrue這個(gè)參數(shù)非常有用。當(dāng)同一個(gè)目標(biāo)物體因?yàn)楣庹詹痪蛔R(shí)別成幾個(gè)相鄰的小色塊時(shí)開(kāi)啟合并功能會(huì)將它們合并成一個(gè)大的色塊使識(shí)別結(jié)果更穩(wěn)定。環(huán)境光的影響顏色識(shí)別最大的敵人是光線變化。務(wù)必關(guān)閉自動(dòng)增益和自動(dòng)白平衡否則攝像頭會(huì)隨著環(huán)境光調(diào)整參數(shù)導(dǎo)致你精心調(diào)好的閾值失效。在固定的光照環(huán)境下開(kāi)發(fā)或者考慮使用輔助光源如LED補(bǔ)光燈來(lái)創(chuàng)造穩(wěn)定的照明條件是項(xiàng)目成功的關(guān)鍵。4. 進(jìn)階應(yīng)用與STM32等主控的協(xié)同工作OpenMV Cam本身可以獨(dú)立完成“感知-處理-決策”的全流程。但在更復(fù)雜的系統(tǒng)中它常常扮演“視覺(jué)傳感器”的角色將識(shí)別結(jié)果通過(guò)串口、I2C、SPI等通信方式發(fā)送給一個(gè)更強(qiáng)大的主控制器如STM32由主控負(fù)責(zé)運(yùn)動(dòng)控制、邏輯決策、網(wǎng)絡(luò)通信等任務(wù)。這是“OpenMV與STM32通信”成為熱門(mén)搜索詞的原因。4.1 串口通信最經(jīng)典的交互方式串口UART是嵌入式設(shè)備間通信最普遍、最可靠的協(xié)議。OpenMV與STM32的通信通?;诖?。我們修改上面的顏色識(shí)別代碼使其通過(guò)串口發(fā)送色塊的中心坐標(biāo)。OpenMV端代碼發(fā)送端:import sensor, image, time from pyb import UART # 初始化UART3波特率115200 (TXP4, RXP5 on OpenMV Cam H7) uart UART(3, 115200) sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(time 2000) red_threshold (30, 70, 40, 80, 10, 70) # 根據(jù)實(shí)際情況調(diào)整 while(True): img sensor.snapshot() blobs img.find_blobs([red_threshold], pixels_threshold100, area_threshold100, mergeTrue) if blobs: largest_blob max(blobs, keylambda b: b.pixels()) # 格式化數(shù)據(jù)為字符串例如X:123,Y:456\n data_str X:%d,Y:%d\n % (largest_blob.cx(), largest_blob.cy()) uart.write(data_str) # 通過(guò)串口發(fā)送 else: uart.write(X:0,Y:0\n) # 未識(shí)別到目標(biāo)時(shí)發(fā)送特定值 time.sleep_ms(50) # 控制發(fā)送頻率避免串口緩沖區(qū)溢出STM32端代碼接收端以HAL庫(kù)為例:在STM32的工程中你需要初始化一個(gè)串口例如USART1并開(kāi)啟中斷接收。在中斷服務(wù)函數(shù)或主循環(huán)的輪詢接收中解析來(lái)自O(shè)penMV的數(shù)據(jù)。// 示例在串口中斷中接收并解析一幀數(shù)據(jù) char uart_rx_buffer[64]; uint8_t uart_rx_index 0; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart-Instance USART1_INSTANCE) { char rx_char uart_rx_buffer[uart_rx_index]; if (rx_char \n) { // 接收到幀結(jié)束符 uart_rx_buffer[uart_rx_index] \0; // 字符串終止符 // 解析數(shù)據(jù)例如使用sscanf int x 0, y 0; if (sscanf(uart_rx_buffer, X:%d,Y:%d, x, y) 2) { // 成功解析出x, y坐標(biāo)可以用于后續(xù)控制邏輯 // 例如控制舵機(jī)轉(zhuǎn)向(x,y)方向 } uart_rx_index 0; // 重置緩沖區(qū)索引 } else { uart_rx_index; if (uart_rx_index sizeof(uart_rx_buffer)) { uart_rx_index 0; // 防止緩沖區(qū)溢出 } } // 重新啟動(dòng)接收中斷 HAL_UART_Receive_IT(huart, (uint8_t*)uart_rx_buffer[uart_rx_index], 1); } }通信協(xié)議設(shè)計(jì)心得幀結(jié)構(gòu)一定要設(shè)計(jì)一個(gè)簡(jiǎn)單的幀結(jié)構(gòu)。最常用的就是“數(shù)據(jù)頭數(shù)據(jù)體幀尾”的形式。上面的例子用換行符\n作為幀尾非常簡(jiǎn)單有效。更復(fù)雜的可以加入數(shù)據(jù)頭如$、校驗(yàn)和等提高抗干擾能力。波特率115200是常用的波特率在傳輸坐標(biāo)這類(lèi)數(shù)據(jù)量不大的情況下完全夠用。如果傳輸小圖片或特征數(shù)據(jù)可以考慮提高到921600甚至更高。流量控制OpenMV處理圖像和發(fā)送數(shù)據(jù)是連續(xù)的而STM32可能忙于其他任務(wù)。如果STM32處理不過(guò)來(lái)會(huì)導(dǎo)致數(shù)據(jù)丟失。一個(gè)簡(jiǎn)單的軟件流控方法是STM32在準(zhǔn)備好接收新數(shù)據(jù)時(shí)發(fā)送一個(gè)特定字符如R給OpenMVOpenMV收到后才發(fā)送下一幀數(shù)據(jù)。4.2 項(xiàng)目案例基于OpenMV和STM32的云臺(tái)跟蹤裝置這個(gè)項(xiàng)目是搜索熱詞“基于stm32及openmv的云臺(tái)跟蹤裝置”的具體實(shí)現(xiàn)。其核心思想是讓OpenMV識(shí)別目標(biāo)如人臉、色塊計(jì)算出目標(biāo)在圖像中的坐標(biāo)偏差然后將偏差值發(fā)送給STM32。STM32根據(jù)偏差值通過(guò)PID控制算法驅(qū)動(dòng)兩個(gè)舵機(jī)俯仰和偏航使攝像頭始終對(duì)準(zhǔn)目標(biāo)實(shí)現(xiàn)閉環(huán)跟蹤。系統(tǒng)分工OpenMV負(fù)責(zé)圖像采集、目標(biāo)識(shí)別、計(jì)算目標(biāo)中心與圖像中心的像素偏差(dx, dy)。STM32負(fù)責(zé)接收偏差數(shù)據(jù)將像素偏差轉(zhuǎn)換為舵機(jī)角度增量執(zhí)行PID計(jì)算輸出PWM信號(hào)控制舵機(jī)。關(guān)鍵點(diǎn)坐標(biāo)映射需要標(biāo)定像素偏差與舵機(jī)轉(zhuǎn)動(dòng)角度的比例關(guān)系。例如圖像中心在(160,120)目標(biāo)在(200,100)則偏差dx40, dy-20。通過(guò)實(shí)驗(yàn)確定“每像素偏差對(duì)應(yīng)多少度舵機(jī)轉(zhuǎn)角”。PID調(diào)參這是讓云臺(tái)運(yùn)動(dòng)平滑、不震蕩的核心。比例(P)系數(shù)決定響應(yīng)速度積分(I)消除靜態(tài)誤差微分(D)抑制超調(diào)。需要耐心在實(shí)物上調(diào)試。通信穩(wěn)定性跟蹤是實(shí)時(shí)任務(wù)通信延遲和丟幀會(huì)嚴(yán)重影響效果。除了使用可靠的串口通信也可以在算法上加入預(yù)測(cè)濾波如卡爾曼濾波在OpenMV端預(yù)測(cè)目標(biāo)下一幀的可能位置使運(yùn)動(dòng)更平滑。5. 常見(jiàn)問(wèn)題排查與性能優(yōu)化技巧在實(shí)際開(kāi)發(fā)中你一定會(huì)遇到各種各樣的問(wèn)題。下面是我總結(jié)的一些典型問(wèn)題及其解決方法。5.1 圖像質(zhì)量與識(shí)別率問(wèn)題問(wèn)題識(shí)別不穩(wěn)定時(shí)有時(shí)無(wú)。排查首先檢查環(huán)境光是否穩(wěn)定。用閾值編輯器工具在目標(biāo)物體位置和背景位置分別取色看閾值是否能把它們明確分開(kāi)。如果光線變化大考慮增加遮光罩或固定光源。技巧嘗試不同的色彩空間。OpenMV也支持sensor.set_pixformat(sensor.GRAYSCALE)進(jìn)行灰度處理然后使用img.find_edges()或img.find_template()進(jìn)行形狀匹配有時(shí)對(duì)光照的魯棒性比顏色更好。問(wèn)題幀率(FPS)太低導(dǎo)致跟蹤卡頓。排查首先降低幀分辨率。QVGA (320x240)是性能和精度的良好平衡點(diǎn)。如果還不行嘗試sensor.set_windowing((160, 120))進(jìn)行區(qū)域裁剪只處理你關(guān)心的圖像區(qū)域。優(yōu)化簡(jiǎn)化算法。find_blobs是比較耗時(shí)的操作。如果目標(biāo)顏色單一且背景干凈可以嘗試先進(jìn)行img.binary([threshold])二值化然后用img.get_statistics()計(jì)算二值化后白色區(qū)域的質(zhì)心這種方法速度更快。5.2 通信與系統(tǒng)集成問(wèn)題問(wèn)題STM32收不到OpenMV的數(shù)據(jù)或者收到亂碼。檢查接線確保TX接RXRX接TXGND共地。這是最常犯的錯(cuò)誤。檢查波特率雙方波特率必須嚴(yán)格一致。在OpenMV IDE的串口終端查看發(fā)送的數(shù)據(jù)是否正??梢韵扔秒娔X串口助手測(cè)試OpenMV單方面發(fā)送是否正常。檢查電平OpenMV Cam的IO口是3.3V電平確保你的STM32也是3.3V電平否則需要電平轉(zhuǎn)換。問(wèn)題系統(tǒng)運(yùn)行一段時(shí)間后死機(jī)或重啟。排查電源舵機(jī)等執(zhí)行機(jī)構(gòu)在啟動(dòng)和堵轉(zhuǎn)時(shí)會(huì)產(chǎn)生很大的瞬時(shí)電流可能導(dǎo)致電源電壓被拉低引起微控制器復(fù)位。務(wù)必為舵機(jī)提供獨(dú)立、功率足夠的電源如專(zhuān)用電池或穩(wěn)壓模塊并與控制板的電源做好隔離共地即可。檢查內(nèi)存泄漏在MicroPython中如果在循環(huán)里不斷創(chuàng)建新的對(duì)象如列表、字典而不釋放可能導(dǎo)致內(nèi)存耗盡。盡量復(fù)用對(duì)象。5.3 進(jìn)階功能實(shí)現(xiàn)思路數(shù)字識(shí)別/物體識(shí)別對(duì)于打印體數(shù)字或特定圖標(biāo)可以使用OpenMV內(nèi)置的image.find_template()進(jìn)行模板匹配或者使用image.find_number()、image.find_letter()功能需要訓(xùn)練字體。對(duì)于更通用的物體識(shí)別可以考慮使用OpenMV的tf模塊加載在PC上訓(xùn)練好的TensorFlow Lite微模型.tflite格式實(shí)現(xiàn)端側(cè)AI推理。巡線這是機(jī)器人比賽的常見(jiàn)任務(wù)。核心是使用img.get_regression()函數(shù)。先通過(guò)顏色閾值獲取賽道線通常是黑色或白色的二值圖像然后使用線性回歸算法擬合出線的方向和中線。根據(jù)擬合出的直線角度和偏移量就可以計(jì)算出小車(chē)的轉(zhuǎn)向控制量。與K210等AI芯片協(xié)作當(dāng)OpenMV的算力無(wú)法滿足復(fù)雜模型如YOLO目標(biāo)檢測(cè)時(shí)可以將其作為高清攝像頭使用通過(guò)DVP或MIPI接口將原始圖像數(shù)據(jù)發(fā)送給K210。K210完成AI推理后再將結(jié)果如物體類(lèi)別和坐標(biāo)通過(guò)串口返回給OpenMV或主控STM32。這種架構(gòu)兼顧了高清采集和強(qiáng)大AI算力。OpenMV的魅力在于它極大地降低了機(jī)器視覺(jué)的應(yīng)用門(mén)檻讓開(kāi)發(fā)者能專(zhuān)注于算法邏輯和系統(tǒng)集成而非底層驅(qū)動(dòng)和移植。從簡(jiǎn)單的顏色追蹤到復(fù)雜的多目標(biāo)識(shí)別從獨(dú)立的智能模塊到與STM32構(gòu)成的強(qiáng)大系統(tǒng)它提供了一個(gè)充滿可能性的平臺(tái)。我個(gè)人的體會(huì)是多動(dòng)手實(shí)驗(yàn)善用IDE的調(diào)試工具從小功能開(kāi)始迭代是掌握OpenMV最快的方式。當(dāng)你看到自己編寫(xiě)的幾行Python代碼讓硬件“看見(jiàn)”并理解世界時(shí)那種成就感是驅(qū)動(dòng)你繼續(xù)探索的最佳動(dòng)力。