node-rpi-ws281x

48
rpi-ws281x Martin Schuhfuss – @usefulthink something with raspberry-pi, hardware-hacking, node.js and other stuff

Transcript of node-rpi-ws281x

Page 1: node-rpi-ws281x

rpi-ws281x

Martin Schuhfuss – @usefulthink

something with raspberry-pi, hardware-hacking, node.js and other stuff

Page 2: node-rpi-ws281x

step0: demystify

Page 3: node-rpi-ws281x

(image from http://www.electrobob.com/ws2812-level-translator/)

this is what bits actually look like.

Page 4: node-rpi-ws281x

rpi-ws281x

Page 5: node-rpi-ws281x

rpi-ws2811ws2812

LED-Controller

full-color LED withintegrated controller

Page 6: node-rpi-ws281x

ws2812

(image from

5mm

‣ SMD5050 Package

‣ ws2811 controller

‣ three separate LEDsred

green

blue

HARDWARE

controller

Page 7: node-rpi-ws281x

3.75µs1.25µs

ws2811one-wire serial data-signal

0V

+5V

t

wavelength λ pulsewidth

frequency 800kHz wavelength 1.25µs

0 2.5µs 5µs

1 0 1 1

Page 8: node-rpi-ws281x

ws2811one-wire serial data-signal

0V

+5V

λ = 1.25µs (±600ns)(f = 800kHz)

350ns (±150ns)800ns (±150ns)

0t

Page 9: node-rpi-ws281x

ws2811one-wire serial data-signal

0V

+5V

λ = 1.25µs (±600ns)(f = 800kHz)

750ns (±150ns) 600ns (±150ns)

1t

Page 10: node-rpi-ws281x

ws2811one-wire serial data-signal

1 0 1 1 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 1 0 1 0 0

082b f 4

#80b2f4in HTML-Notation

Page 11: node-rpi-ws281x

ws2811one-wire serial data-signal

LED 01

DIN DOUT

Register#000000

LED 02

DIN DOUT

Register#000000

LED 03

DIN DOUT

Register#000000

+5V

GND

+5V

GND

+5V

GND

+5VGND

Page 12: node-rpi-ws281x

ws2811one-wire serial data-signal

LED 01

DIN DOUT

Register#ff8800

#ff8800

1

LED 02

DIN DOUT

Register#000000

LED 03

DIN DOUT

Register#000000

— —

+5V

GND

+5V

GND

+5V

GND

+5VGND

Page 13: node-rpi-ws281x

ws2811one-wire serial data-signal

LED 01

DIN DOUT

Register#ff8800

#00ffff

2

LED 02

DIN DOUT

Register#00ffff

LED 03

DIN DOUT

Register#000000

#00ffff —

+5V

GND

+5V

GND

+5V

GND

+5VGND

Page 14: node-rpi-ws281x

ws2811one-wire serial data-signal

LED 01

DIN DOUT

Register#ff8800

#0000ff

3

LED 02

DIN DOUT

Register#ffff00

LED 03

DIN DOUT

Register#0000ff

#0000ff #0000ff

+5V

GND

+5V

GND

+5V

GND

+5VGND

Page 15: node-rpi-ws281x

ws2811one-wire serial data-signal

LED 01

DIN DOUT

Register#000000

reset

4

LED 02

DIN DOUT

Register#000000

LED 03

DIN DOUT

Register#000000

reset reset

+5V

GND

+5V

GND

+5V

GND

+5VGND

Page 16: node-rpi-ws281x

neopixel etc.where to get your ws2812

http://www.watterott.com/index.php?page=search&keywords=ws2812

http://www.adafruit.com/category/168USAhttps://www.sparkfun.com/search/results?term=ws2812

GERMANY

OTHER INTERNATIONAL

ebay, amazon (search "ws2812")

direct from china: banggood.com, www.dx.com, alibaba.com

Page 17: node-rpi-ws281x

build your own :)

Page 18: node-rpi-ws281x

step1: control

Page 19: node-rpi-ws281x

Raspberry Pi

‣ Broadcom BCM2xxx SoC

‣ 700MHz ARM CPU / 512MB RAM

‣ SD-Card as Harddrive

‣ 100MBit LAN / HDMI / USB / Audio

‣ raspbian OS

Ethernet

HDMI

micro-USB(power supply)

SD-Card

GPIO

Digital-Audio

Analog-Audio USB

Status-LEDs

Page 20: node-rpi-ws281x

Raspberry Pi

‣ interface to external hardware

‣ sensors, motors, anything

‣ SPI / UART / I2C

‣ controllable logic-pins

GPIO

Page 21: node-rpi-ws281x

step2: drivers

Page 22: node-rpi-ws281x

(image from http://www.electrobob.com/ws2812-level-translator/)

the signal-level needs to be changed 1.6 Million times per second.

problem

Page 23: node-rpi-ws281x

Arduino: no problem*‣ CPU running at 16MHz

‣ 62 nanoseconds per instruction

‣ lots of time™ in between level changes…

* assembler-programming required :(

Page 24: node-rpi-ws281x

awesomeness

solutionsprogramming it with arduino

sleep

solution awesomeness#hhjs

(based on a totally representative study with 1 participant)

Page 25: node-rpi-ws281x

Raspbian: problem‣ because multitasking.

‣ when the process runs depends on lots

of factors we can’t control

Page 26: node-rpi-ws281x

Raspberry Pi PWM‣ „serializer“-mode

‣ bits in data-registers representsignal-level per PWM-cycle

‣ only a few bytes in registers

‣ needs DMA to transport data

Page 27: node-rpi-ws281x

Raspberry Pi PWM

0V

+5V

(frequency: 2.4 MHz)

0t

PWM cycle: 416ns

1 0 0 bits written toPWM-Registers

Page 28: node-rpi-ws281x

Raspberry Pi PWM

0V

+5V

(frequency: 2.4 MHz)

1t

PWM cycle: 416ns

1 1 0 bits written toPWM-Registers

Page 29: node-rpi-ws281x

Raspbian: problem‣ store prepared pixel-data in memory

‣ let the DMA-Controller transfer data

to PWM-Module

‣ CPU or OS are not involved!

Page 30: node-rpi-ws281x
Page 31: node-rpi-ws281x

awesomeness

solutions

arduino

sleep

solution awesomeness#hhjs

program it in C on raspberry

build a server in C and control

with node

write a node-addon.

Page 32: node-rpi-ws281x

step3: node!

Page 33: node-rpi-ws281x

‣ based on a C-Library by Jeremy Garff

‣ wrapper handles only type-checking and conversions between V8-types and C

‣ simple JS-interface:

ws281x = { init: function(numLeds, options) { … }, /** @param ledData {Uint32Array} */ render: function(ledData) { … }, reset: function() { … } };

node-rpi-ws281x

C-Library source:

Page 34: node-rpi-ws281x

‣ first challenge: get it to compile.

‣ hard to find documentation

‣ solution was actually pretty simple

// binding.gyp (some stuff left out) { targets: [{ target_name: "rpi_ws281x", sources: ["./src/rpi-ws281x.cc"], dependencies: ["libws2811"] }, { target_name: "libws2811", type: "static_library", sources: [ … ], } ]}

writing node-addons

(required reading: http://nethack4.org/blog/building-c.html)

Page 35: node-rpi-ws281x

writing node-addons// rpi_ws281x.cc #include <node.h>#include <v8.h>

using namespace v8;

Handle<Value> Reset(const Arguments& args) { HandleScope scope; // ... binding-code here ... return scope.Close(Undefined());}

void initialize(Handle<Object> exports) { // exports.reset = function Reset() {}; exports->Set(String::NewSymbol("reset"), FunctionTemplate::New(Reset)->GetFunction());}NODE_MODULE(rpi_ws281x, initialize)

no arguments / return undefined

Page 36: node-rpi-ws281x

writing node-addons

// rpi_ws281x.cc Handle<Value> Init(const Arguments& args) { HandleScope scope; if(args.Length() < 1 || !args[0]->IsNumber()) { ThrowException(Exception::TypeError( String::New("init(): argument 0 is not a number"))); return scope.Close(Undefined()); } int numLEDs = args[0]->Int32Value();

// ... the actual binding-code ... return scope.Close(Undefined());}

accepting arguments/ throwing exceptions

Page 37: node-rpi-ws281x

writing node-addons

‣ writing a simple node addon is not as complicated as it seems

‣ i should write more C++

‣ most of the code to deal with arguments and type-checking

‣ better understanding how V8 works

lessons learned…

Page 38: node-rpi-ws281x

finally: Javascript

Page 39: node-rpi-ws281x

hello ws281x-native

var ws281x = require('../lib/binding/ws281x-native');var NUM_LEDS = 100, data = new Uint32Array(NUM_LEDS);ws281x.init(NUM_LEDS);data[42] = 0xff0000;ws281x.render(data);setTimeout(function() { ws281x.reset(); }, 2000);

the javascript-side

Page 40: node-rpi-ws281x

hello ws281x-native

‣ API feels a bit too low-level

‣ numbers as colors are complicated

‣ need to manually manage the data-array

of course it didn't end there

Page 41: node-rpi-ws281x

matrix-APIvar ws281x = require('../lib/ws281x'), m = ws281x.createMatrix(10,10) Color = ws281x.Color;var offset = 0, c1 = new Color('red'), c2 = new Color('blue');setInterval(function() { m.clear(); for(var i=0; i<10; i++) { var color = Color.mix(c1, c2, ((i % 10) / 10)); m.set(i%10, (i+offset)%10, color); } offset++; m.render();}, 1000 / 30);

the javascript-side

Page 42: node-rpi-ws281x

awesomeness

solutions

arduino

sleep

solution awesomeness#hhjs

program it in C on raspberry

build a server in C and control

with node

write a node-addon.

Page 43: node-rpi-ws281x

awesomeness

solutions

sleep

solution awesomeness#hhjs

program it in C on raspberry

build a server in C and control

with node

write anode-addon.

use <canvas>

Page 44: node-rpi-ws281x

canvas-API

‣ web-technology FTW!

‣ has more stuff than we need.

‣ can be rendered server-side with node-canvas

‣ also works in the browser

Page 45: node-rpi-ws281x

canvas-APIvar ws281x = require('../lib/ws281x'), canvas = ws281x.createCanvas(10,10), ctx = canvas.ctx, Color = ws281x.Color;var c1 = new Color('red'), c2 = new Color('blue');function rnd(max) { return (max || 1) * Math.random(); }function rndi(max) { return Math.round(rnd(max)); }setInterval(function() { var c = Color.mix(c1,c2, rnd()); ctx.clearRect(0,0,10,10); ctx.fillStyle = 'rgb(' + c.rgb.join(',') + ')'; ctx.fillRect(rndi(10)-2, rndi(10)-2, rndi(10), rndi(10)); canvas.render();}, 1000/5);

the javascript-side

Page 46: node-rpi-ws281x

more to come…

‣ open-source everything [really soon]

‣ browser-based IDE on the raspberry [in progress]

‣ integrate with other hardware [planning]

‣ improved 3d-printed casing [some day…]

Page 47: node-rpi-ws281x

final thoughts

‣ do something you love. just for the fun.

‣ understand how stuff works.

‣ learn something new.

‣ no deadlines (well, except you do a talk about it)

why would you want to do that?

Page 48: node-rpi-ws281x

thank you!come to me if you have any questions…

<3

Martin Schuhfuss – @usefulthink