###### tags: `NTU Master Thesis` # 軟體 軟體執行在智慧型害蟲監測系統的樹莓派 Raspbian 作業系統中,整個通訊演算法係透過 docker 映像檔 [tonewworld/multi-sensor-image](https://hub.docker.com/r/tonewworld/multi-sensor-image) 執行的。軟體的程式語言為 Python ## 軟體架構和程式碼說明 軟體架構如下圖所示,docker 映像檔`tonewworld/multi-sensor-image`中含有兩個 python 檔案,`run_multiWSN.py`和`multiWSN.py`。該映像檔的執行邏輯是先以`run_multiWSN.py`讀取設定檔裡面的 VMSM 藍牙位址、感測器樣式等資訊,再藉由 Python 的 os 及 argparse 兩個函式庫,一次性執行多個`multiWSN.py`檔。`multiWSN.py`執行的數量取決於設定檔中的字串行數。在部署 VMSM 時,可以透過設定檔的內容與行數,決定要連接到該台 I2PDM 的 VMSM 數量與種類。一支`multiWSN.py`程式對應到一個 VMSM 中藍牙模組的位址,也就是說一支`multiWSN.py`程式負責 I2PDM 與一台 VMSM 間的通訊 ![](https://i.imgur.com/GpoV2rL.png) 接下來,講述`run_multiWSN.py`和`multiWSN.py`兩支程式的重點程式碼 首先,`run_multiWSN.py`的部分如下所示,這是多支`multiWSN.py`程式能與多台 VMSM 一對一通訊的原因。程式中的 if/else 能視 config 檔案夾中的 BTNAME.txt 長度,執行相對應的`multiWSN.py`。並且,每支`multiWSN.py`收到的 sensorType、shadowName、blue_address 都是不一樣的 ```python if len(shadowName) == 1: os.system("python3 multiWSN.py -l {} -t {} -s {} -b {}".format(fieldName, sensorType[0], shadowName[0], blue_address[0])) elif len(shadowName) == 2: os.system("python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {}".format(fieldName, sensorType[0], shadowName[0], blue_address[0], fieldName, sensorType[1], shadowName[1], blue_address[1])) elif len(shadowName) == 3: os.system("python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {}".format(fieldName, sensorType[0], shadowName[0], blue_address[0], fieldName, sensorType[1], shadowName[1], blue_address[1], fieldName, sensorType[2], shadowName[2], blue_address[2])) elif len(shadowName) == 4: os.system("python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {}".format(fieldName, sensorType[0], shadowName[0], blue_address[0], fieldName, sensorType[1], shadowName[1], blue_address[1], fieldName, sensorType[2], shadowName[2], blue_address[2], fieldName, sensorType[3], shadowName[3], blue_address[3])) elif len(shadowName) == 5: os.system("python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {} & python3 multiWSN.py -l {} -t {} -s {} -b {}".format(fieldName, sensorType[0], shadowName[0], blue_address[0], fieldName, sensorType[1], shadowName[1], blue_address[1], fieldName, sensorType[2], shadowName[2], blue_address[2], fieldName, sensorType[3], shadowName[3], blue_address[3], fieldName, sensorType[4], shadowName[4], blue_address[4])) ``` 再來,是`multiWSN.py`的部分。如下程式碼所示,要想完成藍芽連線有兩個步驟。首先,要先更改 bluepy 內建的 handleNotification 成員函數,讓傳進來的 data 變成是 global 的。接下來,要宣告 Peripheral 類別的物件,並把藍芽的 mac address 傳給 Peripheral 物件。此時,若 p 物件建立成功,樹莓派與 Arduino 上的藍芽模組便建立起了通訊。建立通訊後,將 ReadDelegate 當作參數丟進 Peripheral 的成員函數 withDelegate 中,即可完成藍芽設定 ```python ### bluepy Peripheral class setting global dataByte dataByte = 0 class ReadDelegate(btle.DefaultDelegate): def handleNotification(self, cHandle, data): # Access global variables insid class global dataByte dataByte = data ### assign Peripheral p p = btle.Peripheral(blue_address) p.withDelegate(ReadDelegate()) ``` 完成藍芽設定後,如下程式碼所示,要想收到來自 Arduino 傳送過來的資料,要使用 Peripheral 的成員函數 waitForNotifications。若有資料送進來,waitForNotifications 會結束執行並自動跑到下一行,進而把收到的 global data 之長度 print 出來 ```python ### use bluepy function to get data p.waitForNotifications(0) print("Data Length : ", len(dataByte)) ``` ## 軟體使用到的套件和 Docker 設定 軟體使用到的套件中,比較特別的是 bluepy 和 argparse。使用 [bluepy](https://ianharvey.github.io/bluepy-doc/) 能和 Raspberry Pi 上面的 BLE 藍牙做溝通;利用 [argparse](https://docs.python.org/zh-tw/3/howto/argparse.html) 能使每支 `multiWSN.py` 收到不同藍芽模組的 Mac Address 另外,docker 設定如下所示,這是 multi-sensor-image 最新版的 dockerfile。其中,值得注意的是,開發者必須在 AWS 帳號中找到自己的 Root Key,並將之複製貼上到下列的 YourAccessKey 和 YourSecretKey 中,如此一來,裝置上傳的 Json 訊息才會順利地送到先前設定的 IoT Core 實物中。另外,awscli 和 boto3 的版本也必須是 dockerfile 中的版本號,否則上傳時會有 error 出現 ```dockerfile ### Set up image and update it FROM navikey/raspbian-buster:latest RUN apt-get update -y ### Install Packages # Python3.7 and pip3 RUN apt-get install -y python3 RUN apt-get install -y python3-pip # AWS RUN pip3 install awscli==1.18.220 --no-cache-dir RUN pip3 install boto3==1.19.6 --no-cache-dir # Bluetooth RUN pip3 install bluepy --no-cache-dir RUN apt-get install bluez-hcidump # Others RUN apt-get install -y libatlas-base-dev RUN apt-get --reinstall install -y libraspberrypi-bin ### Set up the folder and AWS WORKDIR /app ENV TZ Asia/Taipei ### Set up AWS RUN aws configure set aws_access_key_id YourAccessKey RUN aws configure set aws_secret_access_key YourSecretKey RUN aws configure set region us-east-1 RUN aws configure set output json ### Copy my code COPY run_multiWSN.py ./ COPY multiWSN.py ./ ### Run python code CMD ["python3", "./run_multiWSN.py"] ``` ## 在樹莓派開機後自動執行 Docker 需使用 shell 和[開機自動開啟 Termial ](https://yayar.medium.com/%E6%A8%B9%E8%8E%93%E6%B4%BE-%E9%96%8B%E6%A9%9F%E8%87%AA%E5%8B%95%E9%96%8B%E5%95%9Fterminal%E5%9F%B7%E8%A1%8Cpython%E7%A8%8B%E5%BC%8F-87b6a1690f0a)兩種手法完成。其中,docker 裡面是透過下方的程式碼執行的。這個程式碼比較特別的是,若有兩個 docker 同時在一個 Raspberry Pi 運作,dns 不能是一樣的,否則上傳資料時會有 error。另外,-v 的指令能將本地端的 config 檔案複製到 docker 檔案內部,讓開發者能透過本地端的 config.txt 做修改,進而影響到 docker 程式內部的設定 ```shell sudo docker run --net=host --dns=8.8.8.8 --privileged -v /home/pi/config:/config tonewworld/multi-sensor-image:latest ``` *P.S. 為了能讓 VMSM 的 docker 檔案能和原本 I2PDM 的 docker 並行,因此我在一份 shell 中,同時執行另外兩條 shell,讓實驗室學長 Dan 撰寫的 docker 和我撰寫的 docker 能一起執行* ## 未來建議 軟體上有幾點不足之處,如下所示: * 可以改善 I2PDM 傳資料給 Arduino 的穩定度,讓 I2PDM 不會在短時間內收到重複的資料 * 若有一台 I2PDM 連接五台以上 VMSM 的需求,需要改寫`run_multiWSN.py`裡面的程式,添增一行 elif len(shadowName) == 6: 並照著前面的程式模板撰寫 elif 裡面的內容
{"metaMigratedAt":"2023-06-17T19:41:14.420Z","metaMigratedFrom":"Content","title":"軟體","breaks":true,"contributors":"[{\"id\":\"a6948673-7d60-4391-94e2-15932db2c28b\",\"add\":9354,\"del\":3509}]"}
Expand menu