2014年7月27日日曜日

XBee+ArduinoとXBee+Macを繋ぐ方法

Xbee APIモードの扱い方
なるべく簡単に、かつ間違いなく、安定してXBee+ArduinoとXBee+Macを繋ぐ方法

必要品は、「XBeeをはじめてみよう(ZB編)」
で用いている物に、Mac (MacBook Air)である。

1. xctuのダウンロードとインストール
「ArduinoUnoとXBeeとMac... Mac版のX-CTUを使って設定しちゃおう」
に記載のあるnew xctu for Mac
をダウンロードし、インストールする。

2. XBeeの設定
XBeeをXBee USB アダプターにセットし、それをMacに接続する。
xctuを起動する。
「Add Device」でusbserialを選んで、XBeeを設定できる状態にする。
最終的にMacに接続するXBeeは、
Coordinator API
に設定する。設定方法は、ファーム更新で選択する。

PAN-IDを好きな4桁の数字にする。これがZigBeeネットワークの識別番号、
相互接続する他のXBeeも同じ数字をPAN-IDに入れる。

AP-API Enable 2にする。これでEscモードになる。

一旦、USBを抜いて、XBeeをArduinoに搭載する側に交換する。
Arduino側のXbeeは、
Router API
に設定する。
PAN-IDは上記と同じ数字。AP-API Enableも同じく2とする。

3. XBeeとArduinoの結合
XBeeをXbeeシールドに載せ、XBeeシールドをArduinoに載せる。
XBeeシールドの小さなスイッチをUSB側にする。
ArduinoをUSBで、Macのもう一つのUSBに接続する。
Arduino-IDE(アプリケーション名はArduino)を起動する。

4. XBee-Arduino
XBee-Arduinoのサイトに行き、
xbee-arduino-0.5.zip(番号は更新されているかもしれない)をダウンロードする。
Arduino-IDEの「スケッチ->ライブラリを使用->Add Library...」でダウンロードしたファイルを選択する。

5. サンプルプログラムをArduinoに転送
以下のサンプルプログラムを、Arduino-IDEで「マイコンボードに書き込む」。
一旦ArduinoをUSBから外し、XBeeシールドの小さなスイッチをMICROに変更する。
再びArduinoをUSBでMacに接続する。

----
#include <XBee.h>

XBee xbee = XBee();

// 送付データは1バイトづつの配列に入れる
uint8_t sendData[] = { 'H', 'L' };

// 送付先のXbeeのアドレス (PCに繋いだCoordinatorのアドレスを入れる。アドレスはXbeeの裏に印刷されている。
XBeeAddress64 remoteAddress = XBeeAddress64(0x0013a200, 0x40b93ccb);

// 送付データをAPIパケットに変換する。詳細な説明は以下:
// http://xbee-arduino.googlecode.com/svn/trunk/docs/api/class_z_b_tx_request.html
ZBTxRequest zbTx = ZBTxRequest(remoteAddress, sendData, sizeof(sendData)); 

// counterは送付データの例delay毎に+1する。
int pin5, counter;

void setup() {
  Serial.begin(9600); // シリアルを9600bpsで使用開始
  xbee.setSerial(Serial); // xbeeが受け持つシリアルを設定
  counter=0;
};

void loop() {
  // pin5を使っているのは、Arduinoのpin入力データを送付するイメージだから。今はダミーのcounterを送っている。
  pin5 = counter++;
  
  // 送付データはHigh, Lowの2つに分けて送付する。この作業の役割に関しては以下の解説が詳しい。
  // http://yoppa.org/tau_bmaw13/4832.html
  sendData[0] = pin5 >> 8 & 0xff;
  sendData[1] = pin5 & 0xff;
  
  // データを含んだパケットを送付
  xbee.send(zbTx);
  
  delay(1000); // ちょっと待つ
};

----

6. Cool Termで確認
Macで、Cool Term
を起動する。(入れていないならダウンロードしてインストールする)
Cool Termで、Arduinoではなく、Xbee+USBアダプターが入っている方のシリアルをオープンする。名前はusbserial-...と言った名称である。
文字列が一定時間おきに、ばらばら出てくるようなら接続成功。
Arduino->XBee---->XBee->Mac
という接続がなされている。

7. Processingでサンプルソフトを起動
新しいスケッチ画面を開く。
xbee-apiをダウンロードする。
展開したフォルダの直下にある xbee-api-0.9.jarと、libフォルダに入っているlog4j.jar, RXTXcomm.jarを新しいスケッチ画面にドラッグアンドドロップする。
もしくは、スケッチのcodeフォルダにコピーする。
スケッチのdataフォルダに、xbee-api-0.9フォルダ直下の、log4j.propertiesをコピーする。
以下のサンプルプログラムをスケッチにコピーする。
Runすると、画面に数字などが表示される。数字が更新されていればProcessingでデータを取得できている。

----
// KYDrill氏のコードを元に作成(オリジナルは以下のURL)
import processing.serial.*;
import java.util.concurrent.*;
import java.util.Queue;
import org.apache.log4j.PropertyConfigurator;

XBee xbee;
Queue<XBeeResponse> queue = new ConcurrentLinkedQueue<XBeeResponse>();
boolean message;
XBeeResponse response;

String senderAddress = "00:13:A2:00:40:B9:3C:CB";
String rxStr = "********";
String txStatus = "";
int rssi = 0;
int rxVar, oldrxVar, rxErr;

void setup()
{
  size(640,150);
  colorMode(RGB,256);
  background(0,0,0);
  rxVar = oldrxVar = rxErr = -1;
  
  try {
    //optional.  set up logging
    //PropertyConfigurator.configure(dataPath("")+"/log4j.properties");
    xbee = new XBee();
    // replace with your COM port
    xbee.open("/dev/tty.usbserial-A5025X1E", 9600); // xbeeを繋いでいるシリアルポートを指定
    xbee.addPacketListener(new PacketListener() { // xbeeのレスポンスを待つパケット監視を設定
      public void processResponse(XBeeResponse response) {
        queue.offer(response);
      }
    }
    );
  } 
  catch (Exception e) {
    System.out.println("XBee failed to initialize");
    e.printStackTrace();
    System.exit(1);
  }
}

void draw(){
  // パケット読み取り
  try {
    readPackets();
  }
  catch (Exception e) {
    e.printStackTrace();
  }
  
  background(255);
  textAlign(LEFT);
  textSize(20);
  
  // 受信強度の表示
  fill(0); text("RSSI", 10, 25); fill(0,0,255);
  text(String.format("%d", rssi) + "dB", 100, 25);
  
  // 受信元アドレスを表示
  fill(0); text("Address", 10, 50); fill(0,0,255);
  text(senderAddress, 100, 50);

  // 受信データの表示  
  fill(0);
  text("Rx Data", 10, 75);
  fill(0,0,255);
  //text(rxStr, 100, 75);
  text(rxVar, 200, 75);
  text("ERR:"+rxErr, 300, 75);
  
  // 受信状態の表示
  fill(255,0,0);
  text(txStatus, 10, 100);
}

// パケットの読み込みとエコー、ATDBの送信
void readPackets() throws Exception {

  while ((response = queue.poll()) != null) {
    // we got something!
    try {
      if (response.getApiId() == ApiId.ZNET_RX_RESPONSE && !response.isError()) {
        ZNetRxResponse rxResponse = (ZNetRxResponse) response;
        
        // アドレスをintで取得
        int[] addressArray = rxResponse.getRemoteAddress64().getAddress();
        String[] hexAddress = new String[addressArray.length];
        // 16進数のStringへ
        for(int i=0; i<addressArray.length;i++){
          hexAddress[i] = String.format("%02x",addressArray[i]);
        }
        // 送信元アドレスを文字列で保存
        senderAddress = join(hexAddress,":");
        
        //受信データを取得
        int[] rxData = rxResponse.getData();
        rxStr = "";
        for(int i=0; i<rxData.length; i++){
          rxStr += String.format("%c", rxData[i]);
        }
        // Arduinoのプログラムと対応して、2バイトのintデータを前提にしている。
        rxVar = rxData[0] << 8 | rxData[1];
        if (rxVar != oldrxVar + 1) rxErr++;
        oldrxVar = rxVar;
        
        // エコー (送られてきたデータを、そのまま返信)
        int[] payload = rxData;
        XBeeAddress64 addr64 = new XBeeAddress64(addressArray); // データの送信元アドレスを設定
        ZNetTxRequest request = new ZNetTxRequest(addr64, payload); // 送られてきたデータをAPIパケットに変換
        try {
          // データ送信
          ZNetTxStatusResponse response = (ZNetTxStatusResponse) xbee.sendSynchronous(request);
          txStatus = "";
        } catch (Exception e) {
          txStatus = "tx request timed out";
        }
        
        // ATコマンドを送信し、RSSIを取得
        AtCommand  at = new AtCommand("DB"); // ATDBで、RSSIを取得し、電波強度を調査する。
        AtCommandResponse response = (AtCommandResponse) xbee.sendSynchronous(at, 5000);
        if (response.isOk()) {
          // 成功
          rssi = response.getValue()[0];
          rssi = rssi * (-1);
        }
      }
    }
    catch (ClassCastException e) {
      // not an IO Sample
    }
  }
}



----

以上




2 件のコメント:

Unknown さんのコメント...

このプログラムは、arduinoから送られてきた受信強度のパケットをprocessingで表示させているという解釈で合っておりますか??

fewzio さんのコメント...

arduinoからは、counterという変数の値を送っています。センサーの値を送りたい場合は、センサー値をcounterのように扱って送れば良い、ということです。受信強度は、受信時に自動的に取得されます。Processing側では受信したcounterの値と、受信強度を表示しています。