2019年4月4日木曜日

【M5Stack/MicroPython】lcd.printのAPIが意外と初心者殺しだった件

■ はじめに

M5Stackで手っとり早くなんかプログラムを書いて動かすのはMicroPythonを使うのが最も簡単だと思います。(少なくても自分にとっては。前の記事も参照)

たいていの人はlcd.print("HelloWorld")とか表示させたりして、この世界にようこそ!されるのでしょうが、意外とこのLCDクラスが曲者した。「初心者というのはこんな所で詰まるのか!」というTipsのためにもまとめておきます。


■ lcd.printについて

説明するまでもないけれど、M5StackのLCDパネルに文字列を表示させるためのAPIです。
普通、このテのマイコン開発ボードでは適当な表示器を見繕って自前でSPIとかのドライバを書くことから始めないといけない。表示器がキャラクタ表示に対応していなければフォントも用意することだろう。それこそ「たかがHelloWorld、されどHelloWorld」という世界で、HelloWorldを表示させられたら、もう力尽きてそれ以上の気力が湧いてこないのです(;´Д`)

それがM5StackのMicroPythonでは「from m5stack import lcd」一発で使えてしまうのだから驚きだ
これさえできれば、表示に関してはやりたいことがすぐできる…

…できるはず…

…はずなのですが(笑)


■ 詰まってしまうこと


(1)lcdは小文字
まずはここですね(*_*; 
 lcdはついついシフトキーを押しながらLCDと書いてしまう。
特にVB出身者とかだと関数を大文字で書く習慣がまだあるかもしれない(!?)最近は関数やクラスは小文字で始まる言語が主流になってきただろうけど、僕のように久しぶりにコードを書いてみるような人は注意が必要だ。
Webの検索エンジンとは違って大文字小文字が違うだけでもNot foundで怒られてしまうので、テキストエディタの一括置換のお世話になるわけだ。

(2)フォント定数やカラーコード定数もlcdモジュールの定数である
はじめは本当にフォントや文字色の指定の仕方がわかりませんでした(オヤジギャグではありませんよ!

公式の説明はこうだ。

以下のフォント定数が定義済みで、font引数に指定できます: 
FONT_Default, FONT_DefaultSmall, FONT_DejaVu18, FONT_Dejavu24, FONT_Ubuntu, FONT_Comic, FONT_Minya, FONT_Tooney, FONT_Small, FONT_7seg

だから

lcd.font("FONT_Tooney")

とか書いてもフォントが変わらないのです!
HTMLとかCSSコーダーの方は意外と間違いやすいですかね…
定数と書いてあるのですが、そのまま指定してもダメ。

だから、こう
lstfont = ["FONT_Default","FONT_DejaVu18","FONT_DejaVu24","FONT_Ubuntu","FONT_Comic","FONT_Minya","FONT_Tooney"]
lstfontid = [lcd.FONT_Default,lcd.FONT_DejaVu18,lcd.FONT_DejaVu24,lcd.FONT_Ubuntu,lcd.FONT_Comic,lcd.FONT_Minya,lcd.FONT_Tooney]
lstcolor = [lcd.WHITE,lcd.LIGHTGREY,lcd.MAGENTA,lcd.CYAN,lcd.ORANGE,lcd.GREENYELLOW,lcd.PINK]

lcd.clear()
for i in range(len(lstfontid)):
    lcd.font(lstfontid[i])
    text = "%s = %s\r\n" % (lstfont[i],lstfontid[i])
    lcd.print(text,0,lcd.LASTY,lstcolor[i])

結果

lcdモジュールの定数として指定する必要があるというわけだったんです。
…まあ、落ち着いて考えればそうなのでしょう。


(3)角度やtransparentはキーワード引数である。
これも結構ハマりました(T_T)
公式の説明はこう。

lcd.print(text[,x, y, color, rotate, transparent, fixedwidth, wrap])


それで、
lcd.print("Hello World",100,100,lcd.RED)

こんな具合にx, y, color までは省略可能なのですが指定すれば表示できます。

でも
lcd.print("Hello World",100,100,lcd.RED,90,0)

rotate以降を指定するとtype errorとかになってしまう…
文字列で指定するのか?と思って
lcd.print("Hello World",100,100,lcd.RED,"90",0)

これも当然ダメ(笑)

…はて、わけわかめ@@;;;;

ということでいろいろぐぐってみたけど、text以上の引数が必要になるシーンなんてあるの?とばかり、
lcd.print("Hello World") というtextまで指定されたサンプルしかない(^_^;)

これはファームウェアのソースを見るしかない!というわけで、それらしきメソッドのソースを見ると、こうだ。
const mp_arg_t allowed_args[] = {
        { MP_QSTR_text,         MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = mp_const_none } },
        { MP_QSTR_x,                              MP_ARG_INT, { .u_int = 0 } },
        { MP_QSTR_y,                              MP_ARG_INT, { .u_int = 0 } },
        { MP_QSTR_color,                          MP_ARG_INT, { .u_int = -1 } },
        { MP_QSTR_rotate,       MP_ARG_KW_ONLY  | MP_ARG_INT, { .u_int = -1 } },
        { MP_QSTR_transparent,  MP_ARG_KW_ONLY  | MP_ARG_OBJ, { .u_obj = mp_const_none } },
pythonに慣れた人であれば常識なのかもしれないけど、rotate以降はキーワード引数とのこと。

だから
from m5stack import *
import random
import utime
lcd.clear(lcd.BLUE)
while True:
    x = random.randint(0,320)   
    y = random.randint(0,240)
    r = random.randint(0,360)
    lcd.print("SPAM",x,y,0xFFFFFF,rotate=r,transparent=True)
    utime.sleep(0.2)
としてやれば

結果

はああ〜やっとできた〜(TдT)

リファレンスにrotate以降はキーワード引数ですよ。とか、transparentはbooleanで指定して下さい。とか、突然変更になるかもしれないし、そこまで親切じゃないぞ!。という話です(笑)

でも「type error」だって吐き出すし、いよいよとなったらファームのソースも公開してんだからそっちを見てね(はぁと)ということかもしれません(^_^;)

以上、意外と難しかったlcd.printのお話でした!

0 件のコメント:

コメントを投稿