Arduino と EPICS を使った簡単な例
家庭でも遊べるように、簡単なサンプルをつくることを目的とする。
「ArduinoはUSBシリアル経由でデータを垂れ流しにする」「EPICS IOC(Raspberry Pi) 側からコマンドは送らず、Listenするのみ」という構成とした。
今回作成したEPICS IOC, Protocol File 等は attachment:arduino_simple.tar.gz にまとめて置いてある。
準備
- Arduino Uno
- PC
- Arduino 統合開発環境(IDE)を公式サイト( https://www.arduino.cc/en/Main/Software )からダウンロード・インストールする
- Windows / ver 1.8.7 を使用した
- Raspberry Pi
- Raspberry Pi2 Model Bを使用した(Pi3でも可能のはず)
- EPICSインストールについては別の記事を参照
- USB ケーブル
- ブレッドボード、ジャンパーケーブル等
- 半固定抵抗と固定抵抗(今回は手元にあった 1kΩのモノを使用)
方針
最終的には
EPICS Client --(Ethernet)-- [RasPi (epics IOC)] --(USB)-- [Arduino AnalogIN #0] <-- 可変抵抗に5V印加
という構成にする。
- アナログ入力を読み込み、シリアル経由でホストに通信。最初はPCを使って動作検証し、その後でEPICS化する。
- Arduino Uno の場合、0-5Vを 10bit(0-1024)で読み込むことが可能
- 5V 電圧+可変抵抗+固定抵抗(破損防止)で
- 今回は手元にあった 1kΩの可変抵抗(半固定抵抗)+1kΩの固定抵抗
- ブレッドボードに配線
動作確認
PCを使ってスケッチの検証
最初に
[PC] --(USBケーブル)-- [Arduino] <-- AnalogIN
という単純な構成で確認する。
1秒に1回、ADCの値をシリアル経由でホストPCに送るスケッチを作成する。
int analogPin = 0; int val = 0; void setup() { Serial.begin(19200); } void loop() { val = analogRead(analogPin); Serial.println(val); delay(1000); }
Arduinoにダウンロードし、IDEで「シリアルモニター」を開くと、1秒に1回ADCのカウント値が表示される。
この状態で可変抵抗を動かして、カウント値が変わることを確認する。
Raspberry Pi に接続
次にUSBケーブルをPCから抜いて、Raspberry Pi に Arduino を接続する。
まずは dmesg を確認
[ 3433.753691] usb 1-1.2: new full-speed USB device number 6 using dwc_otg [ 3433.898077] usb 1-1.2: New USB device found, idVendor=2a03, idProduct=0043 [ 3433.898099] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=220 [ 3433.898109] usb 1-1.2: Product: Arduino Uno [ 3433.898120] usb 1-1.2: Manufacturer: Arduino Srl [ 3433.898129] usb 1-1.2: SerialNumber: [ 3433.938398] cdc_acm 1-1.2:1.0: ttyACM0: USB ACM device [ 3433.939634] usbcore: registered new interface driver cdc_acm [ 3433.939644] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
のように、ttyACM0 として認識されている。となればあとは簡単で、rootになってから適当なターミナルプロ ラムで接続すれば良い。ここでは使いなれた GNU Screen を使って、デバイス名と通信速度を指定する
pi@raspberrypi:~ $ sudo su - root@raspberrypi:~# screen /dev/ttyACM0 19200
正常に接続できれば、1秒ごとにターミナル上にADCカウント値が表示される。
GNU Screenを終了するにはホットキー(デフォルトではCTRL-a)を押してから、kを押せば良い(killコマンド)。
※分からなければgoogleで 「GNU Screen の使い方」を検索
EPICS IOC 作成
makeBaseApp
ここまでくれば、あとはEPICSのIOCを書く。 単純に Stream Device で読み込むだけで良いので、 simpleReadという名前でapplicationを作る。
pi@raspberrypi:~/epics/app/arduino $ makeBaseApp.pl -t ioc simpleRead pi@raspberrypi:~/epics/app/arduino $ makeBaseApp.pl -i -t ioc simpleRead Using target architecture linux-arm (only one available) The following applications are available: simpleRead What application should the IOC(s) boot? The default uses the IOC's name, even if not listed above. Application name? pi@raspberrypi:~/epics/app/arduino $
configure/RELEASEを編集
pi@raspberrypi:~/epics/app/arduino $ vi configure/RELEASE ASYN=/opt/epics/R315.5/modules/soft/asyn/4-31 STREAM=/opt/epics/R315.5/modules/soft/stream/2-7-7
src ディレクトリでの作業
srcディレクトリで、MakefileにstreamDeviceの
- SerialPortドライバーを追加
- asyn ライブラリを追加
の2つを追記
pi@raspberrypi:~/epics/app/arduino/simpleReadApp/src $ vi Makefile # simpleRead.dbd will be made up from these files: simpleRead_DBD += base.dbd # Include dbd files from all support applications: simpleRead_DBD += asyn.dbd simpleRead_DBD += stream.dbd simpleRead_DBD += drvAsynSerialPort.dbd # Add all the support libraries needed by this IOC simpleRead_LIBS += asyn simpleRead_LIBS += stream
Database ディレクトリでの作業
Dbディレクトリでdatabaseファイルを追加。スキャンを"I/O Intr"にすることで、シリアル経由でデータが来たときのみレコードをプロセスする。
vi read1.db record(longin, "TEST:READ_INT") { field(DESC, "adc raw input") field(DTYP, "stream") field(INP, "@simple.proto getval PS1") field(SCAN, "I/O Intr") }
Dbディレクトリの Makefile に db ファイルを追加
pi@raspberrypi:~/epics/app/arduino/simpleReadApp/Db $ vi Makefile DB += read1.db
Dbディレクトリに protocol file を作成。数値を"%d"で変換するのみなので単純。
pi@raspberrypi:~/epics/app/arduino/simpleReadApp/Db $ vi simple.proto Terminator = CR LF; getval { in "%d"; }
make すると、とても遅い。セルフコンパイルなので仕方ない(クロスコンパイル環境を整えたい)
stream device のサイト http://epics.web.psi.ch/software/streamdevice/ も参照。
startup
startupディレクトリで st.cmd コマンド編集。 (※注1: /dev/tty*を使わずにデバイスファイル名を指定するやりかたについて、このページ一番下に追記した。)
pi@raspberrypi:~/epics/app/arduino/iocBoot/iocsimpleRead $ vi st.cmd dbLoadRecords("db/read1.db") epicsEnvSet("STREAM_PROTOCOL_PATH", ".:../../simpleReadApp/Db") drvAsynSerialPortConfigure ("PS1","/dev/ttyACM0") asynSetOption ("PS1", 0, "baud", "19200")
その後、st.cmd を実行。root権限が必要なので sudo で実行する。
pi@raspberrypi:~/epics/app/arduino/iocBoot/iocsimpleRead $ chmod +x st.cmd pi@raspberrypi:~/epics/app/arduino/iocBoot/iocsimpleRead $ sudo ./st.cmd
エラーが出ていないことを確認すること。
Client
別ターミナルを開いて、
camonitor TEST:READ_INT
とする。
あるいは、PC上でCSSを実行して、このレコードをモニター・グラフ表示する。
※ 以上の動作が確認できたら、Arduinoスケッチで Delay 1000 としているところを 100 ms に変更して書き込む。
これで可変抵抗を動かしたときの応答が滑らかになる。Arduinoは10Hzという一定速度で電圧を測定してRasPiに送信しているのに対して、
EPICS IOC は値が変化したときのみクライアント側に通知する camonitor 機能がある。
タイムスタンプをみると最速で0.1秒で値が変化している一方で、数値が変化していないときには端末は更新されないことがわかる。
(次に値が変化したときまでタイムスタンプが更新されていない)
コメント・追記
※2018/09/26 : 山本さんからのコメント
USB接続のserial portのデバイス名には、Linuxの場合、/dev/ttyXXXを直接使う より、/dev/serial/by-id/以下のデバイス名を使う方が、長期的には間違いが少ないと 思っています。こちらを使えば、他のArduino(あるいはそれ以外のシリアルデバイス)を接続し た場合にも、st.cmdを変更することなく使えます。
とのこと。例えば今回のArduinoの場合、/dev/serial/by-idの下には以下のデバイスファイルが出来ているのでst.cmdでこれを指定すればよい。
pi@raspberrypi:~ $ ls /dev/serial/by-id/ usb-Arduino_Srl_Arduino_Uno_[[シリアル番号]]-if00
このほかにデバイスファイルを指定する方法としては、以前に路川さんが書いた BBBから複数のATTiny85接続のようにして /dev/ttyUSB* を固定するやりかたもある。
Attachments (8)
- aruduino001.png (13.1 KB) - added by obina 6 years ago.
- aruduino002.png (6.7 KB) - added by obina 6 years ago.
- aruduino003.png (8.6 KB) - added by obina 6 years ago.
- aruduino005.png (33.3 KB) - added by obina 6 years ago.
- aruduino004b.png (15.3 KB) - added by obina 6 years ago.
- DSC05620s.jpg (91.3 KB) - added by obina 6 years ago.
- circuit.png (6.1 KB) - added by obina 6 years ago.
- arduino_simple.tar.gz (4.0 KB) - added by obina 6 years ago.
Download all attachments as: .zip