dothikoのカクカクワールド2D REBOOT

プログラミングとかLinux関連(特にOSSのグラフィックツール関連)とかレトロゲームとか色々。

python2のpropertyとタプルの分解で苦労した話

検索ワードが思いつかず苦労しました。アンパックというのですね。

foo, bar = (100, 200)

みたいなやつ。

例えばこんなクラスがあったとします

class _Node:
       
    def __init__(self, x=0.0, y=0.0):
        self._v = np.array( (x, y, 1) )

    @property
    def x(self):
        return self._v[0]

    @x.setter
    def x(self, v):
        self._v[0] = v

    @property
    def y(self):
        return self._v[1]

    @y.setter
    def y(self, v):
        self._v[1] = v

numpy.arrayを隠蔽して、簡単に行列とかかけられつつ 普段は感覚的に.x, .yとかで位置を変更できるという感じの。

こいつにこれをやっていました

n = Node()
n.x, n.y = (100, 101)

これをやるとダメ。

python2ではインスタンスnのプロパティにアンパックではなく、同名のxやyという属性が作成されてしまい、内部値は二重に存在している状態で、二度とプロパティでアクセスできなくなるのでございました。

なおpython3では普通に動くのでありました

ってこの話、遠い昔に見たような気がしなくもなく…(^^;

また一つpython3に乗り換える理由が増えた気がします

python-OpenCV2のfillPolyで苦労した話

python-opencv2にて、普通に [[x1, y1], [x2, y2], [x3, y3] ....] 的な配列を突っ込んだら、np.int32だろうが何だろうが以下のエラーが出続けた話。

OpenCV Error: Assertion failed (p.checkVector(2, CV_32S) >= 0) in fillPoly, file /build/opencv-L2vuMj/opencv-3.2.0+dfsg/modules/imgproc/src/drawing.cpp, line 2373

ググってたどり着いたのはやはりstackoverflow、本当に有り難い…のだけど、既に閉じてしまって今検索しても何故か見つからない。悲しい (`;ω;´)

そんなわけで書いておきますが要するにreshapeして

[ [[x1, y1] ], [ [x2, y2]], [[x3, y3]] ... ] 

のような超変な形に変えて、しかもfillPolyのptsに与えるやつをlistでくくる*1。これで動きました。

以下、動いたコードをコピペ

        pix = 255
        buf = np.zeros(bufshape, 'uint8')
        points = np.array(points).reshape((-1,1,2)).astype(np.int32)
        cv2.fillPoly(buf, pts=[points], color=pix)

このくだらねー処理に、何時間費やしたことか…

*1:これをしないと、Assertionは出なくなるがポリゴンフィルはされずに点だけ描画される

絶対に許せないmodemmanager@xubuntu 18.04.1

「絶対に許せない!」と言えばプリキュアの定番セリフですが(そうか?)

絶対に許せない現象が発生してしまいました

というのもワタクシ、実はお絵かきの左手デバイスに赤外線テレビリモコンが使えるのでは?という思いつきを胸に実際に使ってみていまして、その受信装置はarduino(の複製) + MCP2221でUSB変換してPCに接続→PC側でuinputを使うソフトがキーコードを発信というようになっているのですね。

そしてそれは、systemdでシステム起動時に自動起動するようになっております。

この状況下でubuntuっていうかxubuntuを18.04.1にアップデートして以来、

  • システム起動時にリモコンソフトが起動するが、機能しない
  • どーもオチているようである(systemdからは落ちたと認識されていないらしい)
  • systemctl restart ir_remocon.serviceすると動作するが、サスペンド→復帰するとまた動かない。
  • ソフト単体で試したら、たしかに復帰すると変換ソフトが超長いリモコンコードを受信し、アサーションを発して落ちている。
  • そこでリモコンコード異常が発生したらポート閉じて再度開く…と言う仕組みにしたら、「device reports readiness to read but returned no data」と言われるようになり、やはりまともに受信できない
  • そこでソフトを一旦落とし、再起動するとこれは動く。
  • acpidで/etc/pm/にスクリプトを置いてresumeでsystemctl restart ir_remocon.serviceするようにしてみたが、駄目

毎回愚直にターミナルからsystemctl restartしてたんですが、いい加減なんとかしなければ…と追ってみたのですが、上記のように自分には想定外の不可思議な現象が起きておりました。

んで/var/log/syslog していてようやく気づきました。

Dec  5 01:08:16 mydesktop ModemManager[649]: <info>  Creating modem with plugin 'Generic' and '1' ports
Dec  5 01:08:16 mydesktop ModemManager[649]: <warn>  Could not grab port (tty/ttyACM0): 'Cannot add port 'tty/ttyACM0', unhandled serial type'

誰だコイツ > ModemManager

いつの間に入ったのか今までは悪さをしなかったのかわかりませんが、どうもコイツが全てのシリアルポートを塞いでいるっぽいですな…そしてシステム起動・復帰時に先に塞いでいるので我がir_remocon.serviceが失敗すると

そう考えると device reports readiness〜エラーとも辻褄が合う。

そこでバッサリapt-get remove modemmanagerしました。

どうもサスペンド復帰しても大丈夫になりました、「今のところは」 あとプラセボ効果かもですが…デスクトップ描画も16.04のときのサックリサクサクに戻った気がするのですよ。気の所為かもですがね。

まぁ、本当にmodemmanagerが悪かったのかは実際の所不明w

systemdでstopした時にpythonのfinallyが呼ばれない問題について

systemdでsystemctl stop hoge.serviceすると、基本的にSIGTERM -> SIGKILLが送られてdaemonプロセスが終了します。

しかしながら、pythonのfinally節はSIGTERMで終了した場合は呼びだされません。 そのため、pythondaemonを作った時、finallyで必ず呼ばれることを期待して記述された終了処理は呼ばれずに終わるという…

これでハメられた…まぁ具体的にはRaspberry PiのGPIOをお手軽にRPi.GPIOでadd_event_detectしていたのですが、サービス化していたので何も考えずにstopしたら、テストでRuntimeErrorを吐くようになってしまいました。

finallyでcleanup()を呼んでたので、SIGTERMで終了時は呼ばれなかった結果、プロセス終了後も握り続けているのか?こうなった

dothiko@raspberrypi:~/python/usbcamcap $ ./usbcamcap.py -p 12345 -f camsconf.json 
- GPIO pin 4 as Button, 3 as LED.
./usbcamcap.py:296: RuntimeWarning: This channel is already in use, continuing anyway.  Use GPIO.setwarnings(False) to disable warnings.
  gp.setup(LED, gp.OUT)
Traceback (most recent call last):
  File "./usbcamcap.py", line 439, in <module>
    camera = Camera(args.cameras, confs)
  File "./usbcamcap.py", line 204, in __init__
    self.init_gpio()
  File "./usbcamcap.py", line 298, in init_gpio
    gp.add_event_detect(BTN, gp.BOTH, callback=self._gpio_callback)  
RuntimeError: Failed to add edge detection

ちな、このusbcamcap.pyというのは自作のUSBカメラキャプチャスクリプトで、カメラを握り続けてhttpでリクエストした時に画像を送るものです。んでもってこの中で同時にGPIOでボタンを見ていて、ボタンが押されるとシャットダウンするようにしています。 普段はラズパイを監視カメラとして使い、整備・移動する時はボタンでシャットダウンして電源断という目論見です。

最近のネットカメラはゴミばかりあまり気に入ったものがなく、スマホでアプリというものばかり。それもお手軽で良いのでしょうが外部のサーバや専用アプリを必要としたりして、しかもそれがOSのバージョンに相性があったりするなど、使い勝手が実に良くない。 もはや自分的には監視カメラはラズパイで自作する他無いという感じです。

話がそれてしまいました。

ともかく、どうすれば直るのか悩みましたがあっさり諦めてリブートしました(^^;

んで調べた結果、対策は2つあって

  • serviceファイルのservice節でKillSignal=SIGINTを記述して、syetemdのシグナルを変える。
  • python側でSIGTERMを捕捉してsys.exit()を呼び出す

後者の方はsignalモジュールでSIGTERMにハンドラを付けて、その中からsys.exit()をコールするわけです。これでsys.exit()がfinallyを呼んでくれるので問題がなくなります。

以下参考用のテストプログラム

import time
import signal
import sys

def termed(signum, frame):
    print("SIGTERM!")
    sys.exit(0)

def main():
    signal.signal(signal.SIGTERM, termed)
    try:
        while True:
            print('loop')
            time.sleep(3)
    finally:
        print("CALL FINALLY")

if __name__ == '__main__':
    main()

まぁどっちでもいいんですけど、後でうっかりパターンを考えるとSIGTERMを捕捉したほうがいいかな?

ubuntu 18.04.1でapt upgradeに失敗

正確には何をしたらおかしくなったのか分かりませんが… また、実際焦っていたのでエラーメッセージなども保存していない。スミマセン。

  • まず普通のデスクトップアプリ「ソフトウェアの更新」で更新しようとした
  • しかし、幾つかファイルがダウンロードできずに更新に失敗
  • そこでサーバを日本からメインに変更(これが悪かったか?)
  • やはり失敗
  • ターミナルからapt update & apt upgrade
  • libgs9-commonのバージョンが合わないのでインストールが出来ないという内容のメッセージが出る。
  • このバージョン番号が末尾が18.04.2なのですが、何かが間違ってないっすかねぇ?
  • apt --fix-broken installしろと出たのでやってみる
  • 無駄無駄無駄ァーッ という感じでやっぱlibgs9がアカンのでダメとなる
  • 以降、apt removeもできなくなる (apt --fix-broken installしろと出続ける)

というわけで困ったのですが、検索して得た以下の情報を元にaptのステータスをいじったところナントカ治りました(汗 そのURLを貼りたいのですがこれまた失念…stackoverflowだったと思ったのですが、ubuntuフォーラムかもしれない。 ともかく。

cp /var/lib/dpkg/status /var/lib/dpkg/status.bak # 念の為、今のステータスファイルを保存
cp /var/backups/dpkg.status.*.gz /var/lib/dpkg # すべての連番ファイル圧縮バックアップがコピーされる
gunzip -d /var/lib/dpkg/dpkg.status.*.gz # バックアップを展開する。
cp -f /var/lib/dpkg/dpkg.status.n /var/lib/dpkg/status # nは任意の番号。もっとも大きい番号のが直前のようだ。
# この状態で、以前は実行不可能だったaptが実行可能になっている。

という情報を得たのでやってみたのですが、apt update->upgradeすると、結局libgs9で同じことに。 そこでふとひらめきました。

「statusファイルを復帰させたらそこでapt remove libgs9-commonする」

という。 あとバージョン番号がなんか18.04.2という、ん〜まだリリース前じゃね?みたいな雰囲気のファイルだったので、もしかしてと思い、upgradeではなくdist-upgradeにしてみました。 結局、やったことは

statusファイル復帰
↓
apt remove libgs9-common
↓
apt update
↓
apt dist-upgrade

そしたら無事終了しました! まぁ偶然サーバのほうで何か修正が入っただけかもですが(^^;

ではでは〜

100均で見かけた電子工作向きっぽい容器

昔は自作の電子工作機器を収納するといえばブルジョワ都会人ならタカチ等のちゃんとしたケース*1、田舎だとせいぜいタッパー類似の食品密閉ケースがありがちなパターンでした。

でも密閉ケースは軟質樹脂で接着もほぼ無理なら塗装もほぼ出来なかった*2んですね…

そんでもって今時は廉価で塗装も可能な硬質スチロール樹脂の容器が簡単に入手できる時代となってますね、100均のお陰で*3

そこで今回は中々良いケースを見つけてきたのでそれを紹介する記事なのでした。

今回探してきた条件は3つ

  • ユニバーサル基板+センサー類が入る大きさ
  • 透明で硬質樹脂
  • 蓋がある

まぁ、蓋はぶっちゃけ無くても良かったのですが(板を貼ってもいいし、同じトレイを2つ向かい合わせでくっつけてもよい)、あるほうが面倒でなくてありがたいですね。

まずはサナダ精工のクリアケース ミニ

f:id:dothiko:20180919232956j:plain:w320

蓋が主張し過ぎの気もしないでもないですが、逆に蓋を底面にしても良いかと思われます。

f:id:dothiko:20180919233124j:plain:w320

ユニバーサル基板*4を収納してみたところはこちら。残念ながら、「ケースを横置きで、基板を縦に入れる」には1mmほど基板が大きいので入りません。まぁ多少削るか、別タイプのユニバーサル基板を使えばいいだけですけどね。

以前はLEDライトケースにこだわって居ましたが別にコレでいいかも…あっ、LEDライトケースには電池ボックス&スイッチ付属という超大きなメリットがありますね。

次は和泉化成のクリアケース ロングです。

f:id:dothiko:20180919233602j:plain:w320

なんとこれ、蓋が一体型で可動式なのですよ〜

f:id:dothiko:20180919233629j:plain:w320

これまた、ケース横置きで基板横置きしか無理です。

f:id:dothiko:20180919233652j:plain:w320

これはもう1mmとかいうレベルではなく完全に無理ということで。まぁ、ケース自体が長いのでいかようにもなるかと。

実は前も書いたかもですが、トイレ照明(&将来的には換気扇も)のセンサー + 赤外線リモコンでの完全自動化を目論んでいまして、タカチ的なABS樹脂ケースは幾つか買い込んであるものの、貧乏性が災いして可能な限り使いたくねえっ!という感じなのでした(^^;

まぁ、センサーや赤外線LED用の窓を綺麗に四角く切り抜くのがめんどいということと、失敗とかすると無駄に穴のあいたケースになってしまったりして悲しいですからね…*5

双方ともスチロール樹脂ゆえ、塗装も接着剤も簡単に効くのはよい*6のですが、耐衝撃性に弱く多少のことで傷つきやすい割れやすい、消しゴムやそのカスが長時間ひっつくと可塑剤のガスで溶けるなどの問題点があります…そのへんを考慮して場所を選んで使えば良いかと思われます。

ではでは〜

*1:ブルジョワの特注とかは無しでおながいしますw

*2:染めQなら行けるのかなぁ?

*3:特にセリアが好きですが、これらの製品は別段セリア限定でもない模様

*4:秋月電子で売っている「片面ガラスコンポジット・ユニバーサル基板 Cタイプ」

*5:250円とかだから別にいいじゃんという感じかもだけど、秋月中毒患者としてはこの250円で他のパーツが買えるとか思ってしまうのですな

*6:なお、今時はセメダインのスーパーXやコニシのウルトラ多用途SUなどの優秀なシリコーン系接着剤もあるので、溶剤系接着剤にこだわらなければ樹脂の選択肢も広がるのですが

セリア100円LEDライトの透明化改造

お絵かき用の左手デバイスとしてテレビの赤外線リモコンを使用しておりますが、中々良いです。 応答速度がやばいほど遅いのではと危惧しておりましたが、試しに作ってみたところ、全然大丈夫。 ローコストで入手性も高く実に良いと思うのですけどねぇ

ちなみに自作受信器の中身はatmega328で受信、MCP2221でUSB-TTL通信し、PC(Linux)側では専用daemonが待ち受けてuinputでキーコードを吐く仕組みにしております。将来的にはこれをPC側のdaemon無しに単体で動くように、大昔買ったまま放置してあるトラ技の78K0オマケ基盤をUSBキーボード化して、それとatmega328が通信してUSB化するという構想なのでした。*1

まぁ普通にビットトレードワンのリモコンキットを買えば廉価かつ確実、しかもこれだけでUSBキーボードになるようです(^^)

ビット・トレード・ワン USB赤外線リモコンアドバンス ADIR01P

ビット・トレード・ワン USB赤外線リモコンアドバンス ADIR01P

が…これはリモコンボタンを押しっぱなしにしてる間、キーを押下したままにしてくれるのだろうか? 例えば、shiftキーを割り当ててそのボタンを押している間、shiftが押しっぱなしになってくれるだろうか?…という疑問が今イチ拭えなかったということも自作に走った一因です。

ちなみに自作受信器では、「同じリモコンボタンが108msぐらいの一定時間内にリピートしない、もしくはリピートコードが来なければ、ボタンを離したという事にしてuinputにキーのリリースコードを生成」という仕組みにしております。

ただ、押下状態を保持したいボタンは極少数。リピートするとパカパカして使いづらい機能のほうが圧倒的多数なのですね。 そこで一部のボタンについてのみ、設定ファイルでモデファイアフラグ「holdable」を指定することで押下状態保持を明示的に指定。 デフォルトでは、「リモコンボタンを一発押したらワンショットですぐにリリースコードを生成し、直後の同一リモコンボタンのリピートを無視する」という仕組みです。*2

ワタクシ、自分の改造版MyPaintではshiftキーを押しっぱなしでペンタブのスタイラスをドラッグするとブラシサイズを変更、という機能に割り当てているので割とキーを押しっぱなしに出来るかどうかは重要なのです。Kritaでも同じです。あとCTRL押しっぱなしでカラーピックとか、これも同じ。

しかし問題がまだひとつあって、それが基板の容器なのですね。

セリアのLEDライトが大きめで余裕があって光を通し、しかも100円と大喜びで買い込みましたが… いざ作ってみるとこのLEDライトのカバーとスイッチを兼ねた半透明の拡散板が、赤外線LEDの信号を送受信ともに多少邪魔してくれる、という…*3

昔の100均ライトはこんな良い拡散板ではなく、透明ドームにブツブツの点があるだけでしたからね。しかし赤外線にはむしろ透明のほうが良い模様。

というわけで結局、ストックしてあった、旧式のブツブツ透明タイプな小型LEDライト容器に入れ替えて使っておりますけどね。もうこのボディは入手できないのだろうなぁという… f:id:dothiko:20180908082421j:plain

まぁ100均ライトにこだわるのをヤメればいいだけなのですが、ライトは電池ボックス付きなのでそこもお得なポイントなのです…

将来的にはESP8266で、留守時にだけリビングに置く電池駆動の遠隔照明操作リモコンとか考えていただけに、ちょっとこの赤外線パワーダウンはなぁと。

んで他の用途にまたまた同じLEDライトを買ってきて、つらつら眺めていてふと思ったのです。

このドームをバキュームフォームで透明プラバンで複製してはどうだろうか?

目の前にバキュームフォームされたような透明の物体があるじゃろ?

f:id:dothiko:20180908082639j:plain:w320

ああっ!! コイツの包装プラがあったわ!!

さっそく切り抜いて

f:id:dothiko:20180908082749j:plain:w320

組み込んでみたらなんと!ピッタリじゃないすか!! いや当たり前なんだけど(^^;

f:id:dothiko:20180908082757j:plain:w320

というわけで、これはただの仮組み。

まぁとりあえず今の動いている左手用リモコン受信器は放置し、 以前、同様に100均ライトボディに組み込んで作ったリモコン発信器*4のカバーを交換してみたところ…

f:id:dothiko:20180908084819j:plain:w320

今まで真下から発射しないと受信してくれなかった天井灯が、斜め遠方からの照射でらくらく反応してくれるように!

これでしばらくは完全透明LEDライトケースに困ることは無さそうです。

うーむ今まで捨てた包装プラを取り戻したい気分ですは…

てかまぁ、「四角いけどフタ付きの完全透明小物収納用硬質プラボックス」をセリアで見つけてしまいまして、これはこれで電子工作のケースにかなり向いてそうに思いましたですね。 普通の食品用密閉容器のような軟質プラではなく、ポリスチレンっぽい感触の接着剤効きそうなプラ容器なのですよ。

ではでは!

*1:78K0の開発環境が独特、かつ自分がなるべくwindows使いたくなく、さらにそのうえ最近のwindowsでは無理があるため、最小限の手数でUSB変換モジュールとしてだけ動くようにする予定

*2:一番最初、作った直後は全ボタン押下可能で使っていましたがピーキー過ぎて俺には無理だよって感じでした

*3:ライトとしてみればこの拡散板はただのプラスチックにしては非常に優秀、かなり光を均一にしてくれます。

*4:ラズパイとUSB接続して防犯タイマー的に使ってます