手軽に使えるサーマルプリンタの代表格『DP-EH600』。画像印刷が遅いというデメリットを克服するため、さまざまな手段を使って(ときには謎のツールも使いながら)高速化する手法を紹介する。
〈投稿者: 斎藤公輔(NEKOPLA)@kawausokawauso〉
組込みエンジニア。エアコンの配管や室外機を愛でながら、ときにはデジタルガジェットを制作したり、ライターとしてデイリーポータルZなどに寄稿したりする生活を送る。
味わい深いサーマルプリンタの世界
サーマルプリンタとは、レシートでお馴染みのインクを使わない感熱式プリンタである。印刷できるのは黒一色のみ。グレースケールのように白と黒の中間色を表現することもできないため、写真を印刷するときなどは「誤差拡散法」という画像処理を使って、黒の密度で濃淡を表現するのが一般的だ。
実際に印刷してみるとこんな感じ。「白黒二値」という制約が付くことで、一周回って強烈な味わいを生み出している。最近ではアナログレコードや「写ルンです」が再ブームになっているというし、サーマルプリンタが時代の先端となる日も近い。
あまりにも良い感じなので、以前レシートに印刷するインスタントデジカメを制作したこともある。その様子はこちらをどうぞ。
そんなサーマルプリンタの中でも、お手軽に使えて、しかも安いのが『DP-EH600』なのだ。
DP-EH600が良い感じ
『DP-EH600』は、OEM先によっては『CSN-A2』とも呼ばれている中国製のサーマルプリンタである。制御インターフェースはUARTで、動作電圧がDC 5~9V、負荷時の電流も1.5A程度ということで、メイカーにとっては非常に扱いやすい仕様となっている(一部ショップではRS-232C版も併売されているので注意)。
ただ一番の欠点は、UARTのボーレートが9600bps(一部には19200bpsの個体もある)と低速なところだ。その影響で、画像を印刷するのが非常に遅い。
と、ここで速度の話をする前に――以降は、速度比較のリファレンス画像として「室外機くん」(原作: TOKYO FLIP-FLOP、作画: koro)を使用する。解像度は384x1280pxの白黒二値PNG形式。ちなみに横幅384pxというのは、DP-EH600で印刷可能な最大サイズである。
この「室外機くん」を9600bpsで印刷すると……
見ての通り、めっちゃ遅いのだ。なんと64秒もかかってしまった。
このままではとても使い物にならない。どう考えても9600bpsがネックになっているので、なんとかUARTの一般的な最高ボーレート115200bpsで動くようにならないものだろうか……。
で、いきなり結論からいうと、115200bps化に成功した。そのうえで、印刷パラメータの調整も行った最終型での速度がこちら。
印刷時間は、なんと7秒! 実に9倍もの高速化に成功した。
この高速化チューニングを行うことによって、DP-EH600は他を大きく引き離す最強に近いサーマルプリンタとなる。安い、早い、使いやすいの、三拍子そろったメイカー向けサーマルプリンタの誕生である。
速度を比較するとこんな感じ。これなら十分実用に耐える。それでは、この高速化を実現する方法を順番に説明していこう。
注:本記事では「Raspberry Pi 3 Model B」を使った方法を紹介する。他にもUARTが使えるマイコン(Arudionoなど)なら、同様の制御は可能である。あとサーマルプリンタを高速化するには、今のところ専用ツールを使う都合でWindows PCが必要である(Macは不可)。いろいろと追加部材も必要なのでご注意を。
なお、改造は自己責任でお願いします。
UARTを使用可能にする
まずは、普通にDP-EH600を使えるようにするところから。
ラズパイでUARTを動かすためには、/boot/config.txt
をエディタで開いて、末尾に以下の設定を追加する。
enable_uart=1 dtoverlay=pi3-miniuart-bt
次に /boot/cmdline.txt
を開き、
Before:
dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=3957d075-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
After:
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=3957d075-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles
console=serial0,115200
という部分だけを削除する(その他の記述は残す)。このあと再起動すれば、UARTが使用可能な状態となる。
ハードウェアのセッティング
DP-EH600本体には、3ピンのXHコネクタが2つ付いている。ひとつが電源用で、もうひとつがUART用だ。
コネクタ形状が同じなので、間違えて刺さないように注意したい。
電源の接続
付属品としてケーブルが2本入っているので、まずは電源用のケーブルをぶった切って、先端にDCジャックを接続する。これで一般的なACアダプタで使えるようになる。
電源はDC 5~9Vで、電流容量は1.5A以上のものが推奨されている。ACアダプタでもいいし、モバイルバッテリでも余裕で動作する。
電源に問題がない場合、正面についているボタンを押しながら給電すると、自動でテスト印刷が始まる。ここで印刷された内容を見れば、現在のボーレートが分かるようになっている。
「波特率」というのがボーレートのことだ。まだ何も手を加えてないため、やはり9600bpsとのこと。もし19200bpsだったあなたは、ちょっとだけラッキーである。詳しくは分からないけど、OEM先によって設定が微妙に違う個体が混ざっているのが確認されている。
UARTの接続
次はUARTの接続。ラズパイ側は、#8 がTx(送信)、#10 がRx(受信)となっている。そこにDP-EH600のTxとRxをクロスする形で接続する。GNDをつなぐのも忘れずに。
これでひとまず、初期設定9600bpsで動かすための準備は完了だ。
テスト印刷する
DP-EH600の制御コマンドは、こちらの仕様書に書かれている。
自分でドライバを作っても良いし、検索すれば誰かが公開しているコードがいくつか見つかるので、それを使うものも手っ取り早くて良いだろう。
ドライバの準備
ここではGitHubに上がっている「py-thermal-printer」を使用する。
まずは適当な場所にclone。
git clone https://github.com/luopio/py-thermal-printer ~/printer
初期状態ではボーレートが19200bps決め打ちになっているため、printer.py
を開いて一部記述を変更する。中を見たら一発で分かると思うが、54行目のBAUDRATEを修正すればよい。
Before:
BAUDRATE = 19200
After:
BAUDRATE = 9600 # 9600bpsに変更
あと実は一カ所バグがあるため修正しておく。関数 print_bitmap()
内の # read the bytes into an array
というコメントがある箇所(353行目)だ。これを直さないと、画像の一部が微妙に印刷されない。
Before:
# read the bytes into an array for rowStart in xrange(0, h, 256):
After:
# read the bytes into an array for rowStart in xrange(0, h, 255):
印刷画像の準備
印刷用の画像として、先ほどの「室外機くん」をダウンロードする。
wget http://www.nekopla.com/nnk/shumi-tech/shitsugaiki.png
室外機くんを印刷するためのメインプログラムは、以下の通り。
# coding:utf-8 import printer from PIL import Image # プリンタ準備 p = printer.ThermalPrinter() # 画像印刷 i = Image.open("shitsugaiki.png") data = list(i.getdata()) w, h = i.size p.print_bitmap(data, w, h) # 少し紙送り p.linefeed(3)
あとはこれを実行すれば、プリンタが動いて「室外機くん」が印刷されるはずだ。そしてきっと、印刷速度をみて絶望するに違いない。なんて遅いんだ。こんなんじゃ使い物にならないじゃないかと。そんなわけで、ようやくここからが本題である。
115200bps化のツールを入手する
115200bps化するにはどうするのかというと、まずは謎のツールを入手する必要がある。
「AClasTool」というWindowsアプリで、これはサーマルプリンタの製造会社が社内で使っている(と思われる)DP-EH600の設定値&ファームウェア書き換えツールである。こんなものがどこで入手できるのかというと……製造会社に直接アリババで連絡を取ると送ってもらえる。どう考えてもウソみたいな話だけど、本当なので仕方がない。
とはいえ、いちいち連絡するのも面倒だと思うので、他の入手先をこっそり教えよう。実はメイカーにはお馴染みAdafruitのサイト内に置かれてるのだ。
Downloads | Mini Thermal Receipt Printer | Adafruit Learning System
ページ下部にある「update_firmware.zip」の中に、目的のツールが入っている。
このAClassToolを使えば、プリンタの高速化が可能となる。あくまで公に配られているツールではないため、使用はご自身の責任でお願いしたい。ちなみに同梱されているファームウェアはかなり古いバージョンであり、誘惑に負けてアップデートしてしまうと挙動がおかしくなるのでご注意を(試した)。あくまで設定値書き換えツールとしてのみ使うのが無難である。
設定ツール用ハードウェアの準備
このツールでは、隠しコマンドをシリアルで送って、DP-EH600の内部設定を書き換えられるようになっている。まずはPCにUSBシリアル変換器をつないで、PC~プリンタの接続を確立する必要がある。
こういう接続にする。USBシリアル変換器は何でもいいけれど、今回は定番の秋月製キットを使用した。
設定ツールの使い方
まずはWindowsのデバイスマネージャを開き、先ほど接続したUSBシリアルのCOMポート番号を確認しておく(この場合はCOM3)。
あとはツールで「PORT」(COM3)、「現在のボーレート」(9600bps)、「変更後のボーレート」(115200bps) を設定し、「SET」ボタンを押すと完了。ちなみに「CODE PAGE」という設定をUTF-8に変えておくと、UTF-8の文字コードで日本語が印刷できるようになる。地味にすごい設定である。
成功すると1秒もかからずに「OK」が出る。失敗すると「ERROR」となるので、その場合は接続方法やボーレートが正しいか、またはプリンタの電源が入っているかを確認しよう。
115200bps化の弊害
さて謎のツールを使って、無事に115200bps化に成功した。実際に設定が効いているかどうかは、テスト印刷(プリンタ正面のボタンを押しながら給電)の結果を見れば分かる。
115200kbpsになっているのを確認。よし、これでシリアルの速度も上がったし、高速に画像が印刷できるぞ! ……と思いきや、実はまだなのである。
実際に印刷してみれば理由は分かるが、その前に printer.py
のボーレート設定を変えておくのを忘れずに。
After:
BAUDRATE = 115200 # 115200bpsに変更
期待に胸をふくらませながら印刷してみると、
画像が途中からグチャグチャになってしまった。
なぜかと言うと、ボーレートを上げることで 画像のシリアル転送速度 > 印刷速度 になってしまい、印刷中にプリンタの内部バッファがオーバーフローしてしまうのである。なんてこった。
仕方ないので、次はこれを回避するための改造を行う。
UARTのフロー制御用ピンを引っ張り出す
このような状況下では、シリアルの「フロー制御」を行うのが一般的だ。具体的には、プリンタ側から「送ってもいいよ! or ちょっと待って!」というReady信号を出して(RTSピン)、その信号をラズパイのCTSピンで監視し、シリアル転送の停止 or 開始を制御する必要がある。
これにはもちろん、プリンタ側がフロー制御に対応している必要がある。でもそんなに都合よくRTSピンなんて……あった。
プリンタの裏側をよく見ると、コネクタにつながっていない端子が2つ見える。このうちコネクタに隣接して半分だけ見えている端子が、何を隠そうRTSピンなのだ。見えやすいように、底板に隙間まで空いているという優しさ。
論より証拠、ロジアナを使ってRTSピンの波形を見ると確証が得られる。LOWがReady(送ってもいいよ)で、HIGHがBusy(ちょっと待って)という意味だ。一定量だけシリアル転送(プリンタにとってのRx)が行われたあと、信号がHIGHになって「ちょっと待って」状態になっていることが分かるだろう。これを無視してデータを送り続けているため、バッファがオーバーフローして印刷がバグっているのだ。
RTSピンを引き出すには、もちろん分解して半田付けしてもいいけれど、ひとまずサンハヤトのスルーホール用テストワイヤをぶっ刺した。そこそこお高いのだが、一本持ってるといろいろ捗るのでオススメである。
ここで引き出したRTSを、ラズパイのCTSピンに接続する。
ラズパイのCTSを有効化する
あまり使う人はいないのか、調べてもほとんど情報が出てこないのだが、ラズパイにはシリアルのハードウェアフロー制御用CTS端子がある。具体的には #16 のピンだ。
#16 はデフォルトではGPIO、つまり単なるI/O端子になっている。これをCTS端子にするために、ピンのモードを「ALT3」に切り替える必要がある。ラズパイのピンにはそれぞれ複数の機能が割り当てられており、モードをALT0~ALT5まで切り替えることで、ピンの役割を変更することができるのだ。
まずは現在のピンの状態を確認する。
gpio readall
#16 のモードが「IN」になっているのを確認。これを「ALT3」に変更する。
gpio -g mode 16 alt3
もう一度ピンの状態を見てみると、
gpio readall
無事にALT3(つまりCTS)に変わった。ただし、このままでは再起動時に設定が元に戻ってしまうため、とりあえず起動時に自動で設定変更するよう ~/.config/lxsession/LXDE-pi/autostart
の末尾に以下を記載しておく。
@gpio -g mode 16 alt3
フロー制御を有効にする
CTS端子は有効になったが、実際にフロー制御を使うためにはシリアル通信の設定を変更する必要がある。ふたたび printer.py
を開いて、
Before:
self.printer = Serial(serialport, self.BAUDRATE, timeout=self.TIMEOUT)
After:
self.printer = Serial(serialport, self.BAUDRATE, timeout=self.TIMEOUT, rtscts=True) self.printer.write(chr(29)) # GS - command self.printer.write(chr(97)) # a self.printer.write(chr(1<<5)) # RTS -> Allow
シリアルポートをオープンしている関数呼び出し(84行目)の引数に rtscts=True
を追加。続いて、プリンタのRTS制御を有効化するコマンドを3行追加する。
これでようやく準備完了。早速、印刷を実行してみよう。
印刷時の波形を見てみると、RTSがHIGHになったタイミングでデータ転送が停止し、またLOWになったら転送開始しているのが確認できる。フロー制御が上手くいっている。
これで115200bps化は完了だ。ずいぶん印刷は早くなった……が、最後の仕上げとして印刷パラメータのチューニングを行う。
印刷パラメータのチューニング
DP-EH600には速度に影響するパラメータが3つあって、これを変更することで速度アップが期待できる。
maxHeatingDots
ヘッドの加熱一回あたりに印刷するドット数 / 8 - 1 を設定する。値は 5 がちょうどよかった。つまり一回の加熱で48ドット印刷する(48 / 8 – 1 = 5)という意味だ。
値を大きくすると印刷は早くなるが、パワーを使うので電流は大きくなる。値を小さくすると印刷は遅くなって、そのぶん必要な電流は小さくなる。印刷品位も理屈では変わるはずだけど、あまり違いは分からなかった。
heatingTime
ヘッドの加熱時間を設定する。値は 30 くらいで良い。
値を大きくすると印刷は濃くなるが、そのぶん電流は大きくなる。最大は40で十分で、それ以上だと濃すぎるくらいに。値を小さくすると印刷は薄くなるが、速度は早くなって、電流は小さくなる。
ちなみにmaxHeatingDotsとheatingTimeの値によって印刷時に必要な電流が変わるので、ある一定値を超えると電流不足になってプリンタがバグる。
heatingInterval
ヘッド加熱間隔を設定する。値は 40 くらいで良い。数字を変えてもほとんど変化がないので、基本的にはいじらなくてもよい。
オススメ設定
これら3つのパラメータの組み合わせによって、印刷速度が大きく変わる。ただし速度が速いと、それだけ印刷濃度は薄くなるバーターの関係にある。用途に応じて、3パターンくらいで切り替えるのがちょうど良いだろう。特にオススメは以下の標準設定だ。
標準設定
- maxHeatingDots:5
- heatingTime:30
- heatingInterval:40
高速設定(印刷は薄い)
- maxHeatingDots:5
- heatingTime:20
- heatingInterval:40
低速設定(印刷は濃い)
- maxHeatingDots:5
- heatingTime:40
- heatingInterval:40
設定値の反映
メインプログラムを書き換える必要がある。短いのでもう一度全文掲載しておこう。
# coding:utf-8 import printer from PIL import Image # プリンタ準備 p = printer.ThermalPrinter(heatingDots=5, heatTime=30, heatInterval=40) # 画像印刷 i = Image.open("shitsugaiki.png") data = list(i.getdata()) w, h = i.size p.print_bitmap(data, w, h) # 少し紙送り p.linefeed(3)
これでフィニッシュだ。チューニングなしの状態よりも、かなり速度が上がったのが体感できるだろう。
おわりに
最後にもう一度、どれくらい高速化できたか見てみよう。
高速化の弊害がないことを確認するために、印刷された「室外機くん」を見てみると、
印刷の品位も全く問題なし。QRコードも読み取れる。これだけ速度が出ればいろんな用途に利用できるだろう。
ちなみにTOKYO FLIP-FLOPでは、このプリンタを使って「コミキャス」という製品を開発している。
イベントでの使用を想定した製品のため、印刷時間を少しでも短縮する必要があったのだ。今回の高速化チューニングは、実はコミキャス開発における成果である。
その他にもコミキャスでは、PythonではなくC++で制御コードを書くなど、主に画像処理部分の高速化も図っている。そのため実際には、今回の手法よりもさらに体感速度は早い。
この価格帯のサーマルプリンタで、ここまで遊び尽くせるのは非常にコスパが高い。みんなどんどん『DP-EH600』を使っていこう!