Quantcast
Channel: CAVEDU教育團隊技術部落格
Viewing all 678 articles
Browse latest View live

新版 BBC micro:bit,多了麥克風與小喇叭還有觸碰功能!

$
0
0
撰寫/攝影 曾吉弘 / 圖片擷取於micro:bit官方網站

 

micro:bit 在上市五年之後,終於推出新版本,預計今年11月陸續供貨,直接為大家整理重點:

  1. 多了麥克風與小喇叭,不用再用擴充板或剪耳接線,就可以有聲音的輸入輸出功能了。效果可參考這個影片:

  1. 舊版程式完全相容
  2. 努力相容所有現有擴充板
  3. 程式語言豐富,make code, c/c++, python , ARM
  4. 藍牙 5.0 !(希望使用起來更穩定)
  5. 可愛小 logo 現在可以觸碰哦!

 

記憶體也從原本的 256 kB flash, 16 kB RAM 提升到 512 kB flash, 128 kB RAM。原廠並表示支援省電模式,這得等到實際拿到板子玩玩看才知道效果如何。

外觀

正面的 logo 變成可以觸碰之外,在 logo 右側就是麥克風的位置,並有一個指示用的 LED。背面則可以看到麥克風本體以及喇叭(中央的黑色大菱形)。常用的五個腳位則是向內凹一點點,據說是為了方便接線(鱷魚夾)。

來看看官方的介紹影片吧,做得愈來愈可愛了!

支援開發環境

新舊版的 micro:bit 一樣都支援以下的開發環境,更多技術資料可以參考原廠網站

  • The micro:bit Device Abstraction Layer (DAL/runtime)
  • MakeCode 編輯器
  • Python Editor:同上述連結,可在同一個專案頁面中切換程式積木與 python 程式碼(別忘了原本有 JavaScript 可以用)。
  • DAPlink:micro:bit 是一款基於 ARM 架構的嵌入式系統,因此可使用 DAPLink 開發介面,可參考維基百科說明

規格比較

最後為對於細節規格有興趣的朋友整理新舊款的規格比較

現行 v1.5 版 規格 最新 (v2)
Nordic Semiconductor nRF51822 處理器 Nordic Semiconductor nRF52833
256 kB flash, 16 kB RAM 記憶體

 

512 kB flash, 128 kB RAM
麥克風 MEMS 麥克風

指示用 LED

喇叭 板載發聲晶片
Logo 觸碰區 支援觸碰功能
共25隻腳位。三組專用 GPIO 以及 PWM, i2C, SPI 與外部供電腳位。三組腳位方便搭配鱷魚夾 接腳 共25隻腳位。三組專用 GPIO 以及 PWM, i2C, SPI 與外部供電腳位。三組腳位方便搭配鱷魚夾

(腳位內凹方便接線)

共用 I2C 匯流排 I2C 專用 I2C 匯流排(週邊裝置)
2.4 GHz micro:bit radio

BLE 藍牙 4.0

無線通訊 2.4 GHz micro:bit radio

BLE 藍牙 5.0

micro USB: 5V

腳位或電池盒:3V

輸入電源 micro USB: 5V

腳位或電池盒:3V

新增 LED 電源指示燈

90 mA 腳位輸出電流 200 mA
ST LSM 303 動態感測器  ST LSM 303  (相同)
C++ / MakeCode / Python /

Scratch

支援程式語言 C++ / MakeCode / Python /

Scratch  (相同)

5 x 4 (cm) 尺寸 5 x 4 (cm) (相同)

 


在NVIDIA Jetson Nano上實現JetBot AI自駕車專案-02控制移動篇

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 郭俊廷、蔡雨錡
難度

★★★☆☆

所需時間 2小時

 

一、介紹

首先來看看我們移動的影片及操作時的照片

JetBot網頁控制車子移動影片

接著介紹我們使用的DFRobot馬達驅動板,因為我們程式裡寫好各個馬達接線對應的腳位,請按照以下腳位接在相對應的位子,JetBot才會朝正確的方向移動。

以下是DFRobot馬達驅動板跟馬達接線表還有圖片。

  馬達                 DFRobot驅動板
左馬達紅線 M1-
左馬達黑線 M1+
右馬達紅線 M2+
右馬達黑線 M2-

DFRobot馬達驅動板跟馬達接線表

DFRobot驅動板接線圖

 

二、JetBot範例介紹基本移動

首先進入JupyterLab的網址是http://<jetbot_ip_address>:8888

點選左邊的路徑”Home > Notebooks可以看到我們JetBot的範例都在這邊。

有基本移動、避開障礙物、目標跟隨、道路跟隨、搖桿控制。

 

今天我們要來介紹Basic Motion跟teleoperation的功能。

Basic Motion的功能是車子操作基本移動的範例。

teleoperation的功能是使用搖桿來控制車子。

 

接下來會介紹部分程式碼所代表的意思跟功能。

首先點選左邊的路徑”Home > Notebooks > basic_motion > basic_motion.ipynb”,就能打開JupyterLab的Basic Motion畫面。

Basic Motion畫面

在JupyterLab中每一段執行的程式碼的地方我們都稱為一個區塊(Cell),區塊的執行順序通常都由第一個執行到最後一個。

在JupyterLab中執行程式碼的方式為點選程式碼區塊,然後按下快捷鍵”Shift+Enter”,或上面RUN的按鈕來執行程式,執行中的區塊會顯示*號。當執行過該區塊程式即會在該區塊前顯示執行順序的數字。

RUN的按鈕位置與執行的區塊如上圖紅色框框所示

執行中的區塊會顯示*號

 

首先這兩個區塊先宣告我們使用到的參數 Robot

並且定義馬達驅動板的參數,不同的馬達驅動板有不同的參數。

 

如果是使用我們DFrobot馬達驅動板需要改成以下參數

robot = Robot(driver_board="dfrobot")

 

如果是使用Adafruit的馬達驅動板,並且使用官方預設的函式庫,使用預設的程式即可

robot = Robot()

如果馬達驅動板沒有問題可以看到以下執行結果:

board begin success

執行程式碼之後車子輪胎會開始移動所以需先抬高車身讓車子輪胎懸空,避免車子撞到或摔落至地板(如下圖)

當您執行到第3個區塊時,應該就可以看到馬達開始動了,以30%的速度向左轉,如果沒有,請確認一下馬達驅動板有沒有接上電或者是馬達驅動板跟馬達接線是否有正確接好。

robot.left(speed=0.3)

這裡的speed=0.3 就是車子移動速度的百分比,可以依照你想要的速度修改數值

執行到第4個robot.stop()區塊時車子才會停止

第5個區塊使用 import time 宣告時間參數

第6個區塊預設的範例是讓車子左轉30%的速度,執行0.5秒後停止。可以依照自己想要的移動跟時間跟速度修改數值。

robot.left(0.3)       車子左轉30%的速度

time.sleep(0.5)     執行0.5秒

robot.stop()          車子停止

執行第7第8個區塊是一樣的移動方式,但有不同的寫法,以下介紹兩種不同的寫法。

分別都是以左馬達30%的速度前進,右馬達60%的速度前進移動車子一秒這樣車子就會朝左拱形移動一秒。

 

第7個區塊的寫法

robot.set_motors(0.3, 0.6)   車子左馬達30%的速度前進、右馬達60%的速度前進

time.sleep(1.0)                     執行1秒

robot.stop()                          車子停止

 

第8個區塊的寫法

robot.left_motor.value = 0.3       車子左馬達30%的速度前進

robot.right_motor.value = 0.6     右馬達60%的速度前進

time.sleep(1.0)                           執行1秒

robot.left_motor.value = 0.0       車子左馬達停止

robot.right_motor.value = 0.0     車子右馬達停止

第9個區塊是建立一個滑桿,用來控制左右馬達,移動速度的數值由-1到1。

第10個區塊會把上面的滑桿真正連結到馬達中,這時候才可以透過滑桿來控制馬達速度。

 

執行到第10個區塊時,就可以回到第9個區塊去拉動滑桿,看看能否用滑桿來分別控制兩個馬達的馬力以及正反轉。

執行到第12個區塊時,會解除滑桿的連結,這時候改變滑桿的數值馬達的轉速就不會跟著改變。

接著是第14個區塊是建立出一個移動的控制視窗,有前、後、左、右跟停止。

第15個區塊是定義前、後、左、右、停止所執行的動作。

第16個區塊是連結各個按鈕所對應到的動作。

所以執行到第16個區塊時,就可以回到第14個區塊去點選按鈕,看看能否透過按鍵來控制馬達的行為,如果前後左右控制都對代表馬達接線正常,基本移動功能正常,不正常移動則檢查接線有無脫落或接線有無錯誤。

創建移動的控制視窗

定義按鈕、按鈕功能連結

以下是我們實際操作的影片:

以上我們基本移動的介紹就在這裡告一段落。

 

注意:

執行完一個檔案的功能之後記得關閉kernel和使用視窗

  1. 點選正在使用的視窗上的叉叉
  2. 點選左邊目錄第二個選項的人離開的圖案
  3. 按SHUTDOWN關閉正在使用的所有kernel才可執行下一個檔案

接下來執行完每個檔案都要這樣做,才不會導致各個執行序互相衝突。

關閉kernel之步驟

 

三、JetBot範例介紹搖桿移動

關閉完Basic Motion的kernel之後

我們來介紹Teleoperation,也就是用搖桿控制車子的功能。

首先點選左邊的路徑”Home > Notebooks > teleoperation > teleoperation.ipynb”,就能打開以下的JupyterLab的Teleoperation畫面。

我們使用Logitech F710 無線遊戲控制器來當作我們的控制器,搖桿部分沒有特別規定型號有線無線都可以,只要支援HTML5 Gamepad的搖桿皆可使用,把接受器或USB插入電腦中即可使用。

進入以下html5gamepad網址檢查搖桿可無使用並查看INDEX的數字是多少,目前我使用的Logitech F710所得到的INDEX是1。

之後需要填入相對應的地方,搖桿才能正常使用控制車子。

http://html5gamepad.com

第1個區塊是定義使用元件,定義搖桿的index,還有顯示搖桿的對應的數字。

按下任何按鈕即可偵測到搖桿,搖桿上每個按鈕都有對應的號碼。例如我的左搖桿往前後時對應的是滑桿1,右搖桿往前後時對應的是滑桿3,按鈕下對應的是13。之後程式有用到的時候只要改變對應的數字就可以使該數字執行相對應的功能。

在下面這一段程式碼index=1的部分這裡要依照你們剛剛網頁取得的INDEX來填入,預設是1,我們得到的是0所以需要把INDEX的數值改成0。(如下圖紅框處)

controller = widgets.Controller(index=1)  # replace with index of your controller

第2個區塊,連結搖桿跟馬達所對應的功能,當使用滑桿1的時候依照滑桿的數值讓左馬達轉動,使用滑桿3的時候依照滑桿的數值讓右馬達轉動。

我們的實際操作畫面如下

第3個區塊會建立一個長、寬各300的畫面來顯示等一下會建立的攝影機畫面。

第4個區塊宣告攝影機的參數跟定義攝影機的instance

第5個區塊這裡才會將攝影機畫面連結到剛剛第3個區塊建立的畫面,這時可以回去第3個區塊看看有無正卻看到攝影機的畫面。

攝影機呈現出的畫面如下圖

第8個區塊則是使用我們的搖桿結合攝影機的功能來達到拍照的功能。

建立一個snapshots的資料夾當我們按了buttons[5]即可儲存當下的照片,儲存的格式用jpeg,長寬都是300。儲存照片檔的命名格式使用uuid。

buttons[5]根據我們的Logitech F710所對應的是RB,當按下RB就會拍下照片顯示在右邊的畫面並存在snapshots的資料夾裡(如下圖所示)。也可以改變按鈕號碼更改搖桿對應的按鈕,各位也可以嘗試看看。

以上移動篇的講解到這邊告一段落,各位有沒有成功讓車子移動呢?接著我們會繼續介紹更多JetBot相關的範例,有興趣的歡迎繼續關注我們。

 

*本文由RS components 贊助發表

在NVIDIA Jetson Nano上實現JetBot AI自駕車專案-03迴避障礙篇(上)

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 郭俊廷
難度

★★★☆☆

所需時間 2小時

上次介紹了如何讓JetBot基本移動功能可以在網頁上操控JetBot移動,並且使用搖桿控制JetBot移動,拍照等等功能。

這次開始會使用JetBot的攝影機讓JetBot達成避開障礙物的功能。

JetBot的迴避障礙效果是使用深度學習來達成的,經過資料搜集、訓練模型之後,執行程式才會有避障的效果。根據你標記的標籤來判斷JetBot透過攝影機看到的畫面該避開障礙物還是繼續行走。

首先來看看我們訓練好的成果是如何呢?

當我們看到綠色的場地直走,看到三角錐或白色的牆壁就會左轉。

 

接著介紹深度學習

所謂的深度學習是機器學習中的一種,它是以神經網路為架構對資料進行特徵學習的演算法。機器學習則是從過往資料和經驗中學習並找到其運行規則,而人工智慧則是包含所有機器學習和深度學習的範疇,只要是讓機器展現人類的智慧可以感知、推理、交流、學習、行動。

下圖是人工智慧、機器學習、深度學習的關係圖。

機器學習可以分成四大分類:

  • 監督式學習Supervised learning
  • 非監督式學習Unsupervised learning
  • 自監督式學習Self-supervised learning
  • 增強式學習Reinforcement learning

 

監督式學習是有標準答案、標註 (Annotation),所有資料都有標籤過,每個標籤提供機器相對應的值來讓機器學習輸出時判斷誤差使用。  Ex. ig、fb廣告推薦

非監督式學習是無標準答案  Ex: 分群、找關聯、編碼、異常檢測

自監督式學習則是自己根據歷史資料產生答案,對部分資料進行標籤,電腦只透過有標籤的資料找出特徵並對其它的資料進行分類。

增強式學習是觀察後,選擇最大化獎勵的行動。

 

而我們的JetBot使用的是監督式學習,把搜集到的資料標註到相對應的類別,執行相對應的動作。

機器學習跟一般傳統程式學習的差別在哪裡呢?

傳統程式是使用規則加上資料經過程式後得出答案的

機器學習是先有答案加上資料經過訓練模型後產生規則來處理後續新的資料

機器學習跟傳統程式的差別

 

使用深度學習通用的神經網路模型建立流程可以分為九個步驟

Step 1. 定義問題

Step 2. 建立資料集

Step 3. 選擇評量的成功準則

Step 4. 根據資料量決定驗證方法

Step 5. 資料預處理

Step 6. 建立並訓練模型

Step 7. 開發出Overfitting的模型

Step 8. 粗胚的精雕細琢 – 調整參數使其變成通用模型

Step 9. 應用

 

JetBot把避障使用的神經網路模型精簡分為三大步驟

Data Collection  資料搜集

Train Model   訓練模型

Live Demo  應用範例

 

接著我們一一介紹這三大步驟如何操作使用,本篇先教大家如何資料搜集,以及資料搜集的一些小技巧。

在以下路徑”Home > Notebooks >collision_avoidance”可以看到以下三個檔案,如下圖的紅框處所示。

避障資料夾的檔案位置

 

*注意:如果你是接續前一個專案繼續執行此專案,執行完前一個檔案的功能之後記得關閉kernel和使用視窗,才不會發生攝影機被占用等錯誤訊息。(相關教學請參考在Jetson nano 上執行JetBot專案Part2 移動篇之說明)

 

二、Data Collection資料搜集

首先點選左邊的路徑”Home > Notebooks >collision_avoidance > data_collection.ipynb”,就能打開以下的JupyterLab的Collision Avoidance – Data Collection畫面。

JupyterLab的Collision Avoidance – Data Collection畫面

 

以下是Data Collection資料搜集執流程圖,根據流程圖我們要先決定資料搜集時的場地背景跟燈光,還有決定甚麼是障礙物甚麼是可自由行走的分類,搜集資料拍照分類時的時間會比較快資料的辨識率也會比較準確。

以下是Data Collection資料搜集執流程圖

 

在範例說明中提到:

要解決最重要的問題之一是防止JetBot進入危險的狀態!我們稱這種行為為避免碰撞。

嘗試使用深度學習和一個非常通用的感測器:相機來解決問題。

採取避免碰撞的方法是在機器人周圍創建一個虛擬的“安全氣泡”,在此安全氣泡內,機器人可以繞圈旋轉而不會撞到任何物體。

執行此操作的方法如下:

首先我們將JetBot放置在違反其“安全氣泡”的場景中,並將這些場景拍照並添加分類為blocked。

之後我們手動將機器人放置在可以安全向前移動的場景中,並為這些場景拍照並添加分類為free。

 

因為是使用照片來訓練模型的關係,我們在搜集資料和實際執行所使用的場景跟光源請在同一場景並使用同樣的光源,不然執行起來的效果會很差。

我們使用場景如下:綠色的地板為(free)

三角錐、其他障礙物、白色牆壁背景為(blocked)

 

首先執行第1個區塊,該區塊的程式先創建一個224×224像素攝影機的畫面即時顯示在畫面上。

第2個區塊,建立一個dataset資料夾裡面有blocked跟free兩個資料夾,用來儲存等等要拍照分類的照片。

第3個區塊會建立一個增加free類別跟增加blocked類別的按鈕,並顯示該類別有幾張照片的數量。此時只是建立元件而以按下去並無任何反應。

第4個區塊將定義並連結按下free跟blocked按鈕所執行的動作,按下add free跟add blocked按鈕會使用uuid1的命名格式儲存jpg檔到相對應的資料夾。

第5個區塊,顯示目前攝影機看到的畫面,並顯示add free、add blocked類別的按鈕跟相片數量的視窗,此時按下去即會儲存照片到相對應的資料夾。

如下圖所示,目前攝影機看到的畫面是有三角錐的畫面,應該使用blocked類別,按下add blocked的按鈕之後會在dataset資料夾裡面的blocked資料夾裡新增一張照片(如圖的紅框所示)

拍好的照片可以直接在JupyterLab點選照片檔案名稱開啟查看,如發現照片拍得不好或是分類錯誤可直接點選該檔案右鍵選擇Delete刪除該檔案。

接著重複執行搜集資料分類的動作,根據檔案上的說明每個類別至少需要100張照片,嘗試不同拍照的方向、不同拍照的光源、嘗試各種物體/碰撞類型。

根據我們的場景blocked類別的拍照技巧為拍攝單一障礙物在正前方(各色測試)、單一障礙物在左側、單一障礙物在右側、雙障礙物在正前方、雙障礙物在兩側、手或腳遮住等等情況。

blocked資料夾的照片內容blocked資料夾的照片內容

 

free類別的照片則是拍攝各種光影角度跟位置來增加照片。

free資料夾的照片內容

 

第6個區塊,可以把我們搜集到的資料壓縮成zip檔,預設壓縮成dataset.zip為檔名,可以根據您執行的日期或場景來決定該zip檔的命名方式,這樣下次想使用不同的情境的場地不同的障礙物才容易分辨。

更改以下指令dataset.zip的名稱來更改要壓縮的檔名。

!zip -r -q dataset.zip dataset

以上障礙迴避篇(上)-資料搜集的講解到這邊告一段落,各位有沒有順利的搜集好資料呢?

下一篇要接著講解如何訓練模型並把模型應用到範例上。接著我們會繼續介紹更多JetBot相關的範例,有興趣的人歡迎繼續關注我們!

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

RK-Jetbot機器學習道路識別競賽 操作手冊

$
0
0

1.連上JupyterLab

首先我們會先把網路線接上jetbot,透過筆電共用網路給jetbot,使用Wireless Network Watcher這套軟體來掃描同網段的IP,並連線進JupyterLab,即可開始我們的道路識別操作流程。

打上你掃描的IP:8888進入JupyterLab

例如我的IP是192.168.137.227

就在網址列輸入192.168.137.227:8888 即可進入以下畫面

密碼是jetbot

1.1 進入道路跟隨範例

進入JupyterLab之後進入以下資料夾可以進入我們修改過的道路跟隨範例

Home>jetbot_CAVEDU>road_following

 

道路跟隨的範例分為三大步驟:資料搜集、訓練模型、即時展示

 

在以下路徑“Home>jetbot_CAVEDU>road_following”可以看到以下三個檔案,如下圖的紅框處所示。

分別是

  • Data Collection資料搜集
  • Train Model 訓練模型
  • Live Demo 即時展示

2.Data Collection資料搜集

2.1打開Data Collection畫面

點選左邊的路徑”Home>jetbot_CAVEDU>road_following > data_collection.ipynb“,就能打開以下的JupyterLab的Road Following – Data Collection畫面。

在資料搜集前先介紹場地與賽道地圖(如下圖)。

賽道地圖

2.2JupyterLab中執行方法跟呼叫函式庫

首先移動到第1個區塊執行第1個區塊Import Libraries,匯入函式庫OpenCV, JetBot, Jupyter Widgets, NumPy等等函式庫,並呼叫馬達參數等等設定。

在JupyterLab中執行程式碼的方式為點選程式碼區塊,然後按下快捷鍵”Shift+Enter”,或上面RUN的按鈕來執行程式。

 

RUN的按鈕位置如下圖紅色框框所示

*號代表程式正在執行(右上角Python3旁邊的黑色圈圈也一樣),請不要急著執行下一個區塊,要等一個區塊執行完在執行下一個區塊,*號變成數字後代表區塊執行完畢。(如下圖紅框處)

2.3更改資料搜集資料夾名稱

接著第2個區塊[Collect data]就會開始進行資料搜集了,這一步驟要注意的是要先更改你的資料搜集資料夾名稱,避免跟別人搜集的資料重複。

規定更改的資料夾名稱為參賽組別_dataset_日期

例如是第一組1030收集的資料可以命名為01_dataset_1030

更改以下程式碼引號內容的資料夾名稱 (如下圖紅框處)

DATASET_DIR = ’01_dataset_1030’

執行完第2個區塊[Collect data]可以看到旁邊新增你剛剛輸入名稱的的資料夾,下面也會顯示出資料搜集的介面了。

可以利用右邊的前、後、左、右、停止控制JetBot移動,或是一個人移動車子一個改變滑桿數值這樣搜集的效率比較快

 

利用中間的滑桿改變X軸、Y軸的數值使綠色圓點在道路的中心點,並按下[save]按鈕,將照片儲存至指定資料夾。

中間的count是顯示目前搜集了幾張照片

2.4搜集資料技巧

基本搜集的資料的訣竅如上述所說是利用中間的滑桿改變X軸、Y軸的數值使綠色圓點在道路的中心點

但你可以決定讓車子是要走在道路的中間,還是道路的內側或外側。車子走在道路的中間最安全車子最不容易跑處賽道外,車子走在道路的內側行走的時間最短但沒有訓練好轉彎很容易跑出賽道外,車子走在道路的外側轉彎比較容易通過但行走的時間也較長。一開始就要先想好你的車子要如何在賽道中行走。

搜集資料示意圖

 

建議階段二、四收集較多資料

 

2.5顯示搜集幾張照片

第3個區塊[Next]執行後會顯示目前共搜集了幾張照片。

2.6壓縮搜集資料夾

第4個區塊執行後會壓縮你搜集好的資料夾,會根據壓縮的資料夾名稱日期來命名。(如下圖的紅框所示)

壓縮好記得要把搜集資料檔案傳入隨身碟才不會不見

下載壓縮檔方式,在左邊檔案處點選右鍵Download,即可將檔案下載至你的電腦中在從電腦傳送至隨身碟。

 

2.7關閉連結攝影機

第5個區塊執行後,會關閉攝影機的連結,攝影機畫面會沒有及時同步在網頁上。

2.8關閉檔案和kernel

執行完一個檔案之後記得關閉kernel和使用視窗,即點選正在使用的視窗上的叉叉還有左邊目錄第二個選項的人離開的圖案,按SHUTDOWN關閉正在使用的所有kernel才可執行下一個檔案,才不會發生攝影機被占用等錯誤訊息。接下來執行完每個檔案都要這樣做。

3.Train Model 訓練模型

3.1打開Train Model畫面

點選左邊的路徑”Home>jetbot_CAVEDU>road_following > train_model.ipynb”,就能打開以下的JupyterLab的Road Following – Train Model畫面。

3.2匯入函式庫

執行第1個區塊[Road Follower – Train Model],匯入函式庫PyTorch, NumPy, Python Imaging Library等函式庫。

3.3解壓縮檔案(從別的地方複製壓縮檔才需要執行)

第2個區塊[Downlad and extract data],可以選擇性執行,如果已有蒐集好的資料夾則不用執行。這裡是解壓縮之前搜集的資料集,要解壓縮的檔名可以更改以下指令的ZIP檔名(如下圖紅框所示)。

!unzip -q road_following.zip

3.4更改訓練時使用資料夾名稱

第3個區塊[Create Dataset Instance],定義資料前處理方式,資料夾用你在搜集資料時所命名的資料夾,例如剛剛我們使用01_dataset_1030為命名資料夾,最下面程式碼引號裡面紅字資料夾的部分要改成對應的名稱。

 

dataset = XYDataset(’01_dataset_1030′, random_hflips=False)

3.5將資料集分成訓練集跟驗證集

第4個區塊,將資料集分成訓練集跟驗證集。

3.6設定模型訓練細節

第5個區塊,建立DataLoader,設定模型訓練細節。

3.7使用ResNet-18

第6個區塊定義神經網絡模型,使用ResNet-18 model檔。第一次使用時需要下載ResNet-18模型檔。(這裡我們都預先下載好了)

3.8轉移模型在GPU上執行

第7個區塊將轉移模型在GPU上執行。

3.9更改訓練回和數和模型檔名稱

第8個區塊[Train Regression]將會開始訓練神經網路模型,原始程式碼是訓練50回合,更改NUM_EPOCHS數字為35就會訓練35回合(目前測試150張圖片50回合為20分鐘35回合為15分鐘),根據你想訓練的回和數和剩下的時間來評估你要訓練的回和數。

模型檔名稱可以更改以下best_steering_model_xy.pth檔案名稱為自己想要的模型檔名稱。

這裡我們規定的模型檔名稱為:組別_model_收集的日期

將以下更改為

NUM_EPOCHS = 50

BEST_MODEL_PATH = 'best_steering_model_xy.pth'

 

NUM_EPOCHS = 10

BEST_MODEL_PATH = '01_model_1030.pth'

訓練完成會顯示D one!並產生一個對應檔名的模型檔.pth檔。

以這裡為例是你剛剛修改檔名的01_model_1030.pth

注意最後要把你的模型檔放入你的隨身碟才不會不見或搞混

根據每個人的搜集資料數量不同而會影響訓練時間,以150張照片35回合大約訓練15分鐘,10回合大約5分鐘。

3.10關閉檔案和kernel

執行完一個檔案之後記得關閉kernel和使用視窗,即點選正在使用的視窗上的叉叉還有左邊目錄第二個選項的人離開的圖案,按SHUTDOWN關閉正在使用的所有kernel才可執行下一個檔案,才不會發生攝影機被占用等錯誤訊息。。接下來執行完每個檔案都要這樣做。

4.Live Demo

4.1打開Live demo畫面

點選左邊的路徑”Home>jetbot_CAVEDU>road_following > live_demo.ipynb”,就能打開以下的JupyterLab的Road Following – Live demo畫面。

這裡會將攝影機看到的畫面根據之前X軸跟Y軸所指向的方向做出相對應的前進方向,這裡需要有相對應的模型檔才可以執行該檔案

4.2使用PyTorch函式庫設定模型參數

首先執行第1個區塊宣告使用PyTorch函式庫設定模型參數

4.3更改模型檔名稱

第2個區塊預設使用模型檔best_steering_model_xy.pth為模型,如果之前有儲存的模型檔為別的檔名一樣在這個部分更改為自己的模型檔名。(如下圖紅框所示)

例如我們剛剛命名的模型檔為01_model_1030.pth即更改為01_model_1030.pth

 

model.load_state_dict(torch.load(’01_model_1030.pth’))

 

第3個區塊是把模型權重從CPU內存轉移到GPU上執行。

4.4定義影像預處理方法

第4個區塊是定義影像預處理方法

4.5創建攝影機畫面、定義馬達參數

4.6定義JetBot控制滑塊和顯示滑塊

第6個區塊定義JetBot控制滑塊和顯示滑塊

右邊定義滑塊來控制JetBot,這裡目前只是定義還沒連結功能所以目前改變數值並不會使車子移動,以下是四個滑塊的數值的解釋。

 

Speed Control (speed_gain_slider): 直線速度,預設是0,請慢慢增加速度不要一開始就調整至最大值。

 

Steering Gain Control (steering_gain_sloder): 搖擺程度,如果看到JetBot搖擺不定,則需要減小此數值。

 

Steering kd (steering_dgain_slider): 微分控制,計算誤差的斜率,斜率越大,系統會對輸出結果做更快的反應。速度緩慢的系統不需要。

 

Steering Bias control (steering_bias_slider): 修正左右馬達偏差,如果看到JetBot偏向道路的最右側或最左側,則應控制此滑塊,直到JetBot在道路正中間行駛。

 

這裡設定完要記得記錄你調整的數值,正式比賽就是使用這組數值來在場地上跑。

 

建議慢慢修改數值,以較低的速度控制上述滑塊,才能得到效果較好的JetBot道路跟隨行為。

 

另外左邊定義

四個滑塊,分別顯示目前X軸、Y軸的數值還有JetBot的直線速度跟搖擺程度的數值。

 

4.7定義執行辨識跟控制馬達的函式

這一步驟要注意車子會開始移動,請注意車子的位置不要擺在桌子上或使用東西讓車子墊高避免車子摔落或撞壞(如下圖)實際執行時車子都放到賽道上

第7個區塊這裡開始JetBot會移動並定義執行辨識跟控制馬達的函式,會根據攝影機的畫面判斷X軸、Y軸的位置並決定該直行還是左轉右轉。並把X軸、Y軸的值傳回第6個區塊,連結第6個區塊並可透過第6個區塊的值來改變JetBot的速度、搖擺程度等等數值。(這時候攝影機畫面還沒同步,車子還沒同步更新改變車子的速度也不會有反應)

4.8傳回攝影機畫面、車子開始移動

第8個區塊這裡會更新攝影機畫面傳回去給程式判斷,如果沒有執行這一步驟,攝影機的畫面將一直是沒有同步的狀態,執行完這個區塊才可以回到第6個區塊控制JetBot的速度、搖擺程度等等數值並將其他狀態顯示在第6個區塊。

4.9停止傳回攝影機畫面、車子停止移動

第9個區塊將停止同步畫面傳送,移動路徑判斷也會停止。並停止JetBot的移動。

4.10關閉檔案和kernel

執行完一個檔案之後記得關閉kernel和使用視窗,即點選正在使用的視窗上的叉叉還有左邊目錄第二個選項的人離開的圖案,按SHUTDOWN關閉正在使用的所有kernel才可執行下一個檔案,才不會發生攝影機被占用等錯誤訊息。接下來執行完每個檔案都要這樣做。

微軟 LOBE ai –離線訓練影像辨識模型!

$
0
0
撰寫/攝影 曾吉弘
時間 1.5 – 2 hrs
成本 具備webcam的筆記型電腦或桌上型電腦
難度

★★★☆☆

Lobe ai

  Lobe ai 是微軟推出的離線版神經網路分類工具,相較於 Google Teachable Machine,離線就能訓練神經網路也許更適合教室使用。這股浪潮確實是資料驅動(data-driven)的時代,誰能掌握高品質的資料誰就能更快擁有合乎需求的神經網路。CAVEDU 2019 年所出版[實戰AI資料導向式學習]也有談到這個概念,使用 Raspberry Pi 搭配 Keras 訓練的視覺分類神經網路模型來實作路牌辨識機器人(讓我打一下書~嘛)

好,回歸正題,快開啟主頁面(https://lobe.ai)來看看!

根據主頁,目前可用的功能為影像分類,後續會推出物件偵測與資料分類等,非常令人期待。

下載與安裝

 

   請由主頁右上角的 Download 選項來下載,安裝包大約 380MB。依照預設設定安裝完畢,開啟主畫面如下,相當清爽。

   點選 New Project 來開啟新專案,目前只有影像分類可用囉

建立專案

 

    空白專案畫面如下,我今天想要辨識兩種目標,都是玩具:薩克頭(zaku) 與 德姆頭 (DOM),因此總共需要三個類別,第三個類別是用來處理以上皆非的狀況,否則後續在辨識時就算看到別的東西,您的神經網路也只能薩克 / 德姆二選一。

 

    Lobe 標榜每個類別只要5張照片就可以訓練,這真的是很厲害的數字啊!

點選右上角 Import,可以看到有三種建立資料集的方式,

Images: 從電腦端上傳照片

Camera: 使用 webcam 拍照

Dataset: 上傳已經整理好的資料集

 

在此使用 Camera 方便我們快速驗證。

建立資料集

 

在此總共建立三個類別:zaku、dom 與 other。

在上一步的 Import → Camera 之後,會出現即時的 webcam 畫面,點選中間的圓圈就會拍照,一直按著就會連拍。

 

本專案針對薩克與德姆各準備兩種不同顏色與略有不同的外型,希望能看看辨識的效果如何。可以看到左側 Unlabeled (未標註) 的影片有 47張,後續再標註就好。

 

下圖左為沙漠型德姆,圖右為一般型德姆(在專業什麼..)

把想要被標誌為 dom 的照片全部選起來,點選任何一張照片左下角標籤名稱,就可以一次全部修改好。如果發現哪張照片糊了或是不滿意,都可以馬上刪除。

再來是薩克,一樣有藍色與紅色的薩克兩種。類別的照片數量請盡量保持差不多的數量。

最後是 other,這裡我放了人臉、水壺以及背景。但是請注意,可能會出現但不希望被辨識錯誤的項目才要放在 other 類別中,否則就不需要放進去喔。

訓練

發現了嗎?只要建立了第二個類別並標註之後,Lobe 就會自動開始訓練了。訓練速度和您的電腦規格有關,以我的筆記型電腦 (i7, 10GB ram),192 張照片大約10分鐘,相較於 Google Teachable Machine 的一分鐘之內來說這實在有點久,但離線執行確實有其方便之處,請您多多評估囉。

測試

   測試分為 Images Camera 兩個選項,前者讓您從電腦端上傳照片,可以看到以下這張照片被分類為 dom,分類錯誤!但您可以點選右下角的紅色禁止符號來告訴 Lobe 他做錯了並給予正確的標籤(zaku),之後再次訓練時就會更好喔!

 

接著是 Camera 即時預覽畫面,正確辨識為 zaku!您可以點選右下角的綠色勾勾將本張照片加入 zaku 類別,這時 lobe 也會馬上開始訓練。

多多調整,盡量讓每個類別的辨識結果都愈高愈好。

匯出

   如果您滿意模型表現的話,就可以匯出(export)了,這也是這類工具最棒的地方。

請點選左上角的[]圖示,開啟選單: Preferences → Project Settings,有兩個選項,分別是針對準確度最佳化以及針對速度最佳化。在此選擇後者,您可以兩個都比較看看。點選之後 Lobe 會需要一些時間完成最佳化。

接著就可以匯出了,請點選左上角的[]圖示,開啟選單:Export,會看到 lobe 提供以下三個匯出選項:TensorFlow、TensorFlow Lite 與 Local API,請點選 TensorFlow Lite 就會開始匯出。

 

下載之後會出現一個與您專案同名並加上 TFLite 的資料夾(例如 DOM_ZAKU TFLite),會有 .example 資料夾,裡面有一個 python 程式可以跑跑看。另外就是 saved_model.tflite 與 signature.json 這兩個模型檔。

在此用 https://netron.app/ 這個神經網路視覺化工具來看看 .tflite 模型,層數約在80層左右,大量使用了 Conv2D 來進行卷積運算。

 

如果選擇 local API 會出現對應的語法與 parse result 說明

範例

馬上寫一個 python 來玩玩看。請先根據本篇文章在您的電腦上安裝好 Anaconda 與所需的套件。

 

執行語法:

python LOBE_WEBCAM_tflite.py --model "DOM_ZAKU TFLite"

 

注意 LOBE_WEBCAM_tflite.py 要與 DOM_ZAKU TFLite 資料夾同一層。

 

LOBE_WEBCAM_tflite.py 內容:

#
#  -------------------------------------------------------------
#   Copyright (c) CAVEDU.  All rights reserved.
#  -------------------------------------------------------------
"""
Skeleton code showing how to load and run the TensorFlow Lite export package from Lobe.
"""

import argparse
import json
import os

import numpy as np
from PIL import Image

import cv2

import tflite_runtime.interpreter as tflite

def get_prediction(image, interpreter, signature):
    """
    Predict with the TFLite interpreter!
    """
    # Combine the information about the inputs and outputs from the signature.json file with the Interpreter runtime
    signature_inputs = signature.get("inputs")
    input_details = {detail.get("name"): detail for detail in interpreter.get_input_details()}
    model_inputs = {key: {**sig, **input_details.get(sig.get("name"))} for key, sig in signature_inputs.items()}
    signature_outputs = signature.get("outputs")
    output_details = {detail.get("name"): detail for detail in interpreter.get_output_details()}
    model_outputs = {key: {**sig, **output_details.get(sig.get("name"))} for key, sig in signature_outputs.items()}

    # process image to be compatible with the model
    input_data = process_image(image, model_inputs.get("Image").get("shape"))

    # set the input to run
    interpreter.set_tensor(model_inputs.get("Image").get("index"), input_data)
    interpreter.invoke()

    # grab our desired outputs from the interpreter!
    # un-batch since we ran an image with batch size of 1, and convert to normal python types with tolist()
    outputs = {key: interpreter.get_tensor(value.get("index")).tolist()[0] for key, value in model_outputs.items()}
    # postprocessing! convert any byte strings to normal strings with .decode()
    for key, val in outputs.items():
        if isinstance(val, bytes):
            outputs[key] = val.decode()

    return outputs


def process_image(image, input_shape):
    """
    Given a PIL Image, center square crop and resize to fit the expected model input, and convert from [0,255] to [0,1] values.
    """
    width, height = image.size

    # ensure image type is compatible with model and convert if not
    if image.mode != "RGB":
        image = image.convert("RGB")

    # center crop image (you can substitute any other method to make a square image, such as just resizing or padding edges with 0)
    if width != height:
        square_size = min(width, height)
        left = (width - square_size) / 2
        top = (height - square_size) / 2
        right = (width + square_size) / 2
        bottom = (height + square_size) / 2
        # Crop the center of the image
        image = image.crop((left, top, right, bottom))

    # now the image is square, resize it to be the right shape for the model input
    input_width, input_height = input_shape[1:3]
    if image.width != input_width or image.height != input_height:
        image = image.resize((input_width, input_height))


    # make 0-1 float instead of 0-255 int (that PIL Image loads by default)
    image = np.asarray(image) / 255.0

    # format input as model expects
    return image.reshape(input_shape).astype(np.float32)


def main():
    """
    Load the model and signature files, start the TF Lite interpreter, and run prediction on the image.

    Output prediction will be a dictionary with the same keys as the outputs in the signature.json file.
    """
    parser = argparse.ArgumentParser(
        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        '--model', help='Model path of .tflite file and .json file', required=True)
    args = parser.parse_args()
    
    with open( args.model + "/signature.json", "r") as f:
        signature = json.load(f)

    model_file = signature.get("filename")

    interpreter = tflite.Interpreter(args.model + '/' + model_file)
    interpreter.allocate_tensors()

    cap = cv2.VideoCapture(0)
    #擷取畫面 寬度 設定為640
    cap.set(cv2.CAP_PROP_FRAME_WIDTH,640)
    #擷取畫面 高度 設定為480
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

    key_detect = 0
    times=1
    while (key_detect==0):
        ret,frame =cap.read()

        image = Image.fromarray(cv2.cvtColor(frame,cv2.COLOR_BGR2RGB))

        if (times==1):
            prediction = get_prediction(image, interpreter, signature)

        print('Result = '+ prediction['Prediction'])
        print('Confidences = ' + str(max(prediction['Confidences'])) )
 
        cv2.putText(frame, prediction['Prediction'] + " " +
                    str(round(max(prediction['Confidences']),3)),
                    (5,30), cv2.FONT_HERSHEY_SIMPLEX, 1,
                    (0,0,255), 1, cv2.LINE_AA)
        
        cv2.imshow('Detecting....',frame)

        times=times+1
        if (times >= 5):
            times=1

        read_key = cv2.waitKey(1)
        if ((read_key & 0xFF == ord('q')) or (read_key == 27) ):
            key_detect = 1

    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

執行效果

    執行效果如下,會開啟一個預覽畫面,並把辨識結果(label)與信心指數顯示出來。

與 Google Teachable Machine 比較與展望

最後免不了要與Google Teachable Machine (簡稱TM)比較一下,暑期的 AIGO 高中職生扎根營隊我們大量使用 TM來匯出視覺分類模型,也可以放在 Raspberry Pi、Jetson Nano 上執行,或者連動 7697 等這類MCU板來做到各種有趣的 AIoT 應用。

 

但Lobe標榜離線運作的話,教室的網路壓力就不會這麼高了,很期待各位後許的意見分享喔!

 

Lobe.ai Teachable Machine
網路需求 下載安裝包才需要,之後都可離線使用 連線到網站使用,全程都須使用網路
訓練速度 於電腦端進行運算

根據該電腦等級而有明顯差異

200張約3-5分鐘(i7 / 16GB ram)

於電腦端進行運算

幾乎都可在1分鐘內完成

支援之神經網路 視覺分類

物件辨識(尚未)

資料分類(尚未)

視覺分類

聲音分類

姿勢分類

匯出模型格式 TensorFlow

TensorFlow Lite

TensorFlow

TensorFlow Lite

TensorFlow js

TFLite 神經網路層數 79 74

 

使用Google Teachable Machine 來實現Raspberry Pi 4 的影像分類推論

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 許钰莨/曾俊霖
難度

★★★☆☆

本文實現影像分類分成幾個步驟:

  • 在TM網頁中蒐集資料,訓練模型,在網站中即時影像分類。
  • 匯出模型及標籤檔。
  • 至樹莓派官網下載最新版本的RPi4映像檔。
  • 安裝模型框架Tensorflow Lite。
  • 安裝OpenCV套件。
  • 實現影像分類於RPi4。

 

了解以上步驟後,其建置RPi4環境的時間花得最久,但讀者們仍可同步進行,例如:RPi4在燒錄SD卡或安裝套件時,又同時在TM網站蒐集資料及訓練模型。

Teachable Machine (TM)介紹

TM網站可供初學者認識AI人工智慧的神經網路應用平台,主要是以「監督式學習Supervised learning」建置而成的訓練平台。目前網站針對使用者提供三種不同的AI應用,分別是影像分類專案(Image Project)、聲音辨識專案(Audio Project) 與身體姿態辨識專案(Pose Project),也提供了Tensorflow、Tensorflow.js與Tensorflow Lite三種訓練模型框架,可供使用者匯入如RPi4的裝置來實現邊緣運算。

每個專案都被設計成三個步驟,分別是蒐集(Gather)、訓練(Train) 與匯出(Export)。

請選擇 「Image Project」開始專案

Step1.  在TM網頁中蒐集資料,訓練模型,在網站中即時影像分類。

進入頁面後會看到幾項操作流程,a.設定標籤及蒐集資料、b.訓練集及c及時預覽功能和匯出模型。

首先在a部分,可將標籤名稱Class 1更名,接著透過電腦Webcam或Upload,從電腦或Google雲端硬碟上傳圖片,及按下「Add a class」來增加類別。本文是開啟電腦Webcam來蒐集資料。

可直接按下「Record 10 Second」,網頁便會倒數計時持續拍攝直到10秒結束,如果認為10秒的張數太少,可以按下齒輪,可以更改秒數等相關參數。初始參數有「24FPS」 (理論值為每秒鐘拍24張)、「Hold-to-record   OFF」(關閉手動拍攝)、「Delay: 2 seconds」(2秒後才開始拍攝)、「Duration: 10 second 」(拍攝10秒鐘,理論值約可拍攝240張,但實際上要取決於網頁執行效能),本文將秒數調成25秒,可以刪掉一些拍攝失敗的照片,再者也可以使資料量豐富。

按下「Save Setting」à 「Record 25 seconds」,開始拍攝,拍攝完成可將拍得不好或模糊的圖片刪除。

本文建立了5種類別,分別是「mouse」、「nothing」、「RaspberryPi」、「PEN」、「Bruce Lee」,但有一個種類必須要建立的是「nothing」,意思是沒有照到「mouse」、「RaspberryPi」、「PEN」、「Bruce Lee」時的情形。當初筆者忘了建立「nothing」種類,當沒有照到物品時,就會一直認為「mouse」。

 

要分辨的影像張數盡量不要相差太遠,本文接近約莫300張左右,在「nothing」類別較多張是為了沒有照到的影像都要視為「nothing」,故照了很多「mouse」、「RaspberryPi」、「PEN」、「Bruce Lee」以外的照片。

接下來是訓練模型,按下「Train Model」即可。但要修改參數,請按下「Advanced」,預設參數有「Epochs :50」(50個訓練回合)、「Batch Size: 16」(批次大小)、「Learning Rate:0.001」(學習率),以下分別說明。

 

Epochs:

訓練的回合設定,訓練回合數和時間成正比,若要針對細微變化的差異進行辨識時則要提高回合數,會助於模型辨識效能,但特別要注意的是過高的回合數可能會使模型產生「過適Overfitting」的問題,若是過低的回合數會產生「乏適Underfitting」的問題,但無論是甚麼問題都會降低模型辨識效能。

 

Batch Size:

適當的批次大小設定有助於模型的優化,而且可以提高訓練的速度,及減少訓練誤差。

 

Learning Rate:

學習率設定影響著訓練模型尋找最佳解的過程中是否會收斂或發散。若設定過大,雖會快速收斂,但也可能難以收斂產生震盪甚至發散;相對的,設定過小會導致尋找最佳解時緩慢收斂。讀者們若有興趣,可以搜尋『梯度下降法』。

 

在訓練過程中會跑出對話框 ,提醒使用者不要更動到標籤類別以免影響訓練。

訓練完成後即可在網頁上作及時的影像推論,影像來源除了根據攝影機之外,還可以從電腦端及Google雲端匯入照片進行物件辨識。

Step2.  匯出模型及標籤檔

按下「Export Model」後可匯出模型檔及標籤檔

請選「Tensorflow Lite」à「Quantized」à「Download my model」。「Floating point」格式建議在個人電腦的環境操作;「Quantized」格式適合在像Raspberry Pi的單板電腦操作則有最佳效能;「Edge TPU」格式則僅限於Google Coral 的系列產品,如: Google Coral USB Accelerator 或 Google Coral Dev Board 的產品上。

 

Step3.  至樹莓派官網下載最新版本的RPi4映像檔。

請到 https://www.raspberrypi.org/downloads/raspbian/ 下載 「Raspbian Buster with desktop」,此版本為桌面簡易版,沒有多餘的軟體,且較不占SD卡空間。

下載至電腦後,須將檔案解壓縮,再準備一張16G的SD卡,利用Win32 Disk Imager 軟體(下載點: https://sourceforge.net/projects/win32diskimager/)燒錄至SD卡中。

a部分先選擇RPi4 的映像檔;b部分選擇燒錄SD卡的磁碟位置(要小心不要選錯,以免燒錯磁區);c部分則選擇資料到「裝置」,將映像檔燒錄至SD卡內。

燒錄完成後可將SD卡插至RPi4 卡槽後,但先別急著開機,而是先將RPi4連結到螢幕再開機,否則開機後再接螢幕是沒有畫面的,最後在接上鍵盤、滑鼠即可,這樣較好設定網路。將網路和地區都設定好之後,請開啟RPi4圖示à「Preferences」à「Raspberry Pi configuration」à「Interfaces」,將所有功能開啟後重新開機,以便可用遠端軟體控制RPi4。

本文所使用的遠端連線軟體為MobaXterm (下載處: https://mobaxterm.mobatek.net/download.html) ,此軟體優點除了可以遠端連線RPi4,也可以對RPi4傳輸檔案,但RPi4必須要和MobaXterm同個網域,開啟後請按「Session」à「SSH」à在「Remote host*」輸入RPi4 IP(本文IP為192.168.12.56),連線成功會出現「login as:」,請輸入預設帳號pi ,再來是預設輸入密碼raspberry(密碼不會顯示在畫面上),按下Enter即可登入成功。

之後的安裝套件步驟可直接將指令複製並貼至MobaXterm中。

登入RPi4成功畫面。

Step4.  安裝模型框架Tensorflow Lite。

請到https://www.tensorflow.org/lite/guide/python  官方網站下載套件,新下載的RPi4 映像檔的版本預設為Raspbian Buster ,Python 版本為3.7版 ,所以在MobaXterm請輸入:

$ pip3 install https://dl.google.com/coral/python/tflite_runtime-2.1.0.post1-cp37-cp37m-linux_armv7l.whl 

(P.S. $指令不需要複製)

Step5.  安裝OpenCV套件。 

  • 擴展文件系統到整張SD卡

首先在MobaXterm輸入

$ sudo raspi-config

選擇”7 Advanced Options” à “A1  Expand filesystem “,重開機。

  • 刪除不必要的軟體Wolfram Engine和LibreOffice,非必要做,但可以省下約1G的SD卡容量。
$ sudo apt-get purge wolfram-engine
$ sudo apt-get purge libreoffice *
$ sudo apt-get clean
$ sudo apt-get autoremove
  • 更新及升級所有套件包
$ sudo apt-get update && sudo apt-get upgrade
  • 安裝開發者套件CMake 需要用來編譯
$ sudo apt-get install build-essential cmake pkg-config
  • 安裝有關OpenCV的相依套件
$ sudo apt-get install libjpeg-dev libpng-dev libtiff-dev
$ sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
$ sudo apt-get install libxvidcore-dev libx264-dev
$ sudo apt-get install libgtk-3-dev
$ sudo apt-get install libcanberra-gtk*
$ sudo apt-get install libatlas-base-dev gfortran
$ sudo apt-get install python3-dev
  • 下載OpenCV4.0版至RPi4 。
$ cd ~
$ wget -O opencv.zip https://github.com/opencv/opencv/archive/4.0.0.zip
$ wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.0.0.zip
  • 並解壓縮檔案
$ unzip opencv.zip
$ unzip opencv_contrib.zip
  • 建立opencv 和 opencv_contrib資料夾及將檔案放置資料夾內
$ mv opencv-4.0.0 opencv
$ mv opencv_contrib-4.0.0 opencv_contrib
  • 先在opencv資料夾內建立名為build的資料夾
$ cd ~/opencv
$ mkdir build
$ cd build
  • 使用CMake來設置OpenCV 4環境(從這步驟開始是最花時間)
$ cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
-D ENABLE_NEON=ON \
-D ENABLE_VFPV3=ON \
-D BUILD_TESTS=OFF \
-D OPENCV_ENABLE_NONFREE=ON \
-D INSTALL_PYTHON_EXAMPLES=OFF \
-D BUILD_EXAMPLES=OFF 
  • 調整RPi4的SWAP交換空間,來解決編譯OpenCV記憶體不足的問題。
$ sudo nano /etc/dphys-swapfile

請把 CONF_SWAPSIZE=100改成 2048

  • 重新開啟SWAP服務
$ sudo /etc/init.d/dphys-swapfile stop
$ sudo /etc/init.d/dphys-swapfile start
  • 開啟四核心編譯OpenCV
$ make -j4
  • 安裝OpenCV
$ sudo make install
$ sudo ldconfig
  • 重新調整RPi4的SWAP 交換空間
$ sudo nano /etc/dphys-swapfile   

將CONF_SWAPSIZE=2048改成 100

  • 重新開啟SWAP服務
$ sudo /etc/init.d/dphys-swapfile stop
$ sudo /etc/init.d/dphys-swapfile start

Step6.  實現影像分類於RPi4

  • 將Step2 下載模型及標籤檔解壓縮後透過MobaXterm傳入RPi4中

  • 匯入OpenCV 檔於專案資料夾內

  • 查詢OpenCV 版本,會顯示4.0.0版
$python3
>>> import cv2
>>> cv2.__version__
'4.0.0'
>>> exit()

可回到指令列

  • 在RPi4實現影像分類推論!
  • 在執行程式之前需要下載分類器的檔案,連結: https://reurl.cc/4R3dVL

連接上Webcam 至RPi4 USB中,本文範例是將下列指令寫入RPi4的Terminal裡執行,讀者們亦可輸入至MobaXterm。

$ python3 TM2_tflite.py --model model.tflite --labels labels.txt

則可成功開啟畫面。

以下是辨識結果:nothing

以下是辨識結果:RaspberryPi

以下是辨識結果:mouse

以下是辨識結果:Bruce Lee

所有步驟在此告一段落,希望讀者們能夠做出屬於自己專案或用於生活當中,謝謝大家!

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

在Raspberry Pi 4設計GUI介面,匯入機器學習模型實現人臉辨識篇

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 許钰莨/曾俊霖
難度

★☆☆☆☆

 

本文章先備知識教學文章

筆者在使用Teachable Machine時,發現網站除了可以分辨物件的圖像外,也能分辨人臉,故智慧商店才將此功能結合進去。本主題會將焦點會放在臉部的圖像分類,在Teachable Machine收集人臉資料後,匯出人臉的模型檔案後,再使用Tkinter 的圖形化介面設計一套分辨人臉系統。

本文將分成下列幾個步驟來完成此專題:

  1. 在Teachable Machine 收集人臉資料,並可以在網站上即時推論人臉圖像
  2. 將模型匯入到RPI4,並可執行人臉圖像分類程式
  3. 設計人臉GUI圖形化介面之程式說明,並執行智慧商店人臉程式

 

1.在Teachable Machine 收集人臉資料,並可以在網站上即時推論人臉圖像

先在Teachable Machine網頁訓練人臉模型,相關步驟可以參考”使用Google Teachable Machine 來實現Raspberry Pi 4 的影像分類推論“,考慮到一般的商店的結帳系統,只要有人即可結帳,並不會去紀錄人名,所以在Teachable Machine 的模型標籤只有兩種情形,有人和無人。

因為只要判別是否有人接近,所以筆者是到網路上收集男性和女性,東方人或西方人的臉孔圖片約莫共120張,直接上傳至”people”的標籤中,讀者也可以程式下載區Store-->face_dataset資料夾中找到圖片,並且全選上傳。另外當初也有想過拍照,但是拍的人數樣本太少,不如直接上網收集人臉圖片,也考慮到不同的膚色、年齡、地方相關的因素。

而收集沒有人臉的圖片則是可以直接設定用Webcam拍照即可。

設定電腦使用的攝影機,本次使用Webcam的是Logi C170

另外,建議可以在電腦外接一個Webcam,收集圖片較為方便。

按下”Train Model” 即可開始訓練模型。

因為在訓練集中放入了相同兩張有帶口罩的人臉,所以即使戴著口罩,推論出來的結果也可以分類得出來是”people”。

無人臉接近則是”no_people”

但如果人臉太遠離鏡頭,則也會被分類到”no_people”

輸出模型

2.將模型匯入到RPI4,並可執行人臉圖像分類程式

點選Tensorflow Lite -->Quantize-->Download my model

下載得到副檔名[專案名稱]+.txt、.tflite的兩個檔案

請將下載的資料夾解壓縮後,將兩個檔名分別改成”label_face.txt”和”model_face.tflite”,並

傳送資料到Rpi4 的”Store”資料夾中。

在”Store”資料夾中有”TM2_tflite_new.py”,可以執行程式,並將有無人臉的狀態顯示及預測值顯示在視窗上面。

先移動資料夾位置到Store

$ cd Store/

執行程式

$ python3 TM2_tflite_new.py --model model_face.tflite --label labels_face.txt 

 

 

在執行程式的視窗中,筆者有將結果顯示在視窗上,”0″為標籤、”people”為預測出人臉的名稱、”0.9921875″為預測值,說明能分辨出人臉類別的預測值為99%。

 

3.設計人臉GUI圖形化介面之程式說明,並執行智慧商店人臉程式

3-1人臉GUI圖形化介面程式說明

設定視窗大小 300*300像素

self.window.geometry('300x300')
 self.window.resizable(False, False)

開啟Webcam攝影機

self.vid_0 = MyVideoCapture(self.video_source_0)

建立人臉尺寸為240*180像素的圖像畫布

self.canvas_face = tkinter.Canvas(window, width = 240, height = 180)

設置畫布尺寸視窗中的於第0行第0列,在grid網格中使用”sticky”參數,是west向左對齊

self.canvas_face.grid(row=0, column=0, sticky="w")

建立具有拍照功能按鈕,並名稱為”Face”,排列在第1行第0列

tkinter.Button(window, text="Face", command=self.face).grid(row=1, column=0)

Webcam得到影像後,必須使用PIL套件,才能在Tkinter 畫布中顯示動態影像。

  def face(self):
        ret_0, frame_0 = self.vid_0.get_frame()

        if (ret_0):
            Face_class(frame_0)
            

    def update(self):
        ret_0, frame_0 = self.vid_0.get_frame()
        
        
        #調整Webcam影像之畫面大小,需和Tkinter畫布同尺寸
        frame_0_small=cv2.resize(frame_0,(240,180))
        
      
        if ret_0:
            self.photo_2 = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(frame_0_small))
            self.canvas_face.create_image(241,0,image = self.photo_2, anchor="ne")
   

        self.window.after(self.delay, self.update)

Webcam影像畫面相關尺寸大小設定

class MyVideoCapture:
    def __init__(self, video_source):
    
        #將原本Webcam影像畫面大小設定為320X240
        self.vid = cv2.VideoCapture(video_source)
        self.vid.set(cv2.CAP_PROP_FRAME_WIDTH,320)
        self.vid.set(cv2.CAP_PROP_FRAME_HEIGHT,240)
        

        if not self.vid.isOpened():
            raise ValueError("Unable to open video source", video_source)

        # 設定視訊來源的尺寸
        self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
        self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)

    def get_frame(self):
        if self.vid.isOpened():
            ret, frame = self.vid.read()
            if ret:
                # 將影像畫面轉換成RGB格式
                return (ret, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            else:
                return (ret, None)
        else:
            return (ret, None)

    # 釋放影像資源
    def __del__(self):
        if self.vid.isOpened():
            self.vid.release()

做人臉圖像推論,若偵測到人臉時則顯示”歡迎光臨智慧商店”,訊息會排序在第2行第0列中顯示出來,並播放歡迎詞音訊,也同時啟動拍照功能。

class Face_class:
    def load_labels(self,path):
        with open(path, 'r') as f:
            return {i: line.strip() for i, line in enumerate(f.readlines())}

    def set_input_tensor(self, interpreter, image):
        tensor_index = interpreter.get_input_details()[0]['index']
        input_tensor = interpreter.tensor(tensor_index)()[0]
        input_tensor[:, :] = image


    def classify_image(self, interpreter, image, top_k=1):
        self.set_input_tensor(interpreter, image)
        interpreter.invoke()
        output_details = interpreter.get_output_details()[0]
        output = np.squeeze(interpreter.get_tensor(output_details['index']))

        # If the model is quantized (uint8 data), then dequantize the results
        if output_details['dtype'] == np.uint8:
            scale, zero_point = output_details['quantization']
            output = scale * (output - zero_point)

        ordered = np.argpartition(-output, top_k)
        return [(i, output[i]) for i in ordered[:top_k]]

    def __init__(self,image_src):
        labels = self.load_labels('/home/pi/Store/labels_face.txt')

        interpreter = Interpreter('/home/pi/Store/model_face.tflite')
        interpreter.allocate_tensors()
        _, height, width, _ = interpreter.get_input_details()[0]['shape']

        image=cv2.resize(image_src,(224,224))

        results = self.classify_image(interpreter, image)
        label_id, prob = results[0]
        
        
        if (labels[label_id] == "1 no_people"):
            labelExample = tkinter.Label(text="____________________")
            labelExample.grid(row=2, column=0)
       
            
        else :
            labelExample = tkinter.Label(text="____________________")
            labelExample.grid(row=2, column=0)
            labelExample = tkinter.Label(text="歡迎光臨智慧商店")
            labelExample.grid(row=2, column=0)

            #開啟拍照功能並存在face_collect資料夾中
            cv2.imwrite("face_collect/" + "face-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg", cv2.cvtColor(image_src, cv2.COLOR_RGB2BGR))

            #播放歡迎光臨音訊檔
            file=r'/home/pi/Store/welcome.mp3'
            while (pygame.mixer.music.get_busy()!=1):
                track = pygame.mixer.music.load(file) 
                pygame.mixer.music.play()


#視窗標題為"智慧商店"
App(tkinter.Tk(), "智慧商店")

3-2 執行程式畫面及元件位置

執行Python程式

$python3 tk_cv_face.py

Tkinter排列的元件,分別為畫布(Canvas)在第0行第0列、”Face”按鈕(Button)在第1行第0列、文字標籤(Label)在第2行第0列。偵測到人臉時,除了可以播放音訊檔案外,也同時會開啟拍照功能,其目的在於收集使用者臉孔,可以達成兩種目的,一、可以大致推論出性別或年齡,哪種族群較多人使用。二、可重新訓練模型,雖然google taechable machine在一般的情況下已經可以偵測人臉,但資料集中卻沒有使用者的照片,會使得預測有稍微的偏差,若要符合真實情形,則需要將收集到的人臉照片到google taechable machine再做一次訓練。

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結 (本篇文章完整範例程式請至原文下載)

在Raspberry Pi 4設計GUI介面,匯入機器學習模型實現商品結帳應用

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 許钰莨/曾俊霖
難度

★★★☆☆

 

本文為前篇『使用Google Teachable Machine 來實現Raspberry Pi 4 的影像分類推論』的延伸,所以本文主要是分享如何更換商品之模型檔,讀者可以沿用前篇所訓練好的模型相關檔案作為商品,直接匯入本文所設計好的GUI介面,同時攝像頭會將照到的人臉和商品拍照,作為資料庫,可進一步優化下次在網頁訓練時的模型。

 

本專題將商品結帳系統設計成GUI介面,讓使用者方便操作,商品結帳系統分辨人臉及商品兩種不同的類別,功能使用如下:

  • 「分辨商品視窗」顯示到商品後,當使用者按下「增加購買商品」鍵,「結帳台」上會出現該商品名稱,反之,若「結帳台」沒有商品,或「分辨商品視窗」顯示非商品(即不是在Teachable Machine所訓練的物件),便會播放”結帳台上沒有商品”的聲音。
  • 當使用者反悔不想購買商品時,可按下「刪除購買商品」鍵,「結帳台」上會出現『———–』的刪除符號,當商品全數刪除後,若又按下「商品結帳」鍵時,會播放”沒有可結帳商品,請先選購商品後再結帳”的聲音。
  • 「結帳台」上有商品,使用者按下「商品結帳」鍵時,會播放”結帳完成謝謝光臨”的聲音。

 

本文將分成幾個部分來介紹:

  1. 介紹 Tkinter 模組。
  2. 將商品結帳系統之相關檔案上傳至RPi4。
  3. 匯入訓練商品之模型檔。
  4. 安裝商品結帳系統播放音訊檔和圖像PIL之套件。
  5. 接上硬體設備之須知
  6. 開啟商品結帳系統程式。
  7. 程式說明。

 

一、介紹Tkinter模組

使用Tkinter ,是因Python 裡已經內建的標準模組,且具有以下兩項優點:

  • 可以跨平台,如: Linux/MAC OS/Windows 可以執行Python的作業系統,而Windows則是安裝Python時會一併安裝Tkinter。即可先在Windows 作業系統中設計介面再到其他作業系統執行,如本文使用的RPi4 。
  • 程式碼簡潔易懂,對於剛接觸人機互動介面的初學者很容易學習,且也很快可以設計出人機介面。

 

因為RPi4的Python中已內建Tkinter ,我們可進一步查詢Tkinter版本,和呼叫內建的測試視窗。

 

(1)Tkinter版本查詢,查詢指令步驟如下:

先開啟RPi4 終端機,並輸入

Python 3 

輸入 import tkinter ,再輸入

tkinter.Tcl().eval('info patchlevel')

即可知道本文的Tkinter版本為8.6.9版。

 

(2)呼叫出內建的測試視窗,執行測試函數_test()即可顯示測試視窗

輸入

import tkinter

再輸入

tkinter._test()

若按下「Click me!」,會顯示中括號,按下「QUIT」則退出

二、將商品結帳系統之相關檔案上傳至RPi4

本文準備了Store資料夾,相關的檔案讀者可以從本文提供的連結下載後上傳至RPi4

三、匯入訓練商品之模型檔

如果讀者想重新訓練商品的模型,請參考前篇文章使用Google Teachable Machine  來實現Raspberry Pi 4 的影像分類推論所訓練的模型檔案,將商品的模型檔及標籤檔改名成labels_goods.txt和model_goods.tflite 。

將商品的模型檔及標籤檔透過遠端連線軟體傳送至RPi4中本文已經創建好的Store資料夾中

四、安裝商品結帳系統播放音訊檔和圖像之套件

本文的人機互動介面除可以分辨人臉及商品功能外,也可以播放音訊檔來得知結果,播放音訊檔的套件是使用pygame,故須先安裝此套件:

$pip3 install pygame

本文pygame套件的版本,可利用以下指令查詢:

$pip3 list

可以得知pygame套件的版本為1.9.6版

還需安裝圖像PIL套件

$  sudo apt-get install python3-pil.imagetk

如果讀者想更換音訊檔,本文是使用文字轉語音的人工語音合成網站,輸入文字後可以依照喜好如:男生、女生、語速、音高,進行調整後下載。當然,讀者有找到不錯的人工語音合成網站也可嘗試使用。

網址連結: https://www.toolfk.com/tool-online-text2video?type=base

 

要注意的一點,本文所下載的音訊語速和音高皆是調到最低值,主要的原因是pygame套件會加速原本音訊檔的語速,這裡請讀者需耐心測試。

本文整理了商品結帳系統所需的音訊檔名稱,及音訊內容

音訊檔名稱 音訊內容(不可隨意更改檔名)
thanks.mp3 結帳完成謝謝光臨
no_goods.mp3 沒有可結帳商品
請先選購商品後再結帳
no_goods_class.mp3 結帳台上沒有商品

 

以上為商品結帳系統所有音訊檔案的說明,音訊內容的語句可以自行設計,但是音訊檔檔名請照原本的名稱,因為tk_cv_goods.py檔案需要和以上音訊檔檔名一致,故不可隨意更改,否則執行時會顯示找不到檔案的錯誤。

 

五、接上硬體設備之須知

開啟程式前,請先確認攝像頭是否插入RPi4的USB3.0孔(藍色USB插孔)

並將喇叭插入3.5mm 音源孔來播出聲音

開啟商品結帳系統。

首先,移動到Store資料夾中

$ cd Store/ 

匯入需要執行影像的檔案

$ ln -s /usr/local/python/cv2/python-3.7/cv2.cpython-37m-arm-linux-gnueabihf.so cv2.so

六、執行商品結帳系統程式

$python3 tk_cv_goods.py

執行畫面如下:

七、程式說明

匯入相關函式庫,本文所使用的框架為Tensorflow Lite ,優點在於若部屬在像RPi4的邊緣裝置,可以使模型優化,執行的效率非常快速,而且也可部屬於Android手機。

import tkinter
import cv2
import PIL.Image, PIL.ImageTk 

import pygame

from tflite_runtime.interpreter import Interpreter

開啟視訊鏡頭

self.vid_0 = MyVideoCapture(self.video_source_0)

Tkinter的GUI視窗的像素大小設為500*400

 self.window.geometry('500x400')
 self.window.resizable(False, False)

設置畫布尺寸,為240*180。

self.canvas_goods = tkinter.Canvas(window, width = 240, height = 180)

設置畫布尺寸視窗中的於第0行第1列,在網格中使用”sticky”參數來指定對齊方式,可指定n、s、e、w,分別為上、下、左、右對齊,這剛好可用指北針的方位圖來表示位置。

self.canvas_goods.grid(row=0, column=1, sticky="w")

設置按鈕尺寸,分別為”增加購買商品”於第1行第1列、”刪除購買商品”於第2行第1列、”商品結帳”於第3行第1列

 tkinter.Button(window, text="增加購買商品", command=self.add_goods).grid(row=1, column=1)
 tkinter.Button(window, text="刪除購買商品", command=self.delete_goods).grid(row=2, column=1)
 tkinter.Button(window, text="商品結帳", command=self.check_out).grid(row=3, column=1)

攝影機還有另一項功能,就是做完影像推論後,會將商品的圖像擷取到goods_collect資料夾中作為資料庫,往後再重新訓練時能提高商品的精確度。

    def add_goods(self):
        ret_0, frame_0 = self.vid_0.get_frame()
        if (ret_0):
            cv2.imwrite("goods_collect/" + "goods-" + time.strftime("%d-%m-%Y-%H-%M-%S") + ".jpg", cv2.cvtColor(frame_0, cv2.COLOR_RGB2BGR))
            self.is_goods = Goods_class(frame_0,self.item)    
        self.item=self.item+1

當按下”刪除購買商品”時,會將商品刪除,標籤元件顯示於第self.item+1行,第二列。

def delete_goods(self):
        self.item = self.item -1
        if (self.item <= 0):
            self.item=0
        labelExample = tkinter.Label(text="____________________")
        labelExample.grid(row=self.item+1, column=2)

接下來說明如何將影像顯示在GUI視窗上,攝像頭原本的影像大小為320*240

  self.vid = cv2.VideoCapture(video_source)
  self.vid.set(cv2.CAP_PROP_FRAME_WIDTH,320)
  self.vid.set(cv2.CAP_PROP_FRAME_HEIGHT,240)

但前面已設置畫布尺寸為240*180,必須符合畫布尺寸,所以將影像尺寸縮放成240*180

frame_0_small=cv2.resize(frame_0,(240,180))

最後在Goods_class的函式裡,開始進行圖像分類,最後推論出來的結果,可以顯示商品標籤及信心指數(即預測值)

#做圖像分類
class Goods_class:
    def load_labels(self,path):
        with open(path, 'r') as f:
            return {i: line.strip() for i, line in enumerate(f.readlines())}

    def set_input_tensor(self, interpreter, image):
        tensor_index = interpreter.get_input_details()[0]['index']
        input_tensor = interpreter.tensor(tensor_index)()[0]
        input_tensor[:, :] = image
    
    
    def classify_image(self, interpreter, image, top_k=1):
        self.set_input_tensor(interpreter, image)
        interpreter.invoke()
        output_details = interpreter.get_output_details()[0]
        output = np.squeeze(interpreter.get_tensor(output_details['index']))
        
        if output_details['dtype'] == np.uint8:
            scale, zero_point = output_details['quantization']
            output = scale * (output - zero_point)

        ordered = np.argpartition(-output, top_k)
        return [(i, output[i]) for i in ordered[:top_k]]


    def __init__(self,image_src,item):
        labels = self.load_labels('/home/pi/Store/labels_goods.txt')
        interpreter = Interpreter('/home/pi/Store/model_goods.tflite')
        interpreter.allocate_tensors() 
        _, height, width, _ = interpreter.get_input_details()[0]['shape']
        
        #驗證畫面尺寸為224X224,改變尺寸會驗證錯誤
        image=cv2.resize(image_src,(224,224))

        results = self.classify_image(interpreter, image)
        label_id, prob = results[0]
        
        #顯示商品標籤id及信心指數
        print(label_id, prob)

筆者在最後加上”print(label_id, prob)”,可以使讀者了解圖片是如何被分類出來,其中紅框表示商品標籤id,黃框為預測值

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結 (本篇文章完整範例程式請至原文下載)


在NVIDIA Jetson Nano上實現JetBot AI自駕車專案-03迴避障礙篇(下)-訓練模型、應用範例

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 郭俊廷
難度

★★★☆☆

所需時間 2小時

一、前言

前篇介紹了機器學習與深度學習的相關基礎知識,並且介紹了如何搜集資料。

後篇我們來介紹如何將搜集好的資料訓練成模型檔,並且實際應用到JetBot小車上,讓JetBot可以判斷前方有無障礙物,該前進還是轉彎呢。

 

注意:如果你是接續前一個專案繼續執行此專案,執行完前一個檔案的功能之後記得關閉kernel和使用視窗,才不會發生攝影機被占用等錯誤訊息。(相關教學請參考在Jetson nano 上執行JetBot專案Part2 移動篇之說明)

 

二、Train Model 訓練模型

點選左邊的路徑”Home > Notebooks >collision_avoidance > train_model.ipynb”,就能打開以下的JupyterLab的Collision Avoidance – Train Model畫面。

這裡是負責把之前搜集到的資料集訓練成模型檔的程式。

以下是Train Model 訓練模型流程圖

首先執行第1個區塊,JetBot使用深度學習庫PyTorch來訓練模型並且使用了多種PyTorch函式庫來訓練模型。

第2個區塊是解壓縮dataset.zip檔,這是給已經搜集完資料想更換搜集資料集的人使用的指令,如果Data Collection程式已搜集完資料並有dataset資料夾者不用執行這一區塊,如果有想要更改資料集的人可以根據剛剛更改壓縮的檔名來解壓縮該檔案。

更改以下指令dataset.zip檔名來更改要解壓縮的檔案名稱。

!unzip -q dataset.zip -y

第4個區塊創建dataset的實例,把dataset資料夾裡面搜集的資料使用torchvision.datasets數據包跟torchvision.transforms數據包來分類跟轉換資料。

第5個區塊將數據集拆分為訓練集和驗證集

第6個區塊將會設定訓練集和驗證集的參數

第7個區塊將會定義我們的神經網路,並且設定使用alexnet模型,初次使用會下載alexnet模型,這裡執行的時間會根據網路的速度而異,請耐心等候,並區塊前面顯示*號。

下載完之後顯示畫面如下圖。

第8個區塊是將alexnet模型原本1000個類別標籤的數據集訓練的轉換成2個輸出。

第9個區塊是將轉移模型在GPU上執行。

第10個區塊即開始將資料集訓練成模型檔,預設訓練30回合,根據建議各類別100張左右的照片訓練時間大約為十分鐘。訓練完成會產生一個best_model.pth的模型檔(如下圖左邊紅框所示)

可以更改以下指令數字更改訓練回合數。

NUM_EPOCHS = 30

更改以下指令best_model.pth檔名可以將訓練的檔案儲存為不同檔名。

BEST_MODEL_PATH = 'best_model.pth'

 

三、Live Demo應用範例

點選左邊的路徑”Home > Notebooks >collision_avoidance > live_demo.ipynb”,就能打開以下的JupyterLab的Collision Avoidance – Live Demo畫面。

這裡將會將看到的畫面根據是free或是blocked做出相對應的動作,這裡需要有相對應的模型檔才可以執行該檔案。

注意這裡執行場地的背景跟燈光請跟訓練時的狀況一樣,否則執行辨識的效果會不好。

Live Demo應用範例執行步驟流程圖

首先執行第1個區塊宣告使用PyTorch函式庫設定模型參數

第2個區塊使用模型檔best_model.pth為模型,如果之前有儲存模型檔檔名為別的檔名一樣在這個部分更改為自己的模型檔名。(如下圖的紅框所示)

model.load_state_dict(torch.load('best_model.pth'))

第3個區塊是把模型權重從CPU內存轉移到GPU上執行。

第4個區塊是定義影像預處理方法

從BGR轉換為RGB模式

從HWC佈局轉換為CHW佈局

使用與訓練期間相同的參數進行標準化(我們的攝像機提供[0,255]範圍內的值,並在[0,1]範圍內訓練加載的圖像,因此我們需要縮放255.0

將數據從CPU內存傳輸到GPU內存

批量添加維度

第5個區塊創建一個攝影機畫面,大小是224*224,並且創建一個滑桿可以顯示攝影機目前看到的畫面是blocked的機率為多少(機率由0.00至1.00)。

第6個區塊,定義馬達參數,這裡使用之前文章講解過的DFrobot馬達驅動板的馬達參數。

robot = Robot(driver_board="dfrobot")

第7個區塊,這裡會開始JetBot會開始移動請注意不要將JetBot放在桌上或是容易摔落撞到的地方。

根據下列程式碼,會執行以下動作當判斷blocked的機率小於0.5的時候就以40%的速度前進,當判斷blocked的機率大於0.5就以40%的速度左轉。可以根據自己的使用情境更改下面的機率跟速度的數值。

    if prob_blocked < 0.5:
        robot.forward(0.4)
    else:
        robot.left(0.4)
    
    time.sleep(0.001)

第8個區塊這裡會更新攝影機畫面傳回去給程式判斷,如果沒有執行這一步驟,攝影機的畫面將一直是沒有同步的狀態,執行完這個區塊可以回到第5個區塊查看JetBot避障效果如何。

當看到綠布的畫面blocked的機率為0.07遠小0.5,所以是free的狀態車子會直走。

當看到三角錐的畫面blocked的機率為1.00遠大0.5,所以是blocked的狀態車子會向左轉。

第9個區塊,這裡會停止同步畫面傳送,blocked的機率判斷會停止執行,JetBot也會停止。

第10個區塊、第11個區塊這裡可以設定是否要將攝影機畫面連結到JupyterLab同步顯示,第10個區塊是中斷連結,第11個區塊是繼續連結。

 

車子避障實際影片:

以上避障篇後篇-訓練模型、應用範例的講解到這邊告一段落,各位有沒有成功讓車子避開障礙物呢?接著我們會繼續介紹更多JetBot相關的範例,有興趣的歡迎繼續關注我們。

 

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

在NVIDIA Jetson Nano上實現JetBot AI自駕車專案-04道路跟隨篇(上)-蒐集資料

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 郭俊廷
難度

★★★☆☆

所需時間 2小時

 

一、前言介紹

之前介紹如何使用JetBot進行避障的資料蒐集、訓練模型、應用範例的教學,這次我們要介紹JetBot的另一個範例道路跟隨,道路跟隨是模擬車子在路上自動駕駛的情況,讓JetBot可以在道路上自動駕駛,遇到轉彎處即會轉彎,直線時即會直行。

首先來看看我們的道路跟隨的執行效果

道路跟隨的範例一樣把神經網路模型精簡分為三大步驟

資料搜集、訓練模型、應用範例

 

本篇文章要來介紹如何搜集資料讓JetBot可以在執行道路跟隨的範例

在以下路徑”Home > Notebooks >road_following”可以看到以下三個檔案,如下圖的紅框處所示。

 

注意:如果你是接續前一個專案繼續執行此專案,執行完前一個檔案的功能之後記得關閉kernel和使用視窗,才不會發生攝影機被占用等錯誤訊息。(相關教學請參考”在NVIDIA Jetson Nano上實現JetBot AI自駕車專案-02控制移動篇”之說明)

 

二、Data Collection資料搜集

點選左邊的路徑”Home > Notebooks >road_following > data_collection.ipynb”,就能打開以下的JupyterLab的Road Following – Data Collection畫面。

在資料搜集前先介紹一下我們的場地,我們使用跟範例影片一樣的樂高地圖場地。當然也可以自己設計一張地圖的場地(如下圖),如果都沒有也可使用跟地板顏色不一樣的電工膠帶自己貼成一個模擬的道路,主要是道路的邊線要跟道路不一樣的顏色這樣辨識效果會比較好。

樂高場地
地圖場地

 

首先執行第1個區塊,可以看到官方樂高場地資料蒐集的影片,在影片中我們可以看到在攝影機拍到的畫面中有一個前端有綠色圓點的線,可以看到原點都是朝道路中心點來對準拍攝的,並且用手移動JetBot在道路的任何一個方向拍照搜集資料。看不到影片的沒關係之後我們會詳細介紹如何搜集資料。

執行第2個區塊,匯入函式庫OpenCV, JetBot, Jupyter Widgets, NumPy等等函式庫。

執行第3個區塊,該區塊的程式先創建兩個224×224像素攝影機影像,即時顯示在畫面上,並且在右邊的畫面上會有一個前端有綠色圓點的線,綠色圓點所代表的是畫面的X軸跟Y軸的值,是用來之後判斷JetBot該朝甚麼方向行駛的資料。

執行第4個區塊,創建並連接手把。

進入以下網站,使用支援HTML5的手把,連接並配對修改得到的index數值(如下圖紅框所示)後按下手把任一按鈕顯示如下圖所示介面即配對完成。

https://html5gamepad.com/

第5個區塊,把X軸跟Y軸的數值跟手把的搖桿2搖桿3配對,方便等等搜集資料時使用手把的搖桿改變X軸和Y軸的數值。

第6個區塊,第一次執行時會建立一個dataset_xy的資料夾,可以根據自己的需求更改資料夾名稱,如果顯示Directories not created becasue they already exist代表資料夾已建立過。

接著可以使用搖桿控制線的X軸、Y軸的數值,並且按下手把按鈕下來儲存目前的影像,影像會儲存於dataset_xy的資料夾裡。

影像的命名格式會如下,有X軸、Y軸的數值跟UUID的格式。

xy_<x value>_<y value>_<uuid>.jpg

搜集資料的技巧如下:

綠色的圓點朝向道路的中心點指引,要搜集各個方向的資料(不同的位置不同的角度),直線前進時綠色圓點對準其道路的中心點,轉彎時Y軸數值可以調低,降低轉彎時的速度。

拍完一張照片將JetBot移動到不同方向繼續拍一下張。

數據變化越多是關鍵,當你搜集的資料不同的角度方向越多執行的效果越好。

直線前進時的圓點位置
轉彎時的圓點位置

 

收集完的資料如下,根據樂高的場地我們搜集了171張的照片。

第7個區塊,可以選擇性執行。是把搜集好的資料壓縮成ZIP檔,會根據壓縮的資料夾名稱日期來命名。(如下圖的紅框所示)

關於如果沒有手把的人是否就不能搜集資料呢,這邊幫大家整理了一下如何使用Jupyterlab的小元件建立出搜集資料所需的功能。並且加上了移動車子的功能,這樣就不用蒐集完一張資料就要移動一次車子。

首先一開始一樣要匯入函式庫,跟原始範例一樣預設的函式庫都要匯入,但這裡要一起連馬達驅動板一起定義所以加上之前常用的馬達參數。

robot = Robot(driver_board="dfrobot")

接著開始整合如何有移動車子的功能,並且使用滑桿拖曳即可更改X軸、Y軸的數值。

首先設定將檔案儲存至甚麼資料夾,資料夾名稱可以根據下圖的紅框處更改檔名,並且設定照片的存檔名稱規則,還有當控制車子時前進的速度跟時間。

接著定義按鈕的功能,有前、後、左、右、停止跟儲存六個按鈕。這部分可以參考我們之前的文章基本移動的部分。

接著創建一個224*224的攝影機,並顯示在畫面上,這裡新增設定 fps=5可以降低網路延遲、攝影機畫面沒有同步的問題。

camera = Camera.instance(width=224, height=224, fps=5)

這裡是創建按鈕跟滑桿等小元件,有前、後、左、右、停止跟儲存還有X軸Y軸的滑桿跟目前儲存照片數量顯示的計數框。

接著將滑桿的X軸Y軸同步連接到攝影機的畫面上,移動滑桿的X軸Y軸數值時攝影機的X軸Y軸也會跟著改變。

最後將按鈕的功能連結再一起就大功告成了

執行的效果如下,可以利用右邊的前、後、左、右、停止控制JetBot移動

利用中間的滑桿改變X軸、Y軸的數值使綠色圓點在道路的中心點,並按下save按鈕,將照片儲存至指定資料夾。

以上Jetson nano上執行JetBot專案Part4道路跟隨篇的講解到這邊告一段落,各位有沒有成功收集道路跟隨的資料呢?接著我們會繼續介紹更多Jetson nano相關的範例,有興趣的人歡迎繼續關注我們

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

在NVIDIA Jetson Nano上實現JetBot AI自駕車專案-04道路跟隨篇(下)-訓練模型、應用範例

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 郭俊廷
難度

★★★☆☆

所需時間 2小時

一、前言介紹

在前篇介紹了如何使用JetBot進行道路跟隨的資料蒐集,本篇要介紹如何訓練模型、應用範例的教學。道路跟隨是模擬車子在路上自動駕駛的情況,讓JetBot可以在道路上自動駕駛,遇到轉彎處即會轉彎,直線時即會直行。

注意:

如果你是接續前一個專案繼續執行此專案,執行完前一個檔案的功能之後記得關閉kernel和使用視窗,才不會發生攝影機被占用等錯誤訊息。(相關教學請參考在Jetson nano 上執行JetBot專案Part2 移動篇之說明)

 

二、Train Model 訓練模型

點選左邊的路徑”Home > Notebooks >road_following > train_model.ipynb”,就能打開以下的JupyterLab的Road Following – Train Model畫面。

執行第1個區塊,匯入函式庫PyTorch, NumPy, Python Imaging Library等函式庫。

第2個區塊,可以選擇性執行。是解壓縮之前搜集的資料集,要解壓縮的檔名可以更改以下指令的ZIP檔名(如下圖紅框所示)。

!unzip -q road_following.zip

第3個區塊,定義資料前處理方式,資料夾用dataset_xy的資料夾。

第4個區塊,將資料集分成訓練集跟驗證集。

第5個區塊,建立DataLoader,設定模型訓練細節。

第6個區塊定義神經網絡模型,使用ResNet-18 model檔。第一次使用時需要下載ResNet-18模型檔。

下載完之後顯示畫面如下圖。

第7個區塊將轉移模型在GPU上執行。

第8個區塊將會開始訓練神經網路模型,原始程式碼是訓練70回合,更改NUM_EPOCHS數字為50訓練50回合就可以了。模型檔名稱可以更改以下best_steering_model_xy.pth檔案名稱為自己想要的模型檔名稱。

NUM_EPOCHS = 50
BEST_MODEL_PATH = 'best_steering_model_xy.pth'

訓練時旁邊的方框會顯示星號下面會顯示訓練的best_loss跟test_loss,直到顯示50次旁邊的方框星號變為數字代表訓練完成。

訓練完成會產生一個best_steering_model_xy.pth模型檔。
根據每個人的搜集資料數量不同而會影響訓練時間,以本文171張照片大約訓練20分鐘。

四、Live Demo應用範例

點選左邊的路徑”Home > Notebooks >road_following > train_model.ipynb”,就能打開以下的JupyterLab的Road Following – Live demo畫面。

這裡將會將攝影機看到的畫面根據之前X軸跟Y軸所指向的方向做出相對應的前進方向,這裡需要有相對應的模型檔才可以執行該檔案。

注意這裡執行場地的背景跟燈光請跟訓練時的狀況一樣,否則執行辨識的效果會不好。

首先執行第1個區塊宣告使用PyTorch函式庫設定模型參數

第2個區塊使用模型檔best_steering_model_xy.pth為模型,如果之前有儲存的模型檔檔名為別的檔名一樣在這個部分更改為自己的模型檔名。(如下圖紅框所示)

第3個區塊是把模型權重從CPU內存轉移到GPU上執行。

第4個區塊是定義影像預處理方法

第5個區塊創建一個攝影機畫面。

第6個區塊,定義馬達參數,這裡使用之前文章講解過的DFrobot馬達驅動板的馬達參數。

robot = Robot(driver_board="dfrobot")

第7個區塊,定義滑塊來控制JetBot,這裡目前只是定義還沒連結功能所以目前改變數值並不會使車子移動,以下是四個滑塊的數值的解釋。

Speed Control (speed_gain_slider): 直線速度,預設是0,請慢慢增加速度不要一開始就調整至最大值。

Steering Gain Control (steering_gain_sloder): 搖擺程度,如果看到JetBot搖擺不定,則需要減小此數值。

Steering kd (steering_dgain_slider): 微分控制,計算誤差的斜率,斜率越大,系統會對輸出結果做更快的反應。速度緩慢的系統不需要。

Steering Bias control (steering_bias_slider): 修正左右馬達偏差,如果看到JetBot偏向道路的最右側或最左側,則應控制此滑塊,直到JetBot在道路正中間行駛。

系統建議慢慢修改數值,以較低的速度控制上述滑塊,才能得到效果較好的JetBot道路跟隨行為。

第8個區塊這裡會定義四個滑塊,分別代表目前X軸、Y軸的數值還有JetBot的直線速度跟搖擺程度的數值。

第9個區塊這裡開始JetBot會移動並定義執行辨識跟控制馬達的函式,會根據攝影機的畫面判斷X軸、Y軸的位置並決定該直行還是左轉右轉。並把X軸、Y軸的值傳回第8個區塊,連結第7個區塊並可透過第7個區塊的值來改變JetBot的速度、搖擺程度等等數值。

第10個區塊這裡會更新攝影機畫面傳回去給程式判斷,如果沒有執行這一步驟,攝影機的畫面將一直是沒有同步的狀態,執行完這個區塊可以回到第7個區塊控制JetBot的速度搖擺程度等等數值並將狀態顯示在第8個區塊。

執行完第10個區塊回到第7個區塊慢慢改變speed gain讓JetBot慢慢前進,避免暴衝不受控制。根據JetBot的前進方向跟偏移更改相對應的數值讓JetBot在道路上能平穩的自動行駛。其相對應的數值也會顯示在第8個區塊。

第11個區塊將停止同步畫面傳送,移動路徑判斷也會停止。並停止JetBot的移動。

在這邊提醒一下如果在道路跟隨時某個轉彎或某個路徑道路跟隨的效果不好的時候可以嘗試在效果不好的地方搜集更多的資料並重新訓練模型並重新執行,會讓JetBot道路跟隨的效果更好。

以下是我們樂高的道路跟隨影片

 

還有另外的綠色地圖場景的道路跟隨影片

以上Jetson nano上執行JetBot專案Part4道路跟隨篇後篇-訓練模型、應用範例的講解到這邊告一段落,各位有沒有成功讓車子自動在道路上行駛呢?接著我們會繼續介紹更多Jetson nano相關的範例,有興趣的人歡迎繼續關注我們。

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

學生挑戰一日訓練AI微型自駕車

$
0
0
作者/攝影 張嘉鈞/吳怡婷

隨著自駕系統越來越普及,不僅大學也導入智慧車輛或自動駕駛的系所及課程,就連國高中也都開始接觸自駕技術,在2020台北市教育博覽會中就可以看到眾多學校商家都在展示相關技術,其中令人印象深刻的是由Nvidia所贊助並由Cavedu機器人王國辦理的競賽「2020 RK-Jetbot機器學習道路辨別競賽」,來參賽的學生們將利用短短幾個小時的時間將微型自駕車從不會動訓練到能夠完成特定賽道,最後能用最短的時間完成賽道將能獲得NVIDIA提供的獎品RTX-3070顯示卡。

想先瞭解「RK-Jetbot機器學習道路辨別競賽」可先閱讀下方兩篇文章:

Cavedu所設計的RK-Jetbot自駕車,透過雷切的方式切割並組合車體,除了基本的配件之外還設計了可調整的相機模組機構。

 

2020 RK-Jetbot機器學習道路辨別競賽以NVIDIA Jetbot自駕車專案為主軸並且利用NVIDIA 推出的開發版Jetson Nano進行機器學習的訓練,讓自駕車最後能夠透過影像識別道路的狀況,來自動駕駛完成特定賽道。

這次來參加的學生有來自西松高中、明倫高中、內湖高中、百齡高中四間的學生,總共有6隊學生,學生們雖然有事先在學校練習,但是因為現場環境不同、現場燈光亮暗,自駕車的攝影鏡頭不同,都會導致跟預期結果不同,所以相當考驗學生的臨場反應,沒有反覆的練習是沒辦法快速修正到正確參數的!

主辦單位為求穩定,蒐集資料的時候會透過網路線進行內網的遠端連線,圖片為學生正在幫自駕車接上網路線。

 

主辦單位也有透過螢幕顯示程式執行頁面以及賽道即時狀況

 

開始之前會讓學生設計行車路線,嘗試分析該賽道的最佳路線;接著透過協作的方式,一人執行Python程式另一人移動自駕車來收集賽道資料並設定標籤,等同於告訴神經網路模型看到類似的圖像應該怎麼做會比較好 (左轉、右轉幅度以及速度);接著進行神經網路模型的訓練,學生可調整訓練參數來達到更好的神經網路模型;最後進行測試並且反覆調整參數來達到最佳的狀態。

 

 

學生在執行過程中將熟悉Python程式語言、機器學習的使用概念、神經網路訓練的方式、資料蒐集的技巧以及重要性,達到對人工智慧-機器學習技術的教育目標,最重要的是因為機器學習的不確定性也讓學生學會「try and error」的方法來解決問題,過程中也有工作人員會提供技術上的協助。

 

學生在程式執行上遇到無法解決的問題可以詢問工作人員

 

本次競賽由西松高中的陳思妤同學以13.15秒的成績獲得第一名;明倫高中的陳羿錦、錢昱名同學以14.24秒獲得第二名;第三名則是百齡高中的梁哲綸、楊曜丞用14.42秒的時間完成賽道。工作人員表示如果要在賽道中獲得佳績需要盡可能的模擬車子會看到的畫面,並且給予的參數必須一致,例如接近彎道時設置的轉彎角度、轉彎速度應雷同,不然神經網路訓練的效果可能會不好。

 

第一名為臺北市立西松高級中學的陳思妤同學,指導老師為施柏豪老師

據工作人員表示獲得第一名的陳同學在擺放位置以及定義參數上速度都非常的快,並且參數調整都有依據她當時規劃的路徑在設置,每個彎道的參數都相當一致,這也是為什麼可以以最快的速度完成賽道。

 

【活動紀錄】2020 RK-Jetbot機器學習道路辨別競賽:

 

【教學】LinkIt 7697 也能玩AI圖像辨識

$
0
0
想要體驗AI互動裝置,但卻只有LinkIt7697單晶片的模組時要如何實現呢? 本篇文章是透過電腦執行圖像辨識後,藉由USB線傳電腦指令給LinkIt7697來進行腳位控制。
撰寫/攝影 許鈺莨
時間 大約一小時
難度

★★☆☆☆

材料表 LinkIt7697 相關套件 (購買連結)  購買請洽機器人王國商城喔~
電腦和LinkIt 7697接線圖

 

本篇文章分成五個部分,才可實現本專題:

  1. 在網站上Teachable Machine上收集資料、訓練及推論,推論後下載檔案至電腦。
  2. 在電腦控制端安裝人工智慧環境建置。
  3. 設計外殼來固定LinkIt 7697、伺服機SG90和三色LED。
  4. LinkIt 7697接上伺服機SG90和三色LED腳位,並貼上要辨識的物品標籤。
  5. 上傳LinkIt 7697受控端的Arduino程式,並執行電腦的圖像辨識程式。

 

第一步:在網站上Teachable Machine上收集資料、訓練及推論,推論後下載檔案至電腦。

先在電腦的C槽根目錄建立名為testAI的資料夾,爾後的程式都需下載到此資料夾中。

建立testAI的資料夾

  本專題的要辨識的類別有四個,優酪乳(Yogurt)、品客(Pringles)、玩具(TOY)及一種反指標其他(Other),需將這四種類別分別上傳至Teachable Machine網站上做訓練,之後將模型檔及標籤檔下載電腦資料夾,而在Teachable Machine網站收集資料、訓練、即時推論及下載檔案相關教學可參考部落格教學文[1]。  

三個辨識物品

  收集圖片至Teachable Machine,如下圖所示:

當然讀者也可以找三種不同特徵的物品來做訓練。    

第二步:在電腦控制端安裝人工智慧環境建置(若已安裝則可以跳過)。 

此步驟非常重要,因為圖像辨識的程式是在電腦端執行邊緣運算的,需在電腦端安裝Anaconda 軟體及執行AI程式的相關套件,有關電腦的環境建置安裝步驟請參考此部落格[2]。  

第三步:設計外殼來固定LinkIt 7697、伺服機SG90和三色LED。

本專案之外殼是利用3mm的白色透明壓克力板雷射切割出來的,想要雷切檔可以來信到機器人王國商城[3]。 若不想做雷切檔外殼,亦可以找紙盒裁切,將LinkIt 7697、伺服機SG90和三色LED固定住,如下圖所示。

第一代紙盒版LinkIt 7697分類器

https://youtu.be/MWgi-Wj412M  

第四步:LinkIt 7697接上伺服機SG90和三色LED腳位,並貼上要辨識的物品標籤。

  • 將伺服機SG90和三色LED接上LinkIt 7697擴充板上

接下來是設計LinkIt 7697的I/O控制,請將伺服機SG90和三色LED接到LinkIt 7697 NANO擴充板的腳位上,如下圖所示。

擴充板接上伺服機SG90和三色LED
SG90腳位 LinkIt 7697擴充板
訊號線(橘色) D10(S)
電源線(紅色) D10(5V)
接地線(棕色) D10(G)
三色LED腳位 LinkIt 7697擴充板
V(黑色) D7(G)
R(紅色) D7(S)
B(藍色) D8(S)
G(綠色) D9(S)
  • 設定伺服機SG90的角度,和貼上類別標籤

本專題將四個類別對應不同角度,利用標籤紙貼在外殼上,已本專題為例,如下圖/表所示

伺服機角度設計圖

 

類別 角度
TOY(玩具) 0
Pringles(品客) 50
Yogurt(優酪乳) 100
Other(其他) 170
  • 標籤的順序及角度是可以改變的

第五步:上傳LinkIt 7697受控端的Arduino程式,並執行電腦的圖像辨識程式。

  • 首先要下載電腦執行圖形辨識的Python檔案及Arduino程式,到testAI資料夾

下載檔案的網址見[4],並解壓縮AI_7697資料夾 *注意:解壓縮時請注意,AI_7697資料夾只需包一層就好

下載檔案之路徑圖

 

  • 確定LinkIt 7697的序列埠USB號碼

將LinkIt 7697 USB插入電腦後,開啟裝置管理員連接埠的COM和LPT看號碼

查看COM號碼

本專案的序列埠號碼為COM3,之後燒錄Arduino程式及執行圖像辨識程式會用到。  

  • 上傳Arduino程式,開啟SERVO_LED_SERIAL.ino 程式並燒錄到LinkIt 7697
燒錄程式至LinkIt 7697
  • 執行電腦的圖像辨識程式
  • 需開啟Anaconda Prompt(testAI) 視窗
開啟Anaconda Prompt(testAI) 視窗
  • 輸入 cd \testAI\AI_7697
輸入移動資料夾指令
  • 輸入python TM2_UART_tflite.py –model model.tflite –labels labels.txt –com3
輸入執行圖像辨識程式指令

 

  • 成功開出攝影機的畫面
成功開出攝影機辨識畫面

 

  • 成功執行畫面
成功執行畫面

  同時伺服機SG90會轉動,三色LED燈號會亮起,即專案成功執行。 [補充]如何換類別後也可以達到一樣的效果,和程式說明。

  • 改寫Python類別程式

請開啟TM2_UART_tflite.py和labels.txt對照

TM2_UART_tflite.py和labels.txt對照圖

若讀者換了別的物品辨識的話,下載下來的labels.txt也會不同,在下段的TM2_UART_tflite.py程式中,的第1行、第5行、第9行、第13行需改成和labels.txt的相同名稱 Python程式片段說明:

    if (labels[label_id]=='0 Toy') :
      ser.write(b'command_1\n')  # 訊息必須是位元組類型
      # time.sleep(0.5)           # 暫停0.5秒,再執行底下接收回應訊息的迴圈

    elif (labels[label_id]=='1 Pringles') :
      ser.write(b'command_2\n')  # 訊息必須是位元組類型
      # time.sleep(0.5)           # 暫停0.5秒,再執行底下接收回應訊息的迴圈

    elif (labels[label_id]=='2 Yogurt') :
      ser.write(b'command_3\n')  # 訊息必須是位元組類型
      # time.sleep(0.5)           # 暫停0.5秒,再執行底下接收回應訊息的迴圈
    
    elif (labels[label_id]=='3 Other')  :
      ser.write(b'command_4\n')  # 訊息必須是位元組類型
      # time.sleep(0.5)           # 暫停0.5秒,再執行底下接收回應訊息的迴圈
TM2_UART_tflite.py

行數

程式片段說明

1~2

當標籤顯示TOY時,就會傳command_1的字串給LinkIt7697
之後的5~14行程式也是相同意思

 

Arduino程式片段說明:

#define LED_RED_pin 7
#define LED_BLUE_pin 8
#define LED_GREEN_pin 9
#define Servo_pin 10

int TOY= 0;
int Pringles = 50; 
int Yogurt = 100;
int otherangle = 170;

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

String str;

void setup(void)  
{
  Serial.begin(9600);

  // init pin states
  pinMode(LED_RED_pin, OUTPUT);
  digitalWrite(LED_RED_pin,LOW);
  pinMode(LED_BLUE_pin, OUTPUT);
  digitalWrite(LED_BLUE_pin,LOW);
  pinMode(LED_GREEN_pin, OUTPUT);
  digitalWrite(LED_GREEN_pin,LOW);
  
  myservo.attach(Servo_pin);  // attaches the servo on Servo_pin to the servo object
}

void loop(void)  
{
  //int i;
  digitalWrite(LED_RED_pin,LOW);
  digitalWrite(LED_BLUE_pin,LOW);
  digitalWrite(LED_GREEN_pin,LOW);
  
  if (Serial.available()) {
    // 讀取傳入的字串直到"\n"結尾
    str = Serial.readStringUntil('\n');

    if (str == "command_1") {     // 若字串值是 "command_1" ,TOY亮RED燈
      digitalWrite(LED_RED_pin,1);
      digitalWrite(LED_BLUE_pin,0);
      digitalWrite(LED_GREEN_pin,0);
      myservo.write(TOY);          //伺服馬達轉到0度
      Serial.println("command_1"); 
    } 
else if (str == "command_2") {  // 若字串值是 "command_2",Pringles亮YELLOW燈
      digitalWrite(LED_RED_pin,0);
      digitalWrite(LED_BLUE_pin,1);
      digitalWrite(LED_GREEN_pin,0);
 
      myservo.write(Pringles);         //伺服馬達轉到100度
      Serial.println("command_2");
    } 
    else if (str == "command_3" ) { // 若字串值是 "command_3" ,Yogurt亮GREEN燈
      digitalWrite(LED_RED_pin,0);
      digitalWrite(LED_BLUE_pin,0);
      digitalWrite(LED_GREEN_pin,1);
      myservo.write(Yogurt);          //伺服馬達轉到150度
      Serial.println("command_3");
    }
    else if (str == "command_4" ) { // 若字串值是 "command_4",Other不亮燈
      digitalWrite(LED_RED_pin,0);
      digitalWrite(LED_BLUE_pin,0);
      digitalWrite(LED_GREEN_pin,0);
      myservo.write(otherangle);          //伺服馬達轉到170度
      Serial.println("command_4");
    }
  }
}
SERVO_LED_SERIAL.ino
行數 程式片段說明
1~4 定義三色LED腳位,紅色接LinkIt7697擴充板D7 藍色接LinkIt7697擴充板D8 綠色接LinkIt7697擴充板D9
6~9       定義物品類別角度,伺服機轉到TOY為0度 伺服機轉到Pringles為50度 伺服機轉到Yogurt為100度 伺服機轉Other到為170度
43~70 當接收到command_1的字串,則伺服機會轉動至0度,同時三色LED燈會亮起紅燈,50~70行程式,也是同樣意思。

 

[1] 在Teachable Machine網站收集資料、訓練、即時推論及下載檔案至電腦步驟:https://blog.cavedu.com/2020/11/26/google-teachable-machine-raspberry-pi-4/

[2]在電腦中安裝人工智慧環境建置:https://blog.cavedu.com/2018/09/28/general_env_setup_anaconda_tensorflow_keras_opencv/

[3]機器人王國信箱:service@robotkingdom.com.tw

[4]下載本專題程式連結:https://pse.is/38mrnh

教學直擊!LinkIt™ 7697環境偵測並上傳MCS(空氣盒子)

$
0
0
撰寫/攝影 郭俊廷
難度

★★☆☆☆

材料表 空氣品質監測基本材料包(使用LinkIt™ 7697)

首先先看我們使用的材料跟完成品是甚麼樣子

 

組裝前

組裝後

1.使用材料

我們使用的材料有以下材料需要購買的空氣品質監測基本材料包(使用LinkIt™ 7697)(欲購買,請洽機器人王國)

 

  • LinkIt™ 7697開發板 *1
  • LinkIt™ 7697 NANO 擴充板 *1
  • Micro USB線 *1
  • 5V 2.1A USB充電器 x 1
  • 攀藤 G5 PMS5003 粉塵濃度感測器(已改成杜邦母座) *1
  • 按鈕模組 *1
  • 0.96 吋 OLED液晶螢幕模組 *1
  • 科易KEYES DHT11温濕度感測器 *1
  • 3pin杜邦線 27CM*2
  • 彩色母母杜邦線20CM *10
  • 束線帶 *3
  • 空氣盒子外殼壓克力 *6
  • 螺絲、螺帽、塑膠柱零件包 *1

 

 

螺絲、螺帽、塑膠柱零件包包含以下之數量:

  • M2*6塑膠螺絲*4
  • M2*6塑膠柱*4
  • M2塑膠螺帽*4
  • M2*10十字螺絲*4
  • M3*12十字螺絲*4
  • M3螺帽*4
  • M3*6塑膠柱*8
  • M3*6十字塑膠螺絲*8
  • M3塑膠螺帽*8

2.接線說明

LinkIt™ 7697 NANO 擴充板與攀藤 PMS5003 粉塵濃度感測器接線表、接線圖

LinkIt™ 7697 NANO 擴充板 攀藤 PMS5003 粉塵濃度感測器
5V VCC(紫色)
GND GND(橘色)
D2 TX(綠色)
D3 RX(藍色)

 

 

LinkIt™ 7697 NANO 擴充板與按鈕模組接線表、接線圖

LinkIt™ 7697 NANO 擴充板 按鈕模組
5V VCC
GND GND
D7 S

LinkIt™ 7697 NANO 擴充板與DHT11温濕度感測器接線表、接線圖

LinkIt™ 7697 NANO 擴充板 DHT11温濕度感測器
5V VCC
GND GND
D5 S

LinkIt™ 7697 NANO 擴充板與OLED液晶螢幕模組接線表、接線圖

LinkIt™ 7697 NANO 擴充板 攀藤 PMS5003 粉塵濃度感測器
VCC VCC
GND GND
SDA SDA
SCL SCL

3.程式說明

使用軟體為BlocklyDuino裡內建的arduino-1.8.5,此版本已把相關函式庫預先下載好,不需再另外下載相關函式庫套件。

只需下載並安裝 CP2102N 驅動程式。相關下載點及安裝說明請參考以下網址。

https://docs.labs.mediatek.com/linkit-7697-blocklyduino/v3-12883405.html

https://github.com/MediaTek-Labs/BlocklyDuino-for-LinkIt/releases/tag/3.0.312b

 

開啟BlocklyDuino裡內建的arduino-1.8.5即可編譯並燒錄程式。(位置如下圖)

沒有MCS版的程式

#include "PMS.h"
#include  <SoftwareSerial.h>
#include "U8g2lib.h"
#include <DHT.h>
#include <LWiFi.h>
#include "MCS.h"


SoftwareSerial PMSSerial(2, 3); //設定7697RX,TX腳位。接到PMS5003的TX,RX
PMS pms(PMSSerial);
PMS::DATA data;
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long time_1 = 0;

int pms1_0, pms2_5, pms10_0;
int t;
int h;
int D7;
DHT dht11_p5(5, DHT11);  //定義dht11腳位在P5



void setup()
{
  pinMode(7, INPUT);
  dht11_p5.begin();
  Serial.begin(9600);
  PMSSerial.begin(9600);
  u8g2.begin();
  u8g2.setFont(u8g2_font_6x10_tf);
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);

}

void loop()
{
  D7 = digitalRead(7);
  t = dht11_p5.readTemperature();
  h = dht11_p5.readHumidity();
 
  

  while (!pms.read(data)) {}      //PM2.5開始讀取資料
  pms1_0 = data.PM_AE_UG_1_0;
  pms2_5 = data.PM_AE_UG_2_5;
  pms10_0 = data.PM_AE_UG_10_0;
  Serial.print("PM 1.0 (ug/m3): ");
  Serial.println(pms1_0);
  Serial.print("PM 2.5 (ug/m3): ");
  Serial.println(pms2_5);
  Serial.print("PM 10.0 (ug/m3): ");
  Serial.println(pms10_0);
  Serial.println("溫度:");
  Serial.println(t);
  Serial.println("濕度:");
  Serial.println(h);
  if (D7 == HIGH) {
    u8g2.firstPage();
    do {
      u8g2.setFont(u8g2_font_8x13_mf);
      u8g2.drawStr(15, 0, String("CAVE_AIR_BOX").c_str());
      u8g2.drawStr(0, 15, String(String() + "PM2.5:  " + pms2_5 + "ug/m3").c_str());
      u8g2.drawStr(0, 30, String(String() + "TEMP:   " + t + "C").c_str());
      u8g2.drawStr(0, 45, String(String() + "HUMID:  " + h + "%").c_str());
    } while (u8g2.nextPage());
    //delay(1000);
  } else {
    u8g2.clearDisplay();
  }


}

有使用MCS版本的程式(需要輸入自己的WiFi帳號密碼、MCS的ID跟KEY,建立自己的MCS通道)

#include "PMS.h"
#include  <SoftwareSerial.h>
#include "U8g2lib.h"
#include <DHT.h>
#include <LWiFi.h>
#include "MCS.h"
#define  MCS_INTERVAL_TIME 30000  //設定MCS多少秒傳一次資料

SoftwareSerial PMSSerial(2, 3); //設定7697RX,TX腳位。接到PMS5003的TX,RX
PMS pms(PMSSerial);
PMS::DATA data;
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

unsigned long time_1 = 0;

int pms1_0, pms2_5, pms10_0;
int t;
int h;
int D7;
DHT dht11_p5(5, DHT11);  //定義dht11腳位在P5

/***************WIFI帳號密碼******************************/
char _lwifi_ssid[] = "自己的WiFi帳號";            //填入自己的WiFi帳號
char _lwifi_pass[] = "自己的WiFi密碼";              //填入自己的WiFi密碼
/********************************************************/


/***********MCS DeviceId、DeviceKey***********************/
MCSDevice mcs("DeviceId", "DeviceKey"); //需改成自己的MCS (DeviceId,DeviceKey)
/*********************************************************/

/************MCS通道**************************************/
MCSDisplayInteger temp("temp");
MCSDisplayInteger humid("humid");
MCSDisplayInteger PM25("PM25");
/*********************************************************/

void setup()
{
  pinMode(7, INPUT);
  dht11_p5.begin();
  Serial.begin(9600);
  PMSSerial.begin(9600);
  u8g2.begin();
  u8g2.setFont(u8g2_font_8x13_mf);
  u8g2.setFontRefHeightExtendedText();
  u8g2.setDrawColor(1);
  u8g2.setFontPosTop();
  u8g2.setFontDirection(0);
  /************MCS通道**************************************/
  mcs.addChannel(temp);
  mcs.addChannel(humid);
  mcs.addChannel(PM25);
  /*********************************************************/
  Serial.println("WiFi開始連線");
  u8g2.firstPage();
  do {
    u8g2.drawStr(0, 0, String("WiFi Connecting.....").c_str());
  } while (u8g2.nextPage());
  while (WiFi.begin(_lwifi_ssid, _lwifi_pass) != WL_CONNECTED) {
    delay(1000);
  }
  Serial.println("WIFI連線成功");
  u8g2.firstPage();
  do {
    u8g2.drawStr(0, 15, String("WiFi Connected").c_str());
  } while (u8g2.nextPage());
  while (!mcs.connected()) {
    mcs.connect();
  }
  Serial.println("MCS連線成功");
  u8g2.firstPage();
  do {
    u8g2.drawStr(0, 30, String("MCS Connected").c_str());
  } while (u8g2.nextPage());
  delay(1000);


}

void loop()
{
  D7 = digitalRead(7);
  t = dht11_p5.readTemperature();
  h = dht11_p5.readHumidity();

  while (!mcs.connected()) {
    mcs.connect();
    if (mcs.connected()) {
      Serial.println("MCS Reconnected.");
      u8g2.firstPage();
      do {
        u8g2.drawStr(0, 30, String("MCS Reconnected").c_str());
      } while (u8g2.nextPage());
    }
  }


  while (!pms.read(data)) {}      //PM2.5開始讀取資料
  pms1_0 = data.PM_AE_UG_1_0;
  pms2_5 = data.PM_AE_UG_2_5;
  pms10_0 = data.PM_AE_UG_10_0;
  Serial.print("PM 1.0 (ug/m3): ");
  Serial.println(pms1_0);
  Serial.print("PM 2.5 (ug/m3): ");
  Serial.println(pms2_5);
  Serial.print("PM 10.0 (ug/m3): ");
  Serial.println(pms10_0);
  Serial.println("溫度:");
  Serial.println(t);
  Serial.println("濕度:");
  Serial.println(h);
  if (D7 == HIGH) {
    u8g2.firstPage();
    do {
      u8g2.setFont(u8g2_font_8x13_mf);
      u8g2.drawStr(15, 0, String("CAVE_AIR_BOX").c_str());
      u8g2.drawStr(0, 15, String(String() + "PM2.5:  " + pms2_5 + "ug/m3").c_str());
      u8g2.drawStr(0, 30, String(String() + "TEMP:   " + t + "C").c_str());
      u8g2.drawStr(0, 45, String(String() + "HUMID:  " + h + "%").c_str());
    } while (u8g2.nextPage());
    //delay(1000);
  } else {
    u8g2.clearDisplay();
  }
  mcs.process(100);

  if (millis() > time_1 + MCS_INTERVAL_TIME) {
    time_1 = millis();
    temp.set(t);
    humid.set(h);
    PM25.set(pms2_5);
  }

}

沒有使用MCS的載點:CAVEDU_AirBox_NOMCS.zip

有使用MCS的載點:CAVEDU_AirBox_MCS.zip

 

建立MCS通道的方法如下:

登入MCS網站 https://mcs.mediatek.com/v2console/zh-TW/
沒有帳號的人請註冊一個帳號

 

按下開發->原型

再按下創建

按下藍字匯入JSON檔.(JSON檔請去上方程式載點下載CAVEDU_AirBox_MCS.zip解壓縮後就可看見)

按下藍字瀏覽

選擇CAVEDU_AirBox_MCS資料夾裡的json檔上傳至MCS

儲存之後可以發現建立了一個CAVE_AIR_BOX的原型,這就完成匯入,再按詳情點進去。

可以發現資料通道都已建立好,按下列表裡的測試裝置,這時候就可以建立我們的測試裝置得到MCS的ID跟KEY。

按下藍字新增測試裝置

接著輸入裝置名稱,可以跟我一樣輸入CAVE_AIR_BOX或修改為自己想命名的名稱皆可,接著按藍色的按鈕創建就可建立一個裝置了。

創建完成後可以看到測試裝置已成功產生的訊息,接著按下方藍色的按鈕詳細資訊。

這時候會跑到該測試裝置的畫面,右上角紅框處可以看到自己的deviceId 和 deviceKey,將他複製到程式碼裡面就可以將你的感測器數值上傳至MCS裡囉。

4.組裝說明

在組裝之前建議先將感測器的接線接好程式都測試完畢沒有問題再來組裝,避免組裝後發現程式或接線有問題會不好拆裝。(感測器的接線請看2.接線說明)

首先先準備好各一隻M2、M3的十字螺絲起子用來鎖接下來的所有螺絲。

接著我們來看我們的壓克力外殼總共有六片,把黏在上面貼紙撕下來後可以看到以下圖片的六塊。

中間黃色那塊是底板,上下兩塊黃色是固定DHT11跟PMS5003 粉塵濃度感測器的固定處,左方黃色的是設計成可掛在牆壁上等地方的掛孔,右邊兩塊透明的壓克力分別是按鈕模組跟OLED固定處還有上蓋。

螺絲、螺帽、塑膠柱分別有以下數量(如下圖)

  • M2*6塑膠螺絲*4
  • M2*6塑膠柱*4
  • M2塑膠螺帽*4
  • M2*10十字螺絲*4
  • M3*12十字螺絲*4
  • M3螺帽*4
  • M3*6塑膠柱*8
  • M3*6十字塑膠螺絲*8
  • M3塑膠螺帽*8

組裝步驟1.底板固定LinkIt™ 7697 NANO 擴充板

首先拿出底板跟LinkIt™ 7697 NANO 擴充板

使用四個M3*6塑膠柱和四個M3塑膠螺帽架起固定住7697 NANO 擴充板的固定柱

接著使用四個M3*6十字塑膠螺絲來固定7697 NANO 擴充板

組裝步驟2.固定按鈕模組跟OLED模組

首先拿出固定模組的板子跟按鈕模組跟OLED模組

接著使用四個M2*6塑膠柱跟四個M2塑膠螺帽鎖上OLED

接著在用四個M2*6塑膠螺絲固定在板子上

同樣的方法使用兩個M3*6塑膠柱跟兩個M2塑膠螺帽鎖上按鈕模組後在用兩個M3*6塑膠螺絲固定在板子上

全部固定後的樣子如下圖

組裝步驟3.固定DHT11温濕度感測器

首先拿出固定DHT11模組的板子跟DHT11温濕度感測器

接著使用兩個M3*6塑膠柱跟兩個M2塑膠螺帽鎖上DHT11

接著將兩個M3*6塑膠螺絲將DHT11固定在板子上(DHT11在開孔裡面)

固定好的樣子如下圖

 

組裝步驟4.固定PMS5003 粉塵濃度感測器

首先拿出固定PMS5003的板子跟PMS5003 粉塵濃度感測器

接著使用四個M2*10十字螺絲將PMS5003 粉塵濃度感測器固定在板子上

固定好的樣子如下圖(注意PMS5003的出風口需朝板子開孔的地方擺放,接線處在下方)

組裝步驟5.將所有模組跟LinkIt™ 7697 NANO 擴充板接線,並將7697插入擴充板上

此時所有感測器跟開發版都已固定完畢,由於將盒子組裝起來後會不好接線,所以這裡就先把所有感測器跟其他模組先接線完畢,另外也要將7697插入擴充版。

接線說明請參考2.接線說明

接完所有感測器的線的樣子如下圖。

組裝步驟6.將空氣盒子組裝起來

首先先把盒子立起來使用M3螺帽放進底板跟DHT11側邊的板子,再用M3*12十字螺絲鎖起來固定住。

接著將另一邊有PMS5003板子跟底板一樣使用M3螺帽跟M3*12十字螺絲鎖起來。

接著再蓋上上蓋之前要先用束線帶將過長的線收起來。

蓋上上蓋時要注意的地方是有孔的地方要朝PMS5003粉塵濃度感測器的那邊擺放,這樣粉塵濃度感測器的出風口才可以正確排出粉塵。

接著使用M3螺帽跟M3*12十字螺絲將兩邊上蓋連接處鎖起來。

全部鎖好組裝完成的成品圖如下。

以下是各個角度的成品圖。

5.功能說明

以有使用MCS版本的程式來說明功能

首先一開始會顯示WiFi連線中:WiFi Connecting…..

如果WiFi連上後會顯示WiFi Connected,如果沒有顯示這段文字,代表你沒有正確連線上WiFi ,請檢查你的網路設備是否可正常連線,或是檢查程式裡的WiFi帳號密碼是否輸入正確。

接著會連線MCS,如果連線成功會顯示MCS Connected,如果沒有顯示這段文字,代表你沒有正確連線上MCS,請檢查MCS網站是否可正常連線或是維修中,或是檢查程式裡的MCS的ID跟KEY是否輸入正確。

正常連線WiFi跟MCS後螢幕上就會顯示CAVE_AIR_BOX訊息會依序顯示PM2.5、溫度、濕度的數值。

按下螢幕旁邊按鈕後,螢幕會清空,放開按鈕會顯示螢幕內容,如果發現螢幕沒有正常顯示可以按下按鈕清空螢幕嘗試看看。

 

【教學】在 OLED顯示Rapberry Pi4主機狀態訊息

$
0
0

如果你是樹莓派玩家,想要一開機就想知道樹莓派網路IP位址,以便直接SSH遠端連線,或下載安裝套件時,知道目前容量有多少,亦或者想知道目前樹莓派的溫度是否過高,本技術文將教學如何將上述的資訊顯示在OLED顯示器中喔。

目前本技術文,以Raspberry Pi4為主,如果有讀者使用Raspberry Pi3或其他系列改造,也請在留言區留言,交流一下大家是如何做出來的吧。

撰寫/攝影  許鈺莨
時間  約半小時
難度

 ★★☆☆☆

材料表

本技術文完整的步驟,可以分成下列7個步驟:

  • 下載並安裝套件
  • 執行範例OLED程式
  • 改寫範例程式,並新增顯示Raspberry Pi4溫度
  • 製作成Shell執行檔
  • 設定開機後可以自動執行程式
  • 縮放字體大小
  • 更改字體字型

在上述1~5步驟中,就已經可以將Raspberry Pi4的相關訊息顯示在OLED上,並可以開機後自動執行程式。而最後的步驟中,可以將OLED顯示的字體縮放,或是從網路上下載字型,本技術文也一併分享給各位讀者。

 

[提醒] 在進行下列步驟前,建議讀者先接上螢幕、鍵盤及滑鼠來設定Raspberry Pi4連上Wi-Fi熱點,再使用遠端連線軟體連進Raspberry Pi4操作[4],會比較方便。本文會使用的遠端連線軟體MobaXterm來輸入指令,而修改程式出處,因需要行數說明,所以使用Raspberry Pi4圖形化介面來講解。

 

那麼,本文開始。

 

1.下載並安裝套件

  • 首先要從Github網站下載OLED的相關套件及程式:

$git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git

  • 移動至Adafruit_Python_SSD1306資料夾:

                 $cd Adafruit_Python_SSD1306

  • 安裝相關套件:

                 $sudo python3 setup.py install

                 $sudo pip3 install –upgrade Adafruit_BBIO       (需注意兩個減號)

2.執行範例OLED程式

  • OLED範例程式是放在「examples」資料夾中,所以要先移動到「examples」資料夾再執行stats.py程式:
    $cd examples

$python3 stats.py

3.改寫範例程式,並新增顯示Raspberry Pi4溫度

(斜線粗體字為需要新增的程式)

  • 可以成功執行stats.py程式後,在顯示的字串面前會產生”b”字元,這代表此字串為byte類型,需轉成UTF-8編碼,可將”b”字元去除,修改下列幾段程式:

 

$sudo nano stats.py

編輯檔案的第122行~第125行

行數 stats.py新增程式片段
122 draw.text((x, top), “IP: ” + str(IP,’utf-8′ ), font=font, fill=255)
123 draw.text((x, top+8), str(CPU,’utf-8′ ) , font=font, fill=255)
124 draw.text((x, top+16), str(MemUsage,’utf-8′ ), font=font, fill=255)
125 draw.text((x, top+25), str(Disk,’utf-8′ ), font=font, fill=255)

  • 若再次執行程式,可以發現”b”字元已經去除,正常顯示畫面。

$python3 stats.py

  • 新增溫度程式:

$sudo nano stats.py

 

在檔案的第119行、第120行及第125新增溫度變數程式

行數 stats.py新增溫度變數程式片段
119 cmd = “vcgencmd measure_temp |cut -f 2 -d ‘='”
120 temp = subprocess.check_output(cmd, shell = True )
125 draw.text((x, top+8), str(CPU,‘utf-8’ ) + ” ” + str(temp,’utf-8′) , font=font, fill=255)

 

4.製作成sh執行檔

  • 製作成sh執行檔,是為了第7步驟順利更改OLED字型所做的準備。其優點為,若要更改字型,需匯入字型檔至Python檔案中,可將這些步驟指令寫入sh執行檔中。

首先,先在「examples」資料夾中建立名為LCD的sh執行檔:

 

$sudo nano OLED.sh 

 

 

行數 OLED.sh執行檔
01 #!/bin/sh
02 cd /home/pi/Adafruit_Python_SSD1306/examples
03 python3 stats.py

  • 按下CTRL+X,再按Y,再按Enter離開。
  • 編輯完sh執行檔,接下來需要開權限:

$sudo chomd +x OLED.sh

 

 

  • 測試sh執行檔是否能開啟,以便之後步驟操作:

$sh OLED.sh

 

5.設定開機後可以自動執行程式

  • 在Linux系統中,開機後自動開啟任務排程或定期執行程式是透過crond服務來啟動,若要設定crond服務排程的指令,就必須使用crontab指令 。透過這個crontab指令,就可以將LCD.sh檔案在開機後自動執行,其指令為:

 

$crontab -e

  • 第一次執行時,按下Enter鍵,會進到crontab的檔案進行編輯,在最後一行輸入以下指令:

                  @reboot  sh  /home/pi/Adafruit_Python_SSD1306/examples/OLED.sh  &

  • 設定完,也可以查看排程的服務

$crontab -l

  • 設定完crond排程後重開機:

$sudo reboot

  • 重新開機後,就會看見OLED顯示Raspberry Pi4的所有資訊了,接下來以下步驟則是說明如何縮放字體大小和更改字型。

 

6.縮放字體大小

  • 修改字體大小程式片段,可以將第47行加”#”註解,將第50行取消註解。

$sudo nano stats.py

 

 

7.更改字型

  • 到網站https://www.dafont.com/bitmap.php下載字型檔。本文以下載Perfect DOS VGA 437 字型檔為例,這放在Bitmap第一頁的最後一個檔案下載。

  • 檔案為壓縮檔,解壓縮後會有兩個ttf字型檔,建議下載至電腦,再透過MobaXterm傳到Raspberry Pi4中。

而Raspberry Pi4路徑為“/home/pi/Adafruit_Python_SSD1306/examples/”

簡單來說,就是要和stats.py檔案在同一個資料夾。

  • 改寫程式,先編輯stats.py 檔案

$sudo stats.py

 

  • 將檔案的第99行的預設字型註解,在第104行新增以下的程式碼。
行數 stats.py
104 font = ImageFont.truetype(‘Perfect DOS VGA 437 Win.ttf’,10)

 

重新開機後,可以看見字型已更改。

當然,讀者亦可以在網路上下載更多更有趣的字型來玩玩看喔,最後以下影片為RaspberryPi4開機後OLED顯示資訊的過程,這次的教學就到這裡囉。

 

相關網頁:

  1. Raspberry Pi4購買連結: https://robotkingdom.com.tw/?s=Raspberry+Pi+4+樹莓派
  2. 超強力樹莓派散熱器購買連結:https://robotkingdom.com.tw/product/ice-tower-cpu-cooling-fan-for-raspberry-pi/
  3.  OLED Display 0.96”購買連結:https://robotkingdom.com.tw/product/oled-display-0-96/
  4. 遠端連線Rasbperry Pi傳輸檔案請參考此篇 :https://blog.cavedu.com/2020/11/26/google-teachable-machine-raspberry-pi-4/

   


新版LinkIt 7697開發板 V1.1版使用序列埠印出指令亂碼問題

$
0
0
撰寫/攝影 郭俊廷
難度

★★☆☆☆

材料表

新版LinkIt 7697開發板 V1.1版使用序列埠印出的指令,燒錄程式後開啟序列埠一開始會有印出亂碼的現象。建議使用者使用Serial指令時鮑率設定為115200。

經檢測發現此亂碼為LinkIt 7697初始化訊息,因新版LinkIt 7697初始化訊息預設鮑率為115200,當使用BlocklyDuino3或arduino預設鮑率為9600時皆會出現亂碼。

現階段解決方案:

把預設鮑率改為115200初次開啟序列埠或按RST 按鈕就會正常顯示以下初始化訊息。

注意:

loader init

fota: TMP is empty, skip upgrade

jump to (0x10079000)

此訊息為加載程序初始化並且跳過升級的正常訊息。

沒有設定鮑率,預設鮑率為9600。
一開始會有亂碼的問題。

把鮑率改為115200

將初始化序列埠鮑率改成115200

 

此時可以發現沒有亂碼,有初始化訊息。

 

參考資料-聯發科技LinkIt 7697:https://bit.ly/2Lx8QHe

跟著做一台桌機風格的樹莓派機殼

$
0
0

本文參照下列連結製作:
https://www.the-diy-life.com/diy-raspberry-pi-4-desktop-case-with-oled-stats-display/?fbclid=IwAR1gWu8XxtggtDWrRfzrjlMvvS8D6xDbas58zB7ux6Ze2Kyd0Ev6SCD-IgQ

撰寫/攝影 腦波弱老闆
難度

★☆☆☆☆ (我腦波弱都做得出來,是能有多難)

時間

材料有齊的話大約3小時,其中2小時在等3D列印。

材料表

我是看了這篇【DIY RASPBERRY PI 4 DESKTOP CASE WITH OLED STATS DISPLAY】就決定跟著做一台。

身為專業的腦波弱老闆,一定有一堆買了但還沒用的材料,像是這個亮晶晶風扇,看起來超威,然後就進了一堆貨,才想到,沒有可以搭配的外殼可以用(挫折)。

前一陣子,在DFROBOT的FB貼文看到這一篇(要時常關心供應商跟乾爹的動向),真是完全命中我的心,終於又可以名正言順的動用公司資源自肥了(編按:那次不是自肥了,還不看看你的肚子)。

 

材料清單:

  • Raspberry Pi 4B(各記憶體版本均適用)
  • ICE TOWER Cooling FAN
  • OLED 顯示器 0.96”
  • Micro SD記憶卡(我是用Patriot Micro SD 快閃記憶卡64GB)
  • M2.5支撐柱x4(其實三個就夠ICE TOWER裡面有多的)
  • M3螺絲x8(固定壓克力側板用,我用六角螺絲,功能跟十字螺絲一樣,但看起來比較威)
  • M3螺帽x4(固定風扇用)
  • 母母杜邦線(長度約15~20公分)
  • 橡膠腳墊(非必要,但我有裝)

 

其他樹莓派需要的周邊

  • Type-C 5V3A電源供應器
  • Micro HDMI轉 HDMI線(如果是VGA螢幕,就用Micro HDMI轉VGA線)
  • HDMI螢幕
  • 鍵盤滑鼠(大推羅技MK240無線鍵盤滑鼠組)

外殼大小剛好在印匠的工作範圍內

再雷切個2MM壓克力就可以。壓克力是透明的,為了方便拍照,所以上面的紙就沒撕掉。

材料都備好後,照著說明組裝就可以完成,但OLED 顯示Raspberry Pi狀態的部分,請參照本團隊的說明【教學】在 OLED顯示Rapberry Pi4主機狀態訊息】,我們寫的比較好。

 

還沒通電的樣子

啟動後

來張遠一點。目前樹莓派基金會提供的作業系統真的相當方便,只要跟著畫面資訊設定就可以。

原作者MICHAEL KLEMENTS也在網站上販售更多的相關設計檔案,有需要的朋友請多多以金錢支持優質創作。

 

如果您缺少部分零組件,也歡迎到我們的機器人王國商城選購。

 

相關文章:

如何正確測得電源供應器電壓電流額定輸出值

$
0
0

目前市面上有很多高性能的嵌入式系統如:Nvidia Jetson系列、樹莓派系列、Google Coral Dev Board系列等,這些系統為了因應各種應用場合不論是AI運算、GUI應用或各類介面控制,都需要一定水準的直流電源供應器,主要的特點就是需要較高且穩定的額定電流輸出的能力。

撰寫/攝影   曾俊霖 
難度

★☆☆☆☆

時間

1小時

材料表
  • 電子負載、直流電源供應器

目前市面上有許多電源供應器都在外殼上標示著各種電路參數,在一般應用時使用者都會特別關注電源供應器的額定電壓值,電源供應器的額定電壓值若超過負載所能承受電壓輸入大小,大都會有燒毀負載的危險,關於這一點,大多數使用者都會特別小心,也較少會出現錯誤,但常常被使用者忽略或是誤解的往往是另一個電路參數,也就是「額定輸出電流值」,更甚者有些不肖廠商會將這個輸出額定電流誇大,讓每個使用者對於這個參數更有著許多疑惑感,本文將針對如何正確量測電源供應器的額定輸出電壓與電流值進行說明。

市面上有許多這類型的電源供應器

 

一、複習基本電學

請參考下圖,這是一個簡單的串聯迴路電路。

在上圖當中,可以透過簡單的歐姆定律可以計算VL = IL × RL。

也由於是串聯電路,所以IP=IL。

在這裡我們必須確實說明VL與IL,通常負載端的VL與IL泛指負載在「正常」運作時所需要維持的電壓與電流大小,在一般而言,若負載(如:嵌入系統電腦),在進行龐大的運算時都會有產生較大的電流需求(IL變大),但對於電源電壓依然必須是保持在穩定的狀態(VL固定),若以歐姆定律RL = VL / IL解釋,此時負載的阻抗RL變小。

在正常運作的狀態下,IP是等於IL的,意思就是負載所需的電流IL都可以正常透過電源供應器所輸出的IP取得。

在這裡也特別說明一個重要觀念,也就是電源供應器所標示電流值,指的是「額定輸出電流值」,意思就是因應負載阻抗的需求所「能提供」最大的輸出電流值,我們來假設一個狀況,若電源供應器「額定輸出電流」為4A,而負載所需的電流IL僅需要2A即可讓負載正常運作,那麼按照電源供應器所標示的額定輸出電流值來看,IL應該是可以穩定的從電源供應器的輸出來取得。

再換另一個狀況來說明,承剛剛的例子,若此時負載(嵌入式系統電腦)因需要進行龐大的運算,產生較大的電流需求以維持負載(嵌入式系統電腦)的正常運作,假設此時的所需的操作電流變大為5A,但維持負載(嵌入式系統電腦)正常運作的操作電壓必須保持在5V,透過歐姆定律的計算,我們可以知道當時的負載阻抗RL = VL/IL = 5V/5A = 1Ω。

但是,電源供應器的額定輸出電流只有4A,透過歐姆定律亦可知當時實際的VL = IL × RL = 4A × 1Ω = 4V,請注意,這裡有個很重要的前提也就是前述—「維持負載(嵌入式系統電腦)正常運作的操作電壓必須保持在5V」,很明顯4V可能已經無法滿足這個5V的操作電壓需求,負載(嵌入式系統電腦)很有可能就無法正常運作。

從上述的例子當中,我們已經可以看出很重要的關鍵,也就是電源供應器的「額定輸出電流值IP」必須是大於(至少要等於)負載所需的操作電流IL,這樣才能確保負載(嵌入式系統電腦)運作的正常。

 

二、電子負載的簡介

要量測電源供應器的額定輸出電流值可以透過「直流電子負載」進行測量,在本文當中採用的直流電子負載型號是BK PRECISION 8601,此型號的電子負載可以承受120V、60A、250W的電氣操作環境條件。

直流電子負載在本文所說明的測試方式中,扮演一個「可調節負載阻抗大小」的角色,透過這種儀器設備可以模擬前述的基本電學的電路操作,透過電子負載我們可以以手動或是自動的方式調節阻抗大小以進行測試。

這裡或許有些人會認為「只要透過可變電阻來調節阻抗大小不是很簡單嗎?」,但事實上在本文的測試情境中,流過阻抗的電流大小往往都會有數A的大小,負載所承受的功率會高達數十W,這種負載功率大小不是一般的常見的「碳膜可變電阻」可以承受的(註:這種碳膜可變電阻往往只能承受<1W的功率),因此絕對不要拿碳膜可變電阻進行數十W功率的測試,以免燒毀元件或造成危險。

 

三、如何測量電源供應器的額定輸出電流值

測試電路連接的方式非常簡單,只要把電源供應器的輸出按照電源電壓極性正確接在電子負載的「INPUT」的正負兩端即可。

電子負載測量電源供應器的模式設定方式,主要有4種方式,分別是:

  1. CC(設定負載汲取電流IL大小)
  2. CV(設定負載兩端電壓VL大小)
  3. CW(設定負載汲取功率大小)
  4. CR(設定負載阻抗大小)

一般量取「穩壓式電源供應器」常用的測試模式為CC、CW、CR三種方式,以下便開始分別介紹這三種模式的操作概念。

  1. CC模式:其實這個模式操作概念很簡單,便是設定流入電子負載的電流IL(或IP)的電流大小,透過逐步增加CC電流設定值,觀察電源供應器的電壓輸出值VL是否穩定在理想的範圍內。
  2. CW模式:基本上就是以「消耗功率」設定的概念呈現測試結果,其概念便是功率的計算公式PL=IL × VL的方式進行測量,透過逐步增加負載消耗功率,檢查電源供應器的功率是否有「線性」的變化,當負載消耗功率變大時(在穩壓的前提下,代表IL(或IP)變大,往往電源輸出電壓(或負載電壓)VL便會隨之變小,此時要觀察VL的電壓是否穩定在理想的範圍內。
  3. CR模式:設定負載阻抗大小來汲取來自電源供應器的輸出電流IP,負載阻抗RL越小則電源輸出電流IP愈大,隨著IP增加,往往電源輸出電壓(或負載電壓)VL便會隨之變小,此時要觀察VL的電壓是否穩定在理想的範圍內。

從前述的三種模式裡,可以知道觀察負載電壓VL的穩定狀況,是評估穩壓式電源供應器的重要關鍵,一般我們都是期望在負載電流IL變大時,負載電壓VL亦能夠穩定在期望的範圍內,若負載電壓VL變小的幅度太大,和電源供應器所標示的穩壓輸出大小差異過大,代表電源供應器的標示有其疑慮之處,使用者就該慎重考慮是否採用該款電源供應器了。

 

以下,針對某個標示為5V / 5A 的穩壓式電源供應器進行實測,列出整個測試的過程紀錄照片供大家參考。

IL=0A,VL=5.1418V,此時等同於「空載」狀態,理論上VL為最大。

IL=0.999A,VL=5.5554V

IL=2.999A,VL=4.8826V

IL=4.999A,VL=4.7063V,很明顯可以看出滿載5A時,電壓已經無法維持在5V了。

 

根據以上的測試結果,便可以判定電源供應器是否有達大家理想的表現了,在這裡特別聲明負載電壓VL的大小必須是要能維持住負載的正常操作電壓的範圍內。

 

以下附上測試時所記錄下來的影片,供大家參考。

 

無塵室等級空氣顆粒偵測操作系統的設計與製作

$
0
0

空氣品質針對不同的應用場域有各種不同的定義,相關的參考指標已偵測種類有以下兩種:

  1. 空氣化學物質濃度,如:CO、CO2、有機物質等。
  2. 空氣灰塵顆粒濃度,如:PM2.5、PM10等。

這兩種空氣品質的偵測各有其適用的場域或情境,化學物質濃度偵測主要是用於醫療照護、危險場域(如:易燃氣體)等,而空氣灰塵顆粒濃度則常用於居家、工廠無塵製造環境等,這兩種的偵測情境,所對應的感測器亦是有所不同。

撰寫/攝影   曾俊霖 
難度

★★★★★

時間

約4小時

材料表
  • Arduino Mega 2560
  • Arduino 專用4吋觸控螢幕
  • OMRON ZN-PD SN300 空氣顆粒偵測器成套模組(含灰塵收集漏斗與濾網)
  • 繼電器模組
  • 空氣電磁閥
  • 空氣靜電清除器

本次的專案主要是針對工廠無塵室對於空氣灰塵顆粒數量的偵測進行一個監控介面設計與製作,適用於對於環境潔淨度要求甚高的場域,透過本專案的製作可以精細的對於環境中的灰塵顆粒數量進行監測與後續的清潔作業,由於工廠無塵室對於空氣中灰塵的數量有著嚴格的要求,因此,在本專案將會採用OMRON製造的ZN-PD SN300空氣灰塵顆粒偵測器當成本專案的感測裝置,本專案將透過Arduino Mega 2560進行整個控制核心的設計與製作,人機操作介面將透過觸控螢幕進行設計,希望透過簡單直覺的觸控手感進行操控。此外,為了適應實際的工廠操作的環境需求,還要透過空氣靜電消除器進行除靜電噴氣的動作,因此還需要透過輸出介面控制繼電器與空氣電磁閥,這個完整系統的建置,經過實測的確可以滿足無塵室的控制所需。

 

一、系統架構

 

系統整體的架構,是一個具有反饋(Feedback)控制流程的控制系統,系統主要是以OMRON的灰塵顆粒偵測器來負責灰塵顆粒的收集與計量,灰塵顆粒偵測器會以TCP/IP有線網路的方式將相關灰塵顆粒數量資料傳出,將資料轉換成為UART進行後續的資料應用,以Arduino Mega 2560作為控制核心透過4吋的觸控螢幕進行人機介面的操作,系統必須能操作空氣電磁閥進行除靜電的噴氣,這部分為了能適應工廠操作環境普遍採用直流24V電源,因此需要透過繼電器進行控制,透過靜電消除器噴出空氣進行表面灰塵的預防性清除。

 

二、各主要零件介紹

1.灰塵顆粒偵測器採用OMRON的ZN-PD SN300進行灰塵顆粒的偵測與計數,本型號的可以針對10um、30um與50um顆粒大小的灰塵進行灰塵量的計數,系統可以設定測量時間間隔、TCP/IP有線網路網點相關資訊、臨界值警示等功能,本型號透過「集塵杯」與「過濾網」進行灰塵顆粒的收集與初期篩選,且擁有較大的吸氣流量可以有效收集到空氣當中的灰塵顆粒,在這裡所採用的無塵室常用的計數單位「Particale / Liter」進行顆粒數量的計數與資料的輸出。

ZN-PD SN300與集塵杯

2.Arduino Mega 2560控制核心主要是接收來自空氣灰塵顆粒偵測器的訊息資料,以UART的方式進行資料的傳輸,透過UART可以較容易進行後續硬體的擴充,且目前許多微控器都也大量使用UART當成標準的傳輸溝通介面,此外,控制核心也負責人機介面的操作,在本專案當中採用的是4吋的TFT觸控螢幕,採用觸控螢幕主要是為了能夠方面使用者能快速直覺的操作系統,並且可以省去各種操作開關的配接線,也方便之後各種軟硬體操作功能的擴充。

Arduino Mega 2560 與 4吋觸控螢幕

3.空氣電磁閥是採用型號為SY5120-5G-C6「3-2雙通型」的空氣電磁閥,這款工業用的空氣電磁閥是以直流24V進行電磁閥的操作,採用標準的機架設計,這種空氣電磁閥常見於工廠的空氣流通通路控制,動作電流約為100mA,操作過程震動也非常小適用於精密氣壓操作機具的應用。

SY5120-5G-C6空氣電磁閥

4.噴氣型靜電消除器是採用SJ-L005M進行消除靜電的動作,灰塵顆粒的積聚與物體表面的靜電有關,物體表面靜電會吸附灰塵,在某些製程為了要防止物體表面殘留灰塵顆粒,除了需要消除物體表面靜電外,還會配合噴氣的方式,將物體表面的灰塵顆粒噴除,因此噴氣型靜電消除器還要透過空氣電磁閥以高壓空氣進行噴氣處理。

SJ-L005M噴氣式靜電消除器

三、設計與製作過程

本專案在設計之初採用透過各種目前常用的介面控制電路模組進行設計與製作,可以有效快速完成原型的製作,而程式的運作採用C語言進行設計,電路的電源來自DC-DC直流電源進行供電,無塵室當中的生產機具有甚多是採用24V的供電,因此必須透過降壓穩壓的電路模組將電源穩定在Arduino Mega 2560可運作的直流電源電壓範圍,此外,為了能夠達成主電源一鍵開關整體系統的設計目的,因此連同OMRON的ZN-PD SN300灰塵顆粒偵測器的電源、電磁閥電源、噴氣式靜電消除器都必須共用電源,因此必須採用較高額定輸出電流的電源供應模組,以期讓整體電路的電源都能穩定維持系統運作。

本專案已經過實際工廠的無塵室進行實測,因此必須將系統的電源系統做必要的隔離運作處理,以維持系統的穩定操作,因此在最後實際運作應用時,採用了多個電源模組進行運作,經實測的確有著較好的效能。

此外,OMROM的灰塵顆粒偵測器與Arduino Mega 2560控制核心均能保持同步運作,控制核心可以透過4吋觸控螢幕進行各種顆粒大小的上限值的設定,只要透過觸控的方式就可以輕易設定系統的運作,相關設定值亦可以透過控制核心進行電源離線紀錄,如此便可以防止因為發生電源斷電重啟後還要進行冗長的設定程序,加速整體系統運作的流暢程度。

測試原型製作與測試

 

1組控制核心控制1部OMRON空氣顆粒偵測器(內部)
1組控制核心控制2部OMRON灰塵顆粒偵測器(內部)
1組控制核心控制2部OMRON灰塵顆粒偵測器(正面)
1組控制核心控制2部OMRON灰塵顆粒偵測器(側面)

 

四、原型機實際測試

相關測試說明影片,請參考影片連結。

Pytorch深度學習框架X NVIDIA JetsonNano應用-生成手寫數字

$
0
0

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結

作者/攝影 嘉鈞
難度

★★★☆☆

材料表

RK-NVIDIA® Jetson Nano™ Developer Kit B01 套件

遇到生成的問題一定是要找現在最流行的GAN,那今天我們除了要讓大家了解GAN是什麼之外,我們也要來挑戰Jetson Nano的極限,上次已經用Nano跑貓狗分類發現對於它來說已經相當的艱辛了,這次要給它更艱難的任務,我們要讓電腦學習如何生成手寫數字的圖片!

GAN 基本觀念

GAN 是生成對抗網路 (generative adversarial network, GAN) 是一個相當有名的神經網路模型也是一個人見人怕的模型,原因是因為它非常的難訓練、耗費的時間也很久,它常常被用於深度學習中的生成任務,不管是圖像還是聲音都可以。

Deep Fake


Image Source : https://aiacademy.tw/what-is-deepfake/

 

CycleGAN

Image Source : https://github.com/junyanz/CycleGAN

 

核心觀念可以這樣想像,GAN就像「收藏家」與「畫假畫的人」,G是畫假畫的,D是收藏家;一開始畫假畫的人技術還不成熟,所以一眼就被收藏家發現問題,所以G就回去苦練畫功慢慢開始能騙過D,這時候D被告知買的都是假畫所以他也開始進步越來越能發現假畫的瑕疵,就這樣反覆的交手成長,等到最後互相僵持不下的時候就達到我們的目的了 – 獲得一個很會畫假畫的G,或者稱為很會生成圖片的G。

在GAN當中,我們可以輸入一組 雜訊 (Noise) 或稱 潛在空間 (Latent Space),然後生成器 (Generator) 會將那組雜訊轉換成圖片,再經由鑑別器 (Discriminator) 分辨是否是真實的圖片,鑑別器將會輸出0或1,其中 0 是 fake,1 是 real 。

DCGAN 架構介紹

一般的GAN都是 FC ( linear ),需要將圖片reshape成一維做訓練,以 mnist 來看的話就是 1*28*28 變成 1*784,而今天我們要介紹的是DCGAN,是利用捲積的方式來建構生成器與鑑別器,它跟一般的CNN有些許不同,作者有列出幾個要改變的點:

  1. 取消所有pooling層。G使用轉置卷積(transposed convolutional layer)進行上取樣而D用加入stride的卷積代替pooling。
  2. 在 D 和 G 中均使用 batch normalization。
  3. 去掉 FC 層,使網路變為 全卷積網路 (Conv2D)。
  4. G使用 ReLU 作為激勵函數,最後一層須使用 tanh。
  5. D使用 LeakyReLU 作為激勵函數。

等等實作程式的時候可以再回來觀察是不是都符合需求了,那基礎觀念的部分先帶到這我們直接開始寫code吧!

準備數據集

今天我們要嘗試生成手寫數字,最常使用的就是MNIST,由於它太常用了可以直接在torch中就下載到,在torchvision.datasets裡面,由於它已經是數據集了所以可以先宣告transform套入,接著就可以打包進DataLoader裡面進行批次訓練

可以注意到圖片已經是灰階圖並且大小為 ( 1, 28, 28)

建構鑑別器

鑑別器的架構就是CNN只差要取消全連階層的部分,所以要想辦法將28*28的圖片捲積成 1*1輸出

最後因為輸出的label是介於 [ 0 , 1 ] 所以最後要透過Sigmoid來收斂。這邊直接使用官方提供的架構可以發現跟以往不同的地方是利用nn.Sequential將所有層在initial的時候就連接起來,你會發現更以前相比簡潔很多;此外我還使用了torchsummary的函式庫視覺化網路架構:

使用torchsummary之前需要先安裝套件

!pip3 install torchsummary

然後記得要先導入

from torchsummary import summary

建構生成器

生成器一樣要全用捲積的方式,但是正如前面所說我們要將一組雜訊轉換成一張圖片,用一般的捲積方式只會越來越小,所以我們必須使用反捲積  ( ConvTranspose2d ),可以想像就是把捲積反過來操作就好,大小一樣要自己算記得最後輸出應該跟輸入圖片一樣大,公式如下:

建置生成器的架構與CNN顛倒,Kernel的數量要從大到小,然後我們不使用MaxPooling改用ConvTranspose,每層都要有BatchNorm並且除了最後一層的激勵函數是Tanh之外其他都是ReLU。

我們一樣使用 torchsummary 來可視化網路架構:

開始訓練GAN

其實訓練GAN的方法不難,只要想像成是訓練兩個神經網路即可。GAN的訓練方式較常見的會先訓練鑑別器,讓鑑別器具有一定的判斷能力後再開始訓練生成器;首先一樣先建立基本的參數。

由於GAN的訓練較複雜,需要的迭代次數也越高,這次我們直接訓練個100次看成效如何,此外這次的損失函數都用BCELoss 因為主要是二元分類問題,對於想要了解更深入的可以去看台大李弘毅教授GAN的教學影片。

訓練Discriminator

訓練鑑別器的目的是讓自己能分辨真實圖片跟造假圖片,首先,先將優化器的梯度清除避免重複計算,接者將真實圖片丟進GPU並給予標籤 ( 1 ),將其丟進D去預測結果並計算Loss,最後丟進倒傳遞中;假的圖片也是一樣的部分,差別只在於假圖片需要由生成器生成出來,所以要先定義一組雜訊並丟入生成器產生圖片,因為要讓鑑別器知道這是假的所以要給予標籤 ( 0 ),接著一樣將假圖片丟進鑑別器並計算Loss。經過反覆的訓練鑑別器就越來越能判斷真假照片了,但是同時生成器也會訓練,所以當鑑別器越強的時候,生成器產生的圖片也會越好!

這個部分要注意的地方是經過鑑別器訓練出來的答案維度是 [ batch ,1, 1, 1],所以需要過一個view(-1)來將維度便形成 [batch, ] 一維大小。

訓練生成器

如果已經看懂鑑別器的訓練方式了,那生成器對你來說就不是個問題!我們一樣要先將梯度歸零,亂數產生雜訊並且透過生成器產生圖片,這邊要注意的是因為生成器的目標是要騙過鑑別器,所以我們要給予真實的標籤 ( 1 ),這樣做的目的是,生成器一開始產生的圖片很差所以鑑別器得出的結果都接近於0,這時候如果標籤是1的話,計算Loss數值將會很大,神經網路就會知道這樣不是我們想要的,它會再想辦法生成更好的圖片讓Loss越來越小。

所以完整的訓練如下,先訓練D再訓練G,有的人會讓D先訓練個幾次再訓練G,聽說效率比較高;而我為了測試jetson Nano的速度所以每一個epoch都有紀錄時間,就連我自己的GPU( 1080 ) 都會爆顯存更不用說用Jetson Nano來跑了!如果遇到顯存爆炸的問題可以嘗試先將batch size調小。

成果

你可以注意到它慢慢能轉換成數字了,轉換的速度其實很快但要更細節的紋路就需要更多時間來訓練。

訓練時間比較

使用GPU 1080 訓練,每一個epoch約耗時310秒左右;而JetsonNano開啟cuda來跑大概每一個epoch約耗時1030秒左右。所以其實要在Nano上面運行GAN也是可行的,速度還算可以。

桌上型電腦 Jetson Nano

結語

這篇教大家如何建構DGAN,接下來我們將會在Jetson Nano上嚐試更多GAN相關的訓練,下一篇將讓電腦玩填色遊戲~

 

*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結 (本篇文章完整範例程式請至原文下載)

Viewing all 678 articles
Browse latest View live