「PIC AVR 工作室」サイトの日記的なブログです。
サイトに挙げなかった他愛ないことを日記的に書き残してます。
PIC AVR 工作室 ブログ



昨日、Pythonのncurses(curses)についてあれこれ
調べてて、なんとなく動きそうな感じだったので、
VirtualBoxのUbuntu Mate上であれこれ実験してた。

結果、とりあえず簡単な文字表示とか、キー入力とかを
行う実験ができた。

書いてみたスクリプトがこれ。

#!/usr/bin/env python3

import time
import curses

stdscr = curses.initscr()

def test3(stdscr):
  stdscr.clear()

  for i in range(10):
    stdscr.addstr(i, 5, str(i))
    stdscr.refresh()
    time.sleep(0.1)


  while True:
    c = stdscr.getkey()  # getch()
    stdscr.clear()
    #curses.beep()
    stdscr.addstr(10, 10, str(c))
    stdscr.refresh()
    if c == "q":
      exit(0)


curses.wrapper(test3)

すごく簡単な内容にとどめてある。
処理内容としては、前半のfor文で0~9の数字を0.1秒ごと
に表示するもの。後半は、キー入力された文字を画面に
表示するんだけど、「Q」キーが押されたら終了。

このあたりの処理は、使ってる関数(メソッド)がcurses
関係のものであるってこと以外は、特に難しいものはない。
多分、cursesを使って入力や表示を行うPythonスクリプト
としては、これがだいたい最小のひな形的に使えるもの
じゃないかなと。


いくつかポイントとなるところがあるので、忘れないように
メモしておく。


(1)ライブラリのimport

Ubuntu Mateでは、どうやら最初からcursesが取り込まれて
いるっぽい。
(もしかしたら、こないだncurses関係のパッケージを
aptでインストールしておいたことで使えるようになって
いるのかもしれないけど、詳細はちょっとわからない。
ただ、Python3を入れるか、プラスしてncurses関係の
パッケージを入れる程度で使えるみたい)

冒頭でcursesをimportしておいて、curses.init()メソッド
を呼び出すと、初期化された画面が返ってくるので、
そのオブジェクトの各種メンバにアクセスすることで、
画面に書き込んだり、(アクティブになってる画面上で
キー入力された)キー入力内容を取得したりできる。


(2)wrapper

上記の表示や入力といった処理を行うだけなら、最後の行
に出てくるwrapperは使う必要がなくて、単にメインロジック
部分をだらだらと書けば動いちゃう。
(ただし、プログラムの終了時に、忘れずに「curses.endwin()」
を呼んでおかないと、画面表示やキー入力が、コマンドライン
に戻ってもおかしな感じになっちゃうので注意)

けど、それだけだと支障がある場合がちらほら出てくる。

具体的には、エラーでプログラムが中断したり、なにか
例外が発生してプログラムが終了しちゃったり、さらには
Ctrl-Cで強制終了させたときにも同様。
(端末をいったん終了させて、再度起動しなおさないと
いけなくなっちゃって、とても不便)

なので、そういったことを踏まえて、意図せずに途中で
終了しちゃっても、コマンドラインに戻った時にちゃんと
画面表示やキー入力ができるようにするのが、wrapper。

メイン処理として処理させたい内容を上記のプログラム
みたいに関数にまとめておいて、wrapperの引数に指定
して、wrapperからその関数を起動することによって、
途中で意図せず終了しちゃっても、コマンドラインが
普通に機能する様にできるという次第。
(なので、これはやっておいたほうがいい、というより、
やらないと絶対困ることになる)


(3)ダブルバッファ

表示を行うメソッドを呼び出しても、その時点では実際の
画面には反映されないし、画面クリアをしても、その時点
では画面はクリアされない。描画やクリアの処理をした
時に内容が更新されるのは、表示前の「バッファ」側の
方で、そのバッファの内容を実際の画面に反映させるには、
refreshメソッドを呼び出す必要がある。

つまり、表示に使っているバッファと、描画処理を行って
いるバッファの2枚(ダブルバッファ)の構成になって
いるので、クリア処理や表示処理をある程度行った時点で、
その内容を画面上に反映させるために、refreshを行う
ことを忘れてはいけない。(忘れると表示内容いが反映
されない)


といったあたり。
多分、そのあたりを踏まえておけば、あとはどんなメソッド
があったりするのかを調べれば、あんなことやこんなこと
ができるはず。


Linux上では動くことが判ったんだけど、せっかくのPython
なので、このままWindowsのidleで動くかなぁ?と思って、
ちょっと実験してみるも、なんかエラーが出る。

そもそも、idleのコマンドライン的なアレって、端末と
おなじことできるのかなぁ?と思って、ちょっと調べてみた。

https://www.raspberrypi.org/forums/viewtopic.php?t=236107

これはRaspberry Piのidleの話だけど、どうやらidleの
コマンドラインは、端末と同様のエミュレーションは行って
いないということらしい。なら、Windowsでも同じだよな。





ダブルバッファといえば、I2CのOLED液晶SSD1306用にオイラ
が書いたオレオレライブラリ。あれは内部にバッファを確保
しているものの、ダブルバッファではなく、バッファに
書き込みすると同時にOLED画面上にも反映させちゃうので、
いわゆるダブルバッファではないんだけど、あれを使って
オシロを作るとして、気になっているのが表示速度。

オシロの表示処理で、どのくらいのデータ通信が発生する
のかで、画面の更新頻度(FPS)が変わってくるんだけど、
波形をドット表示機能で「消去+描画」するのと、ダブル
バッファで全面書き換えるの、どっちが速いの?と。

ドット単位で書き換えするとなると、横方向にずらずらと
消去してから、新しい波形を描画することになるんだけど、
画面の横方向だいたい3/4くらいをグラフの表示領域として
つかっているので、96ドット分くらいかな?
1ドットずつひょうじするとなると、アドレス指定+データ
の最低でも2つのデータを通信する必要があって、それを
消去と描画するとなると単純に2倍。だいたい400回くらいの
通信があるって考えておけばいいのかなぁ。(合ってる?)

一方、ダブルバッファ方式で、全画面転送するってなると、
1kB分(128ドット×64ドット÷8ビット)のデータ転送が
必要。たしか、アドレス指定は最初の1回だけで、あとは
データだけダラダラと転送すれば、よかったはず。つまり、
およそ1000回くらいデータ転送すれば、全画面の更新が
できるはず。

検索してみると、

http://blog3.narimatsu.net/article/181218a

ダブルバッファでの転送に必要な時間は、100kbpsの通常
速度では、1回あたり0.08秒らしい。
ドット描画方式でクリア+表示をしても、その半分くらい
の速度にしかならないので、大同小異ってところなんだなぁ…。
ドット表示方式でも、もっと速いと思ってたよ…。


まぁ、ダブルバッファ方式だとしても、以前ラジオペンチ
さんが作られていたペン型オシロ(使っていたライブラリ
が確かダブルバッファ方式だったかと)が、結構ちゃんと
実用レベルの表示更新頻度だったので、ダブルバッファ
方式でもいいのかもしれないなぁ…

現状のオレオレライブラリだと、ダブルバッファ方式には
対応してないんだよな。(処理した直後に反映されてない
のは、ちょっとキモチワルイ気がして)

オレオレライブラリでも、こういう風にダブルバッファで
描画処理と反映処理を分ける方法も使えるようにしておいた
方が、応用するのに便利なのかもしれないなぁ…。などと
思ったりしてるところ。
(速度気にするほどじゃないSPI方式のモジュール用と
ロジックを共用しているので、あまりいじりたくはないん
だけどなぁ)





https://twitter.com/Shepherd4013/status/1350435144755146753

ウレタンマスクとポリエステルマスクの違い…ぱっと見
はよくわからないよなぁ。
ウレタンマスクはあれこれ言われているけど、ポリエステル
マスクは、不織布マスクと同じくらい高性能なのか。へぇ。



コメント ( 0 )