RaspberryPiでNFCをトリガーにしてサーボモーターを駆動する

フェリーハッカソンでできなかったことをやってみる

以前参加した、フェリーハッカソンでは、QRコードを読み取ってサーボモーターの駆動をしていました。 今回はNFCのリーダーを使用してサーボモーターを駆動させてみたいと思います。時間が余っていればやりきりたかった。

【参考】 uepon.hatenadiary.com

若干異なる点としてはpythonnfcのモジュールが2.7系にまでにしか対応していない点が挙げられます。 とはいえ、今回使用しているRPiのモジュールは2系でも3系でも大きな差がなく使用することができるので 大丈夫ではないかなと。だめであればそれも含めて調査する方向でやっていこうと思います。

nfcモジュールに関して

pythonで使用できるnfcモジュールを使用してトリガーを取得していきたいと思います。

以前も使用しているので細かい部分はそちらをご参考にお願いします。

【参考】

uepon.hatenadiary.com

基本的にはnfcモジュールイベントハンドラを使用して、ループさせ、ReaderからIDmが取得できた場合にサーボ制御を行うものになります。 特に組み合わせれば難しくないかなと思います。こちらの処理は以下のような動きをします。

  1. nfcリーダーでFelicaに含まれたIDmの読み込み待ちをする。(ループ)
  2. IDmが認識できたら、サーボモーターを制御する(鍵を開ける)
  3. 鍵を開けた状態で10秒間ウエイトを行う
  4. サーボモータを再度制御する(鍵を閉める)

コード書いてみた

今回のコードではGPIO4でサーボモータを制御、GPIO17でLEDの制御を行っています。

f:id:ueponx:20190203232411j:plain

import nfc
import binascii
import RPi.GPIO as GPIO
import time

class NFCReader(object):
    def on_connect(self, tag):
        print("touched")
        self.idm = binascii.hexlify(tag.idm)
        return True

    def read_id(self):
        clf = nfc.ContactlessFrontend('usb')
        try:
            clf.connect(rdwr={'on-connect': self.on_connect})
        finally:
            clf.close()

if __name__ == '__main__':
    GPIO.setmode(GPIO.BCM)
    gp_out = 4
    gp_led = 17
    GPIO.setup(gp_out, GPIO.OUT)
    GPIO.setup(gp_led, GPIO.OUT, initial=GPIO.LOW)
    servo = GPIO.PWM(gp_out, 50)

    reader = NFCReader()
    while True:
        print("touch card:")
        reader.read_id()
        print("released")
        print(reader.idm)

        GPIO.output(gp_led, GPIO.HIGH)

        servo.start(0.0)
        servo.ChangeDutyCycle(2.5)
        time.sleep(0.5)
        servo.stop()

        time.sleep(10.0)

        servo.ChangeDutyCycle(7.5)
        time.sleep(0.5)
        servo.stop()

        GPIO.output(gp_led, GPIO.LOW)

        # GPIO.cleanup()

今回はnfcの処理の部分は汎用性をもたせるためにクラス化しています。 また、特定のIDmで開けるといった処理はしていません。リーダーで何らかのデータを読み込めた場合には判断なく処理をする形にしています。 割と簡単にできたなと思います。

おわりに

ある程度組み合わせればなんかできそうなことが増えてきました。今回も2時間もかからず出来上がった感じでした。

できれば、nfcモジュールがそろそろPython3に対応してもらえると…淡い希望でした。

RaspberryPiでNFCタグを使ってみる

RaspberryPiでNFCタグを使ってみる

久しぶりにいろいろと思うところがあって、RaspberryPiでNFCのタグを使ってみることにしました。

基本的には過去エントリー見てもらえればいいのですが、その頃からRaspbianのバージョンもベースが変わっているのでちょっと変わったようです。 というか楽になっただけなので大したことはないです。

【参考1】 uepon.hatenadiary.com 【参考2】 uepon.hatenadiary.com

使用したタグはサンワサプライさんのシールタイプになります。

一枚あたり100円を切っているので、前よりも安くなってきていますね。

今回のOS情報も念の為。今回はRaspberry Pi3ではなく、使っていなかったRaspberry Pi2を使用してます。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.4 (stretch)
Release:        9.4
Codename:       stretch

最新のイメージを使用していますのでRaspbian GNU/Linux 9.4 (stretch)となっています。(イメージ名は2018-04-18-raspbian-stretch.imgでした)

RC-S380の認識

基本的には以前のエントリーと同様にUSBを挿すだけで認識は行われます。不確定な情報ではありますが、過去のバージョンのリーダーではどうも認識はされますが、` ``nfcpy```からは認識出来ないようです。自分も何回か試してみましたがだめでした。nfcpy側では対応デバイスになっていますが、情報から察するにその他ライブラリなどの依存関係も疑われるのではないかと思います。ネットの情報を調べるとベースがDebian 6.0 (squeeze)からDebian 7 (wheezy)に変わったあたりか使えなくなっているのではないかと推測しています。

とりあえずUSBケーブルで接続すると以下のようになります。

【リーダーを1つ接続した場合】

$ lsusb
Bus 001 Device 006: ID 056e:4008 Elecom Co., Ltd
Bus 001 Device 007: ID 054c:06c3 Sony Corp.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

特に問題ありません。2つ接続しても問題なく認識されています。

【リーダーを2つ接続した場合】

$ lsusb
Bus 001 Device 006: ID 056e:4008 Elecom Co., Ltd
Bus 001 Device 007: ID 054c:06c3 Sony Corp.
Bus 001 Device 008: ID 054c:06c3 Sony Corp.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

nfcpyモジュールのインストール

前回とは異なり、pipに登録されていました。気になる点としてはpython2系にしかまだ対応していない点でしょうか。ドキュメント通りインストールすれば問題はありません。 -Uスイッチをつけて置かないとエラーがでるようです。

$ sudo pip install -U nfcpy
Collecting nfcpy
  Downloading https://files.pythonhosted.org/packages/89/2c/3d7378d65c6f21312fae4cc44849606eefa08f5980e06c5bc220c2086808/nfcpy-0.13.5-py2-none-any.whl (214kB)
    100% |????????????????????????????????| 215kB 627kB/s
Collecting libusb1 (from nfcpy)
  Downloading https://files.pythonhosted.org/packages/ec/5d/4fdac6c53525786fe35cff035c3345452e24e2bee5627893be65d12555cb/libusb1-1.6.4.tar.gz (55kB)
    100% |????????????????????????????????| 61kB 1.0MB/s
Collecting pydes (from nfcpy)
  Downloading https://www.piwheels.org/simple/pydes/pyDes-2.0.1-py2.py3-none-any.whl
Collecting pyserial (from nfcpy)
  Downloading https://files.pythonhosted.org/packages/0d/e4/2a744dd9e3be04a0c0907414e2a01a7c88bb3915cbe3c8cc06e209f59c30/pyserial-3.4-py2.py3-none-any.whl (193kB)
    100% |????????????????????????????????| 194kB 680kB/s
Collecting ndeflib (from nfcpy)
  Downloading https://files.pythonhosted.org/packages/01/76/39eb236dc5566618abdb169cb88ba4eabd22245b29cc9e5f8d91d5fcf261/ndeflib-0.3.2-py2.py3-none-any.whl (57kB)
    100% |????????????????????????????????| 61kB 1.0MB/s
Building wheels for collected packages: libusb1
  Running setup.py bdist_wheel for libusb1 ... done
  Stored in directory: /root/.cache/pip/wheels/98/8d/8b/bac0a20eb9757e7dbf46e8ab1f1695c78ad919f53080a58bc1
Successfully built libusb1
Installing collected packages: libusb1, pydes, pyserial, ndeflib, nfcpy
  Found existing installation: pyserial 3.2.1
    Not uninstalling pyserial at /usr/lib/python2.7/dist-packages, outside environment /usr
Successfully installed libusb1-1.6.4 ndeflib-0.3.2 nfcpy-0.13.5 pydes-2.0.1 pyserial-3.4

インストールは終わりましたが、テスト用のコマンドなどはインストールされていませんので、Githubから以下のサイトからcloneします。

github.com

$ git clone  https://github.com/nfcpy/nfcpy.git
$ cd nfcpy/
$ ls
HISTORY.rst  README.rst  requirements-dev.txt   setup.py  tox.ini
LICENSE      docs        requirements-pypi.txt  src
MANIFEST.in  examples    setup.cfg              tests

nfcpyの実行を行う

インストール準備がおわったので続いてはnfcpyモジュールのチェックを行います。 以下のコマンドで行います。ですが、インストール直後はsudoをつけないと以下のようなエラーメッセージが表示されます。(sudoをつければ実行は問題はありません。)

今回はRaspberryPiに2つのリーダーを接続しているのでエラーも2つ表示されています。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.13
on Linux-4.14.34-v7+-armv7l-with-debian-9.4
I'm now searching your system for contactless devices
** found usb:054c:06c3 at usb:001:007 but access is denied
-- the device is owned by 'root' but you are 'pi'
-- also members of the 'root' group would be permitted
-- you could use 'sudo' but this is not recommended
-- better assign the device to the 'plugdev' group
   sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
   sudo udevadm control -R # then re-attach device
** found usb:054c:06c3 at usb:001:008 but access is denied
-- the device is owned by 'root' but you are 'pi'
-- also members of the 'root' group would be permitted
-- you could use 'sudo' but this is not recommended
-- better assign the device to the 'plugdev' group
   sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
   sudo udevadm control -R # then re-attach device
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs
Sorry, but I couldn't find any contactless device

このメッセージをよくみると

-- better assign the device to the 'plugdev' group
   sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
   sudo udevadm control -R # then re-attach device

このメッセージの内容は、「使用するデバイスplugdevグループに入れて続くコマンドをいれるとsudoなしで実行できるようになります。」とのことでした、ベンダIDなどもセットされた形でメッセージが表示されるので、コピペして以下のように実行します。

$ sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
$ sudo udevadm control -R

リーダーが複数ある場合はエラーメッセージにある分だけ実行します。 実行が終わったら、念の為RaspberryPiを再起動し、改めてチェック行ってみます。

$ python -m nfc
No handlers could be found for logger "nfc.llcp.sec"
This is the 0.13.5 version of nfcpy run in Python 2.7.13
on Linux-4.14.34-v7+-armv7l-with-debian-9.4
I'm now searching your system for contactless devices
** found SONY RC-S380/P NFC Port-100 v1.11 at usb:001:005
** found SONY RC-S380/P NFC Port-100 v1.11 at usb:001:004
I'm not trying serial devices because you haven't told me
-- add the option '--search-tty' to have me looking
-- but beware that this may break other serial devs

これでsudoをつけなくてもエラーメッセージは表示されないようになります。デバイスも正しく認識されているようです。

続いてはGithubで落としてきたテスト用のコマンドを使用して交通系ICカードを読み込ませてみます。exampleディレクトリ内のtagtool.pyがテスト用のコマンドです。実行すると読み込み待ちになります。

$ git clone  https://github.com/nfcpy/nfcpy.git
$ cd ~/nfcpy/examples/
$ python tagtool.py
No handlers could be found for logger "nfc.llcp.sec"
[nfc.clf] searching for reader on path usb
[nfc.clf] using SONY RC-S380/P NFC Port-100 v1.11 at usb:001:005
** waiting for a tag **

ここで交通系ICカードをタッチすると読み込んだデータの一部が表示されます。 (IDの部分は一部伏せています)

$ python tagtool.py
No handlers could be found for logger "nfc.llcp.sec"
[nfc.clf] searching for reader on path usb
[nfc.clf] using SONY RC-S380/P NFC Port-100 v1.11 at usb:001:005
** waiting for a tag **
Type3Tag 'FeliCa Standard (RC-S915)' ID=**************** PMM=**************** SYS=0003

このコマンドでは使用するリーダーを指定して起動することになります。(指定しない場合には最初に見つかったリーダーが使用される)

では、改めて今回準備したNFCタグを読み込ませてみます。(IDの部分は一部伏せています) うまく読み込めたようです。購入時は何も書き込まれていないので以下のような表示になります。(この商品は144Byteのデータ書き込みができるようですが、実際には137byteの書き込みになってしまうようです。)

$ python tagtool.py
No handlers could be found for logger "nfc.llcp.sec"
[nfc.clf] searching for reader on path usb
[nfc.clf] using SONY RC-S380/P NFC Port-100 v1.11 at usb:001:005
** waiting for a tag **
Type2Tag 'NXP NTAG213' ID=04D803********
NDEF Capabilities:
  readable  = yes
  writeable = yes
  capacity  = 137 byte
  message   = 0 byte

pythonからタグを操作する

タグ情報をreadする

on_ほげほげみたいな感じのイベントハンドラーのメソッドを作成して、usb接続のデバイスに登録することで読み込むことができます。今回の例ではon_connectが読み込みに当たりますが、今後の例もこの部分を編集して実装しています。

【readNFC.py】

import nfc

def on_startup(targets):
        print("on_startup()")
        return targets

def on_connect(tag):
        print("Tag: {}".format(tag))
        print("Tag type: {}".format(tag.type))
        #print '\n'.join(tag.dump())
        if tag.ndef:
                print tag.ndef.message.pretty()
        #return True

def on_release(tag):
        print("on_release()")
        if tag.ndef:
                print(tag.ndef.message.pretty())

clf = nfc.ContactlessFrontend('usb')
if clf:
        print("Clf: {}".format(clf))
        clf.connect(rdwr={
                'on-startup': on_startup,
                'on-connect': on_connect,
                'on-release': on_release
        })

clf.close()

このプログラム例ではタグ情報をダンプしていますが、初期状態ではタグの内容は空になってます。

【実行】

$ python readNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Clf: SONY RC-S380/P on usb:001:005
on_startup()
Tag: Type2Tag 'NXP NTAG213' ID=04A903********
Tag type: Type2Tag
record 1
  type   = ''
  name   = ''
  data   = ''

タグをフォーマットする

【formatNFC.py】

import nfc

def on_connect(tag):
        print("format:", tag.format())

clf = nfc.ContactlessFrontend('usb')
if clf:
        print("Clf: {}".format(clf))
        clf.connect(rdwr={
                'on-connect': on_connect
        })

clf.close()

【実行】

$ python formatNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Clf: SONY RC-S380/P on usb:001:005
('format:', True)

情報がフォーマットされているかを先程のreadNFC.pyで もう一度読み込ませてみると

【実行】

$ python readNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Clf: SONY RC-S380/P on usb:001:005
on_startup()
Tag: Type2Tag 'NXP NTAG213' ID=04A903********
Tag type: Type2Tag
record 1
  type   = ''
  name   = ''
  data   = ''

無事にフォーマットされていることがわかります。

タグに情報を書き込む

"Hello World!"という文字列を書き込んでみます。

【writeNFC.py】

import nfc

def on_startup(targets):
        print("on_startup()")
        return targets

def on_connect(tag):
        print("Tag: {}".format(tag))
        print("Tag type: {}".format(tag.type))
        #print '\n'.join(tag.dump())
        if tag.ndef:
                record = nfc.ndef.TextRecord("Hello World!")
                tag.ndef.message = nfc.ndef.Message(record)
                print tag.ndef.message.pretty()
        #return True

def on_release(tag):
        print("on_release()")
        if tag.ndef:
                print(tag.ndef.message.pretty())

clf = nfc.ContactlessFrontend('usb')
if clf:
        print("Clf: {}".format(clf))
        clf.connect(rdwr={
                'on-startup': on_startup,
                'on-connect': on_connect,
                'on-release': on_release
        })

clf.close()

【実行】

$ python writeNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Clf: SONY RC-S380/P on usb:001:005
on_startup()
Tag: Type2Tag 'NXP NTAG213' ID=04A903********
Tag type: Type2Tag
record 1
  type   = 'urn:nfc:wkt:T'
  name   = ''
  data   = '\x02enHello World!'

書き込んだタグを先程のreadNFC.pyで読み込ませると…

$ python readNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Clf: SONY RC-S380/P on usb:001:005
on_startup()
Tag: Type2Tag 'NXP NTAG213' ID=04A903********
Tag type: Type2Tag
record 1
  type   = 'urn:nfc:wkt:T'
  name   = ''
  data   = '\x02enHello World!'

無事に書き込まれているようです。また先程のフォーマットをすれば初期化も問題なくできます。

$ python formatNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Clf: SONY RC-S380/P on usb:001:005
('format:', True)

$ python readNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Clf: SONY RC-S380/P on usb:001:005
on_startup()
Tag: Type2Tag 'NXP NTAG213' ID=04A903********
Tag type: Type2Tag
record 1
  type   = ''
  name   = ''
  data   = ''

複数のリーダーを使用した読み込み(スレッド+interruptシグナル対応)

今回は複数のリーダーを接続してそれぞれでタグを読み込ませたいと思っていたのでそれを実装してみます。各デバイスごとにスレッドを生成し、且つデーモン化してCtrl+Cでの終了にも対応させています。

【multiPollingNFC.py】

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import signal
import nfc
import time
import threading

def on_startup(targets):
    # print("on_startup()")
    return targets

def on_connect(tag):
    print("Tag: {}".format(tag))
    print("Tag type: {}".format(tag.type))
    if tag.ndef:
        print(tag.ndef.message.pretty())
    print("-----------------")

def on_release(tag):
    # print("on_release()")
    if tag.ndef:
        print(tag.ndef.message.pretty())

def readNFCThread(device):
    clf = nfc.ContactlessFrontend(device) # バス番号とデバイス番号を指定
    while True:
        if clf:
                # print("Clf: {}".format(clf0))
                clf.connect(rdwr={
                        'on-startup': on_startup,
                        'on-connect': on_connect,
                        'on-release': on_release
                })
    clf.close()

def main(argv):
    t1 = threading.Thread(target=readNFCThread,name="readNFC1",args=('usb:001:004',))
    t2 = threading.Thread(target=readNFCThread,name="readNFC2",args=('usb:001:005',))
    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    while True:
        pass

def handler(signal, frame):
    print("Process Interrupt!")
    sys.exit(0)

if __name__ == '__main__':
    signal.signal(signal.SIGINT, handler)
    main(sys.argv)

ちょっと解説

各デバイスの読み込みをスレッド化しているので以下のようにデバイスの設定をできるようにしています。

clf = nfc.ContactlessFrontend(device) # バス番号とデバイス番号を指定

ここでいうデバイスが接続したリーダーの設定になります。引数として与える情報としてはlsusbコマンドで認識されたBusDeviceIDを与えることになります。

$ lsusb
【略】
Bus 001 Device 005: ID 054c:06c3 Sony Corp.
Bus 001 Device 004: ID 054c:06c3 Sony Corp.
【略】

上記のような表示が行われた場合には以下のように引数で与えれることになります。 USBの接続状態によって毎回変わる可能性のある情報なので注意が必要となります。

t1 = threading.Thread(target=readNFCThread,name="readNFC1",args=('usb:001:004',))
t2 = threading.Thread(target=readNFCThread,name="readNFC2",args=('usb:001:005',))

このプログラムではThread化しているのでCtrl+Cを押してinterruptを発生させても、Threadが終了しない状態になります。 そのため、以下のようにしてDeamonの設定をしています。

    t1.setDaemon(True)
    t2.setDaemon(True)

実行してみる

フォーマットされたタグとHello World!の書き込まれたタグを別のリーダーに読み込ませると以下のような表示になります。

【実行】

$ python multiPollingNFC.py
No handlers could be found for logger "nfc.llcp.sec"
Tag: Type2Tag 'NXP NTAG213' ID=04D803********
Tag type: Type2Tag
record 1
  type   = ''
  name   = ''
  data   = ''
-----------------
Tag: Type2Tag 'NXP NTAG213' ID=04A903********
Tag type: Type2Tag
record 1
  type   = 'urn:nfc:wkt:T'
  name   = ''
  data   = '\x02enHello World!'
-----------------

一応はできていますが、なんとなく処理が遅いです。それぞれのリーダーでポーリングをしているということもあるので、少し待ち時間があるようです。(別のターミナルで別々のreadNFC.pyを動作させたほうが早いかもw)このままの仕組みで高速化するのであれば、もっと別の方法での工夫がいるかなと思います。

終わりに

raspbianなどのバージョンも変わると設定方法もいい感じで簡単になってきているのでいいですね。

RaspberryPiでRFID-RC522を使ってみる【失敗編】

RaspberryPiでRFID-RC522を使ってみる【失敗編】

このエントリーは失敗編です。失敗に至るメモのため、情報が基本ないので読み飛ばしてください。

以前の勉強会で教えてもらった(もう数年も前になりますが)NFCのタグシールを何かに使えないかと思って購入してみました。そのまま使うのもなんなのでArduinoやRaspberryPiでも使えないかなと思って以下も同時に購入してみました。

リーダーもこの値段で購入できるんですね。いい時代なのか、それともちょっとやそっとではお金を稼ぐことができない時代なのか。

このリーダーをネットで検索すると、こちらのリンクにヒットしました。結構Arduinoのネタは多いようなんですが、RaspberryPiはすくないようです。

webcache.googleusercontent.com

ふむふむと読んでいくと…

・the kernel to use Device Tree?
 で Noを選択します。(コレ重要!)

raspi-configコマンドで表示されるメニューで設定値が表示されるようなのですが、うちのRaspberryPiでは表示されないようです。なぜ?カーネルのバージョンなどで違いがあるのでしょうか。念のため、昔使っていたRaspberryPi2でも同様の設定は出ませんでしたし。ネットを検索してもそれっぽい情報はありませんでした。

とりあえず、とても嫌な予感がしますが、そのまま進めていくことにします。

候補としては以下の2つになると思います。そろそろC言語はつらいので…

  • SPI-Py(SPI制御ライブラリ)&MFRC522-pythonの組合せ
  • pi-rc522

今回は、候補の中で使用するのはPythonからこのリーダーを扱えるpi-rc522モジュールになります。 リンク先のページではgitでCloneしてインストールしていますが、ヌルいPython使いの自分はpipでインストールしました。

github.com

$ pip install pi-rc522
Collecting pi-rc522
  Downloading pi-rc522-2.2.1.tar.gz
Collecting RPi.GPIO (from pi-rc522)
  Downloading RPi.GPIO-0.6.3.tar.gz
Collecting spidev (from pi-rc522)
  Downloading spidev-3.2.tar.gz
Building wheels for collected packages: pi-rc522, RPi.GPIO, spidev
  Running setup.py bdist_wheel for pi-rc522 ... done
  Stored in directory: /home/pi/.cache/pip/wheels/83/45/21/0bc28b47c8dfb87d00d806b10c8ffb733e36a8b927668ce42b
  Running setup.py bdist_wheel for RPi.GPIO ... done
  Stored in directory: /home/pi/.cache/pip/wheels/ae/4d/3b/e924997dbf06810adf3b2e37f1d9627b2327eb9cbb285949c9
  Running setup.py bdist_wheel for spidev ... done
  Stored in directory: /home/pi/.cache/pip/wheels/e4/9b/5f/cf0ec030fc958b72315a15412130e4e1dc6040cdb490aa21fb
Successfully built pi-rc522 RPi.GPIO spidev
Installing collected packages: RPi.GPIO, spidev, pi-rc522
Successfully installed RPi.GPIO-0.6.3 pi-rc522-2.2.1 spidev-3.2

同時にGPIOやSPIのモジュールもインストールされるようです。GitでCloneするとサンプルコードも同時に手に入るのですが、pipインストールでは手に入らないので、Githubにいってサンプルを取得します。

【サンプルページ】 github.com

$ wget https://raw.githubusercontent.com/ondryaso/pi-rc522/master/examples/Read.py
--2017-09-18 03:08:03--  https://raw.githubusercontent.com/ondryaso/pi-rc522/master/examples/Read.py
raw.githubusercontent.com (raw.githubusercontent.com) をDNSに問いあわせています... 151.101.72.133
raw.githubusercontent.com (raw.githubusercontent.com)|151.101.72.133|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 983 [text/plain]
`Read.py' に保存中

Read.py             100%[===================>]     983  --.-KB/s    in 0s

2017-09-18 03:08:03 (6.98 MB/s) - `Read.py' へ保存完了 [983/983]

RFIDのリーダーとの接続は RC522側の IRQだけ接続不要です。

RC522モジュール RaspberryPi
1 3.3V GPIO +3.3V(3V3)
2 RST GPIO GPIO25
3 GND GPIO GND(GND)
4 MISO GPIO MISO(GPIO9)
5 MOSI GPIO MOSI(GPIO10)
6 SCK GPIO SCLK(GPIO11)
7 SDA GPIO CE0(GPIO8)

以下のように実行すればうまく…

【Read.py】

#!/usr/bin/env python

import signal
import time
import sys

from pirc522 import RFID

run = True
rdr = RFID()
util = rdr.util()
util.debug = True

def end_read(signal,frame):
    global run
    print("\nCtrl+C captured, ending read.")
    run = False
    rdr.cleanup()
    sys.exit()

signal.signal(signal.SIGINT, end_read)

print("Starting")
while run:
    rdr.wait_for_tag()

    (error, data) = rdr.request()
    if not error:
        print("\nDetected: " + format(data, "02x"))

    (error, uid) = rdr.anticoll()
    if not error:
        print("Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3]))

        print("Setting tag")
        util.set_tag(uid)
        print("\nAuthorizing")
        #util.auth(rdr.auth_a, [0x12, 0x34, 0x56, 0x78, 0x96, 0x92])
        util.auth(rdr.auth_b, [0x74, 0x00, 0x52, 0x35, 0x00, 0xFF])
        print("\nReading")
        util.read_out(4)
        print("\nDeauthorizing")
        util.deauth()

        time.sleep(1)

はずだ…

$ python Read.py
Starting

10分後…全く動かねえ…

ではということで

方法その1であった、SPI-Py(SPI制御ライブラリ)&MFRC522-pythonの組合せもやってみます。

$ git clone https://github.com/lthiery/SPI-Py.git
$ cd SPI-Py
$ sudo python setup.py install
$ cd ..
$ git clone https://github.com/mxgxw/MFRC522-python.git
$ cd MFRC522-python
$ sudo python Read.py

これでも動作せず。/(^o^)\オワタ。

もう少し調べてみる。

ハード側が怪しいということも疑って、Aruduinoでも使用可能なのでそちらでハード側のテストを行ってみました。 Arduinoでやっている例は結構あるので、こちらのほうが楽かなとは思いますが、Unoでは電圧が5V系なのでその部分は注意が必要です。(リーダー系は3.3V系なので)

Arduinoで近距離無線通信 RFID-RC522 NFC by ボクにもわかる地上デジタル

github.com

f:id:ueponx:20170918044058p:plain

実際に動作させてみると…一応、リードできてる?UIDは普通に読めていますがデータブロックは読み取れていません。 (たまにブロックは読み込めることもある…。RFIF側のUIDの読み取りに空振ることもあるぽい…。) ハード的にはかなり怪しいようです。

粘ってみる…その1

更に情報をネットを検索すると

Raspberry PI 3 and RFID-RC522 Problem reading data - Raspberry Pi Forums

なる情報もdtoverlay=spi0-hw-cs/boot/config.txtの設定の追加のようです。

$ sudo vim /boot/config.txt

【変更前】

(略)
# Uncomment some or all of these to enable the optional hardware interfaces
dtparam=i2c_arm=on
#dtparam=i2s=on
dtparam=spi=on
(略)

↓ 【変更後】

(略)
# Uncomment some or all of these to enable the optional hardware interfaces
dtparam=i2c_arm=on
#dtparam=i2s=on
dtparam=spi=on
dtoverlay=spi0-hw-cs
(略)

dtはDeviceTreeの略のようです、最近ではraspi-configではなく/boot/config.txtで設定を行う様です。 でも、こちらを追加したのですが駄目でした。

粘ってみる…その2

ならばということでそもそもOSを変えてやれってバージョンを2つ落として2015-05-05-raspbian-wheezyにしてみました。 これで動かなかったらハードだろぐらいの気持ちです。

wheezyでは、jessie以降にはなかったDevice Treeの設定はちゃんとraspi-configコマンド内にも有効無効は存在しています。 それを設定すると検索でヒットするものと同じ状態になるみたいです。

$ dmesg  | grep spi
[    6.733677] bcm2708_spi bcm2708_spi.0: master is unqueued, this is deprecated
[    7.008711] bcm2708_spi bcm2708_spi.0: SPI Controller at 0x20204000 (irq 80)

$ lsmod |grep spi
regmap_spi              2307  1 snd_soc_wm8804
spi_bcm2708             6018  0

$ ls /dev/spidev* -l
crw-rw---T 1 root spi 153, 0  11  1970 /dev/spidev0.0
crw-rw---T 1 root spi 153, 1  11  1970 /dev/spidev0.1

ですが、動作しません。ムキー。

f:id:ueponx:20170918155520p:plain

粘ってみる…その3

よくわからない気分になってきたので、更に粘ってみました。今度はIchigoJamです。

fukuno.jig.jp

ドライバーもなにもないので、これでだめならハードが悪い(もうそんな気分ですが)と諦められます。

f:id:ueponx:20170918165753j:plain

結果、駄目でした…読み取り待ちにはなってくれるのですが、それ以上の処理には続かないようです。 このためにIchigoJamの使い方をさらに勉強とは、すごい自分にもやる気があるんだなと思いました(棒)

f:id:ueponx:20170918155910p:plain

終わりに

ハードさえ動けばやりたいこと全部やりきった感あります。 新規にハード買うかして再チャレンジしたいと思います。

f:id:ueponx:20170918160821p:plain

2日使ったのでかなり寝たいです。

RaspberryPiで交通系ICカードを読み取る(RC-S380の接続)

RaspberryPiで交通系ICカードを読み取る(RC-S380の接続)

以前、交通系ICカードの読み取りをWindows8.1&Androidにて行うというセッションをまどべんよっかいちさんでさせていただきましたが、 RaspberryPiでもできないかと思いやってみました。WindowsではC#を用いてAPIを呼び出しカード内のIDmの読み込みを行っていましたが、 RaspberryPiではpythonを使うことにします。pythonはなんとなく読める程度の知識しかないのでかなり不安はありますが何とかなるかなという軽い気持ちで。

f:id:ueponx:20160423194225j:plain

【参考】まどべんよっかいち資料(タイトルを気にしてはいけない)

www.slideshare.net

接続に使ったリーダー

使用したリーダは↓です。2000~3000円ぐらいで購入できると思いますが、中古市場で買えばもっと安く手に入ると思います。

RC-S380接続から認識まで

実は接続するとあっさり認識します。

接続前のlsusbの内容

~ $ lsusb
Bus 001 Device 006: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 005: ID 2019:1201 PLANEX
Bus 001 Device 004: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp. LAN9500 Ethernet 10/100 Adapter / SMSC9512/9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

接続後のlsusbの内容

~ $ lsusb
Bus 001 Device 007: ID 054c:06c3 Sony Corp.
Bus 001 Device 006: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 005: ID 2019:1201 PLANEX
Bus 001 Device 004: ID 05e3:0608 Genesys Logic, Inc. USB-2.0 4-Port HUB
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp. LAN9500 Ethernet 10/100 Adapter / SMSC9512/9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Bus 001 Device 007: ID 054c:06c3 Sony Corp.が追加されているのがわかります。

ちなみにdmesgの結果は以下が追加されています。

(中略)
[  100.229467] usb 1-1.3: new full-speed USB device number 7 using dwc_otg
[  100.334131] usb 1-1.3: New USB device found, idVendor=054c, idProduct=06c3
[  100.334171] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=4
[  100.334191] usb 1-1.3: Product: RC-S380/P
[  100.334208] usb 1-1.3: Manufacturer: SONY
[  100.334223] usb 1-1.3: SerialNumber: ????????

(注)SerialNumberは伏せてあります。

デバイスの認識としてはこれで完了です。おめでとうございます。

設定の追加

このままでも使用することはできるのですが、一般ユーザはsudo経由でしか使用することができません。そこで、一般ユーザからでも使用可能なように以下のファイルを作成します。

~ $ sudo vim /etc/udev/rules.d/nfcdev.rules

ファイルの内容は以下になります。違うデバイスを使用するときにはidVendorとidProductの値を変更してください。

SUBSYSTEM=="usb", ACTION=="add", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06c3", GROUP="plugdev"

ファイルの編集が終了すると、ディレクトリは以下のようになります。

~ $ ls /etc/udev/rules.d/* -l
-rw-r--r-- 1 root root 114  318 17:45 /etc/udev/rules.d/40-scratch.rules
-rw-r--r-- 1 root root 506  114 03:44 /etc/udev/rules.d/99-com.rules
-rw-r--r-- 1 root root 117  422 20:58 /etc/udev/rules.d/nfcdev.rules

python側の設定

pythonのものはRaspbianにすでにインストールされているので、実行時に読み込むモジュール類のインストールを行うことになります。NFC関連のモジュールはnfcpyを使用します。

【参考】http://nfcpy.readthedocs.org/en/latest/topics/get-started.html

ネットをみるとbzrで設定することが多いようなのですが、あまり詳しくないので行き当たりばったりで設定をチャレンジして見ました。事前にpython-usbをインストールし、サイトからnfcpyモジュールのソースをwgetして展開をします。

~ $ sudo apt-get install python-usb
(途中経過は略)
~ $ wget https://launchpad.net/nfcpy/0.11/0.11.0/+download/nfcpy-0.11.0.tar.gz
(途中経過は略)
~ $ tar xvzf nfcpy-0.11.0.tar.gz
(途中経過は略)

展開したディレクトリに移動し、その中のexampleディレクトリにあるtagtool.pyを実行します。

~/nfcpy-0.11.0 $ ls
HISTORY.rst  LICENSE  README.rst  docs  examples  nfc  setup.py  tests  tools
~/nfcpy-0.11.0 $ cd examples/
~/nfcpy-0.11.0/examples $ ls
__init__.py              llcp-dta-iut.py      phdc-test-manager.py
beam.py                  llcp-dta-test.py     rfstate.py
cli.py                   llcp-test-client.py  sense.py
handover-test-client.py  llcp-test-server.py  snep-test-client.py
handover-test-server.py  ndeftool.py          snep-test-server.py
listen.py                phdc-test-agent.py   tagtool.py
~/nfcpy-0.11.0/examples $ sudo python tagtool.py

これでうまくいくのかなと思ったのですが…以下のような表示がでます。

~/nfcpy-0.11.0/examples $ sudo python tagtool.py
Traceback (most recent call last):
  File "tagtool.py", line 37, in <module>
    from cli import CommandLineInterface
  File "/home/pi/nfcpy-0.11.0/examples/cli.py", line 35, in <module>
    import nfc
  File "/home/pi/nfcpy-0.11.0/nfc/__init__.py", line 28, in <module>
    from clf import ContactlessFrontend
  File "/home/pi/nfcpy-0.11.0/nfc/clf/__init__.py", line 35, in <module>
    from . import device
  File "/home/pi/nfcpy-0.11.0/nfc/clf/device.py", line 39, in <module>
    from . import transport
  File "/home/pi/nfcpy-0.11.0/nfc/clf/transport.py", line 34, in <module>
    raise ImportError("missing usb1 module, try 'pip install libusb1'")
ImportError: missing usb1 module, try 'pip install libusb1'

最後の一文をみると「usb1というモジュールをpipをつかってインストールしてね」ってことらしいです。インストールしてみます。(pytonに詳しくないのでかなり手さぐりです)

~/nfcpy-0.11.0/examples $ sudo pip install libusb1
Downloading/unpacking libusb1
  Downloading libusb1-1.5.0.tar.gz (45kB): 45kB downloaded
  Running setup.py (path:/tmp/pip-build-HsYzk_/libusb1/setup.py) egg_info for package libusb1

Installing collected packages: libusb1
  Running setup.py install for libusb1

Successfully installed libusb1
Cleaning up...
~/nfcpy-0.11.0/examples $

無事にインストールできたみたいです。では気を取り直して実行してみます。

~/nfcpy-0.11.0/examples $ sudo python tagtool.py
[nfc.clf] searching for reader on path usb
[nfc.clf] using SONY RC-S380/P NFC Port-100 v1.11 at usb:001:007
** waiting for a tag **
Type3Tag 'FeliCa Standard (RC-SA00/1)' ID=??????????????? PMM=???????????????? SYS=????
~/nfcpy-0.11.0/examples $

実行すると読み込み待ち状態になるのでFelicaカードを読み込んでみるとIDなどが表示されます。 無事に動作したようです。(値が?になっていますが伏せているだけで実際には値が表示されます)

もう、動作したのですが折角なのでpythonプログラムから動作するところまでやってみます。このあたりは公式サイトに使い方が乗っているのですが、自分のやり方ではbzrを使ってなかったのではまってしまいましたので、念のための記述になります。

コマンドラインインタプリタを起動します。

~/nfcpy-0.11.0/examples $ python
Python 2.7.9 (default, Mar  8 2015, 00:52:26)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.

通常であれば、import nfcだけでよいのですが、自分のやった方法ではnfcモジュールが読み込めないエラーが発生します。そこで、先ほどのtagtool.pyをのぞいてみたところ、importをする前にパスにnfcpyのモジュールパスをインストールしていることがわかりました。sys.path.insert処理がそれにあたります。

そこでimport nfcを行う前に

>>> import sys
>>> sys.path.insert(1, '/home/pi/nfcpy-0.11.0')

を行うことにします。'/home/pi/nfcpy-0.11.0'の部分を自分の作業したPathに変更してください。

【実行例】

>>> import sys
>>> sys.path.insert(1, '/home/pi/nfcpy-0.11.0')
>>> import nfc
>>> clf = nfc.ContactlessFrontend('usb')
>>> print(clf)
SONY RC-S380/P on usb:001:005
>>> def connected(tag): print(tag); return False
...
>>> clf.connect(rdwr={'on-connect': connected})
Type3Tag 'FeliCa Standard (RC-S???)' ID=???????????????? PMM=???????????????? SYS=????
<nfc.tag.tt3_sony.FelicaStandard object at 0x????????>
>>> clf.close()

これで読み込みができました。

公式サイトの設定例と違うことをしたのではまってしまいましたが、そのままやればもう少し楽ができたのかもしれません。今後はpythonにも触れていこうと思います。

【参考】

http://nfcpy.readthedocs.org/en/latest/index.html

/* -----codeの行番号----- */