36
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ArduinoとRaspberry PiをXBee ZBでZigBee通信させる

Last updated at Posted at 2017-02-10

センサ類を接続したArduinoとRaspberry Piを、XBee ZBを使用してZigBeeで通信させるための作業メモです。Arduino側をIoTデバイス、Raspberry Pi側をインターネットに繋がるIoTゲートウェイとして動かすことを見据えています。

用意するもの

今回は、Arduinoに取り付けるセンサとして、温湿度センサのDHT11を例として扱います。DHT11を基板に取り付けモジュール化したDFR0067を使用して、直接Arduinoに接続します。

まずは以下の部品を準備します。これらは、特に配線等を行わず簡単にDHT11とXBeeをArduinoに繋ぐための部品構成ですので、ご自分で回路を組まれたり、他のセンサを接続したい場合には、適宜読み替えて下さい。また、ArduinoやRaspberry Piは下記バージョンで動作確認をしていますが、他のバージョンでも同じような手順で事は成せると思います。

Raspberry Piのセットアップ用に、必要に応じて以下の周辺機器も用意します。

  • ディスプレイ
  • USBマウス
  • USBキーボード
  • HDMIケーブル

Arduino側のセットアップ

以下の手順でDHT11をArduinoに取り付けます。

  1. Arduino ワイヤレスSDシールドをArduino Unoに取り付けます。
  2. DFR0067の黒色のピンをブレッドボード・ジャンパーコードを介してシールドのGNDピンに接続します。
  3. DFR0067の赤色のピンをブレッドボード・ジャンパーコードを介してシールドの5Vピンに接続します。
  4. DFR0067の緑色のピンをブレッドボード・ジャンパーコードを介してシールドの2番ピンに接続します。

IMG_7912.JPG

Raspberry Pi側のセットアップ

以下の手順でRaspberry Piをセットアップします。マウス、キーボード、ディスプレイなどの周辺機器を必要に応じて準備します。具体的なステップについては、Web上の先人たちの知恵を参考にしましょう。

  1. OSイメージ(Raspbian Jessie)のダウンロード
  2. SDカードのフォーマット、イメージの書き込み
  3. OSの起動
  4. ネットワークの設定

作業端末と同じローカルネットワークに接続して、プライベートIPアドレスでSSHログイン出来るように設定しておくと以降の作業がスムーズです。

XBee ZBのセットアップ

  1. X-CTUのインストール
    作業端末に、X-CTUをインストールします。以下のURLから、お使いマシンに合わせたインストーラをダウンロードして、インストールを行います。
    X-CTU Software
     

  2. デバイスの接続
    XBee USBインターフェースボードを組み立て、XBee通信デバイスとマイクロUSBケーブルを接続します。
    IMG_7917.JPG 

  3. XBee通信デバイスの設定
    XBee USBインターフェースボードから出ているマイクロUSBケーブルを作業端末に接続します。X-CTUで接続したXBee ZBデバイスを検索し、見つかったデバイスに対して以下の設定を行います。2台のXBee ZBデバイスに対して、それぞれ設定を行います。XBee ZBデバイスの世代によって設定方法が異なりますので、X-CTUのオンラインマニュアル等を参照して下さい。設定項目が非常に多くありますが、以下の設定以外はデフォルトのままでも通信は可能です。

  • ファームウェアのインストール(アップデート)
    2台のデバイスで共通です。最新のファームウェアを入れましょう。
  • PAN ID(とScan Channel)の設定
    2台に同一の値を設定します。これが異なっていると通信出来ません。
  • Coordinator/Routerの設定
    1台はCoordinator、もう1台はRouterに設定します。
  • APIモードの設定
    2台ともAPIモードに設定します。
     
  1. 接続確認
    XBee USBインターフェースボードが2つある場合は、双方を作業端末に接続して給電すると、X-CTUから接続確認を行えます。ここでZigBeeの通信が問題なく出来ることを確認しておくと良いです。

Arduino側からZigBeeを送信

  1. Arduino IDEのインストール
    作業端末に、Arduino IDEをインストールします。以下のURLから、お使いのマシンに合わせたインストーラをダウンロードして、インストールを行います。
    Arduino Software
     
  2. Arduinoの接続
    ワイヤレスSDシールドを取り付けたArduino Unoを、USBケーブルで作業端末に接続します。
     
  3. ライブラリのインポート
    今回は、温湿度センサDHT11からデータを取得するadafruitのライブラリ(DHT sensor library)と、XBee通信のためのライブラリを使用します。Arduino IDEのスケッチに、これらのライブラリをインポートします。
  • DHT11ライブラリ
    リポジトリをCloneして、Arduino IDEにワーキングディレクトリを指定してインポートします。
git clone https://github.com/adafruit/DHT-sensor-library.git
  • XBeeライブラリ
    リポジトリをCloneして、Arduino IDEにワーキングディレクトリを指定してインポートします。もしくは、Arduino IDEの「ライブラリを管理」から「XBee」と検索してインポートします。
git clone https://github.com/andrewrapp/xbee-arduino.git

 
4. スケッチの編集
Arduino IDEでスケッチを編集します。スケッチでは、ループ処理の中でDHT11から温湿度のデータを読み込み、XBeeでCoordinatorに送信します。以下に動作確認をしたプログラム例を書いておきます。

```c:DHT11XBeeZBSender.ino
#include <DHT.h>
#include <DHT_U.h>

#include <XBee.h>
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT11

// Initialize XBee ZB client
XBee xbee = XBee();
// Payload byte array
uint8_t payload[8];
// Send to coordinator
XBeeAddress64 addr64 = XBeeAddress64(0, 0);
// Create request for XBee ZB
ZBTxRequest zbTx = ZBTxRequest(addr64, payload, sizeof(payload));

// Initialize DHT sensor module
DHT dht(DHTPIN, DHTTYPE);

void set_float_to_payload(float value, int index) {
  uint8_t *value_array;
  value_array = reinterpret_cast<uint8_t*>(&value);
  for(int i=0; i<sizeof(value); i++){
    payload[i+index] = value_array[i];
  }
}

void setup() {
  Serial.begin(9600); 
  xbee.setSerial(Serial);
  dht.begin();
}

void loop() {
  delay(3000);

  float temperature = dht.readTemperature();
  float humidity = dht.readHumidity();

  set_float_to_payload(temperature, 0);
  set_float_to_payload(humidity, 4);

  xbee.send(zbTx);
}

5. スケッチの書き込み
上記のスケッチを接続しているArduino UNOに書き込みます。このとき、XBeeデバイスをシールドに接続していると書き込みが失敗するので、取り外した状態で書き込みを行って下さい。
 
6. 通信の確認
ここまで来れば、既にArduino側では温湿度のデータがCoordinator側のXBeeデバイスに送信されているはずです。作業端末上で、ZigBee受信モジュールを作成し、データを受信してみます。XBee USBインターフェースボードにCoordinatorに設定したXBeeデバイスを、ArduinoのシールドにRouterに設定したXBeeデバイスを接続し、両者を作業端末に接続します。  
![IMG_7921.JPG](https://qiita-image-store.s3.amazonaws.com/0/61098/a560ef8c-0a31-1916-431c-be74b44ca412.jpeg)    
X-CTUでCoordinator側のXBeeのシリアルモニターを開くと、3秒おきにデータが送られてきていることを確認出来ます。


# Raspberry Pi側でZigBeeを受信
Coordinatorに設定したXBeeデバイスをRaspberry Piに接続します。

![IMG_7922.JPG](https://qiita-image-store.s3.amazonaws.com/0/61098/ec02d14c-9a2d-c95b-529e-2209c76751ca.jpeg)

Raspberry PiのOSを起動し、受信モジュールをRaspberry Pi上に配置すれば、ArduinoからRaspberry PiにZigBee通信することが出来ます。

![IMG_7929.JPG](https://qiita-image-store.s3.amazonaws.com/0/61098/f1abbcab-6f4f-90cf-3658-625f63f626ab.jpeg)

今回は、PythonとJavaでそれぞれ受信モジュールを組む方法をご紹介します。

## Pythonで受信する
以下では、Raspberry Pi上にvirtualenvでPython環境を作っています。virtualenvを使わず、Raspbian Jessie上に事前構成されているPython3の環境を使用しても構いません。その場合は、`python3`コマンドでプログラムの実行を行います。

まず、ベースのアップデートをしてから、Pythonのビルドに必要なものをインストールし、Pyenvとvirtualenvをインストールします。その後、必要なライブラリをインストールします。XBeeをPythonで受信するために、[python-xbee](https://github.com/nioinnovation/python-xbee)を使います。

```bash
# ベースのアップデート
$ sudo apt-get update  
$ sudo apt-get upgrade -y  
$ sudo apt-get dist-upgrade  

# Pythonのビルドに必要なものをインストール
$ sudo apt-get install -y build-essential libssl-dev openssl libbz2-dev libreadline-dev libsqlite3-dev

# Pyenvとvirtualenvのインストール
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
$ git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
$ echo 'export PYENV_ROOT=$HOME/.pyenv' >> ~/.profile
$ echo 'export PATH=$PYENV_ROOT/bin:$PATH' >> ~/.profile
$ echo 'eval "$(pyenv init -)"' >> ~/.profile
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.profile
$ source ~/.profile

# Python3.5以上の環境を準備
$ pyenv install 3.6.0

# 今回のZigBee通信に使うPython作業環境の準備
$ cd <working directory>
$ pyenv virtualenv 3.6.0 3.6.0_xbee
$ pydev local 3.6.0_xbee
$ python -V
Python 3.6.0

# 必要なライブラリのインストール
$ pip install xbee
$ pip install pyserial

次に、Pythonで受信プログラムを書きます。受信プログラムでは、python-xbeeライブラリを使って対象のUSBポートからシリアル通信でデータを受信して、受信した結果からバイト配列のPayloadを取り出して解析し、得られたデータを出力します。以下に動作確認をしたプログラム例を書いておきます。注意点として、中で使われているhex()関数はPython3.5以上でないと動きません。Raspbian Jessie上に事前構成されているPython3の環境を使う場合など、3.5未満のバージョンで動かしたい場合には、hex()に該当する関数を自分で定義して置き換えるか、該当する標準出力部分をコメントアウトして適宜書き換えて下さい。

$ vi XBeeZBReceiver.py
XBeeZBReceiver.py
#!/usr/bin/python

"""
Application to receive data from XBee ZB using XBee Python Library.
"""

from xbee import ZigBee
import serial
import struct

# TODO Replace with the serial port where your receiver module is connected.
PORT = '/dev/ttyUSB0'
# TODO Replace with the baud rate of you receiver module.
BAUD_RATE = 9600

# Open serial port
myDevice = serial.Serial(PORT, BAUD_RATE)

# Create API object
xbee = ZigBee(myDevice)

def prettyHexString(str):
    "split string by 2 length"
    return ' '.join([str[i:i+2] for i in range(0, len(str), 2)])

# Continuously read and print packets
print(">> Waiting for data...")
while True:
    try:
        response = xbee.wait_read_frame()
        source_addr = response['source_addr_long'].hex().upper()
        payload = prettyHexString(response['rf_data'].hex().upper())
        data = struct.unpack('ff', response['rf_data'])
        print('From %s >> [%s] | { temperature: %.1f degrees, humidity: %.1f%% }' % (source_addr, payload, data[0], data[1]))

    except KeyboardInterrupt:
        break

myDevice.close()

上記のPythonコードを実行すると、3秒置きに受信したデータが表示されます。

$ python XBeeZBReceiver.py
>> Waiting for data...
From 0013A20040E7446F >> [00 00 D0 41 00 00 14 42] | { temperature: 26.0 degrees, humidity: 37.0% }
From 0013A20040E7446F >> [00 00 D0 41 00 00 14 42] | { temperature: 26.0 degrees, humidity: 37.0% }
From 0013A20040E7446F >> [00 00 D0 41 00 00 14 42] | { temperature: 26.0 degrees, humidity: 37.0% }
...

Javaで受信する

Raspbian Jessieには、事前構成としてJava SE 8の環境がインストールされていますので、それを使います。

$ echo 'export JAVA_HOME=/usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt' >> ~/.profile
$ echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.profile
$ source ~/.profile
$ java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) Client VM (build 25.65-b01, mixed mode)

XBeeをJavaで受信するために、XBeeJavaLibraryを使います。

$ cd <working directory>
$ wget https://github.com/digidotcom/XBeeJavaLibrary/releases/download/v1.2.0/XBJL-1.2.0.zip
$ unzip XBJL-1.2.0.zip

次に、Javaで受信プログラムを書きます。受信プログラムではPythonと同じく、XBeeJavaLibraryを使って対象のUSBポートからシリアル通信でデータを受信して、受信した結果からバイト配列のPayloadを取り出して解析し、得られたデータを出力します。以下に動作確認をしたプログラム例を書いておきます。

$ vi XBeeZBReceiver.java
XBeeZBReceiver.java
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import com.digi.xbee.api.XBeeDevice;
import com.digi.xbee.api.exceptions.XBeeException;
import com.digi.xbee.api.listeners.IDataReceiveListener;
import com.digi.xbee.api.models.XBeeMessage;
import com.digi.xbee.api.utils.HexUtils;

/**
 * Application to receive data from XBee ZB using XBee Java Library
 */
public class XBeeZBReceiver {

	// TODO Replace with the serial port where your receiver module is connected.
	private static final String PORT = "/dev/ttyUSB0";
	// TODO Replace with the baud rate of you receiver module.
	private static final int BAUD_RATE = 9600;

	/**
	 * Class to manage the XBee received data that was sent by other modules in the same network.
	 * 
	 * @see IDataReceiveListener
	 */
	static class XBeeZBReceiveListener implements IDataReceiveListener {
		@Override
		public void dataReceived(XBeeMessage xbeeMessage) {
			byte[] bytes = xbeeMessage.getData();
			ByteBuffer buffer = ByteBuffer.wrap(bytes);
			buffer.order(ByteOrder.LITTLE_ENDIAN);
			System.out.format("From %s >> [%s] | { temperature: %.1f degrees, humidity: %.1f%% }%n",
					xbeeMessage.getDevice().get64BitAddress(),
					HexUtils.prettyHexString(HexUtils.byteArrayToHexString(xbeeMessage.getData())), buffer.getFloat(),
					buffer.getFloat());
		}
	}

	/**
	 * Application main method.
	 * 
	 * @param args Command line arguments.
	 */
	public static void main(String[] args) {
		XBeeDevice myDevice = new XBeeDevice(PORT, BAUD_RATE);

		try {
			myDevice.open();
			myDevice.addDataListener(new XBeeZBReceiveListener());
			System.out.println(">> Waiting for data...");

		} catch (XBeeException e) {
			e.printStackTrace();
			System.exit(1);
		}
	}
}

コンパイルします。XBeeJavaLibraryのxbee-java-library-x.x.x.jarをクラスパスに加えます。また、android.content.Contextが見えないとコンパイルエラーになるので、extra-libsディレクトリ以下のandroid-sdk-x.x.x.jarもクラスパスに加えます。

$ javac -cp XBJL-1.2.0/xbee-java-library-1.2.0.jar:XBJL-1.2.0/extra-libs/android-sdk-5.1.1.jar XBeeZBReceiver.java

最後に、XBeeJavaLibraryにはARMのCPUで動くRXTXのNative Libraryが入っていないため、自分でダウンロードしてコンパイルします。

$ wget http://rxtx.qbang.org/pub/rxtx/rxtx-2.2pre2.zip
$ unzip rxtx-2.2pre2.zip
$ cd rxtx-2.2pre2
$ ./configure
$ make
$ cd ..

コンパイルしたJavaコードを実行すると、3秒置きに受信したデータが表示されます。実行時には、Native Libraryをjava.library.pathに指定するなどしてリンクする必要があります。

$ java -cp .:XBJL-1.2.0/xbee-java-library-1.2.0.jar:rxtx-2.2pre2/RXTXcomm.jar:XBJL-1.2.0/extra-libs/slf4j-api-1.7.12.jar:XBJL-1.2.0/extra-libs/slf4j-simple-1.7.12.jar -Djava.library.path=rxtx-2.2pre2/armv7l-unknown-linux-gnu/.libs XBeeZBReceiver
>> Waiting for data...
From 0013A20040E7446F >> [00 00 D0 41 00 00 14 42] | { temperature: 26.0 degrees, humidity: 37.0% }
From 0013A20040E7446F >> [00 00 D0 41 00 00 14 42] | { temperature: 26.0 degrees, humidity: 37.0% }
From 0013A20040E7446F >> [00 00 D0 41 00 00 14 42] | { temperature: 26.0 degrees, humidity: 37.0% }
...

これでめでたくArduinoからの通信をRaspberry Pi上で受信することができました!
IMG_7941.JPG

最後に

以上で、センサ類(温湿度センサDHT11)を接続したArduinoとRaspberry Piを、XBee ZBを使用してZigBeeで通信させることが出来ました。Arduino側を2台、3台と増やしても、同じようにRaspberry Pi上で受信することが出来ます(受信側ではXBeeの64ビットアドレスで送信元を区別出来ます)。
Raspberry Pi上にIoTプラットフォームを提供するクラウドサービスのSDKやClient Libraryを入れて、ゲートウェイとしてクラウド上へデータを転送するようにすれば、Arduino側をIoTデバイス、Raspberry Pi側をIoTゲートウェイとして、エッジ側のネットワークをZigBee通信で作ることが出来ますね。

36
36
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
36

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?