hirax.net::Keywords::「シリアル・ポート」のブログ



2009-07-29[n年前へ]

wincom.rbのCOM10以上対応 

 以前、スレッドを使い、Rubyでシリアル通信をするクラスComThreadを書きました。このクラスは、wincom.rbを利用しています。

 少し前、wincom.rbが、COM10以上の番号のシリアル・ポートを開けないことに気づきました。ソースを眺め調べてみると、WindowsAPIのCreateFile()を使った場合の、COM10 以上のシリアルポートを指定方法に沿っていないことが原因でした。対処としては、wincom.rbの71行目を

comno = "\\\\.\\COM#{icomno}\0"
というように変えれば、COM10以上のポートにも(もちろんCOM10以下のポートにも)対応するようになります。

 最近の(各種I/Fがたくさん備えている)PCに、USB接続のシリアルポートI/Fを繋いだ場合、自動的にCOM10以上になる場合も多いと思います。そんな状況下で、wincom.rbを使うためのTipsとして、ここにメモを書いておきます。

2009-07-30[n年前へ]

ComThreadを使った「制御プログラムの作り方」 

 比較的単純なハードウェア制御、たとえば、(シリアル・ポートから値を得ることができる)センサからの入力を使い、(シリアル・ポートからコマンドを送ることで制御することができる)ハードウェアの制御をしたくなることがあります。実例としては、温度センサの値を使い、扇風機のモーターON/OFFを行いたい、というような場合があります。そんな場合のために、(以前作った)RubyのComThreadを使った「制御プログラムの作り方」を、自分のためのメモがてらここに書いておこうと思います。

 まずは、センサーやモーターの各ハードウェア、つまり、各シリアル・ポート毎に個別のクラスを作っておきます。たとえば、センサーの値にアクセスするクラスをこんな感じで作り、

require 'comThread'

class SensorComThread < ComThread
  def start(condition={:receive=>false,:send=>false,
    :receiveMonitor=>false,
    :sendMonitor=>false})
    @info={}
    super
  end
  attr_reader :info
  def receive(data)
     @info=data.gsub(' ','').split(',')
  end
end
次に、たとえば、モーターを操作するクラスをこんな感じで作ります。
require 'comThread'

class MotorComThread < ComThread
  def sendStart
     send("start")
  end
  def sendStop
     send("stop")
  end
end
 各シリアル・ポートに接続された機器に対する「値解釈」や「送信コマンド作成」といった部分は、上のような具合で、各ポート(に接続された各種機器)を扱うクラスを個別に定義しておく方が頭が整理しやすいように思います。

 そして、次は制御用のメイン・コントローラ・クラスを書きます。

require "thread"

class ControlerThread
  def initialize
  end
  def start(inf)
    @sensor=inf[:sensor]
    @motor=inf[:motor]
    @thread=Thread.new do
      while true
         @motor.sendStop if @sensor.info[0].to_f<hoge
         @motor.sendStart if @sensor.info[0].to_f>=hoge
      end
    end
  end
  def stop
    Thread.kill(@thread)
  end
end
 

 最後に、センサ用コントローラ/モータ用コントローラ/メイン制御コントローラを、それぞれ起動する制御スクリプトを、次のように書きます。

require "sensorThread"
require "motorThread"
require "controlerThread"

sendorRq=Queue.new; 
MotorSq=Queue.new;
sensor=SensorComComThread.new(1,sensorRq,nil,
    0x1807,38400) 
sensor.start(:receive=>true)
motor=MotorThread.new(2, nil,motorSq,0x1807,38400) 
motor.start(:send=>true)
  controler=ControlerThread.new
  controler.start({:sensor=>motor,:motor=>motor})
    sleep ARGV[0].to_i
  controler.stop
motor.stop
sensor.stop
 このように、各I/Fに対するコントローラと、メイン制御コントローラと、それらコンローラ・スレッド群を実行するシーケンス・スクリプトを個別に作る、というのが良いように思われます。

 というわけで、日曜大工的なハードウェア制御プログラムを書いたので、プログラムを書き連ねながら考えたことを、ここに『ComThreadを使った「制御プログラムの作り方」』として書いてみました。



■Powered by yagm.net