モノクロタイム

I'm from the future!

【vvvv】vvvv x LattePanda x RaspberryPi Zeroでデジタルサイネージをつくる

こんにちは,れいじです.

以前Raspberry Piで作ったWebAPIサーバと接続して,現時点の降水強度を表示するデバイスを作りました.

reiji1020.hatenablog.com

用意するもの

LattePanda 4GB/64GB

メモリ4GB,ストレージ64GBでWindows10が載った小型PCです.vvvvはWindows上でしか動作しないので,これを使って小型サイネージを作成します.

Lattepanda用散熱ファン

Lattepandaは熱を発しやすいので熱を放出してあげないと熱暴走でシャットダウンしたりします.通常使いの場合はヒートシンクでも十分ですが(所説あり),今回はvvvvを連続で動作させるため通常時よりも高い発熱が予想されます.ファンを付ければ急なシャットダウンのリスクを軽減することができます.

ケース

木製のケースです.中国の組み木の技術を使っているそうで,一見するとかなり簡素な作りに見えますが頑丈です.通気口もきちんとあるので,中に熱がこもるなどの心配もありませんでした.

ファンを取り付けたら下蓋が閉じなくなった

7インチIPSディスプレイ

LattePanda用の7インチディスプレイです.解像度が高く,IoTデバイス用のディスプレイの中では安価なのに満足度が高い商品でした.かなり薄いので,強く摘まんだら割れそうで怖い…

本当はスタンドみたいなのに入れたほうがいいと思うんですが,PC化ケースがめっちゃ高いんすよね…

[asin:B01GJL87NK:detail]

パッチ

API接続側

f:id:yomoyamareiji:20181014123058p:plain

基本的にAPI関連はHTTPGet/Postノードを使うとよしなな感じでデータの送受信が可能です.念のためRenderer(TTY)でデバッグ画面も表示しています.

GetElementを使用すれば,APIの各要素(Data,Rainfall...)にアクセスし,情報の取得ができます.今回は現時点~60分後までの予報情報が返ってくるので,7つのSliceを持つSpreadを返却するようにしています.

ディスプレイ側

f:id:yomoyamareiji:20181014135319p:plain

Particleやら3Dオブジェクトやらを駆使すると確実に熱暴走でシャットダウンするので,表示部分は軽めに作りました.

f:id:yomoyamareiji:20181014135427p:plain

降水強度によって背景色が変化します.

f:id:yomoyamareiji:20181014135458p:plain

f:id:yomoyamareiji:20181014135509p:plain

f:id:yomoyamareiji:20181014135519p:plain

7インチといってもやはり画面の大きさは限られていますので,現時点の降水強度を表示するだけにとどめています(予測値まで表示すると画面がごちゃごちゃ…)

結構ファンの音がうるさいのでベッドサイドに設置するのはやめました.あ,ヒートシンクで冷却賄うなら静音だけどやっぱりシャットダウンが怖いです.

家には掛け時計がないので,時間が表示されているのもポイント高いです.

Lattepandaのハイエンドモデルを買えばもうちょっとリッチな表現も可能になりそうです.

ではでは~

技術書典5にサークル参加しました

こんにちは,れいじです.

10月7日(月・祝)に行われた技術書典5にサークル参加してきました.

技術書典:技術書オンリーイベント

サークル名は「CANDY CHUPS Lab.」で,う51にいました.

新刊は以下3つを持っていきました.

gyaopan.booth.pm

gyaopan.booth.pm

gyaopan.booth.pm

現在新刊・既刊共にBOOTHで通販を行っています.

一番売れ行きが良かった本

「やってみようGoでISUCONパフォーマンスチューニングーISUCON7の予想問題を試してみる本ー」は多くの方に手にとっていただけました.余談ですが表紙のゴーファー君は私が2分で描きました(色塗り込み)

おかげさまでDL販売数も昨日と今日で25部を超えました.ありがとうございます!

Go言語に興味がある方(もしくは実際に使われている方)やISUCONに挑戦している方の2方向の方々に刺さったのかな~という感じです.感想や質問などは

じろう (@dorako321) | Twitter

までお願いします.

冊子版をご注文された方についてはなる早で発送しますので,しばらくお待ちください.

vvvv本の今後について

今回はステップアップ(応用編)ということもあってvvvvをそこそこ使用している方向けの本を書きました.

冊子版はグレースケール印刷→フルカラーにし,ページも増やしたものを2冊出していましたが,そもそもvvvvがニッチ中のニッチである上にvvvvをそこそこ使ってる人って大体フォロワーじゃない?ってな感じで希少種なので本当に一般向けに刺さりにくい本になってしまいました.早い話が赤字でした.需要に対して書く内容のレベルを上げすぎたこと・マーケティング不足だったこと・(フルカラー・少部数印刷のため)本の値段が上がったことが主な要因な気がしています.

技術書典タグで検索すると「ニッチすぎてこんな本誰が読むんだよ!」的な本でも技術書典なら手に取ってもらえる的なムーブがあるけど,ニッチ技術を攻めすぎて本当に手に取りにくい本が爆誕してしまいました… vvvv民増えて…増えて輪になって語ろう…おすすめアドオンとか面白ノード教えあってワイワイやろ…?

とはいえvvvv本2・vvvv本3ともに10冊以上お手にとっていただくことができました.vvvv本の感想とか質問とかは@reiji1020まで投げてくれると糧になります,よろしくお願いします…! 技術書典6ではVLの本を出そうかな~と思っていましたが,今回の新刊以上に読者を選ぶことになるのでちょっと悩んでます.既刊3冊の総集編本は出すけど,もしかしたら新刊は本職のフロントエンド技術であれこれやるかもです.

めちゃめちゃ遅いですがvvvv本のサンプル置きました↓

・vvvvでCGプログラミングやってみる本2-Spreadをマスターしてステップアップ!-サンプル:https://1drv.ms/f/s!AnEEOBHWIMp64jIFR6dFAh2VtP9d

・vvvvでCGプログラミングやってみる本3-マイクやKinectを使ってみよう!-サンプル:https://1drv.ms/f/s!AnEEOBHWIMp64jOwYICCkp9THRjv

買ったもの

15時あたりから暇になってきたので他のサークルさんを覗いてフロントエンド系の本を買いました.

React系は業務直結なので買おうかと思ったけど結構知ってる内容も多かったので見送り.Nuxt.js界隈はアツいですね.撤収・完売しているサークルさんも多かったのであまり多くは買えませんでしたが,これからゆっくり読みます!

CANDY CHUPS Lab.のこれから

CCLはアウトプットお化けなので多分いろんな場所で出没します.直近だとヤフー株式会社主催のHackDay 2018に参加予定です.昨年はFun賞を受賞したので,これより上の賞…つまり最優秀賞を狙ってます.アイデア大丈夫かな…

hackday.jp

書籍関連ではもちろん来年4月の技術書典6で!

ではでは~

【パリピのための電子工作】レインボーに光る電球ソーダを作る

こんにちは,れいじです.非パリピです.

電球ソーダの容器を手に入れたので魔改造して遊びました.

電球ソーダとは

https://womagazine.jp/103628womagazine.jp

韓国発祥のオシャレドリンクです.日本の専門店といえばピカピカソーダが有名どころ.

最近は縁日の定番となりつつありますね.

その影響か,この電球ソーダの容器がAmazonやYahooショッピングなどで販売されています.

本家と縁日用の電球ソーダの違いは

本家:そもそものジュースがカラフル.電球のソケット部分にLEDや電球型のストラップがついている.

縁日用:ソケット部分には何もつけないことが多い(ジュースを入れてすぐに提供できるようにするため).ボトルの底がへこんでいて,赤・青・緑のLEDがくっついた基盤がある.ボタンをぽちっと押せば光る仕様.

主にこんなかんじ.

あんまり光り方がエモくない問題

赤・青・緑のLEDを配置している以上,混色が難しいのでなんだかチープな印象を受けます.

なのでNeoPixel RingとArduino Gemmaを使用して,エモい電球ソーダボトルを作ります.

用意するもの

Arduino Gemma

[asin:B00GEDHO1U:detail]

・NeoPixel Ring(12個つき)

[asin:B07FHYGHSZ:detail]

・リチウムポリマー電池

[asin:B01MG5OWC7:detail]

配線

f:id:yomoyamareiji:20170222154709p:plain

プログラム

Gemmaがシリアルポートに現れてくれないときはTrinketのドライバをAdafruit公式サイトから落としてきてインストールし,

・ボード:Arduono Gemma(ATTiny85 @8MHz) ・書き込み装置:USBTinyISP

にした状態で,メニューバーのスケッチ > 書き込み装置を使って書き込む を選択すればOKです.

f:id:yomoyamareiji:20180808191938p:plain

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 0

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {
  // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  // End of trinket special code


  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  // Some example procedures showing how to display to the pixels:
  colorWipe(strip.Color(255, 0, 0), 50); // Red
  colorWipe(strip.Color(0, 255, 0), 50); // Green
  colorWipe(strip.Color(0, 0, 255), 50); // Blue
//colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW
  // Send a theater pixel chase in...
  theaterChase(strip.Color(127, 127, 127), 50); // White
  theaterChase(strip.Color(127, 0, 0), 50); // Red
  theaterChase(strip.Color(0, 0, 127), 50); // Blue

  rainbow(20);
  rainbowCycle(20);
  theaterChaseRainbow(50);
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
    for (int q=0; q < 3; q++) {
      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (uint16_t i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

もちろんモバイルバッテリーを使って給電することも可能なのですが,リチウムポリマー電池を使うとよりコンパクトにまとまるのでおすすめです.

こうなります.めっちゃインスタ映えする.

レインボーに光るとめっちゃエモい

みんなも電球ソーダのボトルを買って,中にストロングゼロジュース入れてインスタ映えしよう!

最近は電球ソーダよりも哺乳瓶ソーダが流行ってるとかで,さすがにそこまではついていけないなあと思っている非パリピでした.

RaspberryPi ZeroをAPIサーバにして遊んでみる

こんにちは,れいじです.

RaspberryPi Zeroを買ったまま持て余していたので,APIサーバにして遊んでみました.

※ちなみにデコってます.かわいい

セットアップする

ラズパイゼロのセットアップに関してはインターネットに山のように情報があるので割愛します. あ,ラズパイゼロ買うならスターターキット買ったほうが絶対楽です.すでにケーブルなりSDカードなり持て余している方は別ですが,私みたいな初心者勢はスターターキット買ったほうがいいです.必要なコネクタとか全部揃ってるし.

今回はラズパイ上でNode.js+Expressを動かし,REST APIを作ります.使用するOSはRaspbian.

nodeのアップデートをする

使用するパッケージの都合上,すでにインストールされているnodeよりもバージョンをあげる必要があります. ここではnodeのバージョン管理ツールnを使用してみます.

# nのインストール
$ npm install -g n

# stable版にアップグレード
$ n stable
$ node -v  
10.4.1 # 2018/06/20時点

#yarnのインストール
$ npm install -g yarn

これで実行環境の準備は完了です.

RESTAPIを作る

プロジェクトを用意しています.README.mdに沿って準備すればだれでも使えるはず. 3時間くらいで作ったコードなのでものすごい雑です.多分近いうちに座標とかをリクエストパラメータとして受け付けられるようにします.

github.com

※ YORPのappIDについては公式ドキュメントをどうぞ

Yahoo!デベロッパーネットワークヘルプ

あ,nodeやexpressに関してはこの辺りをどうぞ.

qiita.com

ラズパイでgit cloneしてyarnするだけで必要なライブラリが入ってくれます.便利.

appIdを.envで環境変数に登録して,yarn startします.このときラズパイ上で動作確認するときはhttp://localhost/weather/getWeatherにGetメソッドでリクエストを投げると今後1時間の降水予測が返ってきます.

<?xml version="1.0" encoding="UTF-8"?>
<YDF xmlns="http://olp.yahooapis.jp/ydf/1.0" firstResultPosition="1" totalResultsAvailable="1" totalResultsReturned="1">
    <ResultInfo>
        <Count>1</Count>
        <Total>1</Total>
        <Start>1</Start>
        <Status>200</Status>
        <Latency>0.002441</Latency>
        <Description></Description>
        <Copyright>(C) Yahoo Japan Corporation.</Copyright>
    </ResultInfo>
    <Feature>
        <Id>201806192350_0_35.663613</Id>
        <Name>地点(0,35.663613)の2018年06月19日 23時50分から60分間の天気情報</Name>
        <Geometry>
            <Type>point</Type>
            <Coordinates>0,35.663613</Coordinates>
        </Geometry>
        <Property>
                    <WeatherAreaCode >
            <WeatherList>
                <Weather>
                    <Type>observation</Type>
                    <Date>201806192350</Date>
                    <Rainfall >
                </Weather>
                <Weather>
                    <Type>forecast</Type>
                    <Date>201806200000</Date>
                    <Rainfall >
                </Weather>
                <Weather>
                    <Type>forecast</Type>
                    <Date>201806200010</Date>
                    <Rainfall >
                </Weather>
                <Weather>
                    <Type>forecast</Type>
                    <Date>201806200020</Date>
                    <Rainfall >
                </Weather>
                <Weather>
                    <Type>forecast</Type>
                    <Date>201806200030</Date>
                    <Rainfall >
                </Weather>
                <Weather>
                    <Type>forecast</Type>
                    <Date>201806200040</Date>
                    <Rainfall >
                </Weather>
                <Weather>
                    <Type>forecast</Type>
                    <Date>201806200050</Date>
                    <Rainfall >
                </Weather>
            </WeatherList>
        </Property>
    </Feature>
</YDF>

さらにラズパイがネットワークに繋がっていれば,IPアドレスを使用してのアクセスも可能です.

f:id:yomoyamareiji:20180620003116p:plain

この次はvvvvからラズパイにアクセスをして,インタラクティブなお天気デジタルサイネージを作ってみようかなーと思っています.

vvvvからHTTPGETを投げるのはめちゃくちゃ簡単なので,APIサーバを自作できれば色々な団体(企業)が公開しているデータを使用してリアルタイムなメディアアートを作ることができますね. ではでは~

[asin:4822256022:detail]