最終更新日
記事公開日

スカウターを再現!透明ディスプレイでドラゴンボールの世界が現実になるかも?

ドラゴンボールの中で、相手の戦闘力を測定するために使用される『スカウター』

初期のフリーザやベジータといった敵キャラがよく付けてたハイテク装置ですね。

今回はこのスカウターを透明ディスプレイで再現してみました。

透明ディスプレイで再現したスカウター

透明ディスプレイは超最新技術というわけではなく、存在自体はあったのですが、値段が高かったり透明度が低かったりと、まだまだ実用的ではありませんでした。

ところが最近になって、ようやく私のような一般人でも入手可能となり、値段も手頃なところまで落ち着いてきたので、今回購入してみました。

この記事で紹介している内容は、透明ディスプレイの応用編です。

基本的な使い方を知りたい方は、まずは下記の記事をご覧ください↓

OLED透明ディスプレイをArduinoで表示する

使用部品

配線図

スカウターを再現するための透明ディスプレイとArduino Pro Miniの配線図

スカウターに組み込んだ回路(正面)
スカウターに組み込んだ回路(裏面)

バッテリーの消費量を抑えるために、電源をON・OFFするためのスライドスイッチを取り付けてます。

Arduino本体に搭載してあるリセットボタンを押すことで、計測をスタートしています。

電源はスペースの関係で「3.7V・300mAh リチウムポリマーバッテリー」使用しました。

もし乾電池で動かす際は「Panasonic EVOLTA」の使用がオススメです。

百円均一で購入できる乾電池では必要な量の電流を流すことができないので、正常に画面が表示されなかったり、途中でアニメーションが止まってしまいます。

プログラム

#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(13, 11, 10, 9, 8);    // SW SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9

// power set
int power_num = 0;
char power_cnt = 0;
int power_arr[6]; // 100000 - 999999
char power_arr_length;
char power_num_size = 12;
char power_x,power_y;
char power_end_flag = 0;

// circle set
char circle_size = 14;

// triange set
char triangle_cnt = 0;
char triangle_flash = 1; // 1:ON , -1:OFF
char triangle_end_flag = 0;

// line set(diagonal)
char diagonal_line_x = 0;
char diagonal_line_y = 0;
char diagonal_line_end_flag = 0;

// line set(straight)
char straight_line_x = 0;
char straight_line_end_flag = 0;

// message set
int message_y[] = {34,44,54};
String message_body[] = {"completed!","unidentified","No data..."};
int message_flag[] = {0,0,0};
char message_arr_length;
char message_font_size = 5;
char message_hiddenbox_size = 12;
char message_cnt = 0;
char message_no = 0;
char message_end_flag = 0;

// setup
void setup(void) {

  //Serial.begin(9600); 
  //Serial.println("");

  // pixel on
  u8g.setColorIndex(1);

  // random power number generator
  randomSeed(analogRead(0));  
  long power_rand = random(100000, 999999);
  String power_str = String(power_rand);

  power_arr_length = power_str.length();

  // power number position ( MAX: 128*64 )
  power_x = power_num_size * power_arr_length;
  power_y = 20;

  // power arr set
  String power_val;
  for(char i=0; i<power_arr_length; i++) {
      // round set
      if (i>1) {
        power_val = "0";
      } else {
        power_val = power_str.charAt(i);
      }
      power_arr[i] = power_val.toInt();
  }

  // message arr
  message_arr_length = sizeof(message_y) / sizeof(int);
}


void loop(void) {

  u8g.firstPage();
  
  do {

    // all end (dispay clear)
    if (message_end_flag) {
      u8g.setColorIndex(0);
      u8g.drawBox(0, 0, 128, 64);
    }
    else {
    
      // circle draw
      u8g.drawCircle(100,32,circle_size);
      u8g.drawCircle(100,32,circle_size + 3);
  
      // triangle flash
      if (triangle_flash == 1) {
        u8g.setColorIndex(1);
      } else {
        u8g.setColorIndex(0);
      }
  
      // triangle draw
      u8g.drawTriangle(97,5, 103,5, 100,11);
      u8g.drawTriangle(100,55, 103,61, 97,61);
      u8g.drawTriangle(128,29, 123,32, 128,36);
      u8g.drawTriangle(77,32, 72,29, 72,36);
      u8g.setColorIndex(1);
      
      // diagonal_line draw
      if (triangle_end_flag) {
        u8g.drawLine(82, 28, 82 - diagonal_line_x, 28 - diagonal_line_y);
      }
  
      // straight_line draw
      if  (diagonal_line_end_flag) {
        u8g.drawLine(76, 22, 76 - straight_line_x, 22);
      }
  
      // power number draw
      if  (straight_line_end_flag) {
  
        // draw position
        for (char i=0; i<power_arr_length -1; i++) {
          if(power_x <= power_arr_length * power_num_size - ((i + 1) * power_num_size)) {
            u8g.setPrintPos(power_arr_length * power_num_size - ((i) * power_num_size + power_num_size), power_y);
            u8g.setFont(u8g_font_profont22);
            u8g.print(power_arr[power_arr_length - (i + 1)]);
          }
        }
    
        // last number draw
        if(power_x < power_num_size) {
          u8g.setPrintPos(power_num_size - power_num_size, power_y);
          u8g.setFont(u8g_font_profont22);
          u8g.print(power_arr[0]);
          power_end_flag = 1;
        }
        // shaffuru number draw (animation)
        else {
          u8g.setPrintPos(power_x - power_num_size, power_y);
          u8g.setFont(u8g_font_profont22);
          u8g.print(power_num);
        }
      }
  
      // message draw
      if  (power_end_flag) {
  
        for (char i=0; i<message_arr_length; i++) {
  
          if (message_flag[i] == 1 or message_no == i ) {
                       
            u8g.setFont(u8g_font_profont10);
            u8g.setPrintPos(0, message_y[i]);
            u8g.print(message_body[i]);
  
            // hiddenbox draw
            if (message_no == i) {
              
              u8g.setColorIndex(0);
                           
              if (message_cnt <= message_hiddenbox_size) {
                u8g.drawBox(message_font_size * message_cnt, message_y[i] - 8, message_font_size * (message_hiddenbox_size - message_cnt), 10);
              } 
              else {
                message_cnt = -1;
                message_flag[message_no] = 1;
                message_no++;
              }
  
              u8g.setColorIndex(1);
            }
              
          }
        }
      }
    }
     
  } while ( u8g.nextPage() );

  // triangle flash motion set
  if (!triangle_end_flag) {
    // waiting for line_motion to start
    if (triangle_cnt == 0) {
      delay(2000);
    }
    // triangle_cnt = odd only
    if (triangle_cnt > 11) {
      triangle_end_flag = 1;
      delay(500);
    } else {
      triangle_flash = triangle_flash * -1;
      triangle_cnt++;
    }
  }
  // diagonal line motion set
  else if (!diagonal_line_end_flag) {
    if(diagonal_line_x < 6) {
      diagonal_line_x = diagonal_line_x + 1;
      diagonal_line_y = diagonal_line_y + 1;
    } else {
      diagonal_line_end_flag = 1;
    }
  }
  // straight line motion set
  else if (!straight_line_end_flag) {
    if(straight_line_x < 16) {
      straight_line_x++;
    } else {
      straight_line_end_flag = 1;
    }
  }
  // power number motion set
  else if (!power_end_flag) {

    straight_line_x++;
  
    // num animation continue
    if(power_num >= 9) {       
      power_num = 0;
      power_cnt++;
  
      // num animation time set
      if(power_cnt >= 1) {
        power_x = power_x - power_num_size;
        power_cnt = 0;
  
        // last
        if(power_x < 0) {
          power_x = power_num_size * power_arr_length;
        }
      }
  
    } else {
      power_num++;
    }
  
  }
  // message motion set
  else {
 
    if(message_cnt <= message_hiddenbox_size) {
      if(message_cnt == 0) {
        delay(1000);
      }      
      message_cnt++;
    } else {
      if(message_no == message_arr_length) {
        message_end_flag = 1;
      }
    }
  }
  
}

コード解説

このプログラムは、大きく分けて7つの項目で構成されています。

  1. 二重の円を描く
  2. 上下左右の四方向に三角マークを表示する
  3. 三角マークを点滅させる
  4. 斜めに伸びるラインを描く
  5. 横に伸びるラインを描く
  6. 数字アニメーションを表示する
  7. タイプライター風にメッセージを表示する

簡単な処理に見えるかもしれませんが、意外と大変です。

常に画面がクリアされるので、毎回クリアされる前の画面を再描画してから、アニメーションをスタートさせなくてはいけません。

また描画を開始するタイミングを制御するために、各項目ごとに終了フラグを撒き散らしています。

結果、メモリ消費が激しいコードになってしまいました。

特に難しい処理は行っていませんが、アニメーションの一部分だけ特殊なところがあるので、解説しておきます。

三角マークを点滅させる方法

三角マーク「u8g.setColorIndex(1)」「u8g.setColorIndex(0)」を交互に繰り返すことで点滅を表現しています。

setColorIndexは、ドットのONとOFFの切り替えを行うコマンドです。

塗るときは「1」、消すときは「0」という使い方をします。

「triangle_flash」というフラグを用いて、読み込み毎にON・OFFを切り替えています。

// triangle flash
 if (triangle_flash == 1) {
  u8g.setColorIndex(1);
 } else {
  u8g.setColorIndex(0);
 }

~

triangle_flash = triangle_flash * -1;

タイプライター風に文章を表示する方法

カウントを用いて一文字ずつ表示する方法が一般的かもしれませんが、あまりにもコード量が多くなってしまいます。

そこで、最初に文字の上に黒いボックスを被せておいて、一文字分ずつ黒いボックスを小さくする手法を採用しました。

参考

この記事のURLをコピー

メールアドレスは公開されませんのでご安心ください。また、* が付いている欄は必須項目となります。

内容に問題なければ、下記の「コメントを送信する」ボタンを押してください。

関連情報

運営者プロフィール
コダマ

職業はIT系フリーランス。過去、電子配線業務の経験が10年ある為、はんだづけも得意です。宮崎県在住、30代・2児の父親。

カテゴリー