Featured image of post Raspberry Pi のGPIO経由で入力信号を連続的に取得

Raspberry Pi のGPIO経由で入力信号を連続的に取得

矩形波をRaspberry Pi(以下RPi)のGPIOピンに入力して、それを読み出す手順をメモします。RPi 2を使用しました。シェルスクリプトによる方法と、RPiに標準で入っているRPi.GPIOを使った方法です。

入力の矩形波

入力する矩形波は以下です。 pps_sh

GPIOピンの確認

旧型モデルでは26ピン、2ではさらに拡張された40ピンです。配置は「RPi Low-level peripherals - eLinux.org」にあるとおり。今回は基板上の12ピン目、すなわちGPIO18を使用します。

300px-Pi-GPIO-header

引用元:RPi Low-level peripherals - eLinux.org

このピンにジャンパワイヤを指して、信号を入力します。絵としては「橋本商会 » Raspberry PiのGPIOを使う」にあるような感じです。

シェルスクリプトによる方法

シェルスクリプトによる方法は非常に手軽で簡単です。Interface 2012年12月号のRPi特集の記事を参考に、18ピンからの入力を得る方法を書きます。

`$ sudo su -
 $ echo 18 > /sys/class/gpio/export
 $ echo in > /sys/class/gpio/gpio18/direction
 $ cat /sys/class/gpio/gpio18/value
 -> 0 or 1
 $ echo 18 > /sys/class/gpio/unexport
 `

見るだけでだいたいわかると思いますが、各行の意味を書きます。まず2行目以降のコマンドを実行するために管理者権限が必要です。2行目のexportで18ピンをオープンにしアクセスできる状態にします。次に入力なのか出力なのかを指定し、catで値を得ます。3.3Vなら1、0Vなら0が返ります。終わったら、unexportでクローズ。雑誌だとdirectionとvalueが抜けていますが、誤植でしょう。また、見当がつくと思いますが、出力の場合はinがoutになり、またcatがecho と value のセットになります。

このままだと値を一度しか得られません。LEDのON/OFFチェックならそれでもよいでしょうが、今回の入力は矩形波なので、連続して取得したいところです。下記に連続的に値を得られるシェルスクリプトを書きます。管理者権限のもとで実行すると、値をひたすら log.txt に出力します。Ctrl-cで終了します。

`#!/bin/bash
 set -eu
 
 PIN=18
 
 trap "echo ${PIN} > /sys/class/gpio/unexport" 1 2 3 15
 
 echo $PIN > /sys/class/gpio/export
 echo in > /sys/class/gpio/gpio${PIN}/direction
 
 while :
 do
     cat /sys/class/gpio/gpio${PIN}/value >> log.txt
 done
 `

私の環境だと、だいたい1秒間に180-190点ほど取得しました。しかしながらシェルスクリプトなので、ちょっとした拍子で動作速度が変わるのか、1秒間あたりの取得点数はあまり安定せず、160点ほどになることもありました。次にPythonスクリプトによる例を書きますが、こちらはシェルスクリプトよりも高速で多少安定しています。

RPi.GPIOを用いたPythonスクリプトによる方法

Pythonによる方法は色々あって、有名どころではWiringPiなどがあるようですが(「ツール・ラボ » Raspberry PiのGPIO制御方法を確認する(GPIO制御編その2)」、RPiには標準でRPi.GPIOなるものが用意されているので、今回はこちらを使いました。主に「Raspberry Pi GPIO入出力のサンプル(Python, C言語, shellスクリプト) (r271-635)」を参考にさせていただきました。以下のように使います。

`$ sudo python
 > import RPi.GPIO as GPIO
 > GPIO.setmode(GPIO.BCM)
 > GPIO.setup(18,GPIO.IN)
 > GPIO.input(18)
 `

これも管理者権限が必要なことに注意です。参考リンク先によると、GPIO.BCMは、GPIOピンの番号でセットすることを意味します。RPiの基板上のピン番号で数える場合、GPIO.BOARDであるようです。シェルスクリプトと同様、これだけでは一回こっきりの値しか取れないので、スクリプトを書いてループにします(といっても参考記事のものとほとんど同じなのですが…)。以下です。

`# -*- encoding:utf-8 -*-
 import RPi.GPIO as GPIO
 
 PIN = 18
 GPIO.setmode(GPIO.BCM)
 GPIO.setup(PIN, GPIO.IN)
 
 print('start\n')
 fp = open("log.txt","w")
 
 try:
     while True:
         value = GPIO.input(PIN)
         fp.write( str(value) + '\n' )
 except(KeyboardInterrupt):
     fp.close()
     GPIO.cleanup()
     print('end\n')
 `

管理者権限で実行すると、log.txtにログが出力されます。値の取得速度はシェルスクリプトとは段違いで、私の環境だと1秒間に約125000点を取得しました。すなわちだいたい8usに1点取得していると思われます。プラマイ500点くらいの差はありましたが、シェルスクリプトに比べると安定して取得しているように思えます。

まとめ

シェルスクリプトで手軽に入力を得ることができます。今回説明をしませんでしたが、出力も簡単です。ある程度高速性を期待するなら、Pythonスクリプトが標準でモジュールも用意されておりお手軽です。C言語で実装すればもう少し早くなるかもしれませんが、苦労のほうが大きいように思います。ただし、レジスタを直接叩けば話は別で、参考雑誌によると、nsecの世界での制御が期待できそうです…が、そこまで速さに拘るならLinuxでやるのは筋が悪いような。ただ、面白そうではあるので、今度やってみようかな。

ついでに、今回の矩形波ですが、PPS、すなわちPulse Per Secondというやつで、きっかり1秒に1回パルス波を出力します。今回はGPSモジュールから出力しました。

コメント

コメントは承認後に表示されます。

まだコメントはありません。

コメントを書く

或る阿呆の記.
Hugo で構築されています。
テーマ Stack は Jimmy によって設計されています。