このページの機能は Harucom OS 2.0 から使えます。

DMX モジュールは、舞台照明で使われている DMX512 の信号を出力します。 ムービングライトやパーライトを Harucom から制御できます。

信号の送信はバックグラウンドで動くエンジンが受け持ちます。 1秒間に40回、512チャンネル分のデータが自動で送られるので、 Ruby からは値を書き換えるだけで済みます。

目次

接続する

DMX は RS-485 という規格の信号を使うので、変換モジュールが必要です。 M5Stack の DMX Unit のような、絶縁されたトランシーバを Grove コネクタ(J5)につないでください。

項目 値
UART UART1、250000 baud、8ビット、パリティなし、ストップビット2
TX ピン GPIO 20(Grove コネクタ J5)
フレームレート 約 40 Hz

Harucom からは信号を送るだけなので、受信用のピンは使いません。

基本的な使い方

送信を始める

require "board/dmx"

dmx = Board::DMX.new
dmx.start            # すべてのチャンネルを0にして送信を始める

dmx[6] = 255         # 6番のチャンネルを最大にする

loop do
  dmx.keepalive      # 動いていることを知らせる
  sleep_ms 10
end

dmx.stop             # 消灯してから送信を止める

Board::DMX.new で初期化し、start で送信を始めます。 あとはチャンネルに値を書き換えていくだけで、送信はバックグラウンドで続きます。

主ループでは keepalive を呼びます。 これを止めると照明が消える仕組みになっています。 デッドマンスイッチで説明します。

チャンネルに値を書く

チャンネルの番号は 1 から 512、値は 0 から 255 です。 どのチャンネルが何を意味するかは、つないだ照明によって決まります。

dmx[6] = 255                                  # 1チャンネルだけ書く
dmx.set_range(1, [pan, tilt, 0, 0, 0, 128])   # 連続したチャンネルにまとめて書く

ムービングライトのように、まとまった数のチャンネルを1台で使う照明では set_range が使えます。

書いた値は次のフレーム(最大 25 ミリ秒後)で照明に届きます。

照明を制御する

require "board/dmx" で読み込みます。

Board::DMX.new

dmx = Board::DMX.new

基板の既定の配線(Grove コネクタ)で DMX を初期化します。 この時点ではまだ何も送りません。 配線を変えたい場合は DMX モジュールを使います。

Board::DMX#start

すべてのチャンネルを0にしてから、送信を始めます。

start はチャンネルを0に戻します。値を設定するのは start のあとにしてください。

Board::DMX#stop

すべてのチャンネルを0にし、それが照明に届くのを待ってから送信を止めます。

照明は信号が届かなくなっても最後の値を保つので、送信を止めるだけでは点いたままになります。 stop はそれを避けるために、消灯を確かめてから止めます。

Board::DMX#set(channel, value)

dmx.set(6, 255)
dmx[6] = 255      # 同じ意味

1つのチャンネルに値を書きます。channel は 1 から 512、value は 0 から 255 です。 範囲の外を指定した場合は何も起きません。

Board::DMX#set_range(channel, values)

dmx.set_range(1, [pan, tilt, 0, 0, 0, dimmer])

channel から順に、配列の値を書きます。 1台で複数のチャンネルを使う照明に便利です。

Board::DMX#get(channel)

dmx.get(6)   #=> 255
dmx[6]       # 同じ意味

チャンネルにいま書かれている値を返します。

Board::DMX#blackout

すべてのチャンネルを0にします。次のフレームで照明が消えます。 送信は続くので、値を書けばまた点きます。

Board::DMX#keepalive

デッドマンスイッチに、プログラムが動いていることを知らせます。 主ループから毎回呼んでください。くわしくはデッドマンスイッチをご覧ください。

Board::DMX#deadman_ms=(ms)

dmx.deadman_ms = 1000
dmx.deadman_ms = 0      # 無効にする

keepalive が途切れてから照明を消すまでの時間をミリ秒で指定します。 既定は 500 ミリ秒で、0 にすると無効になります。

Board::DMX#active_slots=(count)

送信するチャンネル数を 1 から 512 で指定します。 使っているチャンネルの数まで減らすと、フレームとフレームの間隔が空きます。

Board::DMX#frame_count

start してから送信したフレームの数を返します。 1秒あたり約40増えるので、実際の送信レートを確かめられます。

デッドマンスイッチ

照明は、信号が届かなくなっても最後に受け取った値を保ち続けます。 そのためプログラムが止まってしまうと、照明が点いたままになってしまいます。

これを防ぐために、エンジンにはデッドマンスイッチが組み込まれています。 keepalive がしばらく呼ばれないと、エンジンがすべてのチャンネルを0にして照明を消します。

loop do
  dmx.keepalive
  # ここで値を変える
  sleep_ms 10
end

待ち時間は deadman_ms= で変えられます。既定は 500 ミリ秒です。 keepalive を再び呼ぶと、Ruby で設定した値がまた反映されるようになります。

この仕組みはエンジンの側だけで動くので、Ruby が止まっていても働きます。

DMX モジュール

Board::DMX は DMX モジュールを使いやすくしたものです。 set や keepalive などは DMX にも同じ名前と引数であります(DMX.set(6, 255) のように書きます)。 DMX を直接使うのは、配線を変えたいときです。

DMX.init(unit:, txd_pin:)

DMX.init                                       # 基板の既定の配線を使う
DMX.init(unit: :RP2040_UART1, txd_pin: 20)

UART を DMX512 用に初期化します。引数を省略すると基板の既定の配線になります。 txd_pin には、その UART で TX に使えるピンを指定してください。 確保した DMA チャンネルの番号を返します。

通信速度(250000 baud、8ビット、パリティなし、ストップビット2)は規格で決まっているので変えられません。

Board::DMX.new は、このメソッドを引数なしで呼んでいます。

DMX.stop と DMX.shutdown

DMX.stop は送信を止めるだけです。照明は最後の値を保ったままなので、点いていれば点いたままになります。

DMX.shutdown は消灯してから送信を止めます。Board::DMX#stop が呼んでいるのはこちらです。

照明の定義ファイル

チャンネルの並びは照明の機種ごとに違います。 Open Fixture Library の JSON 形式の定義ファイルを /data/dmx/fixtures に置いておくと、チャンネルに名前を付けて扱えます。

require "dmx/fixture"

paths = DMX::Fixture.list("/data/dmx/fixtures")
fixture = DMX::Fixture.read(paths[0])

fixture[:name]                #=> "SHEHDS 80W LED Spot Light"
mode = fixture[:modes][0]
mode[:label]                  #=> "13ch"
mode[:channels][5][:name]     #=> "Dimmer"

mode[:channels] は信号に流れる順番に並んでいます。 i 番目のチャンネルの番号は、その照明の先頭アドレスに i を足した値になります。

定義ファイルを使ったアプリとして dmx_demo が入っています。 パターンで音と照明をまとめて動かしたい場合は Johakyu を使います。