本文探討如何根據 Jetson Nano 平台,結合感測器、霧運算和雲端服務,構建實用的遠端監控系統。首先,我們將介紹一個遠端病人監測系統,利用 MAX30102 心率感測器和 MLX90614 體溫感測器收集病人生理資料,再透過 ThingSpeak 雲端平台實作資料的視覺化和遠端監控。接著,我們將探討一個家庭監控系統的設計與實作,利用 ESP32-CAM 捕捉影像,並結合 PIR 感測器偵測移動,再透過 MQTT 協定將影像資料傳輸至 Jetson Nano 進行處理。Jetson Nano 作為霧運算節點,不僅能即時處理影像資料,還能透過 Twilio 傳送警示訊息,並將影像上傳至 Google Drive 雲端儲存,實作更全面的監控和資料管理。

5.6 霧計算與雲端運算在Jetson Nano上的應使用案例項

5.6.1 遠端病人監測系統

本文將介紹如何利用Jetson Nano、MAX30102心率感測器和MLX90614體溫感測器,結合ThingSpeak雲端平台,實作遠端病人監測系統。

程式碼解析:心率監測

# heartrate_monitor.py
from max30102 import MAX30102
import hrcalc
import threading
import time
import numpy as np

class HeartRateMonitor(object):
    """
    將max30102裝置封裝成執行緒的類別
    """
    LOOP_TIME = 0.01

    def __init__(self, print_raw=False, print_result=False):
        self.bpm = 0
        self.print_spo2 = 0
        self.print_bpm = 0
        if print_raw is True:
            print('IR, Red')
        self.print_raw = print_raw
        self.print_result = print_result

    def run_sensor(self):
        # 初始化MAX30102感測器
        sensor = MAX30102()
        ir_data = []
        red_data = []
        bpms = []

        # 持續執行直到停止
        while not self._thread.stopped:
            # 檢查是否有可用資料
            num_bytes = sensor.get_data_present()
            if num_bytes > 0:
                # 取得所有資料並存入陣列
                while num_bytes > 0:
                    red, ir = sensor.read_fifo()
                    num_bytes -= 1
                    ir_data.append(ir)
                    red_data.append(red)
                    if self.print_raw:
                        print("{0}, {1}".format(ir, red))

                # 資料處理:計算心率和血氧飽和度
                while len(ir_data) > 100:
                    ir_data.pop(0)
                    red_data.pop(0)
                if len(ir_data) == 100:
                    bpm, valid_bpm, spo2, valid_spo2 = hrcalc.calc_hr_and_spo2(ir_data, red_data)
                    if valid_bpm:
                        bpms.append(bpm)
                    while len(bpms) > 4:
                        bpms.pop(0)
                    self.bpm = np.mean(bpms)
                    if (np.mean(ir_data) < 50000 and np.mean(red_data) < 50000):
                        self.bpm = 0
                        if self.print_result:
                            print("未檢測到手指")
                    if self.print_result:
                        print("心率:{0},血氧飽和度:{1}".format(self.bpm, spo2))
                    self.print_spo2 = spo2
                    self.print_bpm = self.bpm
            time.sleep(self.LOOP_TIME)
        sensor.shutdown()

    def start_sensor(self):
        # 啟動感測器執行緒
        self._thread = threading.Thread(target=self.run_sensor)
        self._thread.stopped = False
        self._thread.start()

    def stop_sensor(self, timeout=2.0):
        # 停止感測器執行緒
        self._thread.stopped = True
        self.bpm = 0
        self._thread.join(timeout)

#### 程式碼解密:
1. **類別初始化**:`HeartRateMonitor`類別初始化時可設定是否列印原始資料或計算結果
2. **感測器執行**:`run_sensor`方法負責持續讀取MAX30102感測器的資料並計算心率和血氧飽和度
3. **資料處理**程式碼對讀取的紅外線和紅光資料進行處理計算心率BPM和血氧飽和度SpO2)。
4. **執行緒控制**使用執行緒來非同步執行感測器讀取任務可透過`start_sensor``stop_sensor`方法控制執行緒的啟動和停止

### ThingSpeak雲端上傳程式碼解析

```python
# main.py中的ThingSpeak雲端上傳部分
import urllib
import http.client

key = "2TN5A7GW7ZYDBAL1"  # 請替換為您的ThingSpeak API Key

# 組裝要上傳的資料
params = urllib.parse.urlencode({'field1': hrm.print_bpm, 'field2': hrm.print_spo2, 'field3': body_temp, 'key': key})
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
conn = http.client.HTTPConnection("api.thingspeak.com:80")
conn.request("POST", "/update", params, headers)
response = conn.getresponse()
print(response.status, response.reason)
data = response.read()
conn.close()

#### 程式碼解密:
1. **API Key設定**需替換`key`變數為您的ThingSpeak頻道API Key
2. **資料封裝**將心率血氧飽和度和體溫資料封裝成HTTP請求引數
3. **HTTP請求**使用`http.client`模組向ThingSpeak API傳送POST請求上傳資料
4. **回應處理**列印伺服器回應的狀態碼和訊息

### 系統流程圖示

```plantuml
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Jetson Nano 霧運算遠端監控系統實作

package "物聯網架構" {
    package "感知層" {
        component [感測器] as sensor
        component [執行器] as actuator
        component [嵌入式裝置] as device
    }

    package "網路層" {
        component [閘道器] as gateway
        component [MQTT Broker] as mqtt
        component [邊緣運算] as edge
    }

    package "平台層" {
        cloud "IoT Platform" as platform
        database [時序資料庫] as tsdb
        component [規則引擎] as rules
    }

    package "應用層" {
        component [監控儀表板] as dashboard
        component [告警系統] as alert
        component [數據分析] as analytics
    }
}

sensor --> device : 資料採集
device --> gateway : 資料傳輸
gateway --> mqtt : MQTT 協議
mqtt --> edge : 邊緣處理
edge --> platform : 雲端上傳
platform --> tsdb : 資料儲存
platform --> rules : 規則處理
rules --> alert : 觸發告警
tsdb --> analytics : 資料分析
analytics --> dashboard : 視覺化

@enduml

本系統結合了MAX30102心率感測器、MLX90614體溫感測器和Jetson Nano開發板,實作了對病人心率、血氧飽和度和體溫的遠端監測。資料透過ThingSpeak雲端平台進行儲存和視覺化,為醫療人員提供了即時、可靠的病人健康資料。未來,這樣的系統可以進一步擴充套件至更多的健康監測場景,提升醫療服務的效率和品質。

5.6.2.1 家庭監控系統實作:霧運算與雲端運算的結合

系統架構與硬體組態

家庭監控系統的核心元件包含ESP32-CAM模組與PIR(Passive Infrared)感測器。ESP32-CAM是一款整合了攝像頭與微SD卡插槽的微控制器,能支援多種影像輸出格式,如YUV422、YUV420、RGB565等。其內建的2百萬畫素OV2640攝像頭模組能夠提供高品質的影像擷取功能。

PIR感測器(HC-SR501)用於檢測人體或動物的移動,透過偵測紅外線輻射變化來觸發警示或進行影像擷取。ESP32-CAM與PIR感測器的連線方式如表5.2所示:

| ESP32-CAM | PIR 感測器 | |



|



-| | VCC | VCC | | GND | GND | | IO13 | OUT |

ESP32-CAM的設定與程式設計

ESP32-CAM需透過FTDI 232介面卡進行程式燒錄。在燒錄前,需將GPIO 0腳位與GND短路以進入程式燒錄模式。燒錄完成後,需移除短路連線以傳回正常工作模式。

程式設計採用MicroPython語言,並使用Thonny IDE作為開發環境。首先,需安裝MicroPython韌體至ESP32-CAM中。接著,利用Thonny IDE安裝必要的函式庫,如umqttcamera,以支援MQTT通訊協定與攝像頭功能。

以下為ESP32-CAM的主要程式碼範例,用於擷取影像並透過MQTT傳輸至Jetson Nano:

from machine import Pin
from umqtt.simple import MQTTClient
import time
import camera
import network

# 連線至Jetson Nano建立的Wi-Fi熱點
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect("jetson-desktop", "11111111")

SERVER = '10.42.0.1'  # Jetson Nano的IP位址
CLIENT_ID = 'esp32-camera'
TOPIC = b'Image'

# 初始化MQTT客戶端並連線至Broker
c = MQTTClient(CLIENT_ID, SERVER)
c.connect()

# 初始化攝像頭
camera.init(0, format=camera.JPEG)

Motion_status = False  # 用於記錄PIR感測器的狀態

def handle_interrupt(Pin):
    global Motion_status
    Motion_status = True

# 設定PIR感測器中斷處理
PIR_Interrupt = Pin(13, Pin.IN)
PIR_Interrupt.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)

while True:
    if Motion_status:
        print('偵測到移動!')
        buf = camera.capture()
        c.publish(TOPIC, buf)
        time.sleep_ms(100)
        Motion_status = False

程式碼解析:

  1. Wi-Fi連線設定:ESP32-CAM需連線至Jetson Nano所建立的Wi-Fi熱點,以確保MQTT通訊的正常運作。
  2. MQTT客戶端初始化:利用umqtt函式庫建立MQTT客戶端,並連線至Jetson Nano上的MQTT Broker。
  3. 攝像頭初始化:使用camera.init()函式初始化攝像頭,並設定影像格式為JPEG。
  4. PIR中斷處理:當PIR感測器偵測到移動時,會觸發中斷,將Motion_status設為True。
  5. 影像擷取與傳輸:在偵測到移動後,ESP32-CAM擷取影像並透過MQTT將其釋出至指定主題。

Jetson Nano霧運算節點的設定

為了使Jetson Nano能夠作為霧運算節點,需啟用其Wi-Fi熱點功能,並安裝Mosquitto與paho-mqtt函式庫,以支援MQTT通訊協定。

主要步驟如下:

  1. 安裝Mosquitto與客戶端工具
    sudo apt-get install mosquitto mosquitto-clients
    
  2. 安裝paho-mqtt函式庫
    sudo apt-get install python3-pip
    sudo pip3 install paho-mqtt
    
  3. 啟用Wi-Fi熱點:透過Jetson Nano的使用者介面設定Wi-Fi熱點。

系統流程圖與整體架構

系統的整體架構如圖5.11所示,包含ESP32-CAM、PIR感測器、Jetson Nano霧運算節點,以及Google Drive雲端儲存與Twilio雲端服務。

此圖示呈現了家庭監控系統的完整架構,包括硬體連線、資料傳輸流程,以及各元件之間的互動關係。

圖表翻譯: 此圖表詳細描繪了家庭監控系統的架構。首先,ESP32-CAM與PIR感測器組成前端監控單元。當PIR偵測到移動時,ESP32-CAM擷取影像並透過MQTT傳輸至Jetson Nano。Jetson Nano接收影像後,一方面透過Twilio傳送通知至使用者手機,另一方面將影像上傳至Google Drive,使用者可即時監控家中狀況。

組態Jetson Nano與雲端服務的整合應用

Twilio雲端通訊平台組態

為了實作即時通知功能,本系統採用Twilio雲端通訊平台傳送WhatsApp訊息。當偵測到入侵活動時,系統會自動傳送警示訊息至使用者註冊的手機號碼。同時,監控影像也會上傳至Google Drive雲端儲存空間。

Twilio帳號設定步驟

  1. 前往Twilio官方網站(https://www.twilio.com/)註冊帳號並完成電子郵件和手機號碼驗證。
  2. 選擇所需的Twilio功能並啟用沙盒模式。
  3. 在帳號設定中複製Account SIDAuth token,這些資訊將用於Python程式碼中實作WhatsApp訊息傳送功能。

在Jetson Nano上組態Twilio

  1. 使用以下指令安裝Twilio套件:
    sudo pip install twilio
    
  2. 從註冊的手機號碼傳送內容為「join every-plain」的WhatsApp訊息至「+14155238886」,以啟用訊息接收功能。

Google Drive雲端儲存組態

為了實作監控影像的遠端存取,本系統將影像上傳至Google Drive。

Google Drive API設定步驟

  1. 建立Google Cloud專案並啟用Google Drive API。

    • 前往Google Cloud Resource Manager(https://console.cloud.google.com/cloud-resource-manager?organizationId=0&authuser=1&supportedpurview=project)建立新專案。
    • 在API函式庫中搜尋並啟用Google Drive API。
  2. 建立OAuth憑證

    • 導航至「憑證」頁面並建立OAuth使用者端ID。
    • 組態OAuth同意畫面,輸入應用程式名稱、使用者支援電子郵件和開發者聯絡資訊。
  3. 下載JSON憑證檔案並重新命名為client_secrets.json,放置於與main.py相同的目錄中。

在Jetson Nano上組態Google Drive

  1. 使用以下指令安裝Pydrive套件:
    pip install pydrive
    
  2. 編寫Python程式碼(main.py)以實作影像上傳功能。

系統運作流程

  1. 當ESP32-CAM偵測到入侵活動並傳送影像至Jetson Nano(FoG節點)。
  2. Jetson Nano接收影像後,將其儲存於本地photos資料夾,並上傳至Google Drive根目錄。
  3. 同時,透過Twilio傳送WhatsApp警示訊息至使用者註冊的手機號碼。

程式碼實作

以下為簡化的Python程式碼範例,用於實作上述功能:

from twilio.rest import Client
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
import os

# Twilio組態
account_sid = 'your_account_sid'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)

def send_whatsapp_message():
    message = client.messages.create(
        body="入侵警示!",
        from_='whatsapp:+14155238886',
        to='whatsapp:your_registered_phone_number'
    )
    print("WhatsApp訊息已傳送:", message.sid)

# Google Drive組態
gauth = GoogleAuth()
gauth.LocalWebserverAuth()
drive = GoogleDrive(gauth)

def upload_to_google_drive(file_path):
    file_name = os.path.basename(file_path)
    file = drive.CreateFile({'title': file_name})
    file.SetContentFile(file_path)
    file.Upload()
    print(f"{file_name} 已上傳至Google Drive")

if __name__ == "__main__":
    # 假設影像檔案路徑為 ./photos/intruder.jpg
    image_path = "./photos/intruder.jpg"
    send_whatsapp_message()
    upload_to_google_drive(image_path)

內容解密:

  1. Twilio簡訊傳送:使用Twilio提供的REST API傳送WhatsApp訊息。首先需要初始化Twilio客戶端,並使用client.messages.create()方法建立訊息物件。在此過程中,需要提供訊息內容、傳送者電話號碼和接收者電話號碼。

  2. Google Drive上傳功能:使用Pydrive函式庫與Google Drive進行互動。首先需要進行OAuth驗證,以取得存取Google Drive的許可權。然後,建立一個GoogleDrive物件,用於上傳檔案。檔案上傳過程中,先建立一個新的檔案物件,並設定其標題和內容,最後呼叫Upload()方法完成上傳。

  3. 系統流程控制:主程式中,先呼叫send_whatsapp_message()函式傳送警示訊息,再呼叫upload_to_google_drive()函式將指定影像檔案上傳至Google Drive。這兩個操作確保了系統在偵測到入侵活動時,能夠即時通知使用者並儲存相關影像記錄。

  4. 安全性和可擴充套件性:本實作使用了環境變數和安全憑證檔案(如client_secrets.json)來管理敏感資訊,提高了系統的安全性。同時,透過雲端服務的整合,提升了系統的可擴充套件性和可靠性。