XBee-WiFi

Arduino UNOからの通信

XBeeを使って、Arduino UNOとホストで通信を行います。
XCTUが起動しているときは、XCTUを停止します。
XBeeをArduino UNOで使う場合、このようなUART通信が可能なベースボードが必要になります。


下側にUARTのピンが出ていますが、マーキングが紛らわしいです。
マーキングは左からRST RX TX GND 5Vとなっていますが、XBee本体のRST TX RX GND 5Vに繋がっていて、
ベースボードのRXとUNOのRX、ベースボードのTXとUNOのTXを繋ぐ必要が有ります。
Arduino UNOとの接続は以下の様になります。
ベースボード UNO
RST RESET
RX IO2 UNOのRX側
TX IO3 UNOのTX側
GND GND
5V 5V

Arduinoに以下のスケッチを書き込みます。
#include <SoftwareSerial.h>

SoftwareSerial MySerial(2, 3); // RX, TX

unsigned long lastMillis;

void setup() {
  Serial.begin(115200);
  MySerial.begin(9600);
  lastMillis = millis();
}

void loop() {
  if (MySerial.available() > 0) {
    // read the incoming byte:
    char c = MySerial.read();
    Serial.print(c);
  }

  unsigned long nowMillis = millis();
  long diffMillis = nowMillis - lastMillis;
  if (diffMillis > 1000) {
    char buffer[64];
    int len = sprintf(buffer, "Hello World %ld", nowMillis);
    MySerial.write(buffer, len);
    lastMillis = millis();
  }
}

ホストマシンで以下のpythonスクリプトを実行します。
# -*- coding : UTF-8 -*-
import socket
HOST_NAME = '255.255.255.255'
PORT = 9750 # 0x2616
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.sendto(b"Hello, UDP BroadCast", (HOST_NAME, PORT))

Arduinoのシリアルモニターに受信したデータが表示されます。
WiFiからの入力が、そのままUARTからの入力になります。


ホスト側で以下のpythonスクリプトを実行します。
# -*- coding : UTF-8 -*-
import socket
HOST_NAME = ''
PORT = 9750
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((HOST_NAME, PORT))
while True:
    rcv_data, addr = sock.recvfrom(1024)
    print("receive data : [{}]  from {}".format(rcv_data,addr))
sock.close()

Arduinoが1秒周期で送信しているデータがホスト側に表示されます。
UARTへの出力が、そのままWiFiへの出力になります。





RP-SMAコネクタタイプを使う場合、注意が必要です。
アンテナ部分が大きいので、上の写真のベースボードを使うと、アンテナ部分とUARTピンが干渉します。
UARTピンが未装着のベースボードを探しましたが見つかりませんでした。
これらの基盤はフローやリフローの設備を使ってはんだ付けされているので、はんだの融点がとても高く、普通の半田ごてでは半田を溶かしたり、
はんだで固定されているピンを除去したりすることができません。


そこで、この様なUNO用のシールドを利用しました。
いつも思うのですが、大陸産のシールドはピンソケットの位置がメチャクチャです。
このソケットの意味(使い道)を知らない人が取り付けているのでしょう。


これで干渉は無くなります。




シールド上にスライドSWが有ります。
XBEE側(左側)にすると、UNOのTXとXBeeのDataInが繋がります。これはスケッチを実行するときに使います。
USB側(右側)にすると、UNOのTXとXBeeのDataOutが繋がります。最初は目的が分かりませんでしたが、これはスケッチを書き込む 時に使います。


このシールドを使って初期設定を行う場合、USB-UART変換が必要になります。
スライドSWをXBEE側(左側)にすると、XBeeのDataOutはRX(IO0)に、DataInはTX(IO1)に繋がるので、
USB-UART変換を以下の様に接続することで、XCTU が使えるようになります。
USB-UART シールド XBee
RX
RX(IO0) DataOut
TX TX(IO1) DataIn
GND GND GND
5V 5V 3.3V

スケッチの書き込みは以下の手順です。
- スライドSWをUSB側にする。
- スケッチ書き込む
- スライドSWをXBEE側にする
- UNOのリセットボタンを押す

今までUNOのRX(IO0)とTX(IO1)を使ってUART通信を行っていたスケッチは、何も変更せずにWiFi化することができます。
UNO以外のボードで使う場合は、MCUのRXD/TXD/GND/5Vと、シールドのRX/TX/GND/5Vをワイヤーケーブルで繋げます。
pythonスクリプトと、以下のスケッチで動作を確認する事ができます。
unsigned long lastMillis;

void setup() {
  Serial.begin(9600);
  lastMillis = millis();
}

void loop() {
  if (Serial.available() > 0) {
    // read the incoming byte:
    char c = Serial.read();
    if (c >= 0x41 && c <= 0x5A) {
      c = c + 32;
    } else if (c >= 0x61 && c <= 0x7A) {
      c = c - 32;
    }
    Serial.print(c);
  }

  unsigned long nowMillis = millis();
  long diffMillis = nowMillis - lastMillis;
  if (diffMillis > 1000) {
    char buffer[64];
    int len = sprintf(buffer, "Hello World %ld", nowMillis);
    Serial.write(buffer, len);
    lastMillis = millis();
  }
}



Nanoで使うためのベースボードも販売されています。




XBee WiFiはTCPもサポートしているので、MQTTやNTPなどのプロトコルを使うことができます。
そこで、MQTTを試してみました。

XCTUではDestination IP Addressで接続先を指定しますが、残念ながらホスト名による名前解決をサポートしていません。
Destination IP Address には必ずIPアドレスを指定する必要が有ります。
そこで、最初にMQTT BrokerのIPアドレスを調べる必要が有ります。
今回、MQTT Brokerには、公開サーバーである broker.emqx.io を使いました。
以下のコマンドで broker.emqx.io のIPアドレスが分かります。


XCTUを起動して以下を変更します。
IP Protocol-->TCP
TCP ClientConnection Timeout-->FFFF
Destination IP Address-->54.87.92.106
Source Post-->75b(=1883)
Destination Port-->75b(=1883)

TCP ClientConnection Timeout は、TCP クライアントがサーバーとの接続を閉じるまでのアイドル時間です。
長くしておかないとTCP接続を維持することができません。
これでMQTTサーバーと通信することができます。




MQTTのサンプルコードはこちらで 公開しています。
コード自体はSoftware Serialを使って、MQTTのパケットを投げているだけなので、非常にシンプルです。
Arduino UNOやMEGAの他に、STM32でも動きます。

こ ちらでW5100/ENC28J60のEthernetモジュールとMQTTクライアントライブラリを使ったMQTT通信を紹介して いますが、
これらのライブ ラリはメモリを大量に消費します。
XBee WiFiを使うとメモリ消費量は半分以下になります。
ESP8266のAT Firmwareを使ったMQTT通信よりもメモリ消費量は少なくなります。

UNO+UIPEthernet+PubSubClient+ENC28J60
Sketch uses 25090 bytes (77%) of program storage space. Maximum is 32256 bytes.
Global variables use 1736 bytes (84%) of dynamic memory, leaving 312 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

UNO+Ethernet+PubSubClient+W5100
Sketch uses 19582 bytes (60%) of program storage space. Maximum is 32256 bytes.
Global variables use 1101 bytes (53%) of dynamic memory, leaving 947 bytes for local variables. Maximum is 2048 bytes.

UNO+Software Serial+ESP01+AT Firmware
Sketch uses 9938 bytes (30%) of program storage space. Maximum is 32256 bytes.
Global variables use 897 bytes (43%) of dynamic memory, leaving 1151 bytes for local variables. Maximum is 2048 bytes.

UNO+Software Serial+XBee WiFi
Sketch uses 7908 bytes (24%) of program storage space. Maximum is 32256 bytes.
Global variables use 581 bytes (28%) of dynamic memory, leaving 1467 bytes for local variables. Maximum is 2048 bytes.

XBee WiFiを使うと、UARTをサポートしているマイコンならば、どんなマイコンでもネットワーク通信を行うことができます。
スケッチのサイズも8K程度なので、32KのUNOやNANOでも楽勝です。



NTP-Clientを試してみました。
XCTUを起動して以下を変更します。
IP Protocol-->UDP
TCP ClientConnection Timeout-->64
Destination IP Address-->133.243.238.163
Source Post-->7b(=123)
Destination Port-->7b(=123)

公開NTPサーバーは幾つか有りますので好きなものを選んでください。
TCP ClientConnection Timeout は、TCP クライアントがサーバーとの接続を閉じるまでのアイドル時間ですが、
NTPを使う場合、UDP接続を維持する必要はないので短い時間にします。




NTP-Clientのサンプルコードはこちらで 公開しています。