pdf-icon

Arduino Guide

Atom DTU LoRaWANシリーズ Arduinoチュートリアル

チュートリアル説明
このチュートリアルは Atom DTU LoRaWAN‑CN470/EU868/US915 シリーズ製品(SKU:A152‑CN470/A152‑EU868/A152‑US915)に適用されます。以下では AtomS3R と Atom DTU LoRaWAN‑EU868 を組み合わせ、LoRa P2P 通信および LoRaWAN ネットワークへの接続方法を例示します。

1. 準備

2. LoRa P2P

LoRa P2P 通信モードは、複数の LoRa デバイスを直接通信させることができます。このモードでは LoRa 変調技術をベースにデータパケットを送信し、フレーム内容を完全にカスタマイズして独自のプライベートネットワークを構築できます。リアルタイム性が求められ、通信範囲が比較的狭く、複雑なネットワーク管理が不要なシーンに適しています。

LoRa TX/RX サンプル

デバイスの実際の使用に合わせて通信パラメータを設定してください。設定が一致するデバイス同士でなければ通信できません。異なる Atom プロセッサを使用する場合は、以下のマクロを参照して適切な TX/RX ピンを指定してください。

#include <M5Unified.h>
#include "rak3172_p2p.hpp"

#define LORA_CONFIG_PRLEN 8
#define LORA_CONFIG_PWR   22
#define LORA_FREQ         868E6
#define LORA_CR           0    // (4/5=0, 4/6=1, 4/7=2,4/8=3)
#define LORA_SF           7    // (6,7, 8, 9, 10, 11, 12)
#define LORA_BW           500  // (125, 250, 500)

#define ATOM_LORA_RX 19
#define ATOM_LORA_TX 22

#define ATOMS3_LORA_RX 6
#define ATOMS3_LORA_TX 5

RAK3172P2P lora;

void LoRaLoopTask(void* arg)
{
    while (1) {
        lora.update();
        vTaskDelay(5);
    }
}

void setup()
{
    M5.begin();
    Serial.begin(115200);
    Serial.println("LoRa Init...");
    while (!lora.init(&Serial2, ATOMS3_LORA_RX, ATOMS3_LORA_TX, RAK3172_BPS_115200)) {
        delay(1000);
    }

    lora.setMode(P2P_RX_MODE, 0);
    if (lora.config(LORA_FREQ, LORA_SF, LORA_BW, LORA_CR, LORA_CONFIG_PRLEN, LORA_CONFIG_PWR)) {
        Serial.println("LoRa config success");
    } else {
        Serial.println("LoRa config failed");
    }
    lora.setMode(P2P_TX_RX_MODE);
    xTaskCreate(LoRaLoopTask, "LoRaLoopTask", 1024 * 10, NULL, 2, NULL);
}

void loop()
{
    M5.update();
    if (M5.BtnA.wasPressed()) {
        if (lora.print("Hello!")) {
            Serial.println("Send success");
        }
    }

    if (lora.available()) {
        std::vector<p2p_frame_t> frames = lora.read();
        for (int i = 0; i < frames.size(); i++) {
            Serial.print("RSSI: ");
            Serial.print(frames[i].rssi);
            Serial.print(" SNR: ");
            Serial.print(frames[i].snr);
            Serial.print(" LEN: ");
            Serial.print(frames[i].len);
            Serial.print(" Payload: ");
            for (uint8_t j = 0; j < frames[i].len; j++) {
                Serial.printf("%02X", frames[i].payload[j]);
            }
            Serial.println();
        }
        lora.flush();
    }
}

このサンプルをデバイスへ書き込んだ後、シリアルモニタでログを確認します。AtomS3R の中央ボタンを押すとデータが送信されます。

3. LoRaWAN

LoRaWAN 通信モードでは、デバイスは LoRaWAN ゲートウェイを介してデータを送受信します。周波数ホッピング技術により、多数のデバイスノードを同時に管理でき、データのセキュリティも確保されます。使用前に、公共の LoRaWAN ゲートウェイが利用可能であることを確認してください。公共ゲートウェイがない場合は、自身でゲートウェイを構築することも可能です。

通信キー

    1. TTN - デバイス作成ガイド を参照し、使用する周波数帯に合わせてノードを作成し、DevEUI、AppEUI、AppKey などのキー情報を取得します。OTAA/ABP の入網モードによって使用するキーが異なります。これらのキーは LoRaWAN ネットワーク接続に必須です。
    1. デバイスの周波数帯とゲートウェイの受信周波数帯に合わせて、サブネットマスク(チャネルマスク)およびデバイスクラス(Class A〜C)を設定します。LoRaWAN の概要やデバイス設定については、 TTN - LoRaWAN ドキュメント を参照してください。
      ?>サブネットマスクパラメータ|サブネットマスク(チャネルマスク)はノードの周波数ホッピング範囲を決定します。ゲートウェイの受信周波数範囲と一致しないと、ネットワークへの参加や通信ができません。AT+MASK コマンドは現時点で US915/AU915/CN470 のみ対応しています。
    1. TTN や Chirpstack などの LoRaWAN サーバから取得したキー情報をサンプルコードに入力し、入網モードと周波数帯を設定後、デバイスへ書き込みます。

OTAA 入網

OTAA 入網では DevEUI、AppEUI、AppKey パラメータを使用します。

#include <M5Unified.h>
#include "rak3172_lorawan.hpp"

#define DEVEUI "****************"
#define APPEUI "****************"
#define APPKEY "********************************"

// get or set the channel mask to close or open the channel (only for US915, AU915, CN470)
#define CHANNEL_MASK "0000"

#define ATOM_LORA_RX 19
#define ATOM_LORA_TX 22

#define ATOMS3_LORA_RX 6
#define ATOMS3_LORA_TX 5

RAK3172LoRaWAN lorawan;
bool isJoin = false;

void joinCallback(bool status)
{
    isJoin = status;
    if (status) {
        Serial.println("[LoRaWAN] Join network successful!");
        Serial.println("Device EUI: " + String(DEVEUI));
    } else {
        Serial.println("[LoRaWAN] Join network failed!");
    }
}

void sendCallback()
{
    Serial.println("[LoRaWAN] Uplink confirmed by server");
}

void errorCallback(char* error)
{
    Serial.print("[LoRaWAN] Error: ");
    Serial.println(error);
}

void LoRaWANLoopTask(void* arg)
{
    while (1) {
        lorawan.update();
        vTaskDelay(5);
    }
}

void setup()
{
    M5.begin();
    Serial.begin(115200);
    Serial.println("[Init] Initializing LoRaWAN module...");
    while (!lorawan.init(&Serial2, ATOMS3_LORA_RX, ATOMS3_LORA_TX, RAK3172_BPS_115200)) {
        Serial.println("[Init] Failed to initialize module, retrying...");
        delay(1000);
    }
    Serial.println("Device Init OK");
    Serial.println("[Config] Setting band to EU868...");
    while (!lorawan.setBAND(EU868, CHANNEL_MASK)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting OTAA parameters...");
    while (!lorawan.setOTAA(DEVEUI, APPEUI, APPKEY)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting device mode to CLASS_C...");
    while (!lorawan.setMode(CLASS_C)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting data rate to DR4...");
    while (!lorawan.setDR(4)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting Link check...");
    while (!lorawan.setLinkCheck(ALLWAYS_LINKCHECK)) {
        delay(1000);
    }

    lorawan.onSend(sendCallback);
    lorawan.onJoin(joinCallback);
    lorawan.onError(errorCallback);
    xTaskCreate(LoRaWANLoopTask, "LoRaWANLoopTask", 1024 * 10, NULL, 5, NULL);

    Serial.println("[Info] Attempting to join the network...");
    if (lorawan.join(true, false, 10, 10)) {
        Serial.println("Start Join...");
    } else {
        Serial.println("Join Fail");
    }
}

void loop()
{
    M5.update();
    if (M5.BtnA.wasReleased()) {
        if (isJoin) {
            String data = "UPlink LoRaWAN Frame: " + String(millis());
            if (lorawan.send(data)) {
                Serial.println("Send Successful");
            } else {
                Serial.println("Send fail");
            }
        } else {
            Serial.println("LoRaWAN not joined");
        }
    }
    if (lorawan.available()) {
        std::vector<lorawan_frame_t> frames = lorawan.read();
        for (int i = 0; i < frames.size(); i++) {
            Serial.print("RSSI: ");
            Serial.println(frames[i].rssi);
            Serial.print("SNR: ");
            Serial.println(frames[i].snr);
            Serial.print("LEN: ");
            Serial.println(frames[i].len);
            Serial.print("PORT: ");
            Serial.println(frames[i].port);
            Serial.print("UNITCAST: ");
            Serial.println(frames[i].unicast);
            Serial.print("Payload: ");
            for (uint8_t j = 0; j < frames[i].len; j++) {
                Serial.printf("%02X", frames[i].payload[j]);
            }
            Serial.println();
        }
        lorawan.flush();
    }
    if (Serial.available()) {
        String ch = Serial.readString();
        lorawan.sendCommand(ch);
    }
}

このサンプルを書き込んだ後、シリアルモニタでログを確認します。Join 成功後、AtomS3R の中央ボタンを押してデータを送信します。

TTN の該当デバイスページで現在のアップリンク/ダウンリンクデータログを確認できます。

Messaging ページに切り替えると、ダウンリンクデータの送信が可能です。

ABP 入網

ABP 入網では DevAddr、AppSkey、NwkSkey パラメータを使用します。Join プロセスは不要で、キー情報を初期化すればすぐにデータ送信を開始できます。

#include <M5Unified.h>
#include "rak3172_lorawan.hpp"

#define DEVADDR "***********"             // Device Address
#define APPSKEY "**********************"  // Application Session Key
#define NWKSKEY "**********************"  // Network Session Key

// get or set the channel mask to close or open the channel (only for US915, AU915, CN470)
#define CHANNEL_MASK "0000"

#define ATOM_LORA_RX 19
#define ATOM_LORA_TX 22

#define ATOMS3_LORA_RX 6
#define ATOMS3_LORA_TX 5

RAK3172LoRaWAN lorawan;

void errorCallback(char* error)
{
    Serial.print("[LoRaWAN] Error: ");
    Serial.println(error);
}

void LoRaWANLoopTask(void* arg)
{
    while (1) {
        lorawan.update();
        vTaskDelay(5);
    }
}

void setup()
{
    M5.begin();
    Serial.begin(115200);
    Serial.println("[Init] Initializing LoRaWAN module...");
    while (!lorawan.init(&Serial2, ATOMS3_LORA_RX, ATOMS3_LORA_TX, RAK3172_BPS_115200)) {
        Serial.println("[Init] Failed to initialize module, retrying...");
        delay(1000);
    }
    Serial.println("Device Init OK");
    Serial.println("[Config] Setting band to EU868...");
    while (!lorawan.setBAND(EU868, CHANNEL_MASK)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting ABP parameters...");
    while (!lorawan.setABP(DEVADDR, NWKSKEY, APPSKEY)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting device mode to CLASS_C...");
    while (!lorawan.setMode(CLASS_C)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting data rate to DR4...");
    while (!lorawan.setDR(4)) {
        Serial.println(" failed, retrying...");
        delay(1000);
    }
    Serial.println("[Config] Setting Link check...");
    while (!lorawan.setLinkCheck(ALLWAYS_LINKCHECK)) {
        delay(1000);
    }

    lorawan.onError(errorCallback);
    xTaskCreate(LoRaWANLoopTask, "LoRaWANLoopTask", 1024 * 10, NULL, 5, NULL);
}

void loop()
{
    M5.update();
    if (M5.BtnA.wasReleased()) {
        String data = "UPlink LoRaWAN Frame: " + String(millis());
        if (lorawan.send(data)) {
            Serial.println("Send Successful");
        } else {
            Serial.println("Send fail");
        }
    }

    if (lorawan.available()) {
        std::vector<lorawan_frame_t> frames = lorawan.read();
        for (int i = 0; i < frames.size(); i++) {
            Serial.print("RSSI: ");
            Serial.println(frames[i].rssi);
            Serial.print("SNR: ");
            Serial.println(frames[i].snr);
            Serial.print("LEN: ");
            Serial.println(frames[i].len);
            Serial.print("PORT: ");
            Serial.println(frames[i].port);
            Serial.print("UNITCAST: ");
            Serial.println(frames[i].unicast);
            Serial.print("Payload: ");
            for (uint8_t j = 0; j < frames[i].len; j++) {
                Serial.printf("%02X", frames[i].payload[j]);
            }
            Serial.println();
        }
        lorawan.flush();
    }
    if (Serial.available()) {
        String ch = Serial.readString();
        lorawan.sendCommand(ch);
    }
}

CayenneLPP

CayenneLPP は最適化されたセンサーデータフォーマットです。TTN や Chirpstack にデータをアップロードする際、コンソールや API で取得できるデフォルトのデータは通常 Base64 でエンコードされており、可読性に欠けます。CayenneLPP はさまざまな基本センサータイプをサポートし、LoRaWAN ネットワークを利用した環境データ収集時に解析しやすいフォーマットを提供します。そのため、関連データの処理には CayenneLPP の使用を推奨します。コンソールのノード設定ページで CayenneLPP デコーダを選択するだけで、センサーデータを直感的に確認できます。詳細やサンプルについては以下をご参照ください。

On This Page