人形の目を光らせ、呪いの人形にする

#はじめに
「球体関節ってエロいよね？」
「人形に魂が入っていたとしても、動いたり喋ることはおろか意思表示の手段がないってのがいい……」
と、フェチをこじらせて球体関節人形を作るに至ってしまいました。

![うちのコ（球体関節人形）](https://qiita-image-store.s3.amazonaws.com/0/171026/12b33b74-5d0b-d484-e680-59277320cf56.jpeg)

作っていくと愛着が出てくるものでして、いろいろやりたくなります。
あるとき、市販ロボットの機能で「目を光らせ、その色で感情を表現する」というのを聞き、その程度だったらうちの子にも仕込めるかな？と、家に転がっていた arduino と フルカラーLED を使いやってみることにしました。

が、実際にやってみると。
**「これ、あかんヤツや」**
軽いホラーになってしまい、呪われた感が……。というわけなので公開して、呪いを皆様におすそわけです。

#やること
長々書いても、やることは「arduinoでLチカ」です（元も子もない
よくあるフルカラーLEDで足がR・G・Bと分かれているものは結線が面倒くさいので、マイコン内蔵RGB LEDを使っていくことにします。

#必要なもの

- 人形 ： 私は自作の人形を使いましたが、眼球にLEDを仕込む余裕があれば市販のドールでもいけるのでしょうか？
- Arduino Uno ： 別にUnoである必要はありません
- [マイコン内蔵RGB LED PL9823-F5](http://akizukidenshi.com/catalog/g/gI-08411/) ： 今回の肝です

他にも線材やユニバーサル基板などがありますが省略します。

今回使ったRGB LED「PL9823」 の特徴としては

- 電源以外に制御信号線だけの結線だけで他の部品が必要ない
- PL9823の出力端子と入力端子とを数珠繋ぎに連結していくことで複数のLEDを制御できる。この場合でもマイコンとの結線は1本だけで済む（多数つなげるときはノイズ対策に他の部品が必要かも）
- Arduino で制御する場合はライブラリが公開されている

といったことが挙げられます。
また、RGBを各256段階で指定できますので「緑が入った青」や「赤味が強い橙」などの微妙な色もできますので、このLEDを使ってスティックライトを作れば赤・ピンクから青や黄色にいつでも変えられますし、アイドルの推しが変わっても安心です ~~みくにゃんのファンやめます~~

# Arduino と LED の接続

今回の人形は、目の数が2つですので、LED PL9823を2つarduinoと接続します。
結線は以下のようになります。LEDをつなぐArduinoのピンは今回はDIGITAL 2を使いました。

![PL9823 LED接続](https://qiita-image-store.s3.amazonaws.com/0/171026/64e36609-1cd5-b296-f16e-63d909d38e0e.jpeg)

|arduino|LED1|LED2|
|:-----:|:----:|:----:|
|5V|3.VDD|3.VDD|
|GND|1.GND|1.GND|
|DIGITAL 2|4.DIN||
||2.DO|4.DIN|

今回は2つだけですが、三只眼の人形でLED3つとか百々目鬼でもっとたくさんの場合でも、LEDのDOとDINを数珠繋ぎにしていくだけで、arduinoとの線の数は変わりません。百目の場合には電源は別にとった方がいいとは思いますが。

# スケッチ
スケッチを書きはじめる前に、PL9823を使うためのライブラリを用意します。
ライブラリマネージャで「Adafruit Neopixel」を探すか、https://github.com/adafruit/Adafruit_NeoPixel から持ってきます。

スケッチは今回は以下のようになりました。

```cpp:dolleye_led.ino
#include <Adafruit_NeoPixel.h>

#define LEDPIN 2
#define NUMLED 2

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMLED, LEDPIN, NEO_RGB + NEO_KHZ800);

typedef struct {
  int r;
  int g;
  int b;
} RGB;

String eyes_color[] = {"#000000", "#0000ff", "#ff0000", "#ff00ff", "#00ff00", "#00ffff", "#ffff00", "#ffffff"};
int eyes_colorCount = sizeof(eyes_color) / sizeof(eyes_color[0]);
int eyes_color_cur = 0 , eyes_color_to=1;

RGB rgb_hex2dec(String hexstr){
  RGB rgb;
  long val = strtol(&hexstr[1], NULL, 16);
  rgb.r = (int) (val >> 16 & 0xff);
  rgb.g = (int) (val >> 8 & 0xff);
  rgb.b = (int) (val & 0xff);

  return rgb;
}

boolean compareRGB(RGB a, RGB b){
  return ((a.r == b.r)&&(a.g == b.g)&&(a.b == b.b));
}

void changeLED(RGB from1, RGB to1, RGB from2, RGB to2){
  RGB s[] = {from1, from2},
      t[] = {to1, to2},
      d[2];

  for(int i=0; i<2; i++){
    d[i].r= (s[i].r < t[i].r)?1:((s[i].r > t[i].r)?-1:0);
    d[i].g= (s[i].g < t[i].g)?1:((s[i].g > t[i].g)?-1:0);
    d[i].b= (s[i].b < t[i].b)?1:((s[i].b > t[i].b)?-1:0);
  }

  while(!compareRGB(s[0],t[0]) && !compareRGB(s[1],t[1])){
    for(int i=0; i<2; i++){
      if(s[i].r != t[i].r){  s[i].r += d[i].r;  }
      if(s[i].g != t[i].g){  s[i].g += d[i].g;  }
      if(s[i].b != t[i].b){  s[i].b += d[i].b;  }
    }
    
    setLED(s[0], s[1]);
    delay(5);
  }
}

void setLED(RGB rgb1, RGB rgb2) {
  strip.setPixelColor(0, strip.Color(rgb1.r, rgb1.g, rgb1.b));
  strip.setPixelColor(1, strip.Color(rgb2.r, rgb2.g, rgb2.b));
  strip.show();
}

void setup() {
  strip.begin();
  strip.setBrightness(30);
  setLED(rgb_hex2dec("#000000"), rgb_hex2dec("#000000")); 
  delay(1000);
  
}

void loop() {
  RGB from = rgb_hex2dec(eyes_color[eyes_color_cur]);
  RGB to = rgb_hex2dec(eyes_color[eyes_color_to]);

  changeLED(from, to, from, to);
  eyes_color_cur = eyes_color_to;
  eyes_color_to = (eyes_color_to + 1) % eyes_colorCount;

  delay(3000);
}
```

Adafruit_Neopixel のライブラリを利用した部分を少しだけ解説をしますと

1. インスタンスの作成。LEDの数・arduinoのピン番号・色の並び・データの転送速度指定``Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMLED, LEDPIN, NEO_RGB + NEO_KHZ800);``
2. インスタンスの開始 ``strip.begin();``
3. 明るさ指定関数 ``strip.setBrightness(30);``
4. 指定したLEDに対する色をRGBで指定 ``strip.setPixelColor(0, strip.Color(rgb1.r, rgb1.g, rgb1.b));``
5. LED表示反映 ``strip.show();``

となります。

スケッチを転送して実行されると、LEDの色が無点灯→青→赤→紫→緑→水色→黄色→白→無点灯→……と イロイッカイズツ の順（X1では逆順？）にじょじょに変化していきます。

# 人形の準備
真似して作ろうという方はほとんどいないと思いますが、人形の方のLEDを仕込む眼球についても触れておきます。
白目部分を眼球は石粉粘土（人形の体も石粉粘土です）で作ったものに、黒目にあたる部分を透明レジンで作ったものを接着し、黒目部分のみLEDの光が透過するようにしています。虹彩は透明シールをPCで作って、黒目と白目の間に貼り付けました。

![人形の眼球・虹彩を透明レジンで作成](https://qiita-image-store.s3.amazonaws.com/0/171026/2ad8b27c-0a15-e7bd-176d-faace291a13a.jpeg)

ドール用にアクリルアイ・グラスアイなどが市販されていますが、これら眼球の中でLEDを光らせると白目部分まで光ってしまいますので、やめた方がいいと思います。

# 人形への組み込みと動作
人形との現物合わせで目の幅にLEDが配置されるようユニバーサル基板に半田付けを行い（ここまでのLEDの動作の確認はブレッドボードで行っていました）、人形の頭部に入るよう基板をカットし、それを人形に取り付けて完成です。

![人形への組み込み用LED基板](https://qiita-image-store.s3.amazonaws.com/0/171026/613c21b4-c63c-9ffd-0fbd-fa211f4c81a7.jpeg)

実際に動作させた様子がこちら

<blockquote class="twitter-video" data-lang="ja"><p lang="ja" dir="ltr">目光る球体関節人形 <a href="https://t.co/luKkJjiJxU">pic.twitter.com/luKkJjiJxU</a></p>&mdash; 球体関節人形 (@CursedDoll_1103) <a href="https://twitter.com/CursedDoll_1103/status/848146131947094017">2017年4月1日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

冒頭で「これ、あかんヤツや」「軽いホラーになった」というのがわかっていただけましたでしょうか？

# 終わりに
今回使いましたPL9823というフルカラーLEDは「arduinoで使う分には使い勝手がいい」ということがわかっていただければ幸いです。

そういうLEDを使うと「簡単にできるから」と人形の目にLEDを仕込む、とやってみたのですが、結果は「簡単に出来るからといっても、やらない方がいいことも世の中にはある」と。でもおかしいな？ロボットだったら目のLEDが光っても普通なのに、なぜ人形だと？

しかし、人形の目を光が通るように作っておく、というのは応用範囲は広そうではあります。たとえば

- 普通に見ている分にはなんの変哲も無い人形なのに、デジタルカメラで撮影すると目が光って写るよう赤外線LEDを仕込む
- 赤外線LEDを仕込んでリモコンの信号を出力し、人形を置いた部屋のテレビが勝手に点いたり消えたりする

といった応用が思い浮かびます……応用範囲、狭かったですね。

なおこの人形ですが。現在私の手元では音声合成ICが内蔵され喋るようにもなっていて、ますますホラーなことになっています。