pdf-icon

Arduino入門

2. デバイス&サンプル

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 ピンを指定してください。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
#include <M5Unified.h>
#include "rak3172_p2p.hpp"
#define LORA_CONFIG_PRLEN 8
#define LORA_CONFIG_PWR 22
#define LORA_FREQ 868E6 // 868E6 equals to 868*10^6, which is the frequency 868M(Hz). It can be modified to 915 or 470 accordingly.
#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...");
// The second and third parameters in the next line should start with `ATOM` or `ATOMS3` according to the device actually used.
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 の中央ボタンを押すとデータが送信されます。

シリアルモニターで表示された "48656C6C6F21" は、"Hello!" のASCIIコードです。

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 パラメータを使用します。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
#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 プロセスは不要で、キー情報を初期化すればすぐにデータ送信を開始できます。

cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
#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