I work with theater and set design. And I often wondered if there was a way to interface stage devices directly with the light table, so that the technical team could synchronize these effects from the lighting booth. This is my first experience in this regard.
The reason I used CircuitPython for this project was to keep the logic as understandable as possible. There are several libraries for Arduino in C++ ready to be used with this protocol. But often, the codes are copied and pasted without much understanding of what is happening. With Python, I think this understanding is easier.
I preferred the Maker Pi RP2040 to reduce the number of external modules. I just added the motors, servos and the external RS485 module and that was it! Everything was ready to run. I have not yet tested it using a light table or other reflectors on the same bus.
First of all, it is important to bring up some points that took me a while to understand. For example, RS485 is a hardware interface standard defining the electrical characteristics of a serial communication network. DMX and MODBus are both Software protocols. So technically it would be possible to use a microcontroller to convert DMX commands to specific MODBUS commands, which is my ultimate goal.
This understanding was what motivated me to try to develop a USB-DMX interface using a microcontroller, which was the first step of my research. There are several solutions for this approach, but I would like to highlight the ARTNet to DMX converter using ESP32.
For now, my solution was to create a proof of concept using simple motors that I already had available. My system allows me to control the angles of four independent servo motors, change the colors of the Neopixel LEDs on the board, move two DC motors independently, with speed, stop and direction control. All this using the light table.
import board, neopixel
from simpleio import map_range
import pwmio
from adafruit_motor import servo, motor
# Copy files from https://github.com/mydana/CircuitPython_DMX_Receiver onto lib folder
from dmx_receiver import DmxReceiver
DMX_PIN = board.GP1 # RS 485 module connected on UART
PIXEL_PIN = board.GP18 # neopixel on board, dois LEDS RGB
# Read 16 sequential channels from DMX starting at Slot 0
dmx_receiver = DmxReceiver(pin=DMX_PIN, slot=0)
# pin: The pin to retrieve data from.
# dmx_basis: If True start slot numbers at 1 not 0. - Use true, to follow DMX Channel standards
# slot: The first DMX slot of 16 to listen for.
# Neopixel Setup
pixels = neopixel.NeoPixel(PIXEL_PIN, 2)
servo_pwm1 = pwmio.PWMOut(board.GP12, duty_cycle=2 ** 15, frequency=50)
servo_pwm2 = pwmio.PWMOut(board.GP13, duty_cycle=2 ** 15, frequency=50)
servo_pwm3 = pwmio.PWMOut(board.GP14, duty_cycle=2 ** 15, frequency=50)
servo_pwm4 = pwmio.PWMOut(board.GP15, duty_cycle=2 ** 15, frequency=50)
motor1_pwm_a = pwmio.PWMOut(board.GP9, frequency=50)
motor1_pwm_b = pwmio.PWMOut(board.GP8, frequency=50)
motor1 = motor.DCMotor(motor1_pwm_a, motor1_pwm_b)
motor2_pwm_a = pwmio.PWMOut(board.GP10, frequency=50)
motor2_pwm_b = pwmio.PWMOut(board.GP11, frequency=50)
motor2 = motor.DCMotor(motor2_pwm_a, motor2_pwm_b)
servo1 = servo.Servo(servo_pwm1)
servo2 = servo.Servo(servo_pwm2)
servo3 = servo.Servo(servo_pwm3)
servo4 = servo.Servo(servo_pwm4)
for data in dmx_receiver:
if data is not None:
# Convert Bytes to a Integer List - Debug only
dmx_list = list(data)
print(dmx_list)
# CHANNEL 1, 2, 3 e 4 - RGB and Brightness
color_red = dmx_list[0] # Channel 1
color_green = dmx_list[1] # Channel 2
color_blue = dmx_list[2] # Channel 3
pixels.brightness = map_range (dmx_list[3], 0,255, 0.0,1.0) # Channel 4
pixels[0] = (color_red, color_green, color_blue)
pixels[1] = (color_red, color_green, color_blue)
pixels.show()
# Channels 5 to 8, Four Servo positions
servo1.angle = map_range (dmx_list[4], 0,255, 0,180) # Channel 5
servo2.angle = map_range (dmx_list[5], 0,255, 0,180) # Channel 6
servo3.angle = map_range (dmx_list[6], 0,255, 0,180) # Channel 7
servo4.angle = map_range (dmx_list[7], 0,255, 0,180) # Channel 8
# Channels 9 and 10 - Motor 1 Speed and Direction
motor1_speed = map_range(dmx_list[8], 0,255,0, 1.0) # Channel 9
motor1_direction = dmx_list[9] # Channel 10
if motor1_speed == 0:
motor1.throttle = None # Shutdown Motor
else:
if motor1_direction in range (0,127):
motor1.throttle = motor1_speed
else:
motor1.throttle = motor1_speed * -1.0
# Channels 11 and 12 - Motor 2 Speed and Direction
motor2_speed = map_range(dmx_list[10], 0,255,0, 1.0) # Channel 11
motor2_direction = dmx_list[11] # Channel 12
if motor2_speed == 0:
motor2.throttle = None
else:
if motor2_direction in range (0,127):
motor2.throttle = motor2_speed
else:
motor2.throttle = motor2_speed * -1.0
Comments
Please log in or sign up to comment.