🗐 電装工芸日記 - 舞台照明機器の製作とか -

能登半島地震で被災された方々にお見舞い申し上げます。

or 管理画面へ

2022年2月 この範囲を時系列順で読む この範囲をファイルに出力する

Icon of admin
 今週末は小屋付きの増員ですが、毎度のことながらそれほどやることはありません。
 居眠りも出来ないので、パソコンに向かって仕事をしている風味でArt-Netのソースコードの見直しです。勢いで書いた関数型のC言語っぽいコードをPythonらしい書き方に直しつつ、贅肉を削っております。

 Pythonには群のデータを扱う方法がいくつかあります。Art-NetというかDMX512のパッチマシンを作るにはこられを巧く使うことが大事です。
 これらには大きく分けて3つあります。list型、taple型、dictionary型です。これらは似ていますが出来ることが違います。また、どれを使っても出来ることでも内容によって処理速度が違ったりします。特徴をよく理解して使わないと損です。

 list型は群に対しても個に対しても計算が出来ます。文字列に対する加工も含まれますが、他の型ではそれが出来ません。
 taple型は様々な型のデータを一つに束ねて扱えます。関数の戻り値は基本的にこれだと思っていいでしょう。taple型の使い方がわかるとPythonの便利さが実感出来てコーディングの幅も広がるような気がします。
 dictionary型はデータ参照用と言ったらいいでしょうか。キーワードに対して様々な型のデータを関連付けられ、なんといっても抽出が速い。キーワードが規則性のある数値の場合は他の2つもあまり変わらないかもしれませんが、キーワードが規則性を持たない場合はdictionary型が圧倒的に速く便利だと思います。
 具体的な違いや用法はその筋の教科書や先達の書き込みに任せますが、PythonがPythonであるところはここなのかもしれません。

 RaspberryPiが見た目以上に優秀なハードウェアなのもありますが、Pythonで制御系を書いても遅いとは感じません。
 もちろん、C言語とかで書いてコンパイルした方が速いのは間違いありませんが、書いてすぐに実行できるPythonは生産性が高いと思います。
 少し遠回りかもしれませんが、C++に書き直すことを前提にPythonで書き、動いたらC++に移植するってのが制御系を作るのにいいかもしれないなぁ~なんて思ったりしてます。コーディングの規則が違うだけで書く内容は凄く似てますので、PythonでスケッチしてC++で清書するのです。勢いで書いたPythonをPythonらしく書き直すなら同じことかなと。

#Python
Icon of admin
 昨晩、思い立って調べてみたのですが、Pythonで並列処理をする方法には大きく分けて2つあると理解する。ThreadingとMultiprocessingです。

 今までに何度も読んでいたサイトばかりですが、何故だか内容が突然理解できるようになりました。たぶん今まではPythonをスクリプト言語だと思っていたからでしょう。Pythonという皮の裏にC言語がある思えばスムーズに理解が進みました。

 似たような別ライブラリもありますが、意味合いとしてはこの二つに集約されていると思っていいでしょう。
 大雑把に言うなら、Threadingは比較的楽に使えるがCPUスレッドは1つしか使えない。Multiprocessingは複数のCPUスレッドを使えるがプロセスが起動するのに時間がかかり記述も少し難しい。
 難しいといっても、プロセス間通信の制約とタイミングくらいなもので、関数自体はThreadingとMultiprocessingはとても似ているので片方を覚えればどちらも使えそう。関数間で通信するQueueは使うライブラリが違うので注意ですが、これも関数が酷似しているのでストレス少ないかも。
 Python3.8からは共有メモリというC言語のポインタに近いことが可能になっているので、RaspberryPiのPythonも3.8になることを心待ちにしております。変数の型やデータ長を厳密に管理しなければなりませんが、それさえやっておけばいいので問題無し。デバイスとやり取りする処理では普通にやっていることだし。

#Python
Icon of admin
 ガラクタ週間が終わり、終日本業のデスクワークでした。
 会場図面書いて、照明プランの概要まとめ、見積りというデスクワークの王道メニューです。
 嫌いじゃないのですが、ガラクタネタが中途なのでソワソワします。
 今やっているArt-Netは卓とデコーダが必要な作業なので、荷物も多いし広いスペースも必要です。しばらくはお休みかな。
 明日から現場が続きますが、RaspberryPiだけ持って行って現在のソースをオブジェクト指向っぽく書く練習をしようかなぁ。

 そうそう、製作というレベルではありませんが、ピンスポット用の照準器を増産しました。その実態は小型カメラ用の自在雲台を介して短いピカティニーレールをピンに取り付けるクランプです。
 細かい部品を買い増しして組み立てるだけなので15分くらいの作業でしたが、なぜ思い立って作ったかと言えば数日後の現場で数年ぶりにピンを振ることになったからです。
 鈍った腕でも対応出来そうな演目ですが、お年頃からくる目のコンディションでバインド照準器が使えませんので、ダットサイトなどの目印が遠くに見える照準器に頼らないとダメだと思われます。
 このクランプは5-6年前に作った代物です。以前作った物は部下にあげてしまったので、余っていた部品で改めて自分用をこさえたワケです。

#RaspberryPi #Python
Icon of admin
 空き時間が少なかったのですが、Art-Netのエンコードを試してみました。
 受信したバイナリをデコードし、パラメータをそのままにエンコードして送信です。単純な動作ですが、これが出来なきゃパッチマシンなど絶対無理というテストです。
 卓からの8ユニバースをすべて処理したのですが、負荷の増加は2.5%くらいでした。十分に許容範囲で収まったのは良いことです。
 パッチマシンは8in8outくらいを想定していますが、16in16outも可能だったりして。16ユニバース出る卓が無いので試せないし作ってもオーバースペックなので私は不要かな。機能全体を組み込んでから悩むことですが・・・。

 今のところ1日1課題。
 あとどれくらいの課題があるのかわかりませんが、納期はありませんのでノンビリいきましょう。ここまで出来れば、丁寧にclassライブラリにまとめ上げ、コメントに使い方を明記して後々も使える様にしておきましょう。
 そういう意味ではキー操作やモニタ表示もclassライブラリにして汎用性を高めるのがいいですね。

 と言いますか、このまま書き増しを続けるとソースコードがグチャグチャになって後で後悔しそうです。
 私のメインはPICのアセンブラなのでANSI-Cの関数タイプっぽい書き方をしがちですが、Pythonならオブジェクト指向な書き方をしたいものです。最近、クラス、インスタンス、継承を使う意味と感覚がわかってきましたので、出来るだけそういった書き方をしていこうと思います。
 以前は「継承」ってのが感覚的にわからんかったのですが、関数を束ねて新しい関数を作るだけだと簡単に考えればいいみたいです。ただ、関数は実体なのであっちこっちの関数から同じ関数を同時に呼ぶと衝突が起こります。解決には親関数の中で使う関数を親関数にとって専用にすればいいのですが、同じ様な関数を使うだけ書くのは面倒だしやらたとソースが大きくなるので、ひな形であるクラスから実体のインスタンスを作るという発想になったのだと最近ようやく「感覚的に」理解出来ました。
 その筋の解説書を読むと「継承はオブジェクト指向という高貴な峰の頂」みたいな奇妙に美化した記述が多いのですが、その実態は「楽して俺様関数書きてぇ〜」って俗っぽい発想でした。美化した手段を書くだけで目的を書かない解説書が多いので感覚的にわからんかったのです。

#Python #[Art-Net]
Icon of admin
 本業もボチボチ忙しくなってガラクタ週間も終わりを迎えようとしています。

 現場と打ち合わせの合間にArt-Netです。
 受信したバイナリをそのままの送信出来ないようでは先には進めませんが送信できない問題。
 解決はしましたが、正規マニュアルや先達の書き込みに「これはちがう」とある設定で動いてしまいました。

 基本環境:RaspberryPi4 Rasbian_buster Python3.7.3
 ネットワークインターフェース:内臓LANポート(eth0)、USB-LANアダプタ(eth1)
 IPアドレス:eth0もeth1もArt-Net用に設定済み。
 試験環境:MAdot2でArt-Netを送出、RaspberryPiを経由、中華電機のArt-Netデコーダで受信、レガシーDMXをDoctorMXでモニタ。
 処理内容:eth0で受信したArt-Netのバイナリをeth1で送信するだけ(これが出来なきゃ始まらない)。

-----

import socket

def artnet_rx_tx():
 """ 基本パラメータセット """
 RECV_HOST_NAME = ''
 SENDTO_HOST_NAME = '255.255.255.255'
 PORT = 6454
 """ socket受信の設定 """
 artnet_rx_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  #UDPによるソケットを宣言(受信で使う)
 artnet_rx_sock.setsockopt(socket.SOL_SOCKET, 25, str("eth0" + '\0').encode('utf-8'))  #ソケットとNICを関連付け
 artnet_rx_sock.bind((RECV_HOST_NAME, PORT))  #送信元とポートをソケットに関連付け この場合はどこからの送信でも受けるって意味になる
 """ socket送信の設定 """
 artnet_tx_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  #UDPによるソケットを宣言(送信で使う)
 artnet_tx_sock.setsockopt(socket.SOL_SOCKET, 25, str("eth1" + '\0').encode('utf-8'))  #ソケットとNICを関連付け
 artnet_tx_sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)  #ソケットをブロードキャストとして使う宣言
 """ 中継 """
 for i in range(800):  #繰り返し
  artnet_rx_bytes, addr = artnet_rx_sock.recvfrom(1024)  #受信処理
  if len(artnet_rx_bytes) > 18:  #受信データ長が最低長以上かを確認 下行とandで一文にしても意味は同じですがヘッダー長を下回った時にエラーになる
   if artnet_rx_bytes[0:12] == b'Art-Net\x00\x00\x50\x00\x0e': #DMXの値データだけを選別 ヘッダーチェック
    artnet_tx_sock.sendto(artnet_rx_bytes, (SENDTO_HOST_NAME, PORT)) #送信処理 ここがわからんで時間を喰う
 """ 終了操作 """
 artnet_rx_sock.close()  #ソケットの仕舞い
 artnet_tx_sock.close()  #ソケットの仕舞い

※ 行頭の空白と#は全角で書いていますので、このままコピペするとエラーになります。
-----

 for文による繰り返しで800回中継を行うテストソースです。

 ポイントはBroadcastの送信先を指示する「SENDTO_HOST_NAME」です。socket.sendtoのパラメータです。「RECV_HOST_NAME」と同様に空白データを割り付けるベシとされるのが一般的ですが動きません。Broadcastアドレスを示す古い方法の'255.255.255.255'にしたところ稼働したという話です。
 '2.255.255.255'や'10.255.255.255'でも稼働しましたが、'255.255.255.255'はゾーンの末尾アドレスを示すマジックナンバーらしく汎用性が高いと思われます。

 動けばいいのですが、かなりの時間を喰ってしまい課題の残りが明日以降になりました。

 ここまで出来ればパッチマップによる入れ替え処理を作ります。
 壮大な繰り返し処理となりますので、どれだけ簡素に出来るかがカギになります。

#Python #[Art-Net]
Icon of admin
 オレメモです。

 パッチマップ(出力側ベース)
 ・フリーフェーダースロット
 ・ディレイ:<0>ならスルー、<1-255>ならディレイ
 ・ユニバース(入力参照)
 ・スロット(入力参照)
 ・カーブプロファイル:<0>ならスルー、<1-511>なら以下とする
   >カーブプロファイル<1-255>はノンディマーとしてしきい値とする
   >カーブプロファイル<256-511>はカーププロファイルマップを参照する

#[Art-Net]
Icon of admin
 Art-Netの受信に成功して処理負荷に余裕もあるとなれば落としどころをどうするか!?って話にもなるワケです。最大の望みはディレイ機能とカーブプロファイル機能を持ったパッチマシンですが、欲を出し過ぎたら頓挫します。
 さてさて、どこまで行けるのでしょう。

 お試しに次ぐお試しでとっ散らかったソースコードを整理整頓し、受信モニタとしてまとめ上げてからの話ですが、受信したArt-Netを送信する試験をしましょう。
 ただし、単にリレーするだけでは面白くないし処理負荷の確認にもなりません。受信をデコードし、1対1のパッチ処理をし、エンコードして送信することにします。1対1とはいえマッピングデータ用いた入れ替えをすれば最終形の負荷に近くなると思います。ここまでやれば天井が見えてくるでしょう。
 もしRaspberryPiには荷が重いならPCで動かせばいいって話もあります。今のところRaspberryPiというよりDebian上のPython3.7で動く様に作っていますのでPCでも動くと思います。レガシーDMXを搭載せずにいる理由の一つでもあります。

 今どきのムービング卓はArt-Netを出しますし、Art-Netのデコーダーは既製品が沢山ありますので、レガシーDMXまで作らなくてもいいかなぁ~なんて思ってます。専用基板を作る初期投資がキツイってのが一番大きいですが・・・

#Python #[Art-Net]
Icon of admin
 Art-Netの受信に成功しました。
 先達のサンプルコードをコピペしてPort番号を書き換えただけで一発OK。積年の成果が出て良かったのですが、あまりにも簡単だったので肩透かし。
 複数のNICを使い分けるsocketの設定は先達情報に何パターンかありますが、Rasbian上のPythonに合うパターンを見つけるのに少し時間がかかったかもしれません。
 今は卓のエフェクトエンジンで出力したデータが画面に流れております。4096chのディマーを256bpmの正弦波で動かしています。アホか。

 テストデータはMAdot2からですが、SequenceとPhysicalにデータが出ていました。
 Sequenceは単純なインクリメント情報、Physicalは卓内のUnivres番号です。
 送信を作るときにはこの流儀を真似しましょう。

 ただ、MAdot2はOpCode<0x5000>以外のArt-Netパケットも出しており、socketで受信したバイナリが19バイト以上で頭12バイトがb'Art-Net\x00\x00\x50\x00\x0E'であることを最初にチェックしないといけません。当初はバイト長も見ずにb'Art-Net\x00'だけでチェックしていたのでデコード処理でエラーが頻発でした。OpCodeによってデータ長も内容も違うので当然の結果ですが、マルチキャストなら<0x5000>以外のOpCodeは出さないと先入観で思ってしまったようです。よくないですね。

 8ユニバースを受信させています。すべてのユニバースをデコード処理までしていますが、思った以上に軽々動いています。
 Sequenceをキーに連続性をチェックしましたが読み飛ばしもしていないようです。

 今のところは先日作った画面ではなくすべてのパラメータを表示するチェック用の画面に表示していますが、先日作った画面を同時に動かしてもCPU負荷は45%程度です。最大値は400%(100%×4コア)なのでまだ余裕があります。

#Python #[Art-Net]
Icon of admin
 雪に隠れていた縁石に自家用車のタイヤをやられました。
 鋭利に割れていたのでサイドウォールがパックリ。雪は滑るだけが危険要素ぢゃないようです。
 サイドウォールは修理が出来ないので交換ですが、冬タイヤはトップシーズンのために割高な物しか手に入らず懐も寒くなりました。
 運が悪かったと思うしかありませんが、テンション下がるわー。
 開発が順調でテンションが上がっているので丁度いいのかもしれませんけど。

#日常
Icon of admin
 RaspberryPiを触っていて思うのですが、普通のPCにもRaspberryPi並みのGPIOがあればいいなと。
 RaspberryPi仕様のGPIOがベストって意味ではありませんが、PCにもローレベルのインターフェースがあったら制御で便利に使えるのになと。
 もちろん存在していますが、あまりにニッチ過ぎて情報が少ないために敷居が高いのです。
 主にUSB接続ですが、PCI-eボード1枚にI2C、SPI、USART、GPIOが「これでもか!」ってくらい載ってるのがあったら欲しいかも。

#妄想

■当面の課題

桜のライトアップの季節です。花粉症の季節でもあります。
自分は平気ですが、花粉症の部下は死にそうな顔をしています。

編集

■複合検索:

  • 投稿者名:
  • 投稿年月:
  • #タグ:
  • カテゴリ:
  • 出力順序:

■日付検索:

■カレンダー:

2022年2月
12345
6789101112
13141516171819
20212223242526
2728

■カテゴリ:

■最近の投稿:

最終更新日時:
2024年4月28日(日) 10時15分49秒