おもちゃの踏切を自動化した

# 1. はじめに

タカラトミーの「[**トミカワールド トミカタウン サウンドライトふみきり**](https://takaratomymall.jp/shop/g/g4904810152859/)」を、[**ATtiny85**](https://akizukidenshi.com/catalog/g/gI-09573/)マイコンを使って自動制御した内容を残しておく。

このおもちゃは、（下の写真に赤色の矢印で示した）トリガーボタンを押し下げると、信号の赤いランプが交互に光り、踏切サウンドが鳴り、遮断機が下がる。もう一度押すと、トリガーボタンが元に戻り、信号と音が止まり、遮断機が上がる おもちゃである。

これを、おもちゃの電車が横切る時にスイッチを入れ、通過したらスイッチを切るように自動化する。

![4904810152859_fca8d968cf4744fc9eca1f34b9087f3d.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/00c99f99-efe7-73be-5312-0274649ef761.jpeg)


# 2. おもちゃの構造を確認する

底側の4本のネジを外し裏蓋を外すと、内部が剥き出しになる。右下の緑色がスピーカー。

![IMG_1798.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/865cab50-b940-061d-c93c-20aa566b1449.png)

小さな基板に黒い樹脂で覆われたマイコン一つで制御しているようだ。トリガボタンが押されると、すぐ横のマイクロスイッチが押され、つながっている2本の黒い導線が短絡する。
遮断機は、カムによりトリガボタンの押し下げに連動して下がる仕組みだ。また、遮断機の支点軸にバネが組み込まれており、押されてなければ跳ね上がる（戻る）仕掛けとなっている。

![pcb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/b726c13d-ba99-1382-f292-d0471255df78.png)

調べたところ、**SW**と記したランドを**HIGH**にすることで信号LEDが点滅しサウンドが再生され、**LOW**にすることで止まることが分かった。


# 3. 自動制御の仕組み

上記の構造が確認できたので、自動化は次の方式とした。

- **電車の検知**<br>線路に置く**CdS**（光センサー）にて、電車が通ると**暗くなる**こと（による抵抗値の変化）で検知する。半固定抵抗と組み合わせることで、感度調整も可とする

- **遮断機**<br>遮断機の上げ下げは[マイクロサーボ**SG90**](https://akizukidenshi.com/catalog/g/gM-08761/)で制御する。カムで押される位置の遮断機のレバーと**SG90**のサーボホーンをナイロン糸で結び、遮断機を下ろすときはホーンを回転させ糸を引っ張る。ホーンを戻すと元々のバネの力で遮断機は元に戻る（上がる）

- **信号LEDと踏切サウンド**<br>前述した通り**SW端子**を<i>HIGH</i>にする。止めるときは<i>LOW</i>にする

- **電源**<br>**ATtiny85**及び**SG90**の電源は、このおもちゃの単三乾電池x2本の3Vを共有し、**VCC**と**GND**端子からいただく


# 4. 回路図

![回路図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/1700a58e-ec48-71a1-c822-34ddf3e83586.png)

上記回路図内のバッテリーはおもちゃ自身の乾電池を示す。**鳴動スイッチ**は前述の**SW端子**のこと。

実験にて、SG90のホーン90°の位置が遮断機が上がっている状態にしたとき、125°の位置が遮断機が一番下がった状態となることを確認した。


# 5. プログラム

Arduino UNOをISPとして、ATtiny85にスケッチを書き込んだ。内容は以下の通り。

```C++
/* ================ 
 * for ATtiny85
 * ================
 *
 */

#include <Servo_ATTinyCore.h>
Servo servo;

const int cds_pin = A1;  //A1(D2)
const int sw_pin =  1;   //D1
const int sg90_pin = 0;  //D0(PWM)

void setup() {
  servo.attach(sg90_pin);
  pinMode(cds_pin, INPUT);
  pinMode(sw_pin, OUTPUT);
  digitalWrite(sw_pin, LOW);
}

const int min_degree = 90;
const int max_degree = min_degree + 35;
int now_degree = min_degree;  //neutral
int status = -1;  //-1: IDLE, 0: DOWN, 1: whole DOWN, 2: UP

void loop() {
  auto cds = analogRead(cds_pin);
  auto sw_on = cds > 900;

  if (!sw_on && status == -1 || sw_on && status == 1) {
    delay(20);
    return;
  }

  if (sw_on && (status == -1 || status == 2)) {
    status = 0;  //DOWN
  } else if (!sw_on && (status == 1)) {
    status = 2;  //UP
  }

  if (status == 0 || status == 2) {
    if (status == 0 && now_degree >= max_degree) {
      status = 1;
      return;
    }
    if (status == 2 && now_degree <= min_degree) {
      status = -1;
      digitalWrite(sw_pin, LOW);
      return;
    }

    digitalWrite(sw_pin, HIGH);

    now_degree += (status == 0) ? 1 : -1;
    servo.write(now_degree);

    delay(20);
  }
}
```

**・ 遮断機の制御**

1. サーボモータは角度を指定すると、一瞬でその角度に移動しようとするが、遮断機を徐々に下げる（上げる）ようにするため、20ミリ秒のサイクルごとに1°づつ移動するように制御した

1. 遮断機が下がり切っていないうちに、電車が通過してしまった場合も、一旦下がり切ってから上げるように制御した

1. 逆に、遮断機が上がり切っていないうちに、再び電車が来た場合は、その位置から遮断機を下げるように制御した

<br>


**・ 信号とサウンドの制御**

1. 遮断機を下ろし始めるタイミングから上がり切るまでの期間をONとし、それ以外をOFFとした。もう少しリアルな踏切を再現するなら、信号とサウンドを先にONにして少し遅れて遮断機を下げ始め、逆は、遮断機が上がり切ってから少し遅れて信号とサウンドをOFFにするとよいだろう





# 6. 組み立て

|ATtiny85ハンダ付け前の動作確認|ハンダ付け後|
|:-:|:-:|
|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/a1dd8e7b-bf9f-f903-2011-92a6c72d86a3.jpeg)|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/867c9448-3fc4-d332-f5bb-e2fc8cdb8c49.png)|

VCCとGNDには、複数本のワイヤーが接続されるため、0.3mm厚のユニバーサル基板を補助として使用。


# 7. 完成ムービ

実際に線路を敷いてやればよかったが、とりあえず動作確認した時のムービーである。

<img width="200" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/e898bd5c-7300-80fa-e007-f4d23f99f9fe.jpeg">


<iframe width="100" height="400" src="https://www.youtube.com/embed/PbZQKSSulW8?rel=0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


# 8. さいごに

ほぼ期待通りに機能した。
一点だけ改善点として、電車通過後すぐに止める（遮断機をあげる）のではなく、1〜2秒待ってからが良い気がした。
プログラムは簡単に対応できるが、ATtiny85に焼くのが（ICクリップをつなぐ作業が）億劫だ。


# 9. あい路事項

1. 当初、3.3V/8MHz仕様のArduino Pro Miniを組み込んだが、乾電池の3Vが非力のため、サーボが回転すると電力不足でPro Miniが落ちてしまう現象に見舞われた。そのため、SG90の電源を外付けの乾電池ボックスで別に用意していた。<br>　しかし、そもそも（アナログ入力x1、デジタル出力x2 しか使わないので）ATMega328Pがオーバースペックのため、ATtiny85に換装した。これにより、外付けの乾電池が不要になり、かつ、省スペースでおもちゃの内部に難なく収納できた。

1. 元々のトリガーボタンのメカ一式を取り外せば、サーボモーターをおもちゃ内部に収納できる可能性もあるが、トリガーボタンによるオン/オフ機能も残しておくため、今回は外付けとした（正面からは見えにくい裏側に両面テープで固定）。<br><img width="100" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/643b2fc8-f20f-8ba9-7159-ea52d654441c.png">

1. アイドル状態が何分か継続したらATtiny85をスリープモード（パワーダウン動作）に移行することで、さらに省エネにできる。ただし、CdSの抵抗値変化で復帰させられるか 検証が必要なため、今後の課題とする。（同時に、電力喰いのSG90もスリープさせるためにMOSFETを使い電源を断つ制御が必要）


---
**以上**