Moving RGB LED from Another Geek Moment Video

* Created by Chris Baird, last modified on Jan 25, 2013

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