rubyのページ

ここでは,rubyを用いて装置の制御をどのようにしているかについて解説したいと思います. 英語のページと差別化を図るために,Linux上からの制御についてに焦点を絞ります. Windowsは英語のページを参考にして下さい.

Debianのインストール

Linuxもいろいろありますが,ここではDebian SargeまたはEtchを用いることにします. 詳しくは,Debianのページを参考にして下さい.

rubyのインストール

とりあえずは,
apt-get install ruby ruby1.8-dev
ぐらいで良いでしょう. Tkを使う場合には,
apt-get install libtk-ruby tk8.4
とでもしておきます.

GP-IBをrubyから制御

linux-gpibのインストール

GP-IBを使うためにlinux-gpibをインストールします. ソースから自分でコンパイルしても良いですが,Sargeのkernel2.6では,aptで取ってきて,module-assistantで処理すれば済みます.kernel-headersは使用しているkernelのものを使って下さい.
apt-get install gpib-modules-source
apt-get install kernel-headers-2.6.8-3-686
apt-get install module-assistant debhelper
m-a a-i gpib
apt-get install libgpib0 libgpib-bin libgpib0-dev
そして,/usr/src/にできたgpib-modulesをdpkg -iでインストールします.

なぜか,Etchには,gpibのパッケージが無いようですので,ソースを取ってきてコンパイルします. Debianのページを参考にして下さい.

一般ユーザーが使えるようにするためには,/etc/groupを編集して,gpibグループに加えて下さい. また,必要に応じて/etc/gpib.confを編集して下さい. とりあえずは,ボードの設定のところのboad_typeとnameだけで良いと思います. ボードが一枚ならname="dev0"です. あとは,立ち上げのときに組み込まれるように設定しておきます.

echo "alias char-major-160 gpib_common" >>/etc/modprobe.d/gpib
echo "alias gpib0 tnt4882" >>/etc/modprobe.d/gpib
echo "install tnt4882 /sbin/modprobe --ignore-install tnt4882;/usr/sbin/gpib_config --minor 0" >>/etc/modprobe.d/gpib

ruby-gpibのインストール

ruby言語supportは,残念ながらまだdebianには組み込まれていないようです. しかし,RAAにあるruby-gpibを利用すれば,rubyからGP-IBを使えるようになります.
wget http://www009.upp.so-net.ne.jp/sakura_home/gpib-ruby.tgz 
tar xfz gpib-ruby.tgz
cd gpib-ruby
ruby ./extconf.rb --with-gpib-include=/usr/include/gpib
make
make install
このとき,ruby1.8-devとflexが必要なようです.

プログラム

あとはGpibを呼び出せば使えます.
require "gpib"
adrs=3
g=Gpib::new(adrs)
g.write(command)
てな感じです.

パラレルポートをrubyから制御

パラレルポート,正確にはセントロニクスのプリンターポートは,単純な外部機器を制御するのに非常に便利です. あたらに投資をする必要もありませんし. 詳しい説明は省きますが,パラレルポートは8本のデータバスと9本のシステムバスからなり,データバスはモードにより出力のみまたは入出力が可能で,システムバスのうち5本は入力で,4本は出力です. これだけの入出力があれば,簡単な装置の制御には十分です. 個人的には,ステッピングモーターやバルブの制御,さらにはGP-IBエミュレーションなどをやって使っています. 最近は,AVRと通信するときにも使ったりもします.

パラレルポートの設定

Linuxから使うためには,デバイスの設定が必要になります.
mknod /dev/parport0 c 99 0
chgrp lp /dev/parport0
chmod 660 /dev/parport0
一般ユーザーが使えるようにするためには,/etc/groupを編集して,lpグループに加えて下さい.

プログラム

もし他のプログラムがlpを使っている場合には,rmmod lpとして開放して下さい. あとは/dev/parport0を開いてioctlで指示すれば良いようなのですが,これを手軽に行うために,parport.rbを作ってみました.
require "parport"
p=ParPort::new()
p.strobe=1
p.command()
p.write(0x20)
というように使えます. 詳しくはソースを見てもらえば分かるのでは無いでしょうか. readするためには,BIOSの設定で,プリンターポートのモードををbi-directionalまたはEPPに設定する必要があります.

シリアルポートをrubyから制御

いわゆるRS232Cですが,最近のPCからは徐々に姿を消しつつあります. しかし,これを使って制御する機器もまだ多いので,使えるようにしておいた方が良いでしょう.

シリアルポートの設定

特に設定は必要ないと思います. permittionぐらいを確認しておけば十分でしょう.

プログラム

通常のファイルと同様にopenして読み書きすれば良いのですが,初期状態では,echo backするようになっていますので,sttyで-echoするのが重要です. あとは仕様に合わせて設定して下さい.
s=open("/dev/ttyS0","r+")
system("stty raw -echo -crtscts 9600 cs7 parenb -parodd </dev/ttyS0")
# 9600bps 7bit, 1 stop bit, even parity
s.write("write")
r=s.gets("\x0d\x0a")
改行がLinuxと機器で異なる場合には,あからさまに指定して下さい.

GUIをrubyで作る

ユーザーインターフェースとしては、通常はCUIで十分ですが、それでは使いにくいと感じる人も多いでしょうし、実行している最中に、条件等を変更したりするためには、GUIが便利かも知れません。 rubyそのものにはGUIはありませんが、ruby/tkを用いることで、GUIを作ることができます。 しかし、測定によく用いられている言語と比較して、ruby/tkには欠点もあります。 まず、比較的マイナーなために、情報が限られています。 また、グラフ等の測定によく用いられるようなものを実現する部品がほとんど知られていません。 ここでは,それらの欠点を補う一助になればと思って書きます.

ruby/tkのインストール

これは前にも書きましたが,こんな感じです.
apt-get install libtk-ruby tk8.4

tkの基本

Tk.mainloopを実行すると,tkでのGUIが使えるようになります. 逆に,別の処理をしているときには,GUIは動かなくなってしまうので, GUIを使いながら処理をする場合には,Threadで走らせておくと良いでしょう.
require 'tk'
include Tk
Tk.mainloop
新しいwindowをつくるときには,TkToplevelを作ります.
TkToplevel.new
titleメソッドでタイトルを指定できます.

Widget

root widgetまたはtop level widgetにwidgetをpackを使って配置していくことによって,GUIを作っていきます. 各widgetを作るときの第一引数で親Widgetを指定する場合が多いのですが,nilだとrootが指定されたことになります.

frame

packをつかっても,うまく配置できないときには, TkFrameを使って,その中にpackするとうまくいく場合があります.
f=TkFrame.new(nil,"relief"=>"ridge","borderwidth"=>2).pack('side'=>'left')
f1=TkFrame.new(f,"relief"=>"groove","borderwidth"=>2).pack('side'=>'left')
f2=TkFrame.new(f,"relief"=>"groove","borderwidth"=>2).pack('side'=>'left')
TkLabel.new(f1){text("label1")}.pack('side'=>'top')
TkLabel.new(f1){text("label2")}.pack('side'=>'top')
TkLabel.new(f2){text("label3")}.pack('side'=>'top')
TkLabel.new(f2){text("label4")}.pack('side'=>'top')
reliefの種類としては,raised, sunken, flat, groove, ridgeなどがあるようです.

label

TkLabelはテキストを表示するために使います. textメソッドで表示するテキストにアクセスできます. text=でも,text()でも良いみたいです.
TkLabel.new{text("label")}.pack('side'=>'top')

entry

TkEntryはテキストを入力するために使います. valueメソッドで値を指定したり,取得したりできます.
e=TkEntry.new{width(10)}.pack('side'=>'top')
e.value="entry"

button

TkButtonはボタンを作るために使います.
TkButton.new{text('line');command(proc{exit})}.pack('side'=>'top')

radiobutton

ひとつの項目を選択するときには,TkRadiobottonを使うと便利です. 同じTkVariableで定義されたもののうち,一つだけが選択されます. TkVariableのvalueメソッドで値を取得できます.
v=TkVariable.new(0)
TkRadiobutton.new{text('a');value(0);variable(v)}.pack('side'=>'top')
TkRadiobutton.new{text('b');value(1);variable(v)}.pack('side'=>'top')

checkbutton

それぞれの項目を選択するかしないかを指定するときには,TkCheckbuttonを使うと便利です. 同じTkVariableを指定すると,ボタンが同期します. TkVariableのvalueメソッドで値を取得できます.
v=TkVariable.new(0)
TkCheckbutton.new{text("a");variable(v);onvalue(1);offvalue(0)}.pack('side'=>'top')

listbox

いくつかの項目の中から,いくつかを選択するときには,TkListboxを使うと便利です.
l=TkListbox.new{width(30);height(15);
  selectmode('multiple');exportselection(0);
  }.pack('fill'=>'both','expand'=>true,'side'=>'left')
l.insert('end','first')
l.insert('end','third')
l.insert(1,'second')
insertメソッドで項目を加えていきます. 項目を消したいときは,deleteメソッドを使います. 選択されているものは,curselectionメソッドを使うと番号の配列として得られます. selection_setやselection_clearでプログラムから指定したり,はずしたりできます.

menubar

一番上にメニューを追加するには,以下のようにします.
menu=[
[['File',0],
  ['Load',proc{file_load()},0],
  '---',
  ['Quit',proc{exit},0],
  ],
]
TkMenubar.new(nil,menu,'tearoff'=>false,'foreground'=>'blue',
  'activeforeground'=>'red').pack('side'=>'top','fill'=>'x')
最初のnilは,親wedgetの指定を無視したものです. optionとして指定しているものは,configureオプションを使っても変えることができます. ここで,配列の中の数字は,メニューに表示する文字の下線が引かれるものの指定です. 細かい指定の仕方は,/usr/lib/ruby/1.8/tk/menuspec.rbを見て下さい.