顯示具有 IoT 標籤的文章。 顯示所有文章
顯示具有 IoT 標籤的文章。 顯示所有文章

Arduino 遇上 Protocol Buffers:當微控制器也要說「高效語言」

Arduino 電路實戰

那是去年夏天,我們要建置一個環境監測系統,用 20 個 ESP8266 節點收集工廠各角落的溫濕度資料。看起來很簡單對吧?用 JSON 格式,HTTP POST 到雲端,搞定!

結果事情沒那麼順利。每個感測器每分鐘上傳一次資料,WiFi 網路很快就被塞爆了。更糟糕的是,有些 ESP8266 因為 JSON 序列化耗用太多記憶體,經常出現重啟的狀況。

當時的我第一次深深體會到:在微控制器的世界裡,每個位元組都很珍貴。

後來一位資深同事建議我試試 Protocol Buffers,我當時的反應是:"這玩意不是給大型系統用的嗎?Arduino 這種小板子能跑得動?"

事實證明,不但跑得動,而且效果驚人。同樣的資料,傳輸量減少了 60%,記憶體使用量降低 40%,系統再也沒有當機過。

今天我想分享這個改變我對嵌入式開發認知的技術:如何在 Arduino 和單晶片上使用 Protocol Buffers。

為什麼微控制器需要「瘦身」的數據格式?

在聊技術實作之前,我們先理解一下為什麼要在資源受限的環境中使用 Protocol Buffers。

Arduino 的現實限制

拿最常見的 Arduino Uno 來說:

  • SRAM:只有 2KB
  • Flash Memory:32KB(還要扣除 bootloader)
  • 處理器:16MHz 的 8位元 AVR

這意味著什麼?一個 JSON 字串可能就佔用了你 10% 的記憶體!

我實際測試過一個簡單的溫濕度讀取:

{
  "device_id": "sensor_001",
  "timestamp": 1640995200,
  "temperature": 25.6,
  "humidity": 60.3,
  "battery": 87
}

這個 JSON 就要 98 bytes。如果你的設備每分鐘上傳一次資料,光是緩衝幾筆資料就可能讓記憶體吃緊。

網路頻寬的珍貴

在 IoT 場景中,很多設備使用的是:

  • WiFi:訊號可能不穩定,傳輸失敗需要重送
  • 3G/4G:按流量計費,每 MB 都是錢
  • LoRa/NB-IoT:傳輸速度慢,資料包大小有嚴格限制

每節省一個位元組,都直接影響系統的穩定性和運營成本。

電池壽命的考量

許多 IoT 設備需要電池供電數月甚至數年。更小的資料包意味著:

  • 更短的傳輸時間
  • 更少的 CPU 運算
  • 更長的電池壽命

認識 nanopb:微控制器的專屬 Protocol Buffers

IoT 系統架構

Google 官方的 Protocol Buffers 庫對 Arduino 來說太重了,這時候 nanopb 就是我們的救星。

nanopb 的特色

nanopb 是專門為嵌入式系統設計的 Protocol Buffers 實作,它有以下特點:

  • 極小的程式碼體積:通常只需要幾 KB 的 Flash 空間
  • 純 C 語言:沒有動態記憶體分配,執行效率高
  • 靜態緩衝區:編譯時就確定記憶體使用量
  • 跨平台相容:與標準 Protocol Buffers 完全相容

實際大小比較

讓我用實際數據告訴你差異有多大:

相同的感測器資料:

格式 大小 記憶體使用 序列化時間
JSON 98 bytes 200 bytes 12ms
nanopb 24 bytes 80 bytes 3ms

你看,同樣的資料,nanopb 只用了 JSON 四分之一的大小!

實戰項目:打造你的第一個 protobuf 感測器

現在讓我們動手實作一個實際的專案:使用 ESP8266 + DHT22 感測器,透過 nanopb 上傳溫濕度資料。

硬體準備

你需要:

  • ESP8266 開發板(如 NodeMCU)
  • DHT22 溫濕度感測器
  • 4.7kΩ 電阻
  • 麵包板和跳線

接線圖:

  • DHT22 VCC → ESP8266 3.3V
  • DHT22 GND → ESP8266 GND
  • DHT22 DATA → ESP8266 D4(GPIO2)
  • 4.7kΩ 電阻連接 VCC 和 DATA

步驟一:定義 Protocol Buffers Schema

首先建立 sensor.proto 檔案:

syntax = "proto3";

message SensorReading {
    string device_id = 1;
    int64 timestamp = 2;
    float temperature = 3;
    float humidity = 4;
    int32 battery_level = 5;
    bool status_ok = 6;
}

步驟二:生成 nanopb C 代碼

下載 nanopb 工具後,執行:

python nanopb_generator.py sensor.proto

這會生成兩個檔案:

  • sensor.pb.h:標頭檔
  • sensor.pb.c:實作檔

生成的結構看起來像這樣:

typedef struct _SensorReading {
    char device_id[32];
    int64_t timestamp;
    float temperature;
    float humidity;
    int32_t battery_level;
    bool status_ok;
} SensorReading;

步驟三:Arduino 程式實作

#include <WiFi.h>
#include <HTTPClient.h>
#include <DHT.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "sensor.pb.h"

// WiFi 設定
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
const char* serverURL = "http://your-server.com/api/sensor";

// DHT 感測器設定
#define DHT_PIN 2
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);

// protobuf 緩衝區
uint8_t buffer[128];
size_t message_length;

void setup() {
    Serial.begin(115200);
    dht.begin();
    
    // 連接 WiFi
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("WiFi connected!");
}

void loop() {
    // 讀取感測器資料
    float temp = dht.readTemperature();
    float hum = dht.readHumidity();
    
    if (isnan(temp) || isnan(hum)) {
        Serial.println("Failed to read from DHT sensor!");
        delay(5000);
        return;
    }
    
    // 建立 protobuf 訊息
    SensorReading reading = SensorReading_init_zero;
    strcpy(reading.device_id, "esp8266_001");
    reading.timestamp = WiFi.getTime();  // 需要設定 NTP
    reading.temperature = temp;
    reading.humidity = hum;
    reading.battery_level = analogRead(A0);  // 假設連接電池檢測電路
    reading.status_ok = true;
    
    // 序列化為 protobuf 格式
    pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
    bool status = pb_encode(&stream, SensorReading_fields, &reading);
    message_length = stream.bytes_written;
    
    if (!status) {
        Serial.println("Failed to encode protobuf message");
        return;
    }
    
    // 發送到伺服器
    sendToServer(buffer, message_length);
    
    // 深度睡眠 5 分鐘(節省電力)
    Serial.println("Going to deep sleep...");
    ESP.deepSleep(5 * 60 * 1000000);  // 5 分鐘,單位是微秒
}

void sendToServer(uint8_t* data, size_t length) {
    if (WiFi.status() == WL_CONNECTED) {
        HTTPClient http;
        http.begin(serverURL);
        http.addHeader("Content-Type", "application/x-protobuf");
        
        int httpResponseCode = http.POST(data, length);
        
        if (httpResponseCode > 0) {
            String response = http.getString();
            Serial.printf("HTTP Response: %d\n", httpResponseCode);
            Serial.println("Data sent successfully!");
        } else {
            Serial.printf("Error sending data: %d\n", httpResponseCode);
        }
        
        http.end();
    } else {
        Serial.println("WiFi not connected");
    }
}

步驟四:伺服器端接收

簡單的 Python 伺服器範例:

from flask import Flask, request
import sensor_pb2  # 由 protoc 生成

app = Flask(__name__)

@app.route('/api/sensor', methods=['POST'])
def receive_sensor_data():
    try:
        # 解析 protobuf 資料
        reading = sensor_pb2.SensorReading()
        reading.ParseFromString(request.data)
        
        print(f"Device: {reading.device_id}")
        print(f"Temperature: {reading.temperature}°C")
        print(f"Humidity: {reading.humidity}%")
        print(f"Battery: {reading.battery_level}%")
        
        # 這裡可以存入資料庫或進行其他處理
        
        return "OK", 200
    except Exception as e:
        print(f"Error: {e}")
        return "Error", 400

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

性能測試與實際數據

性能對比圖

我做了詳細的性能測試,比較 JSON 和 nanopb 在 ESP8266 上的表現:

資料大小比較

單筆感測器讀取資料:

欄位 JSON nanopb 節省比例
device_id "esp8266_001" (12 bytes) field_tag + string (13 bytes) -8%
timestamp 1640995200 (10 bytes) varint (5 bytes) +50%
temperature 25.6 (4 bytes) fixed32 (5 bytes) -25%
humidity 60.3 (4 bytes) fixed32 (5 bytes) -25%
battery_level 87 (2 bytes) varint (2 bytes) 0%
status_ok true (4 bytes) bool (2 bytes) +50%
總計 98 bytes 37 bytes +62%

記憶體使用量測試

使用 ESP8266 的記憶體監控功能,我測量了實際的記憶體使用:

void printMemoryUsage() {
    uint32_t free_heap = ESP.getFreeHeap();
    uint32_t max_free_block = ESP.getMaxFreeBlockSize();
    
    Serial.printf("Free heap: %d bytes\n", free_heap);
    Serial.printf("Max free block: %d bytes\n", max_free_block);
}

測試結果:

操作 JSON 記憶體使用 nanopb 記憶體使用 節省
序列化 250 bytes 100 bytes 60%
網路傳輸緩衝 150 bytes 60 bytes 60%
總記憶體需求 400 bytes 160 bytes 60%

處理時間測試

unsigned long start_time, end_time;

// JSON 序列化測試
start_time = micros();
String json = createJSONString(temp, hum, battery);
end_time = micros();
Serial.printf("JSON serialization: %lu μs\n", end_time - start_time);

// nanopb 序列化測試
start_time = micros();
pb_encode(&stream, SensorReading_fields, &reading);
end_time = micros();
Serial.printf("nanopb serialization: %lu μs\n", end_time - start_time);

測試結果:

  • JSON 序列化:平均 8,500 μs
  • nanopb 序列化:平均 2,100 μs
  • nanopb 快了 75%!

進階應用:多感測器智能監測網路

讓我們把視野放得更大一點,設計一個更複雜的系統。

場景設計

假設你要監測一個溫室,需要收集:

  • 多個位置的溫濕度
  • 土壤濕度
  • 光照強度
  • 二氧化碳濃度

彈性的 Schema 設計

syntax = "proto3";

message SensorReading {
    string device_id = 1;
    int64 timestamp = 2;
    string location = 3;
    
    // 使用 oneof 讓一個訊息可以包含不同類型的資料
    oneof sensor_data {
        TemperatureHumidity temp_hum = 10;
        SoilMoisture soil = 11;
        LightLevel light = 12;
        CO2Level co2 = 13;
    }
}

message TemperatureHumidity {
    float temperature = 1;
    float humidity = 2;
}

message SoilMoisture {
    float moisture_percent = 1;
    float ph_level = 2;
}

message LightLevel {
    int32 lux = 1;
    string spectrum = 2;  // "full", "uv", "ir"
}

message CO2Level {
    int32 ppm = 1;
    bool alarm_triggered = 2;
}

MQTT 整合

在大型 IoT 系統中,MQTT 是更好的選擇:

#include <PubSubClient.h>

WiFiClient espClient;
PubSubClient client(espClient);

const char* mqtt_server = "your-mqtt-broker.com";
const char* mqtt_topic = "greenhouse/sensors";

void setup() {
    // ... 其他初始化代碼 ...
    
    client.setServer(mqtt_server, 1883);
    connectToMQTT();
}

void connectToMQTT() {
    while (!client.connected()) {
        Serial.print("Attempting MQTT connection...");
        String clientId = "ESP8266Client-";
        clientId += String(random(0xffff), HEX);
        
        if (client.connect(clientId.c_str())) {
            Serial.println("connected");
        } else {
            Serial.print("failed, rc=");
            Serial.print(client.state());
            Serial.println(" try again in 5 seconds");
            delay(5000);
        }
    }
}

void publishSensorData(uint8_t* data, size_t length) {
    if (!client.connected()) {
        connectToMQTT();
    }
    
    bool result = client.publish(mqtt_topic, data, length);
    if (result) {
        Serial.println("Data published successfully");
    } else {
        Serial.println("Failed to publish data");
    }
}

踩坑經驗與優化技巧

在實際使用過程中,我遇到了不少坑,這裡分享一些寶貴經驗。

坑一:字串長度限制

問題:nanopb 預設的字串長度限制可能不夠用。

解決方案:在 .options 檔案中指定最大長度:

# sensor.options
SensorReading.device_id max_size:32
SensorReading.location max_size:64

然後重新生成程式碼:

python nanopb_generator.py sensor.proto

坑二:浮點數精度問題

問題:有些感測器讀取的值有很多小數點,但實際上不需要這麼高精度。

解決方案:在傳輸前量化數值:

// 將溫度量化到 0.1 度精度
int32_t quantized_temp = (int32_t)(temperature * 10);
reading.temperature = quantized_temp / 10.0f;  // 或者直接使用整數欄位

更好的方案:直接使用整數:

message SensorReading {
    string device_id = 1;
    int64 timestamp = 2;
    int32 temperature_x10 = 3;  // 實際溫度乘以 10
    int32 humidity_x10 = 4;     // 實際濕度乘以 10
}

這樣可以進一步減小資料大小,因為整數的 varint 編碼更有效率。

坑三:記憶體碎片化

問題:頻繁的序列化/反序列化可能導致記憶體碎片化。

解決方案:使用靜態緩衝區池:

// 預分配多個緩衝區
#define BUFFER_COUNT 3
#define BUFFER_SIZE 128

static uint8_t buffer_pool[BUFFER_COUNT][BUFFER_SIZE];
static int current_buffer = 0;

uint8_t* getNextBuffer() {
    uint8_t* buffer = buffer_pool[current_buffer];
    current_buffer = (current_buffer + 1) % BUFFER_COUNT;
    return buffer;
}

坑四:WiFi 連線不穩定

問題:在網路不穩定的環境下,資料傳輸容易失敗。

解決方案:實作本地緩存和重試機制:

#include <SPIFFS.h>

void saveDataToLocal(uint8_t* data, size_t length) {
    String filename = "/data_" + String(millis()) + ".pb";
    File file = SPIFFS.open(filename, "w");
    if (file) {
        file.write(data, length);
        file.close();
        Serial.println("Data saved locally: " + filename);
    }
}

void uploadPendingData() {
    Dir dir = SPIFFS.openDir("/");
    while (dir.next()) {
        if (dir.fileName().startsWith("data_")) {
            File file = dir.openFile("r");
            if (file) {
                size_t length = file.size();
                uint8_t* buffer = new uint8_t[length];
                file.readBytes((char*)buffer, length);
                file.close();
                
                if (sendToServer(buffer, length)) {
                    // 傳送成功,刪除本地檔案
                    SPIFFS.remove(dir.fileName());
                    Serial.println("Uploaded and deleted: " + dir.fileName());
                }
                
                delete[] buffer;
            }
        }
    }
}

效能調優秘訣

1. 選擇合適的數值類型

// 不好:使用 int64 存儲小數值
int64 sensor_id = 1;  // 浪費空間

// 好:使用合適的類型
int32 sensor_id = 1;  // 對大多數應用已經足夠

2. 批次傳輸

與其每次讀取就傳輸一次,不如累積幾筆資料一起傳:

message SensorBatch {
    string device_id = 1;
    repeated SensorReading readings = 2;
}

3. 壓縮大型資料

對於某些場景(如音訊資料、影像資料),可以在 protobuf 層面再加壓縮:

#include <ArduinoLZ77.h>  // 輕量級壓縮庫

void compressAndSend(uint8_t* data, size_t length) {
    uint8_t compressed[256];
    size_t compressed_size = lz77_compress(data, length, compressed, sizeof(compressed));
    
    if (compressed_size < length) {
        // 壓縮有效,使用壓縮資料
        sendToServer(compressed, compressed_size);
    } else {
        // 壓縮無效,使用原始資料
        sendToServer(data, length);
    }
}

除錯與測試技巧

開發過程中,除錯是不可避免的,這裡分享一些實用技巧。

序列化資料檢查

void printProtobufData(uint8_t* data, size_t length) {
    Serial.print("Protobuf data (");
    Serial.print(length);
    Serial.print(" bytes): ");
    
    for (size_t i = 0; i < length; i++) {
        if (data[i] < 16) Serial.print("0");
        Serial.print(data[i], HEX);
        Serial.print(" ");
    }
    Serial.println();
}

反序列化測試

bool testSerialization() {
    // 建立測試資料
    SensorReading original = SensorReading_init_zero;
    strcpy(original.device_id, "test_device");
    original.temperature = 25.5f;
    original.humidity = 60.0f;
    
    // 序列化
    uint8_t buffer[128];
    pb_ostream_t ostream = pb_ostream_from_buffer(buffer, sizeof(buffer));
    bool encode_status = pb_encode(&ostream, SensorReading_fields, &original);
    
    if (!encode_status) {
        Serial.println("Encoding failed");
        return false;
    }
    
    // 反序列化
    SensorReading decoded = SensorReading_init_zero;
    pb_istream_t istream = pb_istream_from_buffer(buffer, ostream.bytes_written);
    bool decode_status = pb_decode(&istream, SensorReading_fields, &decoded);
    
    if (!decode_status) {
        Serial.println("Decoding failed");
        return false;
    }
    
    // 驗證資料
    bool success = (strcmp(original.device_id, decoded.device_id) == 0) &&
                   (fabs(original.temperature - decoded.temperature) < 0.01f) &&
                   (fabs(original.humidity - decoded.humidity) < 0.01f);
    
    if (success) {
        Serial.println("Serialization test passed");
    } else {
        Serial.println("Serialization test failed");
    }
    
    return success;
}

記憶體洩漏檢查

void memoryLeakTest() {
    uint32_t initial_free = ESP.getFreeHeap();
    Serial.printf("Initial free heap: %d bytes\n", initial_free);
    
    // 執行 1000 次序列化操作
    for (int i = 0; i < 1000; i++) {
        SensorReading reading = SensorReading_init_zero;
        strcpy(reading.device_id, "test");
        reading.temperature = i % 100;
        
        uint8_t buffer[128];
        pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
        pb_encode(&stream, SensorReading_fields, &reading);
        
        if (i % 100 == 0) {
            uint32_t current_free = ESP.getFreeHeap();
            Serial.printf("Iteration %d, free heap: %d bytes\n", i, current_free);
        }
    }
    
    uint32_t final_free = ESP.getFreeHeap();
    Serial.printf("Final free heap: %d bytes\n", final_free);
    Serial.printf("Memory change: %d bytes\n", (int32_t)final_free - (int32_t)initial_free);
}

實際專案案例:智能植栽監控系統

讓我分享一個完整的實際專案,展示如何在真實環境中應用這些技術。

專案背景

我幫朋友設計了一個智能植栽監控系統,用於管理他的小型有機農場。系統需要:

  • 24/7 監控土壤濕度、光照、溫濕度
  • 自動灌溉控制
  • 手機 App 即時查看
  • 低功耗運行(太陽能供電)
  • 資料歷史記錄和分析

系統架構

感測器節點 → WiFi → MQTT Broker → 雲端伺服器 → 手機 App
     ↓
  SD 卡備份

完整的 Proto Schema

syntax = "proto3";

// 感測器讀取資料
message SensorReading {
    string node_id = 1;
    int64 timestamp = 2;
    string location = 3;
    
    // 環境資料
    float temperature = 10;
    float humidity = 11;
    int32 light_lux = 12;
    
    // 土壤資料
    float soil_moisture = 20;
    float soil_temperature = 21;
    float ph_level = 22;
    
    // 系統狀態
    float battery_voltage = 30;
    int32 signal_strength = 31;
    bool pump_active = 32;
    
    // 錯誤和警告
    repeated string warnings = 40;
}

// 控制命令
message ControlCommand {
    string target_node = 1;
    int64 timestamp = 2;
    
    oneof command {
        PumpControl pump = 10;
        ConfigUpdate config = 11;
        SystemCommand system = 12;
    }
}

message PumpControl {
    bool enable = 1;
    int32 duration_seconds = 2;
}

message ConfigUpdate {
    int32 reading_interval = 1;
    float moisture_threshold = 2;
    bool auto_irrigation = 3;
}

message SystemCommand {
    enum Command {
        RESTART = 0;
        DEEP_SLEEP = 1;
        FACTORY_RESET = 2;
        UPDATE_FIRMWARE = 3;
    }
    Command command = 1;
}

Arduino 節點程式(簡化版)

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "plant_monitor.pb.h"

// 硬體定義
#define DHT_PIN 4
#define DHT_TYPE DHT22
#define SOIL_MOISTURE_PIN A0
#define PUMP_RELAY_PIN 5
#define BATTERY_PIN A1

// 感測器物件
DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient espClient;
PubSubClient mqtt(espClient);

// 設定參數
const char* wifi_ssid = "FarmWiFi";
const char* wifi_password = "your_password";
const char* mqtt_server = "farm-mqtt.example.com";
const char* node_id = "plant_node_001";

// 運行參數
int reading_interval = 300;  // 5分鐘
float moisture_threshold = 30.0;  // 30%
bool auto_irrigation = true;

void setup() {
    Serial.begin(115200);
    
    // 初始化硬體
    dht.begin();
    pinMode(PUMP_RELAY_PIN, OUTPUT);
    digitalWrite(PUMP_RELAY_PIN, LOW);
    
    // 連接網路
    connectWiFi();
    mqtt.setServer(mqtt_server, 1883);
    mqtt.setCallback(onMqttMessage);
    connectMQTT();
    
    Serial.println("Plant monitoring node started");
}

void loop() {
    if (!mqtt.connected()) {
        connectMQTT();
    }
    mqtt.loop();
    
    // 讀取感測器資料
    SensorReading reading = readAllSensors();
    
    // 檢查是否需要灌溉
    if (auto_irrigation && reading.soil_moisture < moisture_threshold) {
        activateIrrigation();
        reading.pump_active = true;
    }
    
    // 發送資料
    sendSensorData(reading);
    
    // 深度睡眠節省電力
    Serial.printf("Sleeping for %d seconds\n", reading_interval);
    ESP.deepSleep(reading_interval * 1000000);
}

SensorReading readAllSensors() {
    SensorReading reading = SensorReading_init_zero;
    
    // 基本資訊
    strcpy(reading.node_id, node_id);
    reading.timestamp = getUnixTime();
    strcpy(reading.location, "Greenhouse_A");
    
    // 環境感測器
    reading.temperature = dht.readTemperature();
    reading.humidity = dht.readHumidity();
    reading.light_lux = readLightSensor();
    
    // 土壤感測器
    reading.soil_moisture = readSoilMoisture();
    reading.soil_temperature = readSoilTemperature();
    reading.ph_level = readPHLevel();
    
    // 系統狀態
    reading.battery_voltage = readBatteryVoltage();
    reading.signal_strength = WiFi.RSSI();
    reading.pump_active = false;
    
    // 檢查警告
    checkWarnings(reading);
    
    return reading;
}

void sendSensorData(const SensorReading& reading) {
    uint8_t buffer[256];
    pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
    
    bool status = pb_encode(&stream, SensorReading_fields, &reading);
    if (!status) {
        Serial.println("Failed to encode sensor data");
        return;
    }
    
    // 發送到 MQTT
    bool sent = mqtt.publish("farm/sensors/data", buffer, stream.bytes_written);
    if (sent) {
        Serial.printf("Sent %d bytes of sensor data\n", stream.bytes_written);
    } else {
        Serial.println("Failed to send sensor data");
        // 保存到 SD 卡作為備份
        saveToSDCard(buffer, stream.bytes_written);
    }
}

void onMqttMessage(char* topic, byte* payload, unsigned int length) {
    if (strcmp(topic, "farm/control/commands") == 0) {
        // 解析控制命令
        ControlCommand command = ControlCommand_init_zero;
        pb_istream_t stream = pb_istream_from_buffer(payload, length);
        
        if (pb_decode(&stream, ControlCommand_fields, &command)) {
            processControlCommand(command);
        }
    }
}

void processControlCommand(const ControlCommand& command) {
    if (strcmp(command.target_node, node_id) != 0) {
        return;  // 不是給這個節點的命令
    }
    
    switch (command.which_command) {
        case ControlCommand_pump_tag:
            if (command.command.pump.enable) {
                activateIrrigation(command.command.pump.duration_seconds);
            } else {
                digitalWrite(PUMP_RELAY_PIN, LOW);
            }
            break;
            
        case ControlCommand_config_tag:
            // 更新配置
            reading_interval = command.command.config.reading_interval;
            moisture_threshold = command.command.config.moisture_threshold;
            auto_irrigation = command.command.config.auto_irrigation;
            Serial.println("Configuration updated");
            break;
            
        case ControlCommand_system_tag:
            switch (command.command.system.command) {
                case SystemCommand_Command_RESTART:
                    ESP.restart();
                    break;
                case SystemCommand_Command_DEEP_SLEEP:
                    ESP.deepSleep(0);
                    break;
                // ... 其他系統命令
            }
            break;
    }
}

成果展示

這個系統運行了一年多,效果非常好:

資料傳輸效率:

  • 平均每筆資料:45 bytes(protobuf)vs 180 bytes(JSON)
  • 每天傳輸資料:約 288 筆 × 45 bytes = 12.96 KB
  • 如果用 JSON:約 288 筆 × 180 bytes = 51.84 KB
  • 節省了 75% 的頻寬

電池續航力:

  • 使用 18650 鋰電池 + 太陽能板
  • 持續運行時間:夏季無限,冬季可達 2 週(無陽光)
  • 資料傳輸量減少直接延長了電池壽命

系統穩定性:

  • 運行 365 天,只有 3 次因為網路問題丟失資料
  • 本地 SD 卡備份機制確保資料不遺失
  • 記憶體使用量穩定,無內存洩漏

開發工具與環境建置

讓我分享一套完整的開發工具鏈,讓你快速上手。

工具安裝

1. 安裝 nanopb

# 從 GitHub 下載
git clone https://github.com/nanopb/nanopb.git
cd nanopb
git submodule update --init

# 建置生成器
cd generator/proto
make

# 設定環境變數
export PATH=$PATH:/path/to/nanopb/generator

2. Arduino IDE 設定

在 Arduino IDE 中安裝所需的庫:

  • PubSubClient(MQTT 客戶端)
  • DHT sensor library
  • ArduinoJson(如果需要 JSON 比較)

3. 建立專案結構

my_iot_project/
├── proto/
│   ├── sensor.proto
│   ├── sensor.options
│   └── generate.sh
├── arduino/
│   ├── main/
│   │   ├── main.ino
│   │   ├── sensor.pb.h
│   │   └── sensor.pb.c
│   └── libraries/
│       └── nanopb/
├── server/
│   ├── sensor_pb2.py
│   └── server.py
└── docs/
    └── README.md

自動化腳本

建立 generate.sh 簡化開發流程:

#!/bin/bash
# proto/generate.sh

echo "Generating nanopb files..."
python /path/to/nanopb/generator/nanopb_generator.py sensor.proto

echo "Copying to Arduino project..."
cp sensor.pb.h sensor.pb.c ../arduino/main/

echo "Generating Python files..."
protoc --python_out=../server sensor.proto

echo "Done!"

VS Code 擴展配置

建立 .vscode/tasks.json:

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Generate Protobuf",
            "type": "shell",
            "command": "./proto/generate.sh",
            "group": "build",
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            }
        }
    ]
}

這樣你就可以用 Ctrl+Shift+P → "Tasks: Run Task" → "Generate Protobuf" 快速生成程式碼。

常見問題與解決方案

Q1: nanopb 編譯錯誤

問題:Arduino IDE 報告 nanopb 相關的編譯錯誤。

解決:

  1. 確認 nanopb 版本相容性(建議使用 0.4.x 版本)
  2. 檢查 .options 檔案設定
  3. 確認生成的 .pb.h 和 .pb.c 檔案在正確位置
// 在 .ino 檔案開頭加入
#define PB_ENABLE_MALLOC 0  // 禁用動態記憶體分配
#define PB_FIELD_32BIT 1    // 支援大型訊息

Q2: 記憶體不足

問題:ESP8266 出現記憶體不足,設備重啟。

解決:

  1. 減少緩衝區大小
  2. 使用更精簡的 protobuf schema
  3. 實作記憶體池管理
// 使用更小的緩衝區
#define PROTOBUF_BUFFER_SIZE 64  // 而不是 256
uint8_t buffer[PROTOBUF_BUFFER_SIZE];

Q3: 資料解析失敗

問題:伺服器端無法解析 Arduino 發送的 protobuf 資料。

解決:

  1. 確認兩端使用相同的 .proto 檔案
  2. 檢查資料傳輸的 Content-Type
  3. 除錯序列化資料
// 除錯輸出
void debugProtobufData(uint8_t* data, size_t length) {
    Serial.printf("Protobuf hex dump (%d bytes):\n", length);
    for (int i = 0; i < length; i++) {
        Serial.printf("%02X ", data[i]);
        if ((i + 1) % 16 == 0) Serial.println();
    }
    Serial.println();
}

Q4: WiFi 連線問題

問題:在某些環境下 WiFi 連線不穩定。

解決:實作更強健的連線管理

void ensureWiFiConnection() {
    int retry_count = 0;
    const int max_retries = 10;
    
    while (WiFi.status() != WL_CONNECTED && retry_count < max_retries) {
        Serial.printf("WiFi connecting... (%d/%d)\n", retry_count + 1, max_retries);
        WiFi.begin(ssid, password);
        delay(5000);
        retry_count++;
    }
    
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("WiFi connection failed, entering deep sleep");
        ESP.deepSleep(60 * 1000000);  // 休眠 1 分鐘後重試
    }
}

未來發展與技術趨勢

邊緣計算整合

隨著 ESP32-S3 等更強大的微控制器出現,我們可以在設備端進行更多資料處理:

message ProcessedData {
    string device_id = 1;
    int64 timestamp = 2;
    
    // 原始資料的統計摘要
    StatisticalSummary temperature_stats = 10;
    StatisticalSummary humidity_stats = 11;
    
    // 異常檢測結果
    repeated AnomalyAlert anomalies = 20;
}

message StatisticalSummary {
    float mean = 1;
    float min = 2;
    float max = 3;
    float std_dev = 4;
    int32 sample_count = 5;
}

機器學習推論

未來的 IoT 設備可能會整合 TinyML,在本地進行簡單的機器學習推論:

message MLPrediction {
    string model_id = 1;
    int64 timestamp = 2;
    float confidence = 3;
    
    oneof prediction {
        PlantHealthPrediction plant_health = 10;
        WeatherForecast weather = 11;
        EquipmentFailure failure_risk = 12;
    }
}

5G 和低軌衛星

隨著 5G 和低軌衛星網路的普及,更多偏遠地區的 IoT 設備可以接入網路。Protocol Buffers 的高效率將變得更加重要,特別是在衛星通信的高延遲環境下。

最後的話:小設備,大智慧

回想起那個讓我頭痛一個月的專案,如果當時就知道 nanopb 這個神器,該省多少時間啊!

Protocol Buffers 在 Arduino 和單晶片上的應用,讓我深刻體會到:限制往往是創新的催化劑。正是因為有了記憶體、頻寬、電力的限制,我們才被迫去尋找更高效的解決方案。

在 IoT 的世界裡,每個位元組都有它的價值。當你的設備需要運行數月甚至數年,當你的網路頻寬只有幾 KB/s,當你的記憶體只有幾 KB 時,選擇正確的技術就變得至關重要。

nanopb 不只是一個工具,它代表了一種思維方式:如何在有限的資源下做出無限的可能。

給新手的建議

如果你是第一次嘗試在 Arduino 上使用 Protocol Buffers,我的建議是:

  1. 從小開始:先用最簡單的 schema,確保整個流程跑得通
  2. 測量一切:記憶體使用量、傳輸時間、資料大小都要實際測量
  3. 保持耐心:除錯嵌入式系統比除錯伺服器程式困難得多
  4. 記錄經驗:把遇到的問題和解決方案記錄下來,下次會用到

展望未來

物聯網正在快速發展,邊緣計算、人工智慧、5G 通信等技術都在重塑這個領域。但無論技術如何進步,資源效率始終是嵌入式系統的核心議題。

Protocol Buffers 為我們提供了一個優雅的解決方案,讓小小的 Arduino 也能說一口流利的「高效語言」。

希望這篇文章能夠幫助你在自己的 IoT 專案中更好地應用 Protocol Buffers。如果你有任何問題或想要分享你的經驗,歡迎留言討論!

記住:在 IoT 的世界裡,小設備也能有大智慧。


相關資源

官方文檔

教學資源

開發工具

硬體建議

  • 入門級:Arduino Uno + ESP8266 WiFi 模組
  • 推薦級:ESP32 開發板(內建 WiFi/藍牙)
  • 專業級:ESP32-S3 或 STM32 系列

標籤: #Arduino #ProtocolBuffers #nanopb #IoT #嵌入式系統 #ESP32 #感測器


本文最初發布於 HackMD @BASHCAT。

LoRa優劣勢分析與Mesh組網潛在問題探討

前言

在物聯網(IoT)快速發展的今天,無線通信技術的選擇成為了關鍵因素。LoRa(Long Range)技術憑藉其低功耗、長距離的特性在眾多應用場景中脫穎而出,而基於LoRa的Mesh組網技術更是為複雜環境下的設備互聯提供了新的解決方案。本文將深入分析LoRa技術的優劣勢,探討Mesh組網架構的潛在問題,並通過比較表格幫助読者更好地理解這些技術。

LoRa技術概述

LoRa是Semtech公司開發的一種長距離、低功耗的無線通信技術,採用直序擴頻調製技術,能夠在Sub-GHz頻段實現遠距離通信。LoRaWAN則是建立在LoRa物理層之上的媒體接入控制(MAC)層協議。

LoRa技術的核心特點

  • 長距離通信:在開闊環境下可達15-20公里
  • 低功耗:電池供電設備可運行數年
  • 強抗干擾能力:採用擴頻技術,具備良好的抗干擾性
  • 低成本:晶片和模組成本相對較低

LoRa Mesh組網技術

LoRa Mesh是一種基於LoRa技術的自組網通信協議,將多個設備組成自組織網絡,形成網狀拓撲結構。它結合了LoRa的長距離、低功耗優勢與Mesh網絡的自組織、自修復特點。

Mesh網絡的工作原理

在Mesh網絡中,每個節點都可以作為數據的發送者、接收者或中繼器,形成多路徑的通信網絡。當某個節點失效時,數據可以通過其他路徑傳輸,實現網絡的自我修復功能。

LoRa技術優劣勢分析

優勢

1. 傳輸距離優勢

  • 超長通信距離:在理想條件下可達20公里以上
  • 穿透能力強:能夠穿越建築物和地形障礙
  • 覆蓋範圍廣:單個基站可覆蓋大範圍區域

2. 功耗管理優勢

  • 超低功耗設計:設備可在電池供電下運行3-10年
  • 休眠模式:支援深度休眠,進一步降低功耗
  • 智能功率控制:根據距離自動調整發射功率

3. 成本效益優勢

  • 硬體成本低:晶片和模組價格相對便宜
  • 部署成本低:無需複雜的基礎設施
  • 維護成本低:設備壽命長,維護需求少

4. 技術優勢

  • 抗干擾能力強:擴頻技術提供良好的抗干擾性
  • 多普勒容忍:適用於移動設備
  • 標準化程度高:LoRaWAN聯盟推動標準統一

劣勢

1. 數據傳輸限制

  • 低數據速率:典型速率僅0.3-50 kbps
  • 有效載荷限制:單次傳輸數據量有限(通常<255字節)
  • 不適合高帶寬應用:無法滿足音視頻傳輸需求

2. 網絡容量限制

  • 並發連接數限制:單個基站支援設備數量有限
  • 頻道利用率限制:duty cycle限制影響數據傳輸頻率
  • 碰撞問題:多設備同時傳輸可能發生碰撞

3. 實時性限制

  • 延遲較大:不適合對實時性要求極高的應用
  • 確認機制延遲:雙向通信確認時間較長
  • 網絡同步問題:時間同步精度有限

4. 環境依賴性

  • 頻段限制:受各國頻譜法規限制
  • 環境干擾:易受其他ISM頻段設備干擾
  • 天氣影響:極端天氣可能影響信號傳播

Mesh組網的潛在問題

1. 網絡複雜性問題

路由算法複雜性

  • 動態路由維護:需要持續更新路由表
  • 路由收斂時間:網絡拓撲變化時需要時間重新收斂
  • 路由選擇策略:需要平衡跳數、信號強度、電池電量等因素

網絡管理困難

  • 節點狀態監控:難以實時監控所有節點狀態
  • 故障診斷複雜:網絡故障定位和診斷困難
  • 配置管理:大規模部署時配置管理複雜

2. 性能與擴展性問題

網絡性能退化

  • 多跳延遲累積:數據需要多跳傳輸,延遲累積
  • 頻寬分割:每一跳都會消耗頻寬資源
  • 碰撞概率增加:節點數量增加導致信道競爭加劇

擴展性限制

  • 節點數量限制:網絡性能隨節點數量增加而下降
  • 拓撲不穩定:大規模網絡中拓撲變化頻繁
  • 同步困難:大規模網絡時間同步困難

3. 能耗與可靠性問題

不均勻能耗

  • 中繼節點負擔重:承擔轉發任務的節點能耗更高
  • 電池耗盡不均:部分節點可能過早耗盡電池
  • 網絡分割風險:關鍵節點失效可能導致網絡分割

可靠性挑戰

  • 單點故障影響:關鍵中繼節點故障影響整體連通性
  • 數據重複傳輸:為保證可靠性需要重複傳輸
  • 確認機制複雜:端到端確認機制實現困難

4. 安全性問題

加密與認證複雜性

  • 密鑰管理:Mesh網絡中密鑰分發和管理複雜
  • 節點認證:新節點加入網絡的認證機制
  • 數據完整性:多跳傳輸中保證數據完整性

攻擊面擴大

  • 節點偽造攻擊:惡意節點可能偽造合法節點
  • 中間人攻擊:中繼節點可能被攻擊者控制
  • 洪水攻擊:惡意節點發送大量數據造成網絡癱瘓

技術比較分析

LoRa vs 其他LPWAN技術比較

特性 LoRa/LoRaWAN NB-IoT Sigfox
傳輸距離 2-20km 1-10km 10-50km
數據速率 0.3-50 kbps 1-200 kbps 0.1-0.6 kbps
功耗 極低 低 極低
部署成本 中等 高 低
網絡容量 中等 高 低
雙向通信 支援 支援 有限支援
移動性支援 良好 優秀 有限
標準化程度 高 高 中等

LoRa組網方式比較

組網方式 LoRaWAN星形 LoRa Mesh LoRa點對點
拓撲結構 星形 網狀 點對點
通信距離 長 可擴展 長
網絡可靠性 中等 高 低
部署複雜度 簡單 複雜 最簡單
延遲特性 低 中等-高 最低
功耗表現 最低 中等 低
擴展性 中等 高 低
成本 中等 高 最低

Mesh網絡技術比較

技術 LoRa Mesh ZigBee Mesh WiFi Mesh
通信距離 1-5km 10-100m 50-300m
數據速率 低(kbps級) 中等(250kbps) 高(Mbps級)
功耗 極低 低 高
網絡容量 中等 中等 高
部署難度 中等 中等 簡單
適用場景 廣域IoT 家庭自動化 網絡擴展
成本 中等 低 中等

應用場景分析

適合LoRa技術的應用場景

1. 智慧農業

  • 土壤監測:監測土壤濕度、養分、pH值
  • 氣象監測:溫度、濕度、風速、降雨量監測
  • 牲畜追蹤:動物位置和健康狀況監測
  • 灌溉控制:遠程控制灌溉系統

2. 智慧城市

  • 停車管理:停車位狀態監測
  • 垃圾桶監測:垃圾桶滿溢狀態監測
  • 空氣品質監測:PM2.5、CO2等污染物監測
  • 路燈控制:智慧路燈亮度和狀態控制

3. 工業4.0

  • 設備監控:機器運行狀態和參數監測
  • 預測性維護:設備故障預測和維護提醒
  • 資產追蹤:工廠內設備和物料追蹤
  • 環境監測:工廠環境參數監測

適合Mesh組網的場景

1. 複雜地形覆蓋

  • 山區監測:地質災害監測網絡
  • 森林防火:森林火災早期預警系統
  • 礦井安全:井下人員和環境監測

2. 高可靠性需求

  • 電力巡檢:電力設施狀態監測
  • 石油管道:管道完整性監測
  • 核設施監測:核電站環境監測

解決方案與最佳實踐

針對Mesh組網問題的解決方案

1. 路由優化策略

多指標路由算法:
- 跳數優化
- 信號強度權重
- 電池電量考慮
- 網絡負載平衡

2. 能耗均衡技術

輪換中繼機制:
- 動態中繼角色分配
- 負載均衡算法
- 休眠排程優化
- 功率控制策略

3. 網絡管理方案

分層管理架構:
- 簇頭節點管理
- 區域網絡劃分
- 集中式監控
- 分散式決策

部署最佳實踐

1. 網絡規劃

  • 覆蓋範圍規劃:根據應用需求確定覆蓋範圍
  • 節點密度設計:平衡覆蓋效果和成本
  • 冗餘設計:考慮關鍵節點的備份方案
  • 擴展性預留:為未來擴展預留接口

2. 節點部署

  • 位置選擇:選擇信號覆蓋良好的位置
  • 電源管理:考慮電池更換和太陽能供電
  • 環境保護:選擇適當的防護等級
  • 安裝固定:確保設備安裝牢固

3. 網絡測試

  • 信號強度測試:測試各節點間信號品質
  • 連通性測試:驗證端到端通信能力
  • 容錯測試:測試節點故障後的網絡恢復能力
  • 性能測試:測試網絡吞吐量和延遲

未來發展趨勢

技術演進方向

1. LoRa技術改進

  • 更高數據速率:新的調製技術提升數據速率
  • 更低功耗:晶片工藝改進降低功耗
  • 更強抗干擾:改進的擴頻算法
  • 更好定位精度:結合多種定位技術

2. Mesh組網優化

  • AI路由算法:機器學習優化路由決策
  • 邊緣計算整合:結合邊緣計算能力
  • 5G融合:與5G網絡協同工作
  • 安全性增強:區塊鏈等新技術應用

應用領域擴展

1. 新興應用領域

  • 智慧醫療:可穿戴設備和遠程監護
  • 智慧交通:車聯網和交通管理
  • 災害預警:自然災害早期預警系統
  • 環境保護:生態環境監測網絡

2. 技術融合趨勢

  • 多技術融合:LoRa與其他無線技術結合
  • 雲邊協同:雲計算與邊緣計算結合
  • 數字孿生:物理設備與數字模型結合
  • 區塊鏈整合:去中心化的網絡管理

結論

LoRa技術憑藉其長距離、低功耗的優勢在物聯網領域佔據重要地位,而基於LoRa的Mesh組網技術更是為複雜環境下的設備互聯提供了可靠的解決方案。然而,任何技術都有其局限性,LoRa Mesh組網也面臨著網絡複雜性、性能擴展性、能耗不均和安全性等挑戰。

在實際應用中,我們需要根據具體的應用場景、性能需求和成本預算來選擇合適的技術方案。對於大範圍、低數據量、對實時性要求不高的應用,LoRa Mesh是一個很好的選擇。而對於高數據量、高實時性的應用,可能需要考慮其他無線通信技術。

隨著技術的不斷發展,我們相信LoRa和Mesh組網技術將會在各自的領域中發揮更大的作用,為物聯網的發展做出更大的貢獻。在部署這些技術時,我們應該充分了解其優勢和限制,制定合理的部署策略,並持續優化網絡性能,以實現最佳的應用效果。


本文基於當前技術發展狀況撰寫,隨著技術不斷演進,部分觀點可能需要更新。建議讀者持續關注相關技術發展動態。


本文最初發布於 HackMD @BASHCAT。

前言

截圖 2024-05-08 下午1.50.17

image

[toc]

截圖 2024-05-03 上午11.49.19 大家好,我是BASHCAT...這是一篇面向一般民眾的 Meshtastic 教學文件,讓你可以快速入門 Meshtastic。

本於核心精神,開源、離網、去中心化、網狀網絡,專為在經濟實惠的低功耗設備上運行而構建:『新手入門必讀』並不會提到太多花裡胡哨的炫技(魔改射頻、多頻段組網),但絕對可以讓你快速建立一個節點加入我們。

07/07更新:注意,Meshtastic在數據傳輸上並非絕對安全,尤其在開啟MQTT模式,未定期更換key的狀況下,更容易發發生數據洩漏、或冒名的狀況。 請不要在Meshtastic傳送機敏訊息或是個人資訊!並不要聽信任何人的指示。

至於經濟實惠呢,以最容易購買到的 Meshtastic裝置 Heltec V3 在台灣有代理商可以購買,售價約在台幣650~720。(跳至購買管道)

截圖 2024-05-09 下午2.30.58

如果有能力,或市場買左岸的產品的朋友,也可至某寶進行採購(這邊不進行而外購買教學~)。

截圖 2024-05-09 下午2.28.54

如果還想要更便宜,或是動手能力更好的朋友,可以參考下面影片採用ESP32+SX12xx系列構成,當然這需要相關的編程經驗或是,多花點心力來建構: {%youtube Ivs6mewt-fw%}

2024/05/03 北台灣節點分佈 截圖 2024-05-03 中午12.29.45

2024/06/29 北台灣節點分佈 SCR-20240629-m3y

Meshtastic 簡介

台灣頻道快速 QRCODE ![439337288_10223250809052381_7504192286148581237_n](https://hackmd.io/_uploads/B1RktkzGR.jpg =300x300) (https://meshtastic.org/e/#CgMSAQEKNxIgisDhHrNpJPlGX3GBJBX6kjuK7KQNp4Z0M7OTDpnX5N4aBk1lc2hUVyUBAAAAKAEwAToCCBAKNhIgy1HciVgpl5Hzh05KJUe_umWUH8XhG3UjR1rvZHfUHFUaClNpZ25hbFRlc3QoATABOgIIIAo2EiDLaOd_zp9Ol__gAUB_6YLBvNGjGkJXQ_3R2omjT7D9JhoKRW1lcmdlbmN5ISgBMAE6AgggEg4IATgIQANIAVARWBBoAQ

Meshtastic Taiwan Community 臺灣鏈網 社群簡介

Meshtastic 介紹 by 何封

Meshtastic官方連結 https://meshtastic.org/

An open source, off-grid, decentralized, mesh network built to run on affordable, low-power devices

Meshtastic 採用 LoRa,一種遠端無線電協定,與 HAM 無線電操作不同,該協定可在大多數地區廣泛使用,無需額外的許可證或認證。

這些無線電旨在重新廣播它們收到的訊息,形成網狀網絡。此設定可確保每個群組成員(包括距離最遠的成員)都可以接收訊息。根據所採用的設定,Meshtastic 裝置支援最多可以同時與其他 100 個裝置互動。

此外,Meshtastic 裝置可以與一部手機配對,讓朋友和家人可以直接向您的 Meshtastic 裝置發送訊息,然後你就可以在 Meshtastic 裝置和手機上看到來自朋友的訊息。值得注意的是,每台 Meshtastic 設備一次只能和一臺手機連線(透過藍牙連線的狀況)。

Meshtastic 使用場景

  • 面對兩岸局勢 在台灣,兩岸緊張局勢可能導致通訊中斷或被干擾,特別是在軍事演習或其他安全事件發生時。Meshtastic 能在這些情況下提供一個可靠的通訊網絡,因為它不依賴於傳統的通訊基礎設施。即使在手機網絡不穩定或中斷的情況下,人們仍然可以通過 Meshtastic 裝置保持聯繫,進行基本的溝通和組織應對措施。

  • 面對地震和其他天災 台灣位於太平洋地震帶,經常發生地震,強震可能會導致嚴重的基礎設施損壞,包括破壞通訊塔和電力網絡。在這些災害發生後的首幾小時,迅速而可靠的通訊尤其重要。Meshtastic 裝置由於其耐用性和獨立於傳統網絡的特性,成為災害應對中一個寶貴的工具。它可以幫助救災團隊協調行動,有效進行搜救任務,並且在關鍵時刻使受災居民得以互相聯繫和提供彼此支持。

    地震通報機制目前測試中 441214172_1489341648647640_3889184645701438230_n

    使用英文的地震報告,也可以在OLED有良好的顯示效果 目前已先改為中文,主要因為單筆訊息上限為228字元,英文如直接採用氣象局報告,會出現無法傳輸狀況(待修正)

    ![441285774_8374598445889597_7390305352891841032_n](https://hackmd.io/_uploads/ByHIASsG0.jpg =400x300)

  • 登山救助 台灣的山岳地形吸引了大量的登山愛好者,但山區常常面臨信號涵蓋不足的問題,尤其在偏遠和高海拔地區。在這些情況下,Meshtastic 提供了一個獨特的解決方案,可以極大地增強山區救援的效率和安全性。

Meshtastic 能做到那些事?


  1. 通訊連接 在偏遠地區進行登山活動時,常規的手機信號可能無法涵蓋,這時 Meshtastic 裝置與裝置之間,能夠自行建立出網路,讓隊員間可以相互通訊,即使在崇山峻嶺之中也不會失聯。這對於在遇到緊急情況時快速反應至關重要。

  2. 即時位置共享 利用 Meshtastic 的地圖和 GPS 功能,隊員可以實時分享他們的位置。這對於救援隊來說是一個寶貴的功能,因為他們可以即時確定失蹤者的最後位置,並更有效地計劃搜救路線。

  3. 救援協調 在發生意外時,快速的協調救援行動是救援成功的關鍵。Meshtastic 能夠幫助救援隊伍在沒有其他通訊手段的情況下,通過裝置直接協調救援行動,包括安排救援路徑、調配資源及處理突發狀況。

新手入門必讀(入門)

在台灣,LoRa (Long Range) 射頻技術的使用需符合國家通信傳輸委員會 (NCC) 的相關規範與標準。這些規範確保了射頻技術的使用不會干擾其他無線通訊服務,並且保護用戶的隱私與安全。

Part 1:環境建置

其實建置 Meshtastic 就像是組電腦一樣,你可以選擇套裝電腦,或是有動手能力的,也可以自行組裝,因為 Meshtastic 架構開源的特性,你也可以自行修改程式原始碼執行,但相對的門檻較高。

給新手的提示: 1. 任何射頻裝置,請務必先安裝天線後再進行開機,Meshtastic 也是一樣,要養成好習慣。 2. 請在確認接下來不會需要使用藍牙與裝置連線時,才開啟WI-FI模式。Meshtastic ESP32 的開發板可以開啓 WI-FI 功能,但只能藍牙/WI-FI二選一,不小心開啟的朋友可以透過電腦+裝置IP與裝置連線,或者是使用 USB 與電腦或是安卓手機連線後重新開啓藍牙功能,不一定要重新刷韌體喔。 3. iOS版本中 設定>裝置>Managed Device 選項在尚未完成所有配置前,請先不要開啟,否則會無法透過BLE進行設定,可以跟第2點一樣進行 USB 與電腦或是安卓手機連線後修改回來唷。

快速懶人包

1.硬體的選擇

入門建議使用 HeltecV3、登山與戶外運動者可嘗試跨國購買 LILYGO TTGO T-Echo

2.確認韌體版本或是燒寫韌體

Meshtastic 功能還在持續成長中,若有需要更新韌體,可以參考 https://www.facebook.com/groups/meshtastictw/permalink/414578450951353/

3.軟體設定

需要設定的有:
    使用藍牙連上設備,輸入 Meshtastic 裝置螢幕上顯示的 PIN 碼
    裝置使用地區原先預設是 UNNET,請設定為 TW 
    設定裝置的長名稱與短名稱
    點擊本文章的 QRCODE,或使用掃描方式,加入臺灣的頻道(可以視爲聊天室)設定

4.發送數據

可以挑選頻道(聊天室):MESH TW 或是 SignalTest 跟大家打聲招呼

5.設定 GPS 或開啟 FixedGPS 資訊


再次貼心小提醒,任何射頻裝置,在設備上電前,請確保天線安裝妥當,並且安裝正確的頻率,否則可能損害設備


硬體篇

照片 介紹 補充資料
HeltecV3 Heltec V3- 這款裝置結合了 ESP32 和 LoRa,並有一個 OLED 顯示器,方便顯示訊息和狀態(也是目前台灣最多人使用的裝置)。
TTGO TTGO T-Beam - 擁有 GPS 模組和 LoRa 無線模組,背後有一組 18650 電池座,非常適合戶外使用。也相當容易從網路上找到對應的外殼進行 3D 列印。
截圖 2024-05-03 中午12.04.55 NRF52840 - ,可使用原廠開發板或購買台灣勁達 EVB ,此項為低功耗的藍牙開發板,但不具有 WI-FI 功能,入門門檻較高,適合有長時間待機的節點使用。
RAK4631 RAK4631 - 這是一個模組化解決方案, NRF52+LoRa 整合模組的方案。適合配合太陽能板搭建節點。
SCR-20240629-mom LILYGO T-Echo - 這是一臺開箱即用的裝置,採用 NRF 技術與電子紙螢幕,因此會比 ESP32 系列裝置來的省電。內建 GPS,因此會主推給登山愛好者。目前臺灣沒有代理,需從海外購買。
  • 要如何與 Meshtastic 裝置連線 根據不同裝置所可以使用的介面與工具不同,大致上可分為:
    • BLE 低功耗藍牙進行連接(建議的連線方式)
    • USB 介面 內部 USB to TTL 連接 可配合桌面應用程式或是
      • PythonCli
      • WebClient 當設備的設定頁面消失時,可以使用此工具進行修復
    • WIFI 連接
    • Android 手機 OTA連接 作為 NRF52 系列的一個韌體更新方式

韌體篇

通常在台灣購買 HeltecV3 時,可以付費請商家協助進行韌體的更新。 如果買到的設備無預先燒錄韌體,可以參考下方 flaher 工具,裡面可以選擇不同廠牌的裝置與版本。 https://flasher.meshtastic.org/ 使用工具前要先進入燒綠模式(ESP32base),有兩個方式: ~1. 在未接電的狀況下,按住 PROG/BOOT 按鈕:在連接電源或 USB 線之前,按住此按鈕,上電即會進入。 2. 在已接電的狀況下連接裝置:在繼續按住 PROG/BOOT 按鈕的同時,按下RST後釋放RST,此時PROG/BOOT才能將其放開。

這邊有詳細說明 by 何封: 434851390_10223161407857407_5019292819019651219_n https://www.facebook.com/groups/meshtastictw/permalink/414578450951353/

軟體篇

射頻篇

  • 在臺灣,LoRa 的合法使用頻段爲 920Mhz ~ 925 Mhz。
  • 台灣 Meshtastic 預設使用 923Mhz,切換到其他頻段,不但會有違法的風險,也會無法和其他裝置通聯。
  • 補充資訊
    • LoRa(Long Range) 915 MHz 頻段是一種專為長距離低功耗通訊設計的技術,具有幾個顯著特性,使其在各種應用中都非常實用。以下是 LoRa 915 MHz 頻段的一些關鍵特性和可能的影響因素:
    • LoRa 915 MHz 的特性 長距離傳輸:LoRa 915 MHz 能夠提供遠距離的無線通訊能力,常見的通訊距離可以達到2-5公里(城市環境)和15公里(開放或郊區環境),這得益於其低數據傳輸速率和強大的信號調變技術。 高穿透力:915 MHz 頻段具有良好的建築物穿透能力,這使其在城市和室內環境中也能保持較好的通訊連接,適合於室內外結合的應用。 低功耗:LoRa 技術以其極低的功耗著稱,這使得在電池供電的設備上非常實用。
    • 受影響的因素 干擾:由於 915 MHz 是非授權頻段,它可能會受到其他使用相同或相鄰頻段設備的干擾,例如:其他無線設備、手機基地台、某些家用電子產品等。 地理和環境因素:山脈、高樓、樹木等自然和人造障礙物可以影響 915 MHz 信號的傳播距離和品質。 天氣條件:極端的天氣條件,如雨、雪和濃霧,可能會減弱射頻信號,尤其是在更長的傳輸距離上。 法規限制:不同國家和地區對於 915 MHz 頻段的使用有不同的法規限制,這可能會影響設備的功率輸出、頻道分配和運作模式。

Part 2:基本功能

裝置形態

裝置角色 描述 最佳使用場景
CLIENT 可連接應用程式或做爲獨立的消息傳送裝置。 一般人在使用時都是選擇這個。支持客戶端應用。
CLIENT_MUTE 不轉發其他裝置的數據包的裝置。 當設備需要參與網絡,但不協助轉發接收到的數據包時,以減少網絡負荷的情況。
CLIENT_HIDDEN 僅在需要時廣播,以實現隱蔽或節省電力。 用於隱藏/秘密部署或在仍參與網絡的同時減少空中時間/功耗。
TRACKER 優先廣播 GPS 位置數據包。 跟踪個人或資產的位置,特別是在需要即時且高效的位置更新的情境中。
LOST_AND_FOUND 定期向預設頻道發送位置消息以協助找回設備。 用於協助找回丟失的設備。
SENSOR 優先廣播遙測數據包。 在需要收集環境或其他感測數據的情景中部署,具有高效的能源使用和頻繁更新。
TAK 最佳化 ATAK 系統通信,減少常規廣播。 與 ATAK 系統整合(通過 Meshtastic ATAK 插件),用於戰術或協調操作中的通信。
TAK_TRACKER 啟用自動 TAK PLI 廣播並減少常規廣播。 獨立的 TAK PLI 整合,用於戰術或協調操作中的通信。
REPEATER 通過最小開銷中繼消息來擴展網絡涵蓋的基礎設施節點。不顯示在節點列表中。 最佳放置於戰略位置以最大化網絡整體覆蓋。設備在拓撲中不顯示。
ROUTER 通過中繼消息擴展網絡覆蓋的基礎設施節點。顯示在節點列表中。 最佳放置於戰略位置以最大化網絡整體涵蓋。設備在拓撲中顯示。
ROUTER_CLIENT ROUTER 和 CLIENT 的結合體。不適用於移動設備。 放置於戰略位置,需要優先路由的設備,同時也充當標準 CLIENT。

不同模式下工作狀態

裝置角色 BLE/WiFi/序列埠 螢幕啟用 耗電量 重傳 優先路由 在節點列表中可見
CLIENT 是 是 常規 是 否 是
CLIENT_MUTE 是 是 最低 否 否 是
CLIENT_HIDDEN 是 是 最低 僅本地 否 否
TRACKER 是 否 常規 否 否 是
LOST_AND_FOUND 是 否 常規 否 否 是
SENSOR 是 否 高 否 否 是
TAK 是 可選 常規 是 否 是
TAK_TRACKER 是 可選 常規 是 否 是
ROUTER 否1 否 高 是 是 是
ROUTER_CLIENT 是 是 最高 是 是 是
REPEATER 是 否 高 是 是 否

如何讓節點出現在地圖中

https://www.facebook.com/groups/meshtastictw/permalink/415687787507086/

建立/加入網絡

MQTT 使用與設定

若你所在區域的 Meshtastic 覆蓋率還不高,或是因爲四週都是高樓大廈導致無法穩定的收到其他裝置的 LoRa 訊號,那你就需要需要開啓 MQTT ,來利用網際網路傳送訊息,設定方法如下:

  • Android app

    • Radio configuration(裝備設定) → Lora → 不要勾選 Ignore MQTT → 按下 Send → 裝置會重開機,等它開完機並重新連上手機
    • 回到 Radio configuration(裝備設定) → 往下捲動找到 MQTT → 打開 MQTT enabled 開關 → 打開 Encryption enabled 開關 → 打開 Proxy to client enabled 開關(讓裝置透過手機的網路來接收與傳送訊息) → (其他的開關都不用開)→ 按下 Send → 裝置會重開機,等它開完機並重新連上手機即完成
    • 同樣在 MQTT 的設定頁面,Root Topic 的部分確保設定爲 msh/TW,不要是 msh/TW/XXX 之類的,只要 msh/TW 就好,不然會收不到其他人的訊息
  • iOS app

    • 設定頁 → LoRa → 不要勾選 Ignore MQTT → 按下儲存 → 裝置會重開機,等它開完機並重新連上手機

    • 設定頁 → 往下捲動找到 MQTT → 從畫面最上方數起,第 1 2 3 4 個選項的開關打開。 451786627_792825912839187_4315039696692845276_n

    • 同樣在 MQTT 的設定頁面,Root Topic 的部分確保設定爲 msh/TW,不要是 msh/TW/XXX 之類的,只要 msh/TW 就好,不然會收不到其他人的訊息

    • 確認後按下儲存 → 裝置會重開機,等它開完機並重新連上手機即完成

  • 在使用 MQTT 時,因爲是透過手機網路來接收與傳送訊息,因此請不要把手機網路關掉唷。

發送和接收訊息

教使用者如何透過裝置發送文本訊息和接收來自其他裝置的訊息。

Part 3:進階使用

  • 自訂設定 - 解釋如何通過應用程式自訂裝置設定,如更改頻率、調整發射功率等。
  • 群組通訊 - 介紹如何在 Meshtastic 裝置間設立和管理群組通訊。
  • 連接外部設備 - 講解如何將 Meshtastic 裝置與其他設備如: GPS 或氣象儀器連接。

Part 4:日常維護與常見問題

日常維護

對於太陽能節點

1. 檢查太陽能板清潔度:
    定期清潔太陽能板,去除灰塵、污垢或其他異物,這些都可能阻擋陽光,影響充電效率。
2. 檢查電池狀態:
    定期檢查電池是否需要更換。太陽能系統中的電池壽命有限,長時間使用後可能需要更換。
3. 檢查接線和連接:
    確保所有接線緊固且無腐蝕。接線的松動或腐蝕都會影響系統效能。
    確認系統充電和放電效率:
    定期檢查系統的充電和放電效率,確保太陽能板和電池工作正常。

對於室內LoRa節點

1. 設備擺放位置:
    確保LoRa節點放在通風良好且無電子干擾的地方。避免放置在熱源附近或密封環境中,以免影響性能和壽命。
2. 定期檢查和重啟設備:
    定期檢查設備運行狀況,偶爾重啟設備可以清理內存並解決一些暫時性的問題。
3. 更新固件和軟件:
    定期檢查並更新節點的硬體和軟體,以確保所有功能都能正常工作並擁有最新的安全性更新。
    監控訊號強度和連接穩定性:
    監控節點的訊號強度和連接穩定性,確保訊號覆蓋範圍內無死角,且通信穩定。

常見問題

  • Q.為什麼 GPS 一直沒有訊號? A.GPS 需要於是外使用才能有效進行尋星,當搜到一定數量時,在裝置螢幕上,或是 app 端可以查看到當前座標,或衛星數量。

  • Q.為什麼我的 app 畫面跟群友的不太一樣? A.目前 Meshtastic 在手機端支持的兩大平台(iOS&Android),它們的使用邏輯,與操作方式皆有不同,甚至一些較新的功能會出現在其中一個平臺上,但另一個平臺卻無法使用。另外補充,iOS 可以長按訊息進行進行『回覆』與『回覆表情符號』的功能,但 Android 只能看到訊息依序出現,所以使用 iOS 的朋友要注意一下,Android 朋友實際上看不到你是針對哪一條訊息回覆。

  • Q.設備只有充電指示燈有亮,顯示器與藍牙都連不上? A.請先檢查是否為韌體異常,檢查方式可以使用帶有數據傳輸功能的USB線接上板子。注意,有少部份的USB線材並沒有D+D-數據傳輸線(如行動電源送的),會導致無法排查問題,接上後使用baudrate 115200,連上端口,這時可以按下RST查看打印訊息,正常如下圖: 截圖 2024-05-05 晚上10.07.30 如果沒出現則需要重新下載韌體到板子上。

  • Q.Heltec v3 能否關閉電源? A.長按裝置左上角的按鈕 5 秒鐘,當螢幕顯示 Shutting Down 時就是成功了。按下同一顆按鍵即可喚醒。若是喚醒後感覺秀抖秀抖,可以按一下裝置左下角的按鍵,重新開機。

  • Q.T-beam能否關閉電源? A.長按設備上的電源開關5秒鐘。當設備開機後,通常會有指示燈亮起或OLED顯示LOGO,設備已經成功開機,關機操作也是一樣。

  • Q.為什麼通訊距離這麼短? A.LoRa 和無線電一樣,容易遭遇遮蔽干擾,尤其是建築物,盡可能於『視距通訊』(Line of Sight, LOS)與對方通訊。視距通信是指在發射器和接收器之間的通信路徑上,沒有任何障礙物阻擋,因此信號可以直接傳遞。在視距範圍內,無線電信號的傳輸會更加清晰和穩定,經過實際測試,在沒有阻擋的狀態下,透過 Heltec v3 就可以從林口與汐止的裝置成功通訊。而由於城市內建築物很多,因此會建議大家在自家頂樓架設 Meshtastic 太陽能節點,就可以從高處與遠處的裝置做通聯,由頂樓的節點把資訊轉發給樓下的住戶(也就是你)。

  • Q.HeltecV3 可以工作多久? A. HeltecV3 採用 ESP32 方案,基本待機功耗為 120~130mA 可配合 https://www.digikey.tw/zh/resources/conversion-calculators/conversion-calculator-battery-life 進行待機計算,但要注意計算結果為預估值,實際仍依照電池壽命與使用環境有影響。 截圖 2024-05-05 晚上10.22.19

  • Q.我手上有許多設備,但為在家測試時,通訊時有時無? A.當多個 Meshtastic 設備處於彼此非常接近的位置,並且同時嘗試通信時,可能會發生一種稱為信道飽和或信號干擾的現象。這種情況發生的原因主要是因為所有設備都在同一無線頻段上發送信號,從而導致類似蛙群『共鳴』的狀況。

    1. 可以嘗試關閉幾組設備,或是將其距離拉開。
    2. 可以嘗試從原本的『長距離 快速』切換爲『短距離 快速』的傳輸方式。不過切換後,會無法和其他『長距離 快速』的裝置透過 LoRa 連線。(MQTT 連線則是不影響)
  • Q.433Mhz 與 915Mhz 傳輸的差異? A.在無線通訊領域中,433 MHz 和 915 MHz 都是常用的無線電頻率,主要用於低功耗的短距離通訊,例如物聯網(IoT)裝置、無線遙控器和一些家庭自動化系統。這兩個頻率帶有各自的特點和應用上的差異:

    1. 法規限制: 433 MHz:這個頻率在歐洲和亞洲廣泛使用,但在美國和加拿大的使用受到更嚴格的限制。 915 MHz:主要在美國使用,這個頻率在美國允許較高的發射功率,這使得通訊距離可以更遠。在其他地區,如澳大利亞和一些亞洲國家,也有被使用,但可能有不同的法規限制。
    2. 通信距離和穿透能力: 通常來說,較低的頻率(如433 MHz)可以提供更好的穿透能力(例如穿過牆壁和其他障礙物),但可能有較低的數據傳輸速率。 915 MHz 頻率提供較高的數據傳輸速度,但其穿透能力相比433 MHz 要差一些。
    3. 干擾和擁擠: 由於433 MHz 在多個地區使用較為普遍,可能會遇到更多的干擾,尤其是在人口密集的地區。 915 MHz 雖然在美國較為常用,但由於其使用範圍較窄,相對的干擾可能會較少。
    4. 應用範圍: 433 MHz 適合需要大範圍覆蓋且對數據速率要求不高的應用,如某些類型的家庭自動化系統。 915 MHz 則適用於需要較高數據傳輸速度或較短通訊距離的應用,例如某些高速的物聯網應用。
  • Q.為甚麼我的 iOS app,裝置的設定選單突然不見了?QAQ 這可能表示你與你的裝置現在是處於斷線的狀況(藍牙),請檢查連線確認是否正確連線,或者將 iOS 系統中的藍牙設置移除後重新配對,如配對後仍相同狀況,應該是有去設定到使用者管理的選單,解決辦法有兩種:

    ![截圖 2024-05-10 下午4.08.50](https://hackmd.io/_uploads/SkAfILsGA.png =300x600)

    1. 重新刷韌體,需要完全抹除設置
    2. 使用USB接口連接上電腦後,並使用Web Tools進行重新設定 https://client.meshtastic.org/ 位置在Radio Config>Device>Managed 截圖 2024-05-10 下午4.11.43

    截圖 2024-05-10 下午4.11.21

  • Q.藍牙裝置『偶發』連不上? Meshtastic 使用 BLE 藍牙連線,只能支持同一時間一組裝置,所以連不上時可以依據下面方式確認:

    1. 確保只有一個裝置連上 Meshtastic,如果有使用其他手機或是電腦,有可能會被自動連線占用,請其藍牙關閉或是『遺忘該藍牙裝置』後重新配對,查看是否恢復。
    2. 如果有經過韌體重刷的動作,請於手機端進行『藍牙裝置遺忘』後重新配對,查看是否恢復。
    3. 使用 nrf connect app 進行 BLE Scan,查看是否因為訊號不穩定導致連線失敗。 ![IMG_0469](https://hackmd.io/_uploads/SJxRTYlmC.jpg =500x400) IMG_0470

學習資源

進一步學習資源 - 提供進一步學習的資源,包括官方文檔、在線論壇和社群。

購買管道

各種材料、裝置,可以在這裡買

場勘使用(RF通訊測試)

https://www.facebook.com/groups/meshtastictw/posts/449545847454613/

走火入魔XD(進階延伸)

好還要更好的天線

Q. 我的天線太爛了,我要更好的天線!!(急!在線等... A. 我知道你很急,但你先別急。

待我娓娓道來,Meshtastic 這個開源、離線、去中心化的網狀網路系統,特別設計來運行在價格合理且低功耗的設備上。它基於網狀網路的特性,可以利用LoRa節點進行協力轉發,從而擴展通信距離。當你發出的訊息在地圖上顯示,被一些素未謀面的朋友的節點轉發時,這正展示了 Meshtastic的核心價值。

因此,即使是性價比高的射頻設備,也能有效地進行通訊,不一定需要頂級的天線品質。 對於天線的要求可以不需要達到最高標準,依然能夠達成良好的通訊效果,這才是Mesh用眾人的力量來實現廣域的通聯。

想要更多功能的原始碼修改

使用 vscode + platfomrIO https://github.com/meshtastic/firmware/tree/master

我要漂亮的外殼

截圖 2024-05-03 晚上7.05.31

https://www.printables.com/model/741974-h1-case-for-heltec-v3-running-meshtastic/files

https://www.thingiverse.com/search?q=Heltec+V3&page=1

我要更大的發射功率(請注意當地法規)

如何提升接收的靈敏度

ATAK

https://www.facebook.com/groups/861791915202978

等待整理

截圖 2024-05-10 中午12.30.28

tags: Meshtastic lora

本文最初發布於 HackMD @BASHCAT。

無線電是如何工作的

無線電通訊與Meshtastic指南

無線電是如何工作的

無線電通訊是通過空氣(或其他非物理介質)傳播電磁波來進行資訊交換的技術。無線電波是電磁波的一種,可以在不同的頻率上傳輸聲音、數據或影像。

無線電的基本工作原理:

發射:

  • 調製:將想要傳輸的資訊(如聲音或數據)轉換成適合無線傳輸的形式。這通常涉及將信息信號與一個載波信號結合,過程稱為調製。
  • 放大:增強調製後的信號,使其足以傳輸到目的地。
  • 發射:通過天線將調製和放大後的信號以電磁波形式發射出去。

傳輸:

  • 電磁波沿直線從發射點向外擴散,可以穿過空氣、真空,甚至某些物質。

接收:

  • 捕捉信號:接收天線捕捉由發射天線發射的電磁波。
  • 解調:將接收到的調製信號轉換回原始資訊的過程稱為解調。
  • 處理和輸出:將解調後的信號進行必要的處理,以恢復成可以識別的聲音、圖像或數據形式。

無線電調製的類型

調製是無線通訊的關鍵,它決定了如何將資訊「編碼」到無線電波中

#### 類比調製 1. **振幅調變 (AM)** - 通過改變載波信號的振幅來編碼資訊 - 較易受噪聲干擾,但技術實現簡單 - 常用於廣播電台和航空通訊
  1. 頻率調變 (FM)
    • 通過改變載波信號的頻率來編碼資訊
    • 抗噪性能較好,音質更清晰
    • 廣泛用於FM廣播、無線電對講機等

數位調製

  1. 頻移鍵控 (FSK)

    • 使用不同頻率代表數位1和0
    • 用於低速數據傳輸
  2. 相移鍵控 (PSK)

    • 通過改變載波的相位來表示數據
    • 廣泛用於高速數據通訊
  3. 正交振幅調變 (QAM)

    • 結合振幅和相位調變
    • 用於高效寬頻通訊,如Wi-Fi、4G/5G等

頻率與頻段

無線電頻率範圍從3 Hz到300 GHz,不同頻段有不同用途:

頻段 頻率範圍 主要用途
特低頻 (ELF) 3 Hz - 30 Hz 海底通訊
超低頻 (ULF) 30 Hz - 300 Hz 礦山通訊
甚低頻 (VLF) 3 kHz - 30 kHz 導航、政府通訊
低頻 (LF) 30 kHz - 300 kHz 導航、氣象
中頻 (MF) 300 kHz - 3 MHz AM廣播
高頻 (HF) 3 MHz - 30 MHz 短波廣播、業餘無線電
甚高頻 (VHF) 30 MHz - 300 MHz FM廣播、電視、航空
超高頻 (UHF) 300 MHz - 3 GHz 電視、手機、Wi-Fi
極高頻 (SHF) 3 GHz - 30 GHz 衛星通訊、雷達
太赫頻 (THF) 30 GHz - 300 GHz 天文學、未來通訊技術

Meshtastic 的工作原理

Meshtastic是一個開源、離網、去中心化的網狀網路通訊系統,運行在低成本、低功耗的設備上。

### 核心技術與特點

使用LoRa技術:

  • Meshtastic主要使用**低功耗長距離(LoRa)**技術,這是一種專為小數據量、長距離和低功耗設計的無線通訊方式。
  • LoRa使用展頻調變技術,在在台灣863-928 MHz頻段運行(具體頻率因地區而異)。
  • 在理想條件下,LoRa通訊距離可達16公里。

網狀網路架構:

  • 在Meshtastic網絡中,每個裝置不僅是通訊的終端,還可以作為中繼站,幫助轉發其他裝置的信號。
  • 這樣,即使某些裝置之間沒有直接的通訊線路,信息也可以通過多個中繼點間接傳遞。
  • 依據設定,Meshtastic網狀網路可同時支援多達100個設備。

多點傳輸:

  • 通過LoRa發送的信號可以被網絡中的多個接收器接收。
  • Meshtastic 利用這一特性,結合網狀網路技術,有效擴大了通訊範圍和可靠性。

智能路由:

  • 系統會根據網絡條件和節點的連接狀況智能選擇最佳路由,確保消息能夠有效傳遞。
  • 自動適應網絡變化,形成自我修復網路。

Meshtastic的應用場景

  1. 戶外活動

    • 遠足、登山、露營等沒有手機訊號的地區通訊
    • 團隊成員之間的位置共享和訊息傳遞
  2. 緊急救災

    • 自然災害後通訊基礎設施損壞時的應急通訊
    • 搜救行動中的團隊協調
  3. 遠程地區

    • 缺乏通訊基礎設施的偏遠地區
    • 野外科學考察、探險
  4. 物聯網應用

    • 分佈式傳感器網絡
    • 低頻率數據收集和監控

硬體支援

Meshtastic支援多種硬體平台,包括:

  • T-Beam、T-Echo、T-TWR等TTGO設備
  • Heltec LoRa 32和SX1262系列
  • LILYGO TTGO設備
  • SenseCAP系列
  • 各種基於ESP32和LoRa模組的自製設備

每個Meshtastic設備一次只能與一部手機配對使用

### 使用優勢
  1. 不依賴網絡基礎設施:完全離線運作,不需要網際網路或手機網絡
  2. 開源且可擴展:100%社區驅動的開源項目,持續改進
  3. 低成本:使用價格實惠的硬體設備
  4. 低功耗:設備可以長時間運行,適合野外使用
  5. 加密通訊:提供端到端加密,保護通訊隱私
  6. 易於設置:通過手機應用或電腦軟體輕鬆配置

這種結合了LoRa無線技術和網狀網路的方法使Meshtastic在戶外活動、遠程地區或災難應對等場景下成為一個非常實用的通訊工具。


本文最初發布於 HackMD @BASHCAT。

8GB 的 RK3588 能跑多聰明的 LLM?ROCK 5C 用 NPU 實測 5 個模型

先講結論,省得你滑到最後: 在一片 8GB 的 RK3588 板子上,用 NPU 跑得最聰明的是 Qwen3-4B-Instruct-2507,我出的 7 題全對,但每秒只吐 3.7 個 token。 想要順一點的對話體驗,Qwen3.5-2B 的 8.4 tok/s 是比...