裸のハードディスクを動かしてみた。
ハードディスクの中を見たいという人がいたので、中身を空けて動作中の様子を見せるために、蓋を開けたまま使用してみた。先日、家を片付けていたら出てきた外付けのHDDを使って、蓋をあけて、パソコンに接続して、さて動作をみようとしたら、Linuxでのフォーマットの仕方とかを忘れてしまっていて手間取ってしまった。
ディスクが回転すると、引き起こされる風によってほこりは吹きとぶので、それほどほこりは気にならないということは聞いたことはあったのですが、思ったよりも大丈夫なようだ。いまのところ全く問題なく読み書きできている。もっとも、長期的にはダメだろうが。
最近では1Tとかも出てきて、容量はどんどん大きくなってきている。もうそろそろ限界に近い気もするのだが。
rubyを用いたsocketによる装置制御
socketで装置制御
研究室にsocketを用いて制御されている装置があるのだが、既成のソフトだといろいろと拡張することが困難である。socketの使い方がなんとなく分かって来たので、この装置の制御を試してみた。コマンドに関する情報が不完全なので、そのコマンドを調べながらだったので、それなりに苦労はしたが、とりあえず動くようにはなった。
少し問題だと感じるのは、socketからの入力で、バッファの中にあるものを読み取る方法が分からないということだ。readとかだとEOFまで読もうとしてブロックしてしまうし。getsでも、何行あるかが分からなければ、同じことだし。サーバーも自分で設計する場合には、データのやりとりの際に、データの量などをあらかじめ通信しておけば良いので問題はないでしょうが。
rubyでsocket
socketを使ったプログラムを書いてみた。
測定用の自動化には、いろいろな仕組みがある。全部、ひとつのプログラムがやっているのが多い気がするが、制御の部分にサーバーを立ててGUI部分がクライアントとしてそれにアクセスしに行っているようなシステムも見受けられる。装置の制御部分は、一つのタスクからのみにした方がconflictが無くて良いと思うので、それをサーバーに任せるというのは理にかなっているように感じる。
そこで、そのようなシステムを組む練習がてら、遅ればせながらsocketというものを使ってみた。rubyでは、socketを簡単に使えるらしい。試しに書いてみたサーバー部がこれ。
require 'socket' s=TCPServer.new(12344) Thread.start(s.accept){|cl| print "%s is accepted\n"%cl.peeraddr cl.each{|cmd| str="" case cmd.strip when "status" str=(rand(2)>0)?"good":"bad" when "color" str=["red","green","blue"][rand(3)] end cl.puts str } cl.close print "%s is terminated\n"%cl.peeraddr } while true
cygwin上で書いていたのだが、ポートは12345はトロイの木馬と勘違いされてだめだった。そして、クライアントはこれ。
s=TCPSocket.open("localhost",12344) 5.times{ s.write(["status\n","color\n"][rand(2)]) p s.gets sleep 2 } s.close
とりあえずは動くのだが、いろいろと気に入らない点がある。まず、クライアントからの入力に対して、出力を二行以上にしようとしたら、なぜかうまくいかなかった。print文が働かないように見える。それから、クライアントの接続が切れたことを認識してくれない。これだと、接続がつながって切れる度に、スレッドが増えていくことになってしまう。windows上で動かしているからなのかもしれない。時間ができたらlinux上でいろいろと試してみよう。 他の人が書いたプログラムとかを参考にいろいろと勉強しないといけないようだ。HTMLとかPOPなんかも勉強すると参考になるかな。
2008/12/25追記 接続を切ったときには、Errno::ECONNABORTEDというエラーが起こっているようだ。スレッドはこのエラーで終了してしまうので、どんどんスレッドが増えることはないようだ。気持ちわるいので、rescueとかensureとかでこのエラーが起こったときの対処をすれば、それなりに動いた。
2008/12/25追記 いろいろいじっているうちに、二行以上も受け取れるようになった。おそらく主な原因は、
p s.gets until $_=~/^END/
としていたが、
begin p s.gets end until $_=~/END/
と書き換えることによって、getsが条件判定よりも前に行うようになったからだと思う。untilが後にあるから、後に実行しているような気になっていた。でも、なんか変な気がする。
IOからの一行読み込み
readlineとgets
rubyには、似たようなmothodがいろいろとある。ファイルからデータを取り込んで処理する場合には、最近はreadで一気に読み込んで、改行でsplitしているが、一行ごとに読み込んだ方が良い場合もある。このような目的には、readlineを使っていたが、これだとEOFでエラーがでる。一方、getsでは、nilが返るので、プログラムが終了することはない。また、eachでもエラーになることはない。getsは一見何をするか分かりにくいので、あまり好きではなかったが、この方が動作が素直な気がする。これからは、eachを使うことにしよう。
LinuxのUMPC
ubuntu
最近、いろいxろなメーカーからUMPCと呼ばれる、小型で安価なモバイルPCが発売されている。ASUS,MSI,Gigabyteなどのマザーボードメーカー、Acer,MCJなどに加えて、Dell,HP,Lenovoなどのメーカー、さらにはNECや東芝などの日本メーカーも参入してきた。気に入らないのが、日本で発売されているものは、なぜかWindowsだということだ。海外ではLinux版もあるのに。これまで、有名なPCメーカーのものはあまり期待していなかったが、実はDellのInspiron miniでは、Ubuntu版があるらしい。他の会社のはまだ見つけていないが、あるのだろうか。
2008/12/20追記 やはり九月の発売の時点では、日本では初のLinuxということらしい。
arrayのmethod
いくつか便利そうなメソッドを知った。
rubyでプログラムを組んでいると、arrayをよく使う。当然、arrayのmethodも良く使う。arrayとhashをあわせてコレクションと呼ぶらしいが、これにはEnumerabuleのメソッドが数多くある。これをいかに使うかで、プログラムの見通しが良くも悪くもなる。
最近よく使うメソッドは、collect, select, sortなどだろうが、こんなメソッドがあったら、と思うことがある。そのいくつかは、すでにあるメソッドをうまく使うと良いことが分かった。例えば、
a.reject{|l| l~/^#/} a.grep(/^[^#]/)
の上のような使い方を良くしていたのだが、これは下のように書けることが分かった。ちなみに後者では、空の文字列も除ける。また、sortの時に、いちいち二つのものの比較を書くのが面倒だと思っていたが、
a.sort{|x,y| x.abs<=>y.abs} a.sort_by{|x| x.abs}
上と同じことを下のように書けるようだ。実際にはこれらは内部処理も異なっているようだが。それから、maxやminはあるけど、sumが無いと思っていたが、これは足すという作業は一般的ではないからだろう。しかし、
a.inject{|s,i| s+i}
とすると、合計を求めることができる。 あと、多項式の値の計算をどうやったらきれいに書けるかで悩んでいる。新しくメソッドを定義すればよいのだが、一行で書けるのならその必要もないし。とりあえず考えたのが、
x=1.2 s=0.0 [0.0,1.0,0.0,-1.0/6].each_with_index{|c,i| s+=c*x**i} p s
というものだ。これだと、新しく変数を定義する必要がある。次に考えたのが、
x=1.2 p [0.0,1.0,0.0,-1.0/6].reverse.inject{|s,c| s*x+c}
というものだ。これはとりあえずの目的は達しているように思われるが、直感的ではない。今のところこのくらいは仕方が無いのかな。collect_with_indexとかがあればもう少しシンプルに書ける気がする。
rubyの変数のスコープ
変数名の重複
変数名の重複があると、プログラムが予想外の挙動をする。昔使っていたBASICでは、すべての変数がglobalだった。つまり、サブルーチンでのみ使う変数の名前も重複してはならない。たとえば、forループなどで使うiさえも重複してはいけない。iを使ったforループの中で呼んだサブルーチンの中でiを使っていたら、問題が起きる。
一方、rubyでは特に指定しなければ、すべての変数はlocalである。サブルーチン(正確にはmethod)の中でどんな変数を使っても気にしないでよい。ブロックの中で定義した変数もそのブロックが終わったら無くなってしまう。普段は変数名にあまり気を使わないでよい。しかし、これに慣れすぎると、思わぬ失敗をする。
iteratorで使う変数は、すぐに開放されるので、同じものをよく使う。
4.times{|i| print i} data=open("test.dat","r"){|f| f.read.split(/\n/)} data.delete_if{|l| l=~/^#/} data.each{|l| p l}
こんな感じだ。この数日しか使わないであろうプログラムを書き殴っていて、iteratorの中でiteratorを使ってしまった。すると、当然のことながら、この変数が重複することになる。このとき注意しなければいけないのは、iteratorの変数が前もって定義されている場合には、変更されてしまうということである。その結果、予想しない結果になってしまう。そのあたりは、次期バージョンでは仕様が変わって、おそらくエラーが出るようになるようだ。 ちなみに今日知ったのだが、イテレータは古い表現で、最近はブロック付きメソッドというらしい。
Windowsでsleep
Windowsにはsleep命令がない
同じ処理を永遠にさせるようなバッチファイルを作ろうと思い、ウェイトのためにsleepを使おうとしたら、そんなコマンドないと言われてしまった。そのくらいの基本的なコマンドは用意しておいて欲しい。同じように困っている人も世の中には多いようで、調べてみたら良い方法を見つけた。
ping localhost -n 6 >null
とすると、だいたい5秒ぐらいのsleepと同じ挙動をする。あとは、gotoをつかって永久ループにすれば、バッチ処理をしてくれるバッチファイルができる。
rubyでRS232C
LinuxとWindowsの違い
RS232CのないPCも増えてきたが、装置の制御にはまだまだ使える。個人的にはGPIBの方が好きだが、今回はボードなどが見つからなかったので、RS232Cを使うことになった。
普段ならLinuxから制御するのだが、今回はWindowsを使わざるを得なかった。まあ、それほど違わないだろうと思っていたが、LinuxとWindowsでかなりやり方が違った。
Linuxでは、
r=open("/dev/ttyS0","r+") system("stty raw -echo -crtscts 9600 -parenb cs8 -ctsopb < /dev/ttyS0") r.write("read\n") print r.gets("\x0d\x0a")
という感じでやっている。Windowsでは、いろいろと調べたり試したりした結果、
system("mode com1 baud=9600 parity=N data=8 stop=1") r=open("com1","r+") r.write("read\n") s="" s<<r.sysread(1) until s[-1]==10 print s
というようになった。本当はsyswriteにすべきかも知れないが、writeでもとりあえずは動いている。しかし、readでは動かなくてしばらく悪戦苦闘していた。自分でLFを探さなければならないのも少し面倒だ。 まあ、苦労したおかげで、実験が多少楽にできるようになった。
FileUtils
rubyでfileのcopy
徹夜で実験していると、だんだん集中力が無くなってくる。絶対にやってはいけない誤りをしないように気を使う必要がある場合には、その他のことに割く労力を少しでも減らすようにするとよい。
測定が終わったら、そのファイルをコピーして、データを解析するという単純作業に飽きたので、その部分をrubyにまかせることにした。ファイルをコピーする方法があった気がして調べたら、FileUtileをrequireして使うらしい。昔は別のmethodを使った気がするのだが。徐々にrubyも変化してきているのですね。進化するのは喜ばしいのですが、あまり変わると覚えられなくなってしまうので、ほどほどの改良が望まれます。