Hardware


Shell Lab L2 is programmable LED strip (WS2812 chip) with USB/serial interface

Characteristic:

● supports WS2812 LED chip, 5V powered
● configurable strip length
● signal lamp mode: whole strip treated as same color, color/frequency configurable
● RGB each channel is independently adjusted from 0~255
● blinking effect (freq adjustable from 0.1~20Hz, 0 for static)
● addressable mode: assign color for each single LED chip
● interactive serial console with ASCII command, online manual embedded
● programming language is not limited (Python recommended)
● quick test with Testbench App (with various demo codes)
● pip install mcush library (support windows/linux/mac) and write scripts easily

Use cases:

● prototype design
● fault/exception indication in product/software cycle test
● indication in assembly line, green for PASS and red for FAIL
● experiment progress indication
● kanban/placard indication
● logistic/storage management, goods location indicator
● ROS robot indication
● interactive game design
● educational experiment design
● outdoor case, auto indicator
● system integration for industrial equipment
● art creativity
● DIY toy
● shop sign for advertisement

Work modes:

● signal lamp mode (all LEDs blink in same color and frequency)
● addressable mode (each LED is configurable with its own static color)

Customize:

● customize PCB and case
● customize firmware for module integration
● switch to bluetooth communication, for mobile control
● RS232 interfaced

● Multi strips controller

● customized for outdoor use (16 chips serialized internally)

Attention:

● commands in lamp mode are very similar to L1 signal lamp, easy for replacement
● limited for USB power capacity, add extra 5V power for longer strip (at the strip tail)

Software

Serial Communication FAQ
C Programming FAQ

Serial command:

1. Signal lamp mode
=>strap --help
usage: strap [-l length] [-c RGB_color] [-r red_color] [-g green_color] [-b blue_color] [-f freq]
options:
 -l/--length     led number
 -c/--color      RRGGBB format
 -r/--red        red value
 -g/--green      green value
 -b/--blue       blue value
 -f/--freq       0~20 Hz(default 1)
=> 

Example:

After poweron, assign the actual strip length first:
=>strap -l 30   (suppose to have 30 LEDs)
=> 
Then send the color
(basic colors):
black: 0x000000
red: 0xFF0000
green: 0x00FF00
blue: 0x0000FF
yellow: 0xFFFF00
cyan: 0x00FFFF
purple: 0xFF00FF
white: 0xFFFFFF

blink in RED color, 1Hz(default):
=>strap -c 0xFF0000
=> 
blink in YELLOW color, 2Hz:
=>strap -c 0xFF00 -f 2
=> 
blink in BLUE color, 0.5Hz:
=>strap -c 0xFF -f 0.5
=> 
blink in YELLOW color, 0.1Hz:
=>strap -c 0xFFFF00 -f 0.1
=> 
blink in PURPLE color, 10Hz:
=>strap -c 0xFF00FF -f 10
=> 
static CRAY color:
=>strap -c 0x00FFFF -f 0
=> 
single RED channel as 64:
=>strap -r 64
=> 
single GREEN channel as 0x80:
=>strap -g 0x80
=> 
single BLUE channel as 0x200:
=>strap -b 200
=> 
query current length/color/freq setting:
=>strap
length: 30
color: 0x000000
freq: 1.0
=> 
2. Addressable mode:
=>ws2812 --help
usage: ws2812 [-l length] [-G group] [--glist_file] [-L file] [-D] [-w] [-g] 
[-o offset] [-p pin] [-I] [-f] [-b] [-F] data options: -l/--length number of groups -G/--group number of pixels per group --glist_file /c/glist -L/--load load data file -D/--deinit deinit -w/--write write -g/--grb GRB instead of RGB -o/--offset data offset -p/--pin default 0.0 -I/--init init -f/--forward push forward -b/--backward push backward -F/--fill fill pattern data data to be written =>

Example (standard mode):

signal lamp mode must be disabled first (modes conflict), reset length to zero with strap command,
then init length with ws2812 command:
(note: limited to chip memory, actual length is no longer than 300)
=>strap -l 0
=>ws2812 -l30 -I
=>
all leds are allocated with independent memory and set zero/black, but not synced to strip, update them:
=>ws2812 -w
=>
fill #3~5 leds with red/green/blue, sync and update:
=>ws2812 -w -o3 0xff0000 0xff00 0xff
=>
fill #10~20 leds with purple, sync and update:
=>ws2812 -w -o10 -l11 -F 0xff00ff
=>
move whole leds forward, fill #0 led with blue, sync and update:
=>ws2812 -w -f 0xff
=>
move whole leds backward, fill #29 led with green, sync and update:
=>ws2812 -w -b 0xff00
=>
move top half leds backward, fill #29 led with green, no sync,
move bottom half leds forward, fill #0 led with green, sync together:
=>ws2812 -l15 -o29 -b 0xff00 
=>ws2812 -w -l15 -f 0xff00
=>
if leds pattern (in sequence of 0xRR,0xGG,0xBB 3bytes) has been saved into file (by script tool),
the file can be quickly/directly loaded into strip, suitable for load preset patterns/bitmaps.
=>ws2812 -w -L imgfile
=>

Example (group mode):

combine continuous leds together into group, share the same memory,
more leds can be controlled with same memory, total sync time will be longer.
30 leds split into 10 groups (3 leds in each group), init:
=>ws2812 -l10 -G3 -I
=>
fill whole strip in pattern green/blue alternatively:
=>ws2812 -w -f 0xff0000 0xff
=>

Example (resizeable group length):

practically, for assembly reason, assign groups with different length may be more effective
group list length needs to be defined into config file and written into flash (script tool needed)
if /c/glist has been written, contains binary defination0x03,0x05,0x0A.. for each group length, init:
=>ws2812 --glist_file -I
=>

Python API:

Install: sudo pip3 install mcush
Upgrade: sudo pip3 install -U mcush
class ShellLabStrip(mcush.ShellLab.ShellLab):
    def strap(self, color=None, red=None, green=None, blue=None, freq=None, count=None):
        # lower level serial command

    def color(self, c, freq=None, count=None):
        # color, freq and blink downcounter
    
    def reset(self, freq=1):
        # mode reset

class ShellLabStaticStrip(mcush.ShellLab.ShellLabStrip):
    def color( self, c, brightness=None ):
        # color and brightness

    def brightness( self, b ):
        # adjust brightness

class LEDS(mcush.Ws2812):
    def __init__( self, controller, length=None, group_length=None, swap_rg=None, pin=None ):
        # initialization

    def write( self, mem, offset=0, push=None, fill=None, length=None ):
        # write color/pattern

    def pushf( self, mem, offset=None, length=None ):
        # push forward color/pattern

    def pushb( self, mem, offset=None, length=None ):
        # push backward color/pattern

    def fill( self, mem, offset=None, length=None ):
        # fill color/pattern

Examples:

import mcush
from mcush.linkong.ShellLab import ShellLabStrip
lamp = ShellLabStrip('COM10', length=30)  # fill the actual serial port and strip length
lamp.color('red', freq=2)  # blink fast in red color

Download:

Shell Lab Testbench Application


CH341 VCP Driver(Windows)


Application

Blink effect in signal lamp mode

Multi color blinking

Long strip

Use push command

Push command (faster)

Push command (32*8=256 LEDs, rainbow waterfall)




Configured as RGBCMY loop after poweron download
# this script runs in ShellLab Testbench Application
strip_length=30
freq = 0.2  # hz
delay_ms = int(1000/freq)  # ms

fcfs = Utils.FCFS()
fcfs.appendFile("rgbcmy", '''\
s -c 0xFF0000
delay {delay_ms}
s -c 0x00FF00
delay {delay_ms}
s -c 0x0000FF
delay {delay_ms}
s -c 0x00FFFF
delay {delay_ms}
s -c 0xFF00FF
delay {delay_ms}
s -c 0xFFFF00
delay {delay_ms}
load /c/rgbcmy
'''.format(delay_ms=delay_ms))

fcfs.appendFile("init", '''\
delay
s -l {strip_length} -f {freq}
load /c/rgbcmy
'''.format(strip_length=strip_length, freq=freq))

s = ShellLabStrip(PORT)
s.fcfsFormat()
s.fcfsProgram(fcfs.generate())
s.port.write('reboot\n')
Color heart lamp customized with the above code


Configured as police alarm flashdownload
# half red, half blue, three blinks alternatively
strap_length = 30
delay_ms = 100

fcfs = Utils.FCFS()
fcfs.appendFile("flash", '''\
W -w 0xFF0000 0
delay {delay_ms}
W -w 0 0
delay {delay_ms}
W -w 0xFF0000 0
delay {delay_ms}
W -w 0 0
delay {delay_ms}
W -w 0xFF0000 0
delay {delay_ms}
W -w 0 0
delay {delay_ms}
W -w 0 0xFF
delay {delay_ms}
W -w 0 0
delay {delay_ms}
W -w 0 0xFF
delay {delay_ms}
W -w 0 0
delay {delay_ms}
W -w 0 0xFF
delay {delay_ms}
W -w 0 0
delay {delay_ms}
load /c/flash
'''.format(delay_ms=delay_ms))

fcfs.appendFile("init", '''\
W -I -G{half_length} -l2
load /c/flash
'''.format(half_length=int(strap_length/2)))

s = ShellLabStrip(PORT)
s.fcfsFormat()
s.fcfsProgram(fcfs.generate())
s.port.write('reboot\n')
Code effect


C-API Compiled waterfall
#include < stdio.h >
#include "mcush_api.h"

#ifdef WIN32
const char device_name[] = "\\\\.\\COM14";
#else
const char device_name[] = "/dev/ttyUSB0";
#endif

int strap_length = 30;
int push_delay_ms = 50;
int steps = 3;
int colors[] = { 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF };

int main( int argc, char *argv[] )
{
    mcush_dev_t dev;
    char buf[512];
    int i;

    if( mcush_open( &dev, device_name, 9600, 5 ) <= 0 )
    {
        printf("fail to open port\n");
        return 0;
    }

    if( mcush_connect( &dev ) <= 0 )
    {
        printf("fail to connect the device\n");
        return 0;
    }

    /* identify */
    if( mcush_scpi_idn( &dev, buf ) > 0 )
        printf( "%s", buf );

    /* init strip */
    sprintf( buf, "W -l %d -I", strap_length );
    mcush_write_command( &dev, buf );

    /* push colors again and again until Ctrl-C */
    while( 1 )
    {
        /* push colors */
        for( i=0; i<6; i++ )
        {
            sprintf( buf, "L -l%d -n%d W -w -f 0x%X", push_delay_ms, steps, colors[i] );
            mcush_write_command( &dev, buf );
        }
    }

    mcush_close( &dev );
    return 0;
}
Effect for the above code


Configured as a command-triggered waterfall stripdownload
# use this script to make L2 controller a simple
# "command triggered" waterfall LED strip
# after configured, send "load /c/run" command to start
# use ShellLab Testbench App to run this script
# download at www.linkongsoft.com/shell-lab/

strap_length = 30 # total length
delay_ms = 100  # movement delay in ms
steps = 10 # length of water bar
color = 0xFF0000  # red bar

fcfs = Utils.FCFS()
fcfs.appendFile("run", '''\
L -l{delay_ms} -n{steps} W -w -f {color}
L -l{delay_ms} -n{strap_length} W -w -f 0
'''.format(delay_ms=delay_ms, steps=steps, 
      color=color, strap_length=strap_length))

fcfs.appendFile("init", '''\
W -I -l{strap_length}
'''.format(strap_length=strap_length))

s = ShellLabStrip(PORT)
s.fcfsFormat()
s.fcfsProgram(fcfs.generate())
s.port.write('reboot\n')

# wait for reboot and test the effect
time.sleep(0.5)
s.disconnect()
s.connect()
s.writeCommand('load /c/run')
Effect for the above code


Configured to switch between two icons(8x8) after powerondownload
# this script runs in ShellLab Testbench Application
fcfs = Utils.FCFS()
for fname in ['heart', 'heart2']:
    img = cv2.imread("emblems/%s.png"% fname)
    img = cv2.cvtColor( img, cv2.COLOR_BGR2RGB )
    pixels = []
    img = img / 4.0
    img = img.astype('int8')
    for i in range(8):
        for j in range(8):
            p = img[i][j] if i & 0x01 else img[i][7-j]
            pixels.append( bytes(p) )
            logAdd( ('%d %d ->'%(i,j)) + str(p) )
    logAdd(pixels)
    fcfs.appendFile(fname, b''.join(pixels))

fcfs.appendFile('init', '''\
W -l64 -I
load /c/play
''')

fcfs.appendFile('play', '''\
W -w -L heart
delay 400
W -w -L heart2
delay 400
load /c/play
''')

s = ShellLab(PORT)
fcfs.setIntegerUID( s.getIntegerSerialNumber() )  # keep original one
s.fcfsFormat()
s.fcfsProgram(fcfs.generate())
s.reboot()
Effect for the above code

customized lamp for outdoor use


Connect and control with raspberry

Single step debugging with raspberry


Control with Turtle Editor


switch color alarm for collision detection in ROS


test with mcush_util
#!/bin/sh
# Shell Lab L2 strip controller demo with mcush_util
# download/compile/install mcush_util firstly
# Shanghai Linkong Software Tech. Co., Ltd.
# www.linkongsoft.com
set -e
PORT=/dev/ttyUSB0
STRIP_LENGTH=30

# model match
mcush_util -p$PORT -mShellLab-L2 -r

# basic colors
mcush_util -nq -p$PORT run "s -l$STRIP_LENGTH -f0.9" \
    "s -c0xff -C1" "delay" \
    "s -c0xff00 -C1" "delay" "s -c0xff0000 -C1" "delay" \
    "s -c0xffff -C1" "delay" "s -c0xffff00 -C1" "delay" \
    "s -c0xff00ff -C1" "delay" "s -c0xffffff -C1" "delay"

# police alarm light
mcush_util -nq -p$PORT run "s -f10 -c0xff" "delay" \
    "s -c0xff0000" "delay" "s -c0xff" "delay" \
    "s -c0xff0000" "delay" "s -c0xff" "delay" \
    "s -c0xff0000" "delay" "s -c0xff" "delay"

# end, turn off 
mcush_util -nq -p$PORT run "s -c0" "delay" "s -l0"