wiki:epics/arduino/simpleRead

Arduino と EPICS を使った簡単な例

家庭でも遊べるように、簡単なサンプルをつくることを目的とする。
「ArduinoはUSBシリアル経由でデータを垂れ流しにする」「EPICS IOC(Raspberry Pi) 側からコマンドは送らず、Listenするのみ」という構成とした。
今回作成したEPICS IOC, Protocol File 等は attachment:arduino_simple.tar.gz にまとめて置いてある。

準備

  • Arduino Uno
  • PC
  • 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* を固定するやりかたもある。

Last modified 4 weeks ago Last modified on 09/26/18 21:36:21

Attachments (8)

Download all attachments as: .zip