マークシートリーダ交換

概要

マークシートリーダを交換したため読み取りソフトウェアを書き換えなければならなくなった。Javaで書こうと志したが間に合わず、とりあえず F-BASIC で当面間に合わせることにした。

RS-232Cで接続し、SR-600互換モードで動作させることで、生のデータを得るところまでを記録した。

セコニックの SR-505が使えなくなった

まず機器を交換せざるを得なくなった経緯。

試験の採点やアンケートの集計にマークシートリーダ(OMR:Optical Mark Reader)を導入したのが1990年12月11日。昨年2011年2月まで故障もなく働いてくれた。ただローラーは消耗品で交換が必要。製造中止から部品の保管期限がきれる時に交換してもらったローラーもついにベタベタになり紙送りがうまくいかなくなった。

このため後継機を新規購入。採点・集計プログラムを移植することになった。

後継はセコニックの SR-3500(機種選択)

以前の機械はセコニックの SR-505。A4程度の用紙に24行(センサが24)。60枚/分の性能。コンピュータはNEC98シリーズ。接続はRS-232C。プログラムはN88-BASICであった。

今回の機械はおなじくセコニックの SR-3500。A4までの用紙に32行(センサが32)。58枚/分の性能。ただしIBM形式大きさのカードやハガキの大きさの紙も通せる。接続はUSBまたはRS-232C

購入時に本当にソフトウェアはいらないのかと念を押されたが、SR-505では自作プログラムで運用していたのでコストと運用の自由度を考えて本体だけとした。Windows用のドライバとVCのサンプルプログラムが入ったCDはついてきた。

プログラムはjavaにしたい(当初の計画)

素直に考えると、Windows上でVC++を使いUSBで接続となる。PCも1台OMR専用のを設置することになるのでWindowsでもよいのだが、OMRは測定器と同様の使われ方をするもの。日頃、計測・制御の分野こそオープンソースでやりたいと考えていたことからなんとか次の組み合わせでできないかと考え始めた。

  1. OSはLinux
  2. プログラミング言語はjava
  3. 接続はUSB

プリンタなどと同様、メーカーの用意するドライバはWindows用のみ。

意外にもjavaからUSBにアクセスするための道具が揃っていない。RS-232Cについても標準のライブラリでは使えず拡張をいれるなどいろいろ面倒な割に情報が極めて少ない。

結局F-BASICでプログラムを組む

しばらく調べたが、結局移植の期限が迫り、次のように妥協せざるを得なくなった。(これでも一旦退却しただけでまた挑戦するつもりではいる)

  1. OSはWindows(2000またはXP)
  2. プログラミング言語はF-BASIC
  3. 接続はRS-232C

F-BASICは富士通が出していた製品で現在は販売終了となっている。N88-BASICで運用していた本校の校務のシステムをNEC98の製造中止に伴ってWindows上に移植するために購入したもの。javaで書き直す計画はあるもののF-BASICで作られたプログラム群は現役である。

F-BASICで作られたプログラムは Windows 7 でも動作するが、F-BASICそのものはWindows2000までしか動作が保証されていない。このため現在でもWindows2000を残している。

しかし、最近エディタに別のものを使用し、コンパイラ部分だけを利用するならばXPやvistaでも使えることが経験的にわかってきた。もっとも私が使っているのはN88-BASICからの移植の手続き型のプログラムなのでフォームの上にボタンを配置してという機能は一切使っていないからかもしれない。

ただ経験的にF-BASICのエディタはもともと動作がおかしいところがあった。コンパイルできてエラーの場所が行番号で示されれば、私の作業には十分である。

RS-232Cでつなぐ

RS-232Cの9ピンのストレートケーブルが必要。RC-232Cケーブルは見た目ではわからない。各ピンが同番号で繋がっていればいいのでテスターで確認した。PC側にも232Cのコネクタがあるものを用意する。USBとの変換アダプタもあるようだが、ポートの違いなどでトラブルの可能性がある。

RS-3500 を RS-600モードにする。本体のメニューから設定できる。

デフォルトのパラメータは次のようになっていた。

RS-3500側ではフロー制御は なし | RS/CS | Xon/Xoff の三択である。

できるだけデフォルトで接続したい。

F-BASIC では次のようにオープンする。

baud 0,38400
open "COM0:(S7N2N7E)" as #1
            S clock:dumy
             7 bit:7/8
              N parity:N/O/E
               2 stop bit:1/2
                N Xon/Xoff:X/N
                 7 jis:7/8
                  E flow(RTS/CTS):N/E

F-BASICでは整数は2バイトの符号つき整数だからボーレートの38400は限界を超えてしまう。ロング整数(F-BASICの言い方)にして38400&と書く必要があるとマニュアルにある。リテラルで&なしで書いても受け付けられたが都合によりロング変数に代入しておいて使用した。

nbaud& = 38400&

F-BASIC側のフロー制御はXon/XoffをX/Nで、RTS/CTSとDTR/DSRをそれぞれN/Eで切り替える。そこでXon/XoffをNにし、RTS/CTSをEにして、DTR/DSRは触らずデフォルトのNのままにする。

0は、2つあるいは4つあるRS-232Cポートの番号である。

とりあえず読むプログラム

N88-BASICで作ってあるプログラムのうち一番短い生のデータを読んで表示するだけのものを移植する。実際のプログラムは用紙の解答欄も表示するので、マークデータの部分だけ拾って解説する。

nport = 0
nbaud& = 38400&  '9600 19200 は整数でよいが、38400はロング整数
COMMPORT$="COM0:(S7N2N7E)"

baud nport,nbaud&
OPEN COMMPORT$ as #2

わざわざ変数に入れるのは設定をまとめておきたいから

入出力の指定を省くことで、inputもoutputもこのファイル番号で行うことができる。

読みやすくするためいくつかの定数と関数を定義。以下の解説では★しか使用していない。

CR$=CHR$(&HD)                   '&H はF-BASICで16進数の前につけるもの★
RDCMD$="?"+CR$                      'シートを1枚読み,エラーコードを返すコマンド★
TMCMD$=CHR$(&H5)+"T"+CR$        'タイミングマーク数を問うコマンド★
CCMD$=CHR$(&H10)+"C"            'データ転送を指示するコマンドの冒頭部  6Bytes chr 形式
DCMD$=CHR$(&H10)+"D"+CR$        'データ転送を指示するコマンド(1欄のみ) 6Bytes chr 形式
ECMD$=CHR$(&H10)+"E"            'データ転送を指示するコマンドの冒頭部  可変長文字列形式★
FCMD$=CHR$(&H10)+"F"+CR$        'データ転送を指示するコマンド(1欄のみ) 可変長文字列形式
DEF FNSTR0$(X,N)=RIGHT$(STRING$(N,"0")+MID$(STR$(X),2),N)   '66(int) -> 066(N桁のstring)★

プログラムはこんな感じ。

PRINT #2,RDCMD$;                'シートを1枚読みエラーコードを返すコマンド
E1$=INPUT$(1,#2)                '1バイトを読む。これが0なら読み込み成功
PRINT #2,TMCMD$                 'タイミングマーク数を問うコマンド
TMMK=VAL(INPUT$(3,#2))          'レスポンスは3バイトの文字列で来るので数値に変換している
PRINT #2,ECMD$;"001";FNSTR0$(TMMK,3);CR$;  '最初からタイミングマーク数までデータを転送させる
FOR T=1 TO TMMK
    line INPUT #2,SE$(T)        '転送させたデータをバッファから読む。ここのlineはシートの欄にあたる
    print se$(t)                '画面に表示する。
NEXT

実際のプログラムではシートのイメージが表示されるが、ここでは簡単のため生で表示している。

また、上記ではシートを1枚しか読まない。もちろん読み終わったら礼儀正しくクローズする。

close #2

このプログラムの骨子の部分はSR-505とほとんど同じである。セコニックのコマンド体系が変わっていないと言うことである。ただしSR-3500のマニュアルにはRS-232Cで使う場合のコマンドは全く記述がなく、SR-600互換モードなので、SR-601のマニュアルをセコニックのウェブサイトからダウンロードして確認する必要があった。

SR-505に比して一番の変更点は行数(OMRではマークを読むために並んだセンサの数)が増えたこと。SR-505は24だったので、ECMD$で返される行を表す記号が ABCDE.....STUWX でよかった。SR-601やSR-3500は32あるので 01234....LMNO となる。中にはコロン、セミコロンなどの記号が含まれるので、input文で入力するとデータの区切りと解釈してしまう。line inputでなければならない。

Eコマンドで得られるデータ

次の図は本校の2011年度入学試験理科の解答用紙である。A4用紙を横長に使っているがその左の一部を90度回転して示している。

この紙は図の上方に送られてマークリーダーに入っていく。マークリーダーは上から下に読んでいくことになる。

マークシートの例

タイミングマークが左にあり、このマークの位置でマークを読む。説明のためさらに左に青色で「欄番号」を書いておいた。

上部に橙色で示した記号は行を表す記号。要するにこの場所にセンサーが取り付けられているのでセンサーの番号と考えてもよい。図に橙色の帯で 0 の行と B の行を示した。

ただし、このシートはSR-505用に設計されているので行のピッチが0.30インチである。それで行は25までしかないが説明には問題ない。

上に示したプログラムではデータはSE$(T)という配列に読み込まれる。図に対応させてどのようなデータになるかを示すことで詳細の説明を省く。

SE$(1) "D"
SE$(2) "C"
SE$(3) "0B"
SE$(4) "A"
SE$(5) "?"
SE$(6) "01;B"
SE$(7) ">C"
SE$(8) "6A"
SE$(9) "7@"
SE$(10) "="
SE$(11) " "
SE$(12) " "
SE$(13) " "

マーク以外の手書き部分も位置や太さ濃さが適度であればマークとして認識される。(細い字だと紙の送りの誤差があるので紙を通すたびに読んだり読まなかったりする)

たとえば1~4欄ではG行に3456の手書きがあり、2,3ではHのところにスミで受験番号とあるのでこれを読むかもしれない。 これを読んだとするとデータは次のようになる。

SE$(1) "DG"
SE$(2) "CGH"
SE$(3) "0BGH"
SE$(4) "AG"

このデータから受験番号や解答を読み取るにはさらに処理が必要になるが、とりあえずここまでで、マークリーダーからデータを受け取るところまではできたということになる。


Jan.2012
安達順一
http://www.seiai.ed.jp/