Raspberry PiからGolangでWS2812Bを操作してみる

Raspberry PiからWS2812BというLEDを操作してみました。Amazonで60個のLEDが繋がっているものを購入しましたが、白黒、防水の有無で4種類あります。防水の白を買いました。

Golangインストール

とりあえず、Golangインストールします。アーキテクチャarmv6l のものを選択します。

$ version=1.10.1
$ wget https://storage.googleapis.com/golang/go${version}.linux-armv6l.tar.gz
$ sudo tar -C /usr/local -xzf go${version}inux-armv6l.tar.gz
$ echo "export PATH=\$PATH:/usr/local/go/bin" >> ~/.profile
$ . ~/.profile
$ go version
go version go1.10.1 linux/arm

WS2812操作用ライブラリ

WS2812の操作にはこちらのライブラリを利用します。

github.com

git cloneしてきた後はSCons使ってビルドします。

$ sudo apt-get install scons
$ git clone https://github.com/jgarff/rpi_ws281x.git
$ cd rpi_ws281x/
$ scons

ビルドしたCのライブラリを所定のフォルダにインストールしておきます。

$ sudo cp -ai ./ws2811.h ./rpihw.h ./pwm.h /usr/local/include/
$ sudo cp -ai ./libws2811.a /usr/local/lib/

Golangのライブラリをインストールします。

$ go get -u github.com/jgarff/rpi_ws281x/golang/ws2811

exampleプログラム

Exampleが用意されているので、まずは実行してみます。

$ cd ~/go/src/github.com/jgarff/rpi_ws281x/golang/examples/

変数の調整

以下の3つの変数で動きを調整できます。

const (
    pin = 18 // GPIOピン(PWM)
    count = 16 // 操作するLEDの数
    brightness = 255 // LEDの明るさ
)

https://github.com/jgarff/rpi_ws281x/blob/e4a05d6538c02bb9714f2efc6630f2bfdcf35bf6/golang/examples/basic.go#L12-L14

LEDの数の 60count の変数に入れます。 他にも変数名の通り、 pin でGPIOを指定、brightness でLEDの明るさを指定できます。

example実行

これでexampleのプログラムの準備ができました。ビルドしてsudoで実行します。

$ cd golang/examples/
$ go build basic.go
$ sudo ./basic

動かしてみたところです。

youtu.be

exampleを改造してみる

このexampleのコアになっているws2811.goというファイルはかなりシンプルなので、読みながら何ができるか試せばすぐに使い方がわかってきます。

サンプルプログラム

簡単なサンプルプログラムです、赤、青、白の帯が動きます。

設定

以下の設定ができるようにしました。

const (
    pin        = 18 // GPIOピン
    series     = 4 // 同じ色のLEDが連続する数
    count      = 60 // LEDの数
    brightness = 100 // LEDの明るさ
    interval   = time.Millisecond * 100 // 動きのスピード
)

色も適当にコメントアウトしたり外したりします。

var (
    colors = []uint32{
        0xFFFFFF, //white
        //0xFF0000, //green
        0x00FF00, //Red
        0x0000FF, //Blue
        //0x00FFFF, //pink
        //0xFFFF00, //yellow
        //0xFF00FF, //light blue
    }
)

ソース全体

package main

import (
    "fmt"
    "time"

    "github.com/jgarff/rpi_ws281x/golang/ws2811"
)

const (
    pin        = 18
    series     = 4
    count      = 60
    brightness = 100
    interval   = time.Millisecond * 100
)

var (
    colors = []uint32{
        0xFFFFFF, //white
        //0xFF0000, //green
        0x00FF00, //Red
        0x0000FF, //Blue
        //0x00FFFF, //pink
        //0xFFFF00, //yellow
        //0xFF00FF, //light blue
    }
)

func main() {
    defer ws2811.Fini()
    err := ws2811.Init(pin, count, brightness)
    if err != nil {
        fmt.Println(err)
    } else {
        gen := genLedSet()
        for {
            set := gen()
            for i, c := range set {
                if i == count {
                    break
                }
                ws2811.SetLed(i, c)
            }
            err := ws2811.Render()
            if err != nil {
                ws2811.Clear()
            }
            time.Sleep(interval)
        }
    }
}

func color() func() uint32 {
    i := -1
    return func() uint32 {
        i++
        return colors[i%len(colors)]
    }
}

func vLeds() []uint32 {
    alength := series * len(colors)
    for {
        if alength >= count {
            break
        }
        alength += alength
    }
    return make([]uint32, alength)
}

func genLedSet() func() []uint32 {
    color := color()
    base := 0
    return func() []uint32 {
        vled := vLeds()
        for i := base; i < base+len(vled); {
            color := color()
            for j := 0; j < series; j++ {
                vled[i%len(vled)] = color
                i++
            }
        }
        base++
        return vled
    }
}

動かしてみるとこんな感じです。

youtu.be

簡単なのに、なかなか迫力あります。