ESP-WROOM-02とRFID-RC522で非接触Lチカ


カードかざしたらピコーンと鳴らせてみたいと思ったのですが、鳴らすためのブザー用意するのも面倒だったので、カードかざしたらピカ!と光るLチカ(LEDをチカチカさせる)に挑戦してみました。

調査

カードかざしたら反応するモジュールはどれ?

Suicaの技術あたりから攻めるのがよさそうなので、「Suica 仕様」で検索すると、「非接触型IC」という言葉が出てきました。
「非接触型IC チップ」で検索してみると、どうも「RFID」という技術ということです。

電子工作絡みで検索する時、「自作」というキーワードを入れると鉄板です。
今回も「RFID 自作」で検索すると、それっぽいのがいっぱい出てきました。

電子工作系は、古いと2000年の歴史、ではなくて西暦2000年頃からの記事もあって、現在も手に入るのかどうかよくわからない内容もあります。金額と調達可能性、開発の簡単さ(本当の難易度は実際やってみないとわからないので、加工しなくていいかとか、部品点数が少ないかとかをみる)を考慮して、モジュールを選定します。

調査していくと、Arduinoと組み合わせてRFIDでLチカがそこそこ見つかりました。実績があるRFID-RC522モジュールがよさそうです。

参考URL

Wifiとも接続したいよ

Lチカできたら、その後はカードかざしたらインターネット接続して何かしたいよね、ということで将来を見据えてWifiモジュールで単体でArduinoとして使える、ESP-WROOM-02と組み合わせることにしました。

※今回の記事では、最終的にESP-WROOM-02上でLチカさせてますが、Wifiとして外部にHTTPリクエスト送ったりしていません。

どうESP-WROOM-02とRFID-RC522を接続するの?

物理的につなげても、両方のモジュールがお話できないといけません。RFID-RC522の通信仕様をみると、SPI/UART/I2Cと書いてあるのですが、SPI以外の通信方法が可能かどうかわからなかったので、SPIで通信することにしました。(サンプルもあるので)

SPI通信のピンを確認すると、SS/MOSI/MISO/SCKの4本が最低必要なようです。また使っているかどうかわからないのですが、リセット用の信号線もRFID-RC522に接続されているので用意します。

ESP-WROOM-02のブレークアウトボードのピン設定の詳細がいまいち確認できないのですが、どうもmikroBUS規格互換だということで、そちらを見るのがよさそうということに気づきました。(なので+5VのところがESP-WROOM-02では無効化されている)

参考URL

用意するもの

モジュール

※(リンク先はたぶん今回説明するのと同等品。購入時の参考まで)

その他(今回使用したもの)

  • ブレッドボード(長)
  • ブレッドボード用 ジャンパーワイヤ各種
  • USBケーブル(PCと接続できる端子と、AE-FT234Xと接続できる端子が両端にあるケーブル)
  • 発光ダイオード(赤) x 2 (電源確認用と、Lチカ用)
  • 1KΩ抵抗 x 2 (LED用 ※抵抗の値は発光ダイオードの許容範囲にあわせて適宜調整してください)
  • 0.1μF積層セラミックコンデンサ x 1 (パスコン用)
  • 出力DC3.3V スイッチング電源(AC100Vコンセントから安定的に電源取得するため)
  • スイッチング電源用DCジャック

開発環境

  • MacBook Air (OS X Yosemite)
  • Arduino IDE 1.6.5

作業手順

  1. Arduino IDEにESP-WROOM-02の開発ボード追加を行います
  2. Arduino IDEにRC522のライブラリを追加します
    • MFRC522:githubから、一式をZIPダウンロードします。
    • Arduino IDEのメニューの「スケッチ」→「Add .ZIP Library..」から、ダウンロードしたファイルを選択します。
    • Arduino IDEのメニューの「ファイル」→「スケッチの例」の下の方に「MFRC522」という項目が追加されていたら追加完了です。
  3. ブレッドボード上に配線します
    • ESP-WROOM-02モジュールの下の空間を利用できると、配線がすっきりします
    • 発光ダイオードは向きがあるので注意
  4. USBケーブルでMacとAE-FT234Xを接続します
    • Arduino IDEのメニューの「ツール」から、ポートを「/dev/cu.usbserial~」にします。(環境によって~の後がいろいろ変わるようです)
  5. プログラムをコンパイルしてESP-WROOM-02に書き込みます。
    • ESP-WROOM-02側のモードを書き込みモードにしないと、Arduino IDEで書き込めない旨のエラー表示となります
    • USBからは電源供給せずに、3.3Vのスイッチング電源側から供給しますので、USBとは別にスイッチング電源を接続して通電状態としてください(少なくともESP-WROOM-02には電源が供給されていないと書き込めません)
    • MFRC522ライブラリをESP-WROOM-02デバイスで使おうとすると、コンパイル時に、「WARNING: library MFRC522 claims to run on [avr, STM32F1] architecture(s) and may be incompatible with your current board which runs on [esp8266] architecture(s).」といって、警告が出ます。出ますが、コンパイル通るし動くので無視しました。
  6. Arduino IDEがプログラム書き込んだ後、自動的にリセットされてESP-WROOM-02がフラッシュROMから立ち上がります。なので、そのままでも動きます。USBからのケーブルは抜きたい人は、一度電源切って、USB周りのケーブル抜いて、フラッシュROM起動モードにしてから再度電源ONにしてください。

ブレッドボードに全部載せた

左上の3本ぐらい明後日の方向に伸びているのが、AE-FT234Xにつながっています(小さすぎてUSBのケーブルの重さでブレッドボードから離れてしまうので、あえて外しています)

これはプログラムの書き込みとシリアルコンソールでのデバッグに使うだけなので、動作時はこの明後日の方向に伸びているケーブルは外しています。

ちなみに電源はスイッチングアダプタから直供給で、電源スイッチとかはないです。

動かしてみた

実際に動かしてみました。RFID-RC522買ったらついてきたカードをかざすとカードが検出されます。

横方向に外れた場合にLEDが光らなくなる(カード未検出となる)のは理解しやすいですが、縦方向も10cm程度離すとLED光りませんでした。

回路図

電子回路作ったら清書しましょうという教えに従い、作成しました。
回路図エディタBSch3V利用させて頂きました。とても使いやすいですね。

プログラム(Arduino)

ESP-WROOM-02のフラッシュROMを書き込みモードにして、Arduino IDEから突っ込むプログラムは以下になります。

  • SSピンと、REESTピンは自由に変更可能です。変更可能なのですが、ESP-WROOM-02のGPIO15ピン使おうとすると、どうも挙動があやしいので、GPIO15ピンは使わない方がいいかもしれません。(ジャンパー設定で使っているからかもしれませんし、ESP-WROOM-02のリセット挙動に使うピンらしいのでそのせいかもしれません)
  • 先ほども書きましたが、WifiでIPアドレス取得しているだけで、HTTP通信とかしていません。ただ、IPアドレスは取得しているので、SSIDとパスワードは必要です(不要なら削ってください)
ESPWROOM02_RC522.ino
/*
 * ESP-WOORM-02とMFRC522を接続する
 * 2015/10/12
 * 
 * 配線(SPI通信):
 *  ESP-WROOM-02 : MFRC522
 *        GPIO 5 -> SDA(1) - ESP-WROOM-02側はSS_PINで定義
 *        GPIO14 -> SCK(2)
 *        GPIO13 -> MOSI(3)
 *        GPIO12 <- MISO(4)
 *                  RQ(5)   - 未使用
 *                  GND(6)  - GNDにつなぐ
 *        GPIO16 -> RST(7) - ESP-WROOM-02側はRST_PINで定義
 *                  3V3(8)  - 電源につなぐ
 * 
 * LED:   GPIO 4
 * 
 */
#include <SPI.h>
#include <MFRC522.h>
#include <ESP8266WiFi.h>

#define RST_PIN 16 // MFRC522用リセットピンGPIO NO
#define SS_PIN  5  // MFRC522用SS(SDA)ピンGPIO NO

MFRC522 mfrc522(SS_PIN, RST_PIN); // MFRC522のインスタンスを作成

#define CARD_PRESENT_PIN 4 // MFRC522にカードが検知されたら光らせるGPIO NO
bool cardset;     // MFRC522にカードが検知されているかどうか
int timeoutcount; // MFRC522からカードが連続で離れた回数を記録

const char* ssid = "xxxxxxxx";         // ESP-WROOM-02用 Wifi SSID(各自設定してください)
const char* password = "xxxxxxxxxxxx"; // ESP-WROOM-02用 Wifi パスワード(各自設定してください)

void setup() {
  // UART接続初期化
  Serial.begin(115200); // UARTの通信速度を変更したい場合はこちらを変更
  delay(10);

  // カード検出用のGPIO初期化
  pinMode(CARD_PRESENT_PIN, OUTPUT);
  digitalWrite(CARD_PRESENT_PIN, LOW);

  // MFRC522用変数初期化
  cardset = false;
  timeoutcount = 0;

  // MFRC522のスケッチのDumpInfoを参考にした。ref) https://github.com/miguelbalboa/rfid
  SPI.begin();          // SPI初期化
  mfrc522.PCD_Init();   // MFRC522初期化
  ShowReaderDetails();  // MFRC522 Card Readerのバージョンを返す。00かFFなら配線間違いの可能性

  // とりあえずWifiにつなぐ
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void loop() {
  // カードの検出
  if ( !mfrc522.PICC_IsNewCardPresent()) {
    // 検出されなかった場合の処理
    if (cardset) {
      // すでにカードが検出されていた場合で、連続4回未検出になったらLEDをLOWにする
      // 検出後、タイムアウトと検出を繰り返すのでその対策 
      if (timeoutcount > 4) {
        digitalWrite(CARD_PRESENT_PIN, LOW);
        Serial.println("LED LOW");
        cardset = false;
        timeoutcount = 0;
      } else {
        // 4回以内なら連続未検出回数を増やす
        timeoutcount++;
      }
    }
    delay(5);
    return;
  }

  // カードが初めてor改めてセットされた場合、LEDをHIGHにする
  if (!cardset) {
    digitalWrite(CARD_PRESENT_PIN, HIGH);
    Serial.println("LED HIGH");
    cardset = true;
  }
  timeoutcount = 0;
  delay(100);
}

 // MFRC522のスケッチのDumpInfoのまま。ref) https://github.com/miguelbalboa/rfid
 // LICENSE:https://github.com/miguelbalboa/rfid/blob/master/UNLICENSE
void ShowReaderDetails() {
  // Get the MFRC522 software version
  byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
  Serial.print(F("MFRC522 Software Version: 0x"));
  Serial.print(v, HEX);
  if (v == 0x91)
    Serial.print(F(" = v1.0"));
  else if (v == 0x92)
    Serial.print(F(" = v2.0"));
  else
    Serial.print(F(" (unknown)"));
  Serial.println("");
  // When 0x00 or 0xFF is returned, communication probably failed
  if ((v == 0x00) || (v == 0xFF)) {
    Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?"));
  }
}

免責事項

回路図どおり、プログラムどおりに作っても動かなかったらごめんなさい。無保証です。

おまけ

今回「動かしてみた」で使った動画は、デジタルカメラの動画モードで撮影→ffmpegで変換してアニメーションGIFとして作成しました。GUIで編集するよりも手軽で綺麗なアニメーションGIFが作れました。

  1. 入力動画を横320、縦は入力動画のアスペクト比に合わせて縮小
    • $ ffmpeg -i input_origin.MP4 -vf scale=320:-1:flags=lanczos -strict -2 -y input_mini.mp4
  2. 今回の動画で抽出したい部分を抽出するため、開始16秒から4秒間分だけ出力する
    • $ ffmpeg -i input_mini.mp4 -ss 16 -t 4 -strict -2 -y input_mini_16_4.mp4
  3. 最適化されたパレット画像を生成(fpsを10に設定)
    • `$ ffmpeg -i input_mini_16_4.mp4 -vf fps=10,palettegen=stats_mode=diff -y mp4_palette.png'
  4. パレット画像を利用してアニメーションGIFを生成(fpsを10に設定)
    • $ ffmpeg -i input_mini_16_4.mp4 -i mp4_palette.png -lavfi fps=10,paletteuse -y output.gif

動画フォーマットは圧縮が効いているのですが、アニメーションGIFにするとファイルサイズが肥大化するので、1Mbyte以内に収めようと思うと、5秒程度が限界ですね。

参考URL