🚀 NITELITE V2.0A – Gesture-Controlled RGB LED using PICAXE 08M2+, VL53L0X & WS2801

radiosparks

Well-known member
klaatu-ship-interior-from-the-day-the-earth-stood-still-1951_320.jpg
After watching The Day the Earth Stood Still (1951) for the gazillionth time, I was inspired by the gesture control panel in Klaatu’s ship.

My code library is now pretty solid, thanks to digging through the Forum for all the snippets I needed. I mashed together a little gesture control setup for myself. There’s a lot of silicon in this project, but the wiring is surprisingly simple.

The main microcontroller is the infamous PICAXE 08M2+. Right next to it is a VL53L0X Time-of-Flight (ToF) laser-ranging module, which also handles gesture recognition via I2C. Beside that is a WS2801—a PWM constant-current LED driver with an integrated RGB LED, controlled by the MCU using bit-banged ports. For this to work, the PICAXE runs at 16MHz. The RGB LED uses logarithmic brightness ramping stored in EEPROM.

In this snippet, gesture detection toggles the LED:
  • Move toward the sensor → LED turns on
  • Move away → LED turns off
  • If the LED stays on, it times out after ~10 seconds
Distances between 50mm–150mm trigger LED_ON, while 150mm–200mm or a timeout trigger LED_OFF.

I’ve got one precious pin left—C.3. Perfect for a future IR remote-controlled lighting effect.

Memory usage is super low. Syntax Check reports 183 bytes, plus 32 bytes of EEPROM for the brightness table.

Code:
#rem

  ---[ Program Description ]---------------------------------

   NITELITE V2.0A ? Gesture-Controlled RGB LED using
   PICAXE 08M2+ Microcontroller
   VL53L0X Time-of-Flight (ToF) laser-ranging
   WS2801 PWM constant current LED driver

  ===========================================================
   PICAXE Editor ... Version 6.2.1.0
   Library File  ... 08M2_WS2801_RGB_LED_LIGHTHOUSE_FLASH.bas
   Library File  ... PICAXE_08M2_VL53L0X_TOF V2.bas
   Author        ... radioSPARKS [VE3XRM]
   Started       ... rhb.20250828
   Nitelite      ... rhb.20250903 Refactored code for ToF Nitelite
  ===========================================================

   Memory Used: 183 BYTES plus 32 BYTES for EEPROM - rhb.20250904

#endrem

' ---[ Compiler Directives ]--------------------------------

#picaxe 08M2
setfreq M16     ; It's "The need for Speed", to Bit-Bang the WS2801
#no_data        ; REM to store EEPROM data in the PICAXE chip

' ---[ MCU PORT Connections ]-------------------------------

'// WS2801
symbol SDataPIN      = pinC.0    ; SDI PIN #7 - used to output 1 bit of data to WS2801 Data-In Pin
symbol S_Data        = C.0         ; SDI - also defined this way to use with the LOW command in Init:
symbol S_Clock       = C.4         ; CKI PIN #3 - clock to WS2801 Clock-In Pin

'// VL53L0X
symbol SDA          = c.1       ; I2C Serial Data  on PIN #5
symbol SCL          = c.2       ; I2C Serial Clock on PIN #6

' ---[ Constants ]------------------------------------------

symbol Step_Delay   = 10         ; 4000 for a 1 sec delay at 16 MHz on M2 MCU
symbol RAMbaseADDR  = $08        ; start of LED data - stored in B8, B9, and B10 RAM registers
symbol NUM_LED      = 3         ; number of individual LEDs in one RGB LED (RED,GREEN,BLUE)
symbol stepCount    = 31        ; number of EEPROM steps in brightness

' ---[ Variables ]------------------------------------------

'// WS2801
symbol LED_Data     = b0         ; NOTE: BIT register for subroutine: sendData
symbol MemPTR       = b2        ; RAM memory pointer for LED RGB Byte Data
symbol sendBYTE     = b3        ; BYTE counter for data to WS2801
symbol ledTimer     = w3        ; LED Auto OFF Timer
symbol RED_Data     = b8        ; RAM Data byte for RED
symbol GREEN_Data   = b9        ; RAM Data byte for GREEN
symbol BLUE_Data    = b10       ; RAM Data byte for BLUE

'// VL53L0X
symbol DISTANCE     = w2        ; distance in mm recorded in registers (b5:b4) as word w2
symbol hiByte       = b5        ; high byte data from VL53L0X
symbol loByte       = b4        ; low  byte data from VL53L0X

'symbol ircmd       = b13       ; not used
                                ; - reserved [Future Feature!] to add IR remote control - rhb.20250903

' ---[ EEPROM Data WS2801 ]---------------------------------

    #rem - from stackoverflow
        5 bit CIE Lightness to 8 bit PWM conversion Math
        L* = 116(Y/Yn)^1/3 - 16 , Y/Yn > 0.008856
        L* = 903.3(Y/Yn), Y/Yn <= 0.008856
    #endrem

    '// RAMP LONG 32 logarithmic values - RAMP OFF/ON Data
    EEPROM $00, (  0,  1,  2,  3,  4,  5,  7,  9)
         EEPROM ( 12, 15, 18, 22, 27, 32, 38, 44)
         EEPROM ( 51, 58, 67, 76, 86, 96,108,120)
         EEPROM (134,148,163,180,197,216,235,255)

    '// RAMP SHORT 19 logarithmic values - RAMP OFF/ON/OFF Data for a quick blink
    'EEPROM $00, (0,1,2,3,7,15,31,63,127,255,127,63,31,15,7,3,2,1,0)

' ---[ Program Start ]--------------------------------------

' ---[ Initialization ]-------------------------------------

Init:

    ' WS2801
    Low S_Data        ; set pin as an output
    Low S_Clock        ; set pin as an output

    ' VL53L0X
    hi2csetup i2cmaster, 0x52, i2cfast_16, i2cbyte

' ---[ Program Code ]---------------------------------------

Main:
    do
        ' ---[ Toggle LED Controller ]---
      
        call readDistance
      
        if DISTANCE > 50 and DISTANCE < 150 and MemPTR = 0 then
            call LED_ON             ; LED ON only when object closer than 150mm and LED is OFF
            ledTimer = time + 10    ; Set Auto-off LED Timer - currently for demo is 10 seconds

        elseif  DISTANCE > 150 and DISTANCE < 200 and MemPTR > 0 then
            call LED_OFF            ; LED OFF when object moves away and LED is ON

        else
            if time > ledTimer and MemPTR > 0 then
              
                call LED_OFF        ; Auto-off after timeout - rem if using dim over time feature
              
                ' Slowly dim the LED over a long period of time
                ' - starts after the timeout - takes a little over 1 minute to be OFF
                'dec MemPTR
                'call assignColour
                'ledTimer = time + 1
            end if
        endif
   loop

' ---[ END Program Code ]-----------------------------------

end  ; I don't know why putting an END here saves 2 BYTES of memory, must be a compiler thing - rhb?

' ---[ Subroutines ]----------------------------------------

LED_ON:
    MemPTR = 0                ; SET EEPROM data pointer to the first location
      do
        inc MemPTR
        call assignColour
    loop until MemPTR = stepCount
return

LED_OFF:
    MemPTR = stepCount      ; SET EEPROM data pointer to the last location
    do
        dec MemPTR
        call assignColour
    loop until MemPTR = 0
return

assignColour:
    '// This could be used for future features, such as colour blending
    read MemPTR, LED_Data
    RED_Data   = LED_Data
    GREEN_Data = LED_Data
    BLUE_Data  = LED_Data
    call sendData
return

sendData:

    '// BIT-BANG data to the WS2801 chip

    bptr = RAMbaseADDR                            ; set start RAM address for RGB LED data

    for sendBYTE = 1 to NUM_LED
        LED_Data = @bptrinc                        ; load the data into b0 to extract each bit
        SDataPIN = bit7 : PulsOut S_Clock, 1    ; msb first
        SDataPIN = bit6 : PulsOut S_Clock, 1
        SDataPIN = bit5 : PulsOut S_Clock, 1
        SDataPIN = bit4 : PulsOut S_Clock, 1
        SDataPIN = bit3 : PulsOut S_Clock, 1
        SDataPIN = bit2 : PulsOut S_Clock, 1
        SDataPIN = bit1 : PulsOut S_Clock, 1
        SDataPIN = bit0 : PulsOut S_Clock, 1    ; lsb last
    next sendBYTE                               ; continue until all bytes sent

return

readDistance:

    '// I2C data to VL53L0X chip

    hi2cout 0x00,(0x01)         ; start and re-arm
    pause 25                    ; chip init settle pause
    hi2cin 0x1e,(hiByte,loByte) ; read the range in mm from 0x1e
  
return

' ---[EOF]---

PEBBLE_BreadBoard_Capture(5).jpg
NOTE: PEBBLE has been silently updated to version 4.1, with most changes tucked away in code refactoring.

 

Attachments

Last edited:
Back
Top