RaspberryPi

Raspberry PiとRGBマトリクスで電光掲示板作ってアニメ流したった

More than 1 year has passed since last update.

この記事は、Raspberry Pi Advent Calendar 2015の22日目の記事です。

製作記

RasPi2も出たし(Zeroなんてのも出てますが。)そろそろ触ってみたいな〜なんて思ってなんとなーく作りました。

適当な説明ですが、ご容赦を。

作った物

16×32のRGBフルカラーマトリクスを9枚つかってアニメを流してみました。

大体の仕様

マトリクスは3つまで並列に接続することができます。直列にはいくらでもイケルと思います。今回は3枚直列に、3枚並列に接続し、3×3=9枚(解像度は48×96)使用しました。

使ったもの

配線

  • 太字のものが並列接続する初段のマトリクスに接続します。
  • 直列に接続するディスプレイはチェーン状に接続します。
  • [数字]の太字で表記しているのは並列接続初段の1段目・2段目・3段目に対応しています。対応した数字と接続してください。
  • [数字]表記されてなく、太字で書かれているものは並列接続初段のマトリクス全てと接続してください。
  • 普通の文字のものはその辺の基板とその辺の部品使って電源作ってそれを接続してください。

haisen.jpg

ラズパイ側接続図

接続先 ピン ピン 接続先
3.3V 1 2 5V
[3] G1 3 4 5V
[3] B1 5 6 GND
strobe 7 8 [3] R1
GND 9 10 -
clock 11 12 OE-
[1] G1 13 14 GND
A 15 16 B
3.3V 17 18 C
[1] B2 19 20 GND
[1] G2 21 22 D
[1] R1 23 24 [1] R2
GND 25 26 [1] B1
- 27 28 -
[2] G1 29 30 GND
[2] B1 31 32 [2] R1
[2] G2 33 34 GND
[2] R2 35 36 [3] G2
[3] R2 37 38 [2] B2
GND 39 40 [3] B2

マトリクス側ピンアサインなど

マトリクス側

hub75-other.jpg

付属ケーブル接続時

idc-hub75-connector.jpg

ラズパイ設定

Raspbianなどの適当なOSをラズパイに突っ込んで起動しましょう。
SSHとかやりたければご自由に。

必要そうなソフトウェア
- Python(標準で入ってるよね?・適当にあそぶなら。)
- make(最初からありそう)
- gcc/g++(最初からありそう)
- git(なかったらapt-getなりyumなりで入れてください)
- OpenCV(動画再生するときに使う)
- SDL(音も出したければどうぞ)

この辺を入れてください。

デモを動かす

hzeller/rpi-rgb-led-matrixを使います。
cloneしてmake。

git clone https://github.com/hzeller/rpi-rgb-led-matrix.git
cd rip-rgb-led-matrix
make
# Pythonであそぶなら
make install-python

これでデモがビルドされます。

以下でデモが動きます。

sudo ./led-matrix -t 10 -D 9 -P 3 -r 16 -c 3
  • -P:並列接続数
  • -c:直列接続数
  • -r:マトリクスの縦のピクセル数
  • -D:デモ番号

-Dの数字いじって遊んでみてください。

アニメを流す

動画の解像度が高い場合は最初にある程度の解像度まで落としておいてください。

先のデモのライブラリを新たにsubmoduleとして使います。

git submodule add https://github.com/hzeller/rpi-rgb-led-matrix.git matrix

Makefile作ります。

Makefile
CXX=g++-4.8


OBJS=matrix-app.o 
TARGET=matrix-app

CXXFLAGS=-std=c++11
RGB_INCDIR=matrix/include
RGB_LIBDIR=matrix/lib
RGB_LIBRARY_NAME=rgbmatrix
RGB_LIBRARY=$(RGB_LIBDIR)/lib$(RGB_LIBRARY_NAME).a
LDFLAGS+=-L$(RGB_LIBDIR) -l$(RGB_LIBRARY_NAME) -lrt -lm -lpthread -lopencv_core -lopencv_highgui -lopencv_imgproc -lSDL -lSDL_mixer


all: $(TARGET)

$(RGB_LIBRARY):
    $(MAKE) -C $(RGB_LIBDIR)


$(TARGET): $(OBJS) $(RGB_LIBRARY)
    $(CXX) $(CXXFLAGS) $(OBJS) -o $@ $(LDFLAGS)

%.o : %.cc
    $(CXX) -I$(RGB_INCDIR) $(CXXFLAGS) -c -o $@ $<


install:
    cp $(TARGET) /usr/local/bin/$(TARGET)

clean:
    rm -f $(OBJECTS) $(TARGET)
    $(MAKE) -C matrix clean

プログラム書きます。
このプログラムは音流すつもりで書いてますが適宜どうぞ。

matrix-app.cc
#include <iostream>
#include <stdio.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <unistd.h>
#include <chrono>
#include <SDL/SDL.h>
#include <SDL/SDL_mixer.h>
#include "led-matrix.h"
#include "graphics.h"


using namespace rgb_matrix;

int main(int argc, char *argv[]){

    if(argc != 2){
        std::cout << "little or many argments" << std::endl;
        return 0;
    }

    std::string path_prefix = "/usr/local/movieplayer/";

    std::string file_prefix = argv[1]; 

    std::string audio_file = path_prefix + "audio/" + file_prefix + ".flac";
    std::string movie_file = path_prefix + "movie/" + file_prefix + ".mp4"; 

    //Setting
    GPIO io;
    int chain = 3;
    int parallel = 3;
    int rows = 16;

    if(!io.Init())
        return 1;

    SDL_Init(SDL_INIT_AUDIO);
    Mix_OpenAudio(48000, MIX_DEFAULT_FORMAT, 2, 4096);
    Mix_Music *music=Mix_LoadMUS(audio_file.c_str());
    if(!music)return 1;

    RGBMatrix *matrix = new RGBMatrix(&io, rows, chain, parallel);
    matrix->set_luminance_correct(true);
    matrix->SetBrightness(100);
    matrix->SetPWMBits(11);
    FrameCanvas *canvas = matrix->CreateFrameCanvas();
    const int width = canvas->width();
    const int height = canvas->height();

    //Loading

    cv::Mat src_img;
    cv::Mat dst_img(height, width, src_img.type());
    cv::VideoCapture cap(movie_file.c_str());

    auto fps = cap.get(CV_CAP_PROP_FPS);
    long fps_ustime = 1000000.0/(double)fps+0.5;

    const auto hoseicount = (int)fps*10;
    auto hcnt=0;
    //Drawing


    if(Mix_PlayMusic(music, 1)==-1) {
        printf("Mix_PlayMusic: %s\n", Mix_GetError());
        return 1;
    }
    auto pre_dc=1ll;

    auto frame_cnt = cap.get(CV_CAP_PROP_FRAME_COUNT) - 1; // Magic!!!
    auto start = std::chrono::system_clock::now();
    while(true){

        auto fpos = cap.get(CV_CAP_PROP_POS_FRAMES);
        if(!(fpos < frame_cnt)){
            std::cout << "end." << std::endl;
            break;
        }

        cap >> src_img;

        auto pos = cap.get(CV_CAP_PROP_POS_MSEC);
        auto r = (double) height / src_img.rows;
        auto w = (int) (src_img.cols * r);
        auto d = (width - w) / 2;
        cv::resize(src_img, dst_img, cv::Size(w, height), cv::INTER_AREA);
        for(int y=0; y<height; y++){
            for(int x=0; x<w; x++){
                cv::Vec3b bgr = dst_img.at<cv::Vec3b>(y, x);
                canvas->SetPixel(x + d, y, bgr[2], bgr[1], bgr[0]);
            }
        }
        matrix->SwapOnVSync(canvas);
        auto end = std::chrono::system_clock::now();

        auto delaytime = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();

        auto delaycount = pos * 1000 - delaytime;
        if(delaycount > 0) {
            usleep(delaycount);
        }
    }
    matrix->Clear();
    Mix_HaltMusic();
    Mix_FreeMusic(music);
    Mix_CloseAudio();
    SDL_Quit();

    delete matrix;

    std::cout << "See You!" << std::endl;
    return 0;
}

  1. /usr/local/movieplayer/movieにmp4の動画ファイルを置きます
  2. /usr/local/movieplayer/audioにflacの音声ファイルを置きます
    • ここで動画ファイルと音声ファイルのファイル名を同じにしておいてください
  3. make && make installする
  4. sudo matrix-app 拡張子なしファイル名を実行
  5. 動画が流れる
  6. 喜ぶ!

こんな感じにできました

anime.gif

終わりに

雑ですが、以上です。
ラズパイ、いろんなことができて楽しいですね。Linuxがのってますからコレ一個でやりたい放題です。

一応PS3のコントローラとBluetoothでテトリス作ったり、リモコンでアニメ流せるようにしたんですが、それはまた別の機会にでも。

明日は@kaiware007 さんです。

それでは!!