くらげアクアリウムの仕組み(後編)

   

こんにちは! ShibaLabのPIC MANです。

この記事は前編の続きになります。

くらげアクアリウム:ソフトウェア編

くらげアクアリウムのプログラムは大きく分けて3つあります。

  1. WEBサーバ上のコード
  2. 親マイコン(Raspberry Pi)上のコード
  3. 子マイコン(Arduino)上のコード

それぞれについて解説していきたいと思います。

1.WEBサーバ上のコード

WEBサーバでは色を変えるWEBページの提供と親マイコンからの色データ要求に答える仕事をしています。

以下の画像のように、このくらげアクアリウムWEBページ上では4種類のプログラミング言語を使って構成されています。

 

WEBページの文章データはHTML、装飾はCSSで構成しています。それらが表向き(見た目)を構成するために使われる主な言語です。

さらに3つの色の成分量を調整するスライドバーを動かしたときに、WEBページ上に表示されている現在のパーセンテージを動的に変更するためにjavaSccriptを使っています。

これらの裏ではPHPという言語を用いて決定ボタンを押したときにサーバへ色の成分データを送ったり、データを保存したりしています。

更に親マイコンから色データの要求があったときサーバは色のデータを返す作業を行っております。


このうち、HTMLとCSS、javascriptについてはブラウザーの開発者ツールや「ソースの表示」等でそのまま見ることができます。

気になる方はちらっと見てみてください。

2. 親マイコン上のコード

親マイコン(今回はRaspberry Piを利用)ではWEBサーバから色のデータをもらってきて、子マイコンへTwe-Liteという無線機経由で送信するお仕事をさせています。

これらのコードはRubyで書きました。以下に実際に利用していたコードを置いておきます。

require 'serialport'
require 'net/http'
require 'uri'
require 'json'

debug = true  # デバッグ用
wait = 1   # 更新頻度[s]

puts "start"

# シリアルポート設定
serial = SerialPort.new('/dev/serial0' , 9600, 8, 1, SerialPort::NONE ,"\n")
serial.read_timeout = -1

# ctr + cで止める
Signal.trap(:INT) {
    serial.close
    puts "END"
    exit
}

# ループ処理
loop do
    begin
        # サーバからデータをGETする
        uri = URI.parse('http://api.shibalab.com/get_hikari/')
        json = Net::HTTP.get(uri)   # json形式で帰ってくる
        result = JSON.parse(json)   # パースする
        puts result if(debug)       # デバッグ用に結果をPiのコンソールへ表示
        # パースした結果を整形してTwe-Liteに出力
        result.each do |data|
            serial.write "$DATA,#{data['id']},#{data['red']},#{data['green']},#{data['blue']}\n"
        end
        # ちょっと待つ
        sleep wait
    rescue => e     # 例外
        puts e
        sleep 3
    end
end

serialportというRuby gem(ライブラリ)を利用してTwe-Liteと通信を行っております。
Raspberry PiとTwe-Liteは物理的に配線をつなげています。GPIOの14, 15ピンがそれぞれシリアルのTX, RXとなっているのでそこにTwe-LiteのRX, TXピンを接続します。

またTwe-Lite側はシリアル通信アプリを利用しています。詳しくはホームページをご覧ください。
このうちインタラクティブモードに入り、透過モードに設定し、ボーレート等を合わせて使いました。

お気づきの方もいらっしゃったかもしれませんがTwe-Liteの電源は3.3V, ArduinoやRaspberry Piの電源は5Vです。つまりシリアル通信する際には電圧が異なるためレベルシフタを挟む必要があります。
しかしこのことをすっかり忘れてつないでRXTXをつないでしまったのですがTwe-Liteは壊れてない…?
トレラント機能があるといった記述も見当たらないので単に運が良かっただけかもしれません。これらの機器を使う場合はレベルシフタをしっかり挟みましょう。

 

3. 子マイコン上のコード

子マイコンでは親マイコンからもらった情報をもとにフルカラーLED(NeoPixcel)の色を変えます。

以下に実際に利用していたコードを置いておきます。

#include <Adafruit_NeoPixel.h>
#define PIXEL_PIN 6
#define PIXEL_COUNT 8
#define MY_ID 2           // IDは子マイコンごとに変える
#define DEBUG_FLAG false

// NeoPixcelのインスタンス
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Serial.begin(9600);
  strip.begin();
  strip.show();
}

// 色を1つのLEDずつ変える関数
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 loop() {
  char buf[64]; // シリアルのバッファ用変数
  char c;
  int count = 0;

  // シリアル通信で先頭の文字($)から終端文字(\n)までbufに保存する
  while(1){
    if(Serial.available()){
      char c = Serial.read();
      if(c == '$'){
        count = 1;
        buf[0] = c;
      } else if(c == '\n') {
        break;
      } else if(count >= 63) {
        break;
      } else {
        buf[count] = c;
        count++;
      }
    }
  }
  buf[count] = '\0';

  if(0 == strncmp("$DATA", buf, 5)){
    char *char_id, *char_red, *char_green, *char_blue;

    // カンマ区切りで送られてくるのでそれらを分ける
    strtok(buf, ",");
    char_id = strtok(NULL, ",");
    char_red = strtok(NULL, ",");
    char_green = strtok(NULL, ",");
    char_blue = strtok(NULL, ",");
    
    // デバッグモードがTRUEならPCへ色データ出力
    if(DEBUG_FLAG){
      Serial.print("id : ");
      Serial.print(char_id);
      Serial.print(", red : ");
      Serial.print(char_red);
      Serial.print(", green : ");
      Serial.print(char_green);
      Serial.print(", blue : ");
      Serial.println(char_blue);
    }

    // カンマで区切ったものを文字列から数値へ変換
    int my_id = atoi(char_id);
    int red = atoi(char_red);
    int green = atoi(char_green);
    int blue = atoi(char_blue);

    // IDが自分の物だったら色を変える
    if(my_id == MY_ID){
      colorWipe(strip.Color(red, green, blue), 100);
    }
  }
}

こんな感じです。
くらげは5つ設置したので、頭の部分のMY_IDをそれぞれ変えてコンパイルしArduinoで実行させます。

Arduinoなど安価で便利な機器を利用しているのであまり難しいことを考えずにこういったものを作成できます。
いい時代になりましたね。

しかしながらこのくらげはRaspberry Piを経由してデータを取得するなどちょっと無駄な部分が多いとも感じます。
ESP-WROOM-02 Wi-Fiモジュールなどを使うとよりスマートに作れそうです(というより実際にyanakattyが作ってくれました)。

ここまでご覧いただきありがとうございます。何か質問等ありましたらコメント欄へどうぞ。

 - 作品紹介