uart2dmx

Para os mais especializados em mecânica e electrónica em LEGO.
Responder
Avatar do Utilizador
CyberX
Sócio
Sócio
Mensagens: 4529
Registado: 10 mar 2014, 20:09
Localização: Mira Sintra
Contacto:

uart2dmx

Mensagem por CyberX »

Na sequência do meu post anterior (uart2midi) venho agora mostrar uma forma de usar Pybrics para controlar dispositivos DMX como luzes de palco.

O objectivo de ambos (uart2midi e uart2dmx) é poder estender a demonstração do meu gira-discos vinil
para um ambiente "disco" com sintetizadores, luzes, máquinas de bolhas de sabão e quem sabe canhões
de confetti :)

Agora a introdução LONGA e no final o video. O código segue logo à noite.

DMX surgiu em 1986 como um standard para controlo de iluminação de palco, para acabar com a confusão de incompatibilidades entre diferentes fabricantes. Evoluiu depois para um standard ANSI e é agora um padrão universal, com evoluções para wireless e até TCP. E já não se limita a iluminação, foram adicionados efeitos e coisas mais complexas.

Na prática, um controlador DMX (um PC ou um equipamento semelhante a uma mesa de mistura) tem pelo menos uma ams habitualmente mais portas de saída, cada porta gerindo um "universo" de dispositivos ligados em daisy chain:

- do controlador sai um cabo DMX que liga à ficha IN do dispositivo mais próximo
- cada um dos restantes dispositivos liga à ficha OUT do dispositivo anterior
- o ultimo dispositivo termina a rede ligando-se um terminador à ficha OUT (à semelhança das primeiras
redes Ethernet que usavam cabo coaxial)

Internamente cada dispositivo tem a porta IN ligada à porta OUT. Assim se estiver desligado ou avariado não põe em causa a comunicação com os restantes dispositivos da cadeia (como é suposto acontecer nas luzes de natal).

A comunicação em si é semelhante aos outros protocolos série, sendo enviados 8 bits seguidos de 2 stop bits, sem paridade (portanto 8N2). Só o ritmo de transmissão é um bocado invulgar (250 kbps) e antes da transmissão é gerado um preâmbulo que é um género de start bit mas bastante mais longo. Depois é enviado um primeiro byte (o Start Code, que em geral e para o caso é 0) seguido de um byte para cada endereço no universo (por exemplo se tiver 2 projectores de palco, um que responde ao endereço 1 e outro que responde ao endereço 9, é enviado um byte com os dados para o endereço 1, depois 7 bytes vazios e finalmente outro byte para o endereço 9).

Isto significa que, querendo efeitos rápidos, é preferível ajustar cada dispositivo para endereços baixos para reduzir a duração de cada broadcast. No limite, distribuir por vários universos (controladores com várias portas).

Além disso como a comunicação não é bidirectional 1 para 1 (em que se cruzam os Tx/Rx de 2 dispositivos) e sim unidirectional 1 para muitos (broadcast) o meio é um pouco mais complexo, tendo sido escolhido o RS-485, muito utilizado em ambientes industriais e laboratoriais por ser muito mais imune ao ruído e permitir distâncias muito grandes.

Como existem circuitos conversores UART-RS485 foi só uma questão de arranjar um que suportasse a alimentação e níveis lógicos dos Hubs Powered Up (3.3 Volt). Bastou ligar os mesmos 3 fios do meu adaptador uart2midi (3V3, GND e TX) ao lado UART do circuito e ligar meio cabo DMX aos pontos A, B e GND do lado RS484.

(na verdade tive também de soldar uma resistência para puxar o pino RTS do circuito para poder pô-lo
em modo de envio. Há circuitos que controlam o fluxo automáticamente, mas este não)

Do lado do software, a implementação UART do Pybricks só prevê 8N1 sem preâmbulos. 8N2 não é problema, basta fazer uma pausa muito curta entre cada byte enviado (depois acabei por descobrir que nem é preciso) mas o preâmbulo é mais complicado e ainda por cima é vital por servir para acordar todos os dispositivos no mesmo universo para estarem atentos a um broadcast. Depois dalgumas contas arranjei um hack: baixo o baudrate de 250 kbps para 90909 kbps e envio um 80h que na prática são 7 bits zero seguido de um bit 1 e acaba funcionando como preâmbulo.

A prova de conceito: um Hub Technic a controlar um universo DMX com dois focos PAR (um RGB no endereço 1 e outro RGB no endereço 8 orque o primeiro requer 8 bytes para as várias funcionalidades). O script python lê o IMU do hub para controlar os valores de Red, Green e Blue com a orientação e um contador para controlar a luminosidade do UV:

Jorge Pereira
«De génio, criança e louco... porquê só 1 pouco?»
Avatar do Utilizador
CyberX
Sócio
Sócio
Mensagens: 4529
Registado: 10 mar 2014, 20:09
Localização: Mira Sintra
Contacto:

Re: uart2dmx

Mensagem por CyberX »

E agora o código - com comentários e tudo, até pareço uma IA!

Código: Selecionar todos

from pybricks.hubs import TechnicHub
from pybricks.parameters import Port
from pybricks.iodevices import UARTDevice

hub = TechnicHub()
ser = UARTDevice(Port.A)

payload = [b'\x00']*513 # DMX512 supports up to 512 channels
                        # preceded by a Start Code

payload[0] = b'\x00'    # Start Code

# PAR RGB has 7 channels and DMX address = 1
payload[1] = b'\x00'    # CH1 Mode
payload[2] = b'\xFF'    # CH2 RGB Color
payload[3] = b'\x00'    # Speed
payload[4] = b'\xFF'    # Master dimmer
payload[5] = b'\xFF'    # R
payload[6] = b'\x00'    # G
payload[7] = b'\x00'    # B

# PAR UV has 4 channels and DMX address = 8
payload[8] = b'\xFF'    # Master Dimmer
payload[9] = b'\xFF'    # UV Color
payload[10] = b'\x00'   # Strobe off
payload[11] = b'\x00'   # Mode

num_channels = 11       # no need to send more frames than the
                        # number of channels usable in the whole fixture

def pause():
    pass

i = 0
while True:
    pitch, roll = hub.imu.tilt()
    heading = hub.imu.heading()

    payload[5] = int((abs(int(pitch))*360/256)).to_bytes(1,'endian')   # R
    payload[6] = int((abs(int(roll))*360/256)).to_bytes(1,'endian')    # G
    payload[7] = int((abs(int(heading))*360/256)).to_bytes(1,'endian') # B

    payload[9] = i.to_bytes(1,'endian')     # UV Brightness
    i+=2
    if i>255:
        i=0

    # Break + Mark-After-Break
    # need an hack because Pybricks UART doesn't allow to define a preamble
    # so we send something similar at a lower baud rate
    ser.set_baudrate(90909)
    ser.write(b'\x80')

    ser.set_baudrate(250000)

    for frame in range(0, num_channels):
        ser.write(payload[frame])

        # DMX uses 8N2 instead of 8N1
        # so a small pause would be needed
        # but it turns out it isn't (at least
        # with my PARs)

        # pause()

    wait(15)

Jorge Pereira
«De génio, criança e louco... porquê só 1 pouco?»
Avatar do Utilizador
AVCampos
Sócio
Sócio
Mensagens: 13802
Registado: 27 fev 2007, 19:26
Localização: Barreiro
Contacto:

Re: uart2dmx

Mensagem por AVCampos »

Para além do potencial inerente a uma coisa dessas, foi isto o que me saltou mais à vista:
CyberX Escreveu: 11 jun 2026, 14:37 e quem sabe canhões
de confetti :)
Imagem
Avatar do Utilizador
CyberX
Sócio
Sócio
Mensagens: 4529
Registado: 10 mar 2014, 20:09
Localização: Mira Sintra
Contacto:

Re: uart2dmx

Mensagem por CyberX »

"DMX512 does not include automatic error checking and correction and therefore is not an appropriate control for hazardous applications, such as pyrotechnics or movement of theatrical rigging. However, it is still used for such applications.
False triggering may be caused by electromagnetic interference, static electricity discharges, improper cable termination, excessively long cables, or poor quality cables."
DISCLAIMER: Não me responsabilizo pelo uso indevido de LEGO e DMX
(até porque a minha experiência é que normalmente os meus dois projectores acendem-se por breves momentos se os tiver ligados antes de começar a correr o meu script, há ali um handshaking qualquer que para o lado dos projectores equivale a um "bora lá acender tudo!")

Posto isto... se alguém que quiser pagar uns 500 cafés ando a namorar uma máquina de faíscas frias, supostamente 101% segura (vê-se que o tipo do marketing nunca lidou com um engenheiro)
Jorge Pereira
«De génio, criança e louco... porquê só 1 pouco?»
Responder