2009-11-11[n年前へ]
■Rubyシリアル通信用スレッドクラスで簡単なバイナリ受信処理をしてみよう
以前、Rubyでシリアルポート通信(いわゆるRS-232C)を楽に行うためのクラス"ComThread"を作りました(ここが関連ファイルの置き場です)。そのcomThread.rbを使えば、たとえば、COM3で受信した内容をコンソールに出力するだけであれば、このようなコードで動く、というようなものです。
require 'comThread' receiveComThread=ComThread.new({:icomno=>3}) receiveComThread.start({:receive=>true, :receiveMonitor=>true}) sleep 60 receiveComThread.stopこれは、「シリアルポートを使って簡単に各種機器からの情報を取得したり、あるいは操作したりするためのクラス」です。もうひとつ例を挙げれば、「シリアルポートで受信した内容を最前面アプリにキー送信するアプリケーション」くらいであれば、以前書いたように十行程度のコードを書けば「はい、できあがり」という具合に(少なくとも私が良く見るシチュエーションにおいては)割に使いやすいクラスです。
ところで、シリアルポートで送受信を行う機器は多いですが、ものによってはASCII(アスキー)コードでなく、バイナリでデータを送ってくるものもあります。小型の計測器などでは、そんな風にシリアルポート(見かけ上はUSB接続で)経由で出力をバイナリ送信するものも多いかもしれません(もちろん、テキスト送信するものも多いです)。そんな場合でも、簡単なものであれば、comThread.rb でも普通に処理を行うことができます(データが頻繁に大量に送られてくるようなものは扱えません)。
そこで、バイナリデータをシリアルポートに送りつけてくる機器に対応するスクリプトを書いてみましょう。それは、たとえばこんな具合です。
require 'comThread' class Comport def receive(size) rcv=@com.receive ret=nil if rcv!=nil if rcv.length==size aHigh=rcv[0] & 0b00001111 aLow=rcv[1] re+=(aHigh*255+aLow).to_s end end ret end end period=ARGV[0] # time(seconds) Waint 10 # waint to activate teraterm receiveComThread=ComThread.new( {:icomno=>4, :ibaud=>57600}) receiveComThread.start( {:receive=>true, :receiveMonitor=>true, :delimeter=>4}) sleep period receiveComThread.stopこれは「4バイトのデータ列を定期的に出力する機器のデータを(COM4に57600bpsで受信し)パース処理した上で、その結果をテキストに変換しコンソール出力する」というスクリプト例です。
バイナリデータとしては、1バイト目のがハイバイトで、2バイト目がローバイトからなるデータ構成になっていて、さらに、ハイバイトは下位4ビットのみが使われる、というような処理がなされています。
サンプル用に書いたので、本来なら書くべき処理をはしょっています。それでも、数バイト程度のデータが、数秒の時間間隔で送信されるような機器のデータ加工程度の用途であれば、(たまにデータを処理しないで無視してしまうこともあるでしょうが)こんなものでも、(プロトタイピング用途としては)十分使うことができることもあるのではないでしょうか。
ところで、comThread.rbを少し手直ししました。そのため、(今日段階で置いてある)zipファイルは以前作ったものとサンプルソース類となっていて、comThread.rbの方は、今日少し作りなおしたものとなっています。異なるのは、ComThread.start の部分に、delimeter指定が入っていること・メンテナンスがしやすいように内部で使う関数の引数をHash(ハッシュ)で渡すようにした、ということくらいです。とはいえ、そのまま上位互換で使うことができるのではないか、(多分)と思います。動かない場合があれば、メールして頂ければ、時間を作って直しておきます。
ふと気付くと、最近Perlを触っていないような気がします。来週あたりは、Perlでも使って何かしてみることにしましょうか。
2009-11-14[n年前へ]
■「若さ」は勝つ
最先端【ロボマニア】という記事を読んだ。この 鉄腕アトムの腕だけなら! 「ロボットアーム」は手軽で最先端【ロボマニア】という記事を読んだ。このロボットアーム は、非力ではあるが確かに楽しい。
そのMOVE MASTERを思い出させるようなデザインのロボットアームがEK Japanから発売されている「MR-999」です。5つの関節(モーター)で構成されており、専用コントローラーで「ウィ~ン」と動かして物体を持ち上げたり、ピンポン球を移動させる競技などもできるので面白いですね。ドラえもんが好きだという人がいて、その人がこのロボットアームを貴重な小遣いを使い2本買っていた。自分の勉強のために、そして少しの楽しさのためにロボットアームを2本買っていた。その行動力がとてもうらやましく思うと同時に、とても感心したものだった。いつの間にか、彼女がMatLab/Simulinkでそのロボットアームを制御するまでになっていたのには心から驚かされ、感動したものだ。
実は、このロボットアームは手動ではなく、パソコンからプログラム制御で動かすこともできるんです。MOVIT-LAB II(IF-100)という専用のロボット制御インターフェイスボードを使い、アイコンを多様した簡単なアプリケーションでプログラム制御できます。このインターフェイスがセットになった商品「MR-999CP」も発売されています。ちょっとお買い得です。それと純正以外の制御ボードもあって、好きなプログラミング言語でのプログラミングも可能です。共立電子から発売されているリレーボードRBIOシリーズです。このボードは、前回ご紹介したプチロボシリーズと同様な方法で、シリアルポートにコマンドを送る方法で制御できる方式を採用しています。
よく、「若さ」に勝てるものはないよなぁ・・・と思う。私がVBAを教えたはずの人が、もう私には全然わからない次元のVBAマクロを組んでいたり、Perlを紹介した人が、さまざまなことをPerlを駆使して自動化していたりした時には、「若さ」に勝てるものは(なかなか)ないのだな、と実感した。
「愛」は勝たないことも多いからこそ「愛は勝つ」が売れた、と誰かが書いていた。けれど、「若さは勝つ」とは誰も言わない。それは、「若さ」が勝つことが多いから、と信じたいものだ。
2009-12-15[n年前へ]
■ComThreadを使った「制御プログラムの作り方」図解編
以前、Rubyでテキストや(比較的単純低速な)バイナリデータ送受信のためのクラスであるComThreadを作りました(情報ページ)。それでは、どんな風に使うかということも、これまた以前、ComThreadを使った「制御プログラムの作り方」に書いたことがあります。
ComThreadという名前が、実にありがちな名前であるので、他のライブラリともしかしたら混同されているのかもしれませんが、「送受信に2つのポートを必要とするのか?」という質問があったので、「そんなことはないですよ」とここに書いておきます(もしかしたら、最初に作成した際の紹介記事の2番目の例が、機器間のシリアル通信をモニタリングする例だったから、そういう風に勘違いされたかもしれません)。
最初の記事の2番目の例、すなわち、機器間のシリアル通信をモニタリングする例は、AとBという機器間で行われている通信をモニタしたい、AとBは通常通り通信しあう関係にしたままで、その互いのやり取りを知りたい、という場合に、シリアル通信の内容を調べる、というプログラムです。つまり、簡略図にすると、A<->Bという関係をA<->PC<->Bというにしてやり、PCはAから受信した内容をBに送り、Bから受信した内容をAに送るわけです。だから、PCからみると、機器Aへの接続を行うCOMポートと、機器Bへの接続を行うCOMポートの2つが必要だったというわけです。
もちろん、それは2機器間の通信をモニタリングする例だったからで、(最初の紹介記事の)一番最初に挙げた例のように、1つの機器相手に送受信を行うだけであれば、当たり前のはなしですが、COMポートは1つしか必要としません。
さて、これだけではつまらないので、今日は、ComThreadを使った「制御プログラムの作り方」で書いたことを図にしてみました。つまり、前回、文章とコードで書いた内容を「図」にしてみました。それが下の図になります。
前回書いたように、(センサーやモーターといった)各ハードウェア機器に対するモデル・クラスをConThreadクラスを継承させて作り、また、制御を行うコントローラをThreadクラスを継承して作り、そのコンローラインスタンスに、各モデルのインスタンスを渡してやる、というのがComThreadを使い、複数機器を制御するのであれば、一番整理しやすいような気がします。
つまり、(各ハードウェア)モデル・インスタンス(スレッド)を作成し、コントローラ・インスタンス(スレッド)を作成して、(各ハードウェア)モデル・インスタンスをコントローラ・インスタンスに渡した上で、必要な期間だけそれらのスレッドを動かしておく、というようなスクリプトを作る、という具合です。
2009-12-28[n年前へ]
■VISTAで使うUSB接続シリアルポート+wincom.rb
「TEXCELLのRubyシリアル通信ライブラリ wincom.rb で、(WindowsXP上では受信できるのに)Windows VISTA上では、レガシーなCOM1ではデータ受信できるが、(Prolificのチップ・ドライバーを使った)USB I/F接続シリアルポート接続では受信できなかった」という記事を読んだ。原因は、
Vista環境にて、USB接続シリアルポートでは、(Windows APIの)ReadFileを実行した際、「読み取ったバイト数」として常にゼロが帰ってくるため。ということで、USBシリアルI/Fドライバのバグらしいが、考えてみれば、「VISTAマシンでシリアル接続をしたことがないことに気づいたこと」「ATEN製UC-232A・シグマAPO製URS232GFと同タイプを使う可能性もあること」から、リンク先の記事にあった対処法を自分用に書き写しておく。機会があれば、自分でも確認してみよう、と思う。
対処法:ReadFileの「読み取ったバイト数」は使わず、ClearCommErrorを実行した際に得られたCOMSTAT構造体の「受信バッファにあるデータ・バイト数」を使う(常に0バイトよりはマシだ)。def receive # rcvchar=@wcrecv.unpack("a#{irlen[0]}")[0] rcvchar=@wcrecv.unpack("a#{ilen}")[0]
2010-04-05[n年前へ]
■Windowsディレクトリが壊れて、「Rubyコード」になっていた。
Windows マシンで、ディスクの一部にアクセスできなくなりました。正確にいえば、ディレクトリにアクセスはできるのですが、そのディレクトリの中身が「ワケがわからない状態」になってしまっているのです。それが、下の画像です。
何だか、とても奇妙な状態です。まるで、何やらRubyのコードのようなファイル・ディレクトリ名が並んでいる…ような気がします。このディレクトリには、Rubyのコードなどないはずなのですが、何やら、Rubyでスレッドを使って書いたシリアルポート制御プログラムが透けて見えるような気がする感じです。
こういう現象というのは、一体どういう時に起きるものなのでしょう?そして、どうしたら、こんな現象を回避することができるのでしょうか?
ディレクトリが壊れるたび、そのディレクトリが色んな言語の化身に変身したら「面白いだろうな」と少し思いおかしくなります。1時間ほど作業した内容がすべて消えたので、結構ショックなのですが、消えたファイル群が「Ruby プログラム」になっていたりしたので、少し楽しくなったのです。