はじめに
目的はタイトルの通りですが,タイトルの通りまだうまく行っていないので経験者の方にアドバイスをお願いしたいです。
n_takeshiさんのご助言により動作確認しました!ありがとうございました!
- DMX信号をPython(またはC)で制御したい
- Windows環境(Unixでも根幹は同じと思う)
E社の製品との比較
お金がある人はまず,ENTTEC社などの整備された商品を買うべきです。
あちらはもっと手軽に制御ができます。
後ほど,ENTTEC社の製品を買って試しましたがPython用のLibraryは試せませんでした。
なにかセットアップ手順が欠けてたのかな?
関連記事
上記のちゃんとしたパッケージはべらぼうに高く(数万円くらい),これを手作りする需要は結構あります。
https://kizaihan.jp/?p=199
https://qiita.com/Ina3/items/f88a584d2011e99fc7ed
実はDMXはRS485というRS232の上位互換的なシリアル通信の規格の一部であるのでUSB-RS485変換器で自作できるという寸法のようです。
今回はそれを用いてプログラムで制御したいというのが悩ましいところなのですが…
DMX信号とは
DMX信号というものの仕様について述べます。
以下のサイトにあるように,DMX信号はRS485の規格を用いたシリアル通信の亜種だと思って良さそうです。
http://www.tamatech.co.jp/tamada/benkyo04.php
構成としては,
- 88us以上のBreak(LOW)信号
- 8us以上のMAB(High)信号
- 本体のデータ
- 0~1秒の休止
となっているらしいです。以上というのが曲者でこれが明確に仕様として決定されておらず,機器間の相性という問題が生じる原因となっております。
また,本体となる通信データに関しては,
- 250kbpsのBaudrate
- スタート1bit(Low)
- ストップ2bit(High)
と決まっております。
PySerialを用いたDMX信号もどきを作る挑戦
このように仕様さえわかってしまえばArduinoなどで自作できるわけですが,
https://qiita.com/Ina3/items/56a89c3cf8958bb6a0f8
やっぱり汎用PCで組んで制御したいです。
最近はもっぱらPythonを使ってプロトタイプ作成をしているのでPythonでこれを実現しようとした試みが本記事です。(上手く行っていないが)
プランとしては
- 接続を確立
- 通信を88us以上BreakStateにしてLowを送る。
- その後BreakStateを解除して8usの間Highを送る。
- 512chのデータを整形して送る。
となっています。レファレンスとにらめっこしながら進めます。
8/2 Trial :失敗
ここでの失敗の原因はスタートビット0x00を忘れていたことでした。
n_takeshiさん,ご助言どうもありがとうございました。
8/3 Trial:成功
データを512byteとするとスタートビットを含めて513byte送る必要があるのでデータサイズを変更します。
1.接続を確立
シリアルポートへの初期接続時にバイトサイズやストップビット,baudrateを設定します。
import serial
import time
import numpy as np
# start serial
ser = serial.Serial('COM8',baudrate=250000,bytesize=8,stopbits=2)
2.データ作成
みんな大好きnumpyでデータを作成します。(個人的都合もある)
512ch+スタートビット1chなのでuint8
の513列の配列を作成します。
# make data
data = np.zeros([513],dtype='uint8')
data[0] = 0 # スタートコードは0
data[0] = 255
data[1] = 20
なお,このままだと送信できないのでbytearray()
というコマンドで送信用のバイト列へと変換する必要があります。このへんはシリアル通信あるあるですね。
3.DMXとしてデータ送信
鬼門です。
レファレンスを読むに,break_condition = True
とすることでLow信号を送れるような記述になっているのでこれとsleep()
を組み合わせてDMX信号もどきを制作します。
for i in range(1,20): # 繰り返し回数は適当
ser.break_condition = True # Break
time.sleep(176.0/1000000.0)
ser.break_condition = False # MAB
time.sleep(16.0/1000000.0)
ser.write(bytearray(data)) # データ送信
time.sleep(500.0/1000.0) # 一休み
んで,変換器の応答やCOMポートの監視をすると,ちゃんと送信はされてるっぽいんですけど,DMX信号としては認識してくれてないんですよね~。
総評
8/2現在ではDMX信号の生成に成功していないです。
- Pythonでusレベルの制御ができているのか謎(とくにWindowsではどうなんでしょうねぇ?)
- break_conditionを使うべきではない?
など懸念は山盛りですが,とりあえず動作はしております。
** 公開用ソースコード
シンプルなコードですが一応レポジトリを作ってみたり。
https://github.com/YoshiRi/PyDMX
オブジェクト指向でパッケージ化するかは必要に駆られたら考えます。