DesignSpark Electrical Logolinkedin
Menu 検索
フォーラムで質問

XinaBoxによるLoRa無線モニタリングのプロトタイピング パート2: データの送信

モジュール形式のエレクトロニクスプラットフォームであるXinaBoxを用いて長距離無線センサシステムを迅速にプロトタイプしよう

パート1ではユースケースとLoRa無線変調、利用できるXinaBoxハードウェアのオプション、XinaBoxを利用する理由について紹介した。

今回は、マイクロコントローラーと無線が統合されているCR02モジュール、もしくは「☒チップ」(おそらくXinaBoxのブランドアイコンが☒であることから)のプログラミングに進もう。これによりLoRa無線リンクによりデータの送受信が可能になる。

設定

まず初めに、xBUSコネクタ(174-4977)を利用してIP01(174-3703)プログラマをCR02(174-3699)へと接続しする。LoRaのサンプルを動作させる前に、Whip tunes SMA868MHz帯アンテナ(054-2563)のような適切なアンテナを用意する必要がある。

もちろん、送信と受信の両方のテストには上記の2つのパーツのセットが必要だ。

また、Arduino IDEのインストール、もしくはそのほかのArduino互換ボードのプログラミングが可能である環境が必要だ。例えばほぼ同じ環境で動作することができるPlatformIO IDEだ。

今回RadioHeadと呼ばれるライブラリを利用して一般的な無線でパケット化されたメッセージの受信と送信を可能にする。一般的な無線としては我々が利用しているCR02チップに統合されているRFM95Wも対応している。そのため今回は、XinaBox GithubによりforkされたRadioHeadを利用する必要があるだろう。

Arduino IDEに新しいライブラリをインストールする方法にはいくつか方法がある。しかし、最も簡単であるのはArduino IDEにて「スケッチ→ライブラリをインクルード→追加」から、ダウンロードしたZIPアーカイブを直接追加する方法だろう。

ツール→ボードメニューから「Arduino ProまたはPro Mini」を選択する必要があり、またツール→ポートから、適切なポートを確認する必要がある。例えばLinuxの場合、IP01の場合/dev/ttyUSB0に見えるはずだ(もしくはこれより大きい数字であり、お使いの環境におけるFTDIベースの機器の台数による)。

Hello, World

セットアップを終えれば、次は「ハードウェアのHello World」であるLEDチカチカだ(LED Blink)。

CR02は3色LEDを持っている。提供されているLEDチカチカの例はArduino IDEで提供されているサンプルのものより少しだけ大きくなっている。本質的にはサンプルと変わらず、ただ3色の色が繰り返されるだけである。IP01にLEDのスケッチがアップロードされた際に、一瞬フラッシュする必要があることに注意してほしい。もししなかった場合、ポート権限のエラーやハードウェアのエラーが表示される場合がある。

それではLoRa無線を利用してデータの送受信について見ていこう。

LoRaサーバー

それではスケッチ例の「サーバ」を実行してみよう。これには、無線モジュール要のRadioHeadライブラリが含まれている。これを利用して、まず初めに動作周波数など、いくつかの定数を定義する。この場合、868MHz帯を利用することにする。日本では920MHzにすること。

#include <RH_RF95.h>

#define LED_BUILTIN 16

#define CR02_FREQUENCY 868.0

uint8_t tempdata[30];

次にsetup()関数を利用して、デバッグ用のLEDピンとシリアルポートを設定する。その後、無線モジュールの初期化、周波数と送信出力の設定が必要となる。

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  Serial.begin(115200);

  if (!CR02.init()) {
    Serial.println("init failed");
  }
  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then
  // you can set transmitter powers from 5 to 23 dBm:
  // Failure to do that will result in extremely low transmit powers.

  //CR02.setModemConfig(CR02.Bw31_25Cr48Sf512);
  CR02.setFrequency(CR02_FREQUENCY);
  CR02.setTxPower(23, false);
}

次に通信帯域幅とLoRa拡散率であるSFの値を設定する。このとき、デフォルトのSFの値は7であり、プログラム中のコメントに任意の値を設定できることが示されている。このSF(Spreading Factor)はLoRaにおける拡散率を示したパラメータであり、この値を大きくするとリンクバジェットが増え、通信距離が大きくなる。しかし、そのかわりに帯域幅が小さくなり、送信時間が長くなるなどのトレードオフが必要となる。

またデフォルトの拡散率は開発を目的としている場合には問題ないが、特定の開発の環境似合わせて最適化することもでき、求められる通信距離とエネルギー消費率、そしてスペクトラムの使用方法に応じて自由に設定できる。一般的に、送信時間の減少はエネルギー消費の面や電波法などの面からいいことだ。しかしながら、メッセージを確実に送信したい場合にはアラームや警告システムが備えられているなどの理由により、帯域幅やバッテリ寿命の懸念が少ない場合は、常に最も高いSF(=12)の値を設定することが理想だろう。

CR02 LoRa無線を設定するためのsetModemConfig()関数の呼び出しの詳細な利用方法についてはRadioHeadのドキュメントを確認してほしい。

メインのループを見てみよう。以下に、受信したメッセージを確認し、LEDをオンにするプログラムを示している。LEDをオンにしたのち、受信信号強度(RSSI)と受信したメッセージをシリアルポートに書き込んだ後、LEDを消灯し、最後にメッセージを返信する。非常にシンプルであることがわかる!

void loop()
{
  if (CR02.available())
  {
    // Should be a message for us now
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    if (CR02.recv(buf, &len))
    {
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.print("got request: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(CR02.lastRssi(), DEC);

      // Send a reply
      sprintf(tempdata, "%s", "Hello Client");
      CR02.send(tempdata, sizeof(tempdata));
      CR02.waitPacketSent();
      Serial.println("Sent a reply");
      digitalWrite(LED_BUILTIN, LOW);
    }
    else
    {
      Serial.println("recv failed");
    }
  }
}

LoRaクライアント

CR02のスケッチ例「クライアント」は、上記のものと非常に似ているプログラムだ。これはメッセージを送信する代わりに、受信を待ち、受信後返信を行う。以下にプログラムのメインループを示す。

void loop()
{
  Serial.println("Sending to CR02_server");
  // Send a message to CR02_server

  sprintf(tempdata, "%s", "Hello Server");

  CR02.send(tempdata, sizeof(tempdata));

  CR02.waitPacketSent();
  // Now wait for a reply
  uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
  uint8_t len = sizeof(buf);

  if (CR02.waitAvailableTimeout(3000))
  {
    // Should be a reply message for us now
    if (CR02.recv(buf, &len))
    {
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.print("got reply: ");
      Serial.println((char*)buf);
      Serial.print("RSSI: ");
      Serial.println(CR02.lastRssi(), DEC);
    }
    else
    {
      Serial.println("recv failed");
    }
  }
  else
  {
    Serial.println("No reply, is CR02_server running?");
  }
  digitalWrite(LED_BUILTIN, LOW);
  delay(400);
}

繰り返しになるが、その内容が非常にシンプルであることがわかる。これにより、メッセージに対する応答とサーバから受信した信号の強度であるRSSIの値を表示する。

さらに高度なオプション

今回は非常にシンプルな例を示した。今回はメッセージの暗号化や認証、アドレス付けなどは行っていないプログラムであった。多くのLoRaを利用したシステムでは、これで問題は無いだろう。しかしながら、もしもっと高度な機能が必要になった場合、RadioHeadの暗号化のスケッチ例があり、簡単なノードのアドレス付けのサポートなどを完全に提供している信頼性の高いデータグラムサービスも提供している。しかし、これらについてはCR02ではテストされていないため、必要に応じてそれぞれ利用と実装を検討してほしい。

次回の内容

このシリーズの次の投稿では、周辺機器やワイヤレス監視システムを取り上げる予定だ。

— Andrew Back氏

Open source (hardware and software!) advocate, Treasurer and Director of the Free and Open Source Silicon Foundation, organiser of Wuthering Bytes technology festival and founder of the Open Source Hardware User Group.

2 Feb 2019, 10:05