Introduction Video
Features
Cree MC-E Red/Green/Blue/Neutral White LED (1w per color)
Wakefield Starboard LED Heat Sink
Ledil 26° Lens (±13°) for Cree MC-E LEDs
Pan / Tilt servos, each with 180° of movement
Four Diodes Inc. AL8805 1A constant current LED drivers
Microchip PIC24FJ16GA002 16-bit 32MHz microcontroller
UART interface at 115,200bps, 8N1 via two 10 position 2mm-pitch sockets spaced for an XBee (series 1 is preferred) or the PAN1555 Bluetooth Breakout board.
Windows GUI interface to control color, intensity, and position, as well as create custom patterns and sequences.
DMX-512 interface
Functional Description
The Moving RGB LED combines a 4x1W LED (red, green, blue and neutral white), optics, heat sink, four adjustable constant current controllers, two servo motors (pan and tilt), a microcontroller, three PCBs, and the wireless interface of your choice, into a compact and powerful moving RGBW light source. The source is controllable via a Windows GUI, DMX512, our Joystick Remote (details forthcoming), or the wireless serial interface of your choice. The socket accepts any Digi XBee radio or any radio using the same land pattern and pinout. The only required connections to the XBee (or similar) are +3.3V (pin 1), Ground (pin 10), and UART data out (pin 2).
Communication
The Moving RGB LED currently accepts two packet types: position and color. The tilde [~] character denotes a position packet, and the asterisk [] character denotes a color packet. Following the tilde, the system expects an 8-bit pan value, followed by an 8-bit tilt value. Following the asterisk, the system expects 8-bit dimming values for Red, Green, Blue, and White, in that order. Controllers may send either packet type at any time, and a continuous stream of packets is acceptable. The receiver implements a simple state machine to enter color [] or movement [~] states, and resets to the start state if any other character is received. Should a packet of data become corrupted or incomplete, the state machine will reset.
Schematics
Because three separate PCBs exist, three schematics were created.
Left:
Center:
Right:
PCBs
The PCBs were fabricated by OSH Park
Mechanical Structure
From top to bottom, the Moving RGB LED is made of the LED optics, the LED, the LED heat sink, two spacers, three PCB’s, two servos, several zip-ties and copious amounts of hot glue. The PCBs are configured in an up-side-down “U” shape, allowing the weight of the heat sink and PCBs to be supported from two points. One side of the up-side-down “U” is a mechanical connection to the tilt servo output shaft, and the opposing side slides around a bushing which is concentric to the output shaft. The PCBs are connected orthogonally with ten position 0.1" right-angle header pins soldered to both PCBs. These pins provide mechanical coupling, as well as ten electrical connections, between each of the two side PCBs and the center PCB.
Software
Embedded
The Moving RGB LED is controlled locally by the PIC24FJ16GA002. The PIC24 generates PWM signals to dim (modulate) the brightness of each LED, and to control each servo. The LED PWMs are operated by the hardware PWM generator, and the servo signals are generated in software via a timer interrupt. The communication state machine operates in a UART receive interrupt.
main.c (7.7 KB)
Windows GUI
The GUI was developed in Visual Basic 2010 Express (free from Microsoft).
The GUI source files can be downloaded and built within Visual Basic. Currently, the COM port must be set in the source before compiling. If using the PAN1555 breakout board from Digi-Key, pair the device and connect a virtual COM port to determine the COM port number
Imports Microsoft.VisualBasic
Imports System
Imports System.Timers
Imports System.IO.Ports
'Imports System.Threading
Public Module global_variables
Public timer1_toggle As Boolean = False
Public timer1_started As Boolean = False
Public BlueTooth As IO.Ports.SerialPort = My.Computer.Ports.OpenSerialPort("COM33", 115200, IO.Ports.Parity.None, 8, IO.Ports.StopBits.One)
End Module
Public Class Form1
'Dim FTDI As IO.Ports.SerialPort = My.Computer.Ports.OpenSerialPort("COM1", 115200, IO.Ports.Parity.None, 8, IO.Ports.StopBits.One)
Dim color_MouseDown As Boolean = False
Dim vector_MouseDown As Boolean = False
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Integer, ByVal x As Integer, ByVal y As Integer) As Integer
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Integer) As Integer
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Integer)
Shared _timer As Timer
Shared _list As List(Of String) = New List(Of String)
Private Sub Start()
_timer = New Timer(5)
AddHandler _timer.Elapsed, New ElapsedEventHandler(AddressOf Timer1_Handler)
_timer.Enabled = True
End Sub
Private Sub Timer1_Handler(ByVal sender As Object, ByVal e As ElapsedEventArgs)
Static rgb(0 To 4) As Byte
Static Dim state As Byte
Static Dim counter As Byte = 0
If (timer1_toggle) Then
rgb(0) = 42
Select Case state
Case 0
rgb(1) = counter
Case 1
rgb(2) = counter
Case 2
rgb(1) = 255 - counter
Case 3
rgb(3) = counter
Case 4
rgb(2) = 255 - counter
Case 5
rgb(1) = counter
Case 6
rgb(3) = 255 - counter
End Select
counter = counter + 1
If (counter >= 255) Then
counter = 0
state = state + 1
If (state >= 7) Then
state = 1
End If
End If
BlueTooth.Write(rgb, 0, 4)
End If
End Sub
Private Sub PictureBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.MouseDown
Dim lColor As Integer
Dim lDC As Integer
lDC = GetWindowDC(0)
lColor = GetPixel(lDC, MousePosition.X, MousePosition.Y)
Dim red As Byte = lColor Mod 256
Dim grn As Byte = (lColor \ 256) Mod 256
Dim blu As Byte = lColor \ 256 \ 256
Dim rgb(0 To 4) As Byte
color_MouseDown = True
UpdateColors(red, grn, blu)
rgb(0) = 42
rgb(1) = red
rgb(2) = grn
rgb(3) = blu
BlueTooth.Write(rgb, 0, 4)
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.MouseMove
Dim lColor As Integer
Dim lDC As Integer
lDC = GetWindowDC(0)
lColor = GetPixel(lDC, MousePosition.X, MousePosition.Y)
Dim red As Byte = lColor Mod 256
Dim grn As Byte = (lColor \ 256) Mod 256
Dim blu As Byte = lColor \ 256 \ 256
Dim rgb(0 To 4) As Byte
If (color_MouseDown) Then
UpdateColors(red, grn, blu)
rgb(0) = 42
rgb(1) = red
rgb(2) = grn
rgb(3) = blu
BlueTooth.Write(rgb, 0, 4)
End If
End Sub
Private Sub PictureBox1_MouseUp(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.MouseUp
color_MouseDown = False
End Sub
Private Sub MovementBox_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MovementBox.MouseDown
Dim rgb(0 To 3) As Byte
Dim x As Integer
Dim y As Integer
Dim newMousePosition As New System.Drawing.Point
newMousePosition = Cursor.Position
' Send a Tilde (~), then the x and y coordinates of the mouseclick within the picturebox.
vector_MouseDown = True
If (e.X < 10) Then
newMousePosition.X = MovementBox.Left + 10
ElseIf e.X > 775 Then
newMousePosition.X = MovementBox.Right - 10
End If
If (e.Y < 10) Then
newMousePosition.Y = MovementBox.Top + 36
ElseIf e.Y > 775 Then
newMousePosition.Y = MovementBox.Bottom + 10
End If
System.Windows.Forms.Cursor.Position = newMousePosition
x = MovementBox.Width - e.X - 10
y = MovementBox.Height - e.Y - 10
If (y < 0) Then
y = 0
ElseIf (y > 765) Then
y = 765
End If
If x < 0 Then
x = 0
ElseIf (x > 765) Then
x = 765
End If
TextBox5.Text = x
TextBox6.Text = y
rgb(0) = 126
rgb(1) = x / 3
rgb(2) = y / 3
BlueTooth.Write(rgb, 0, 3)
End Sub
Private Sub MovementBox_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MovementBox.MouseMove
Dim rgb(0 To 3) As Byte
Dim x As Integer
Dim y As Integer
Dim newMousePosition As New System.Drawing.Point
newMousePosition = Cursor.Position
If vector_MouseDown Then
If (e.X < 10) Then
newMousePosition.X = MovementBox.Left + 10
ElseIf e.X > 775 Then
newMousePosition.X = MovementBox.Right - 10
End If
If (e.Y < 10) Then
newMousePosition.Y = MovementBox.Top + 36
ElseIf e.Y > 775 Then
newMousePosition.Y = MovementBox.Bottom + 10
End If
System.Windows.Forms.Cursor.Position = newMousePosition
x = MovementBox.Width - e.X - 10
y = MovementBox.Height - e.Y - 10
If (y < 0) Then
y = 0
ElseIf (y > 765) Then
y = 765
End If
If x < 0 Then
x = 0
ElseIf (x > 765) Then
x = 765
End If
TextBox5.Text = x
TextBox6.Text = y
rgb(0) = 126
rgb(1) = x / 3
rgb(2) = y / 3
BlueTooth.Write(rgb, 0, 3)
End If
End Sub
Private Sub MovementBox_MouseUp(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MovementBox.MouseUp
vector_MouseDown = False
End Sub
Private Sub StrobeButton_MouseDown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StrobeButton.MouseDown
If (timer1_started = False) Then
Start()
timer1_started = True
End If
If (timer1_toggle = True) Then
timer1_toggle = False
Else
timer1_toggle = True
End If
End Sub
Public Sub UpdateColors(ByVal red As Byte, ByVal grn As Byte, ByVal blu As Byte)
Button1.Text = red
Button2.Text = grn
Button3.Text = blu
BackColor = Color.FromArgb(red, grn, blu)
End Sub
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
Dim lColor As Integer
Dim lDC As Integer
lDC = GetWindowDC(0)
lColor = GetPixel(lDC, MousePosition.X, MousePosition.Y)
Dim red As Byte = lColor Mod 256
Dim grn As Byte = (lColor \ 256) Mod 256
Dim blu As Byte = lColor \ 256 \ 256
Dim rgb(0 To 4) As Byte
color_MouseDown = True
UpdateColors(red, grn, blu)
rgb(0) = 42
rgb(1) = red
rgb(2) = grn
rgb(3) = blu
BlueTooth.Write(rgb, 0, 4)
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
End Sub
End Class