マイコンを使うのは9割甘え。タイマーICとかカウンタICがあればなんとかなる。

# 背景
[以前のロボット](https://qiita.com/tanutanup/items/8cad22d386e8295a3e84)では***マイコンを搭載しておりバグの温床***になっていました。そのマイコンの仕事は以下のとおりです。
1. 大会のルールに準拠した走行・停止を行う(後述)
1. ラインセンサや速度、左右輪指示トルクなどを計測
1. (一応）アナログコンピュータ無しで走行

このマイコンが行っていた1の動作を**マイコンなどという甘えたデバイスなんか使わずに実行**することを考えたいと思います。

# 大会のルール
[マイクロマウス・ロボトレース競技](https://www.ntf.or.jp/?page_id=27)はただライントレースするだけではなく、ゴール後に自動的に停止してゴールからスタートの間にとどまる必要があります。その目印として**進行方向右側**に**スタート・ゴールマーカー**が設置されています。光センサでマーカーを捉えれば良さそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/62793e93-5bee-1852-427b-99cd7126d780.png)
ところがコースには交差点が設定されているので、ゴールマーカー用のセンサは交差点を**マーカーだと誤検知して停止**してしまいます。コース上で停止してしまうとリタイアとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/60612c63-4834-de86-25fc-8476bd9c8e43.png)
ついでに、**進行方向左側**にもマーカーがあります。これはコーナーの曲率が変わる目印です（**コーナーマーカー**）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/53236961-f263-f2c0-54e0-85d1dc1103b2.png)
以上より、大会で完走扱いされる最低限の要求は**走行開始後２回目のスタート・ゴールマーカー（以降ゴールマーカー）で停止**と言えそうです。

# 要求分析

## スタート・ゴールマーカーの検出（＝交差点との区別）
左右のマーカーは同時に存在しないので、交差点とは区別が可能そうです。では同時にセンサが検出した場合はスルーすればよいのでしょうか？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/34a08972-f9bd-ec74-a152-0210e960a071.png)

### 課題
これは実際走らせるとうまくいきません。なぜならば、少しでの**斜めに交差点へ侵入**したり、交差点自体が斜め(**±5度まで許容**)だからです。その場合、**一瞬交差点以外を検出しゴールを誤検知**してしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/b128d214-5984-a09d-1c8b-846e2a2a2615.png)


なお、この待ち時間は$想定されるズレ距離 <【待ち時間】<  10cm(次のマーカ・交差点までの距離)】$の関係にあり、**速度に反比例**した値となります。

### 対策１：少し待ってから判定する
下図のようにマーカーセンサの検出に遅れて状態の判別を行う方法です。交差点とゴールを区別するだけならば、**左マーカーセンサが検出する前後一定時間(距離)以内で右マーカーセンサが反応したら交差点。右マーカーセンサが単独で反応したらスタート・ゴール**と判定すればよいでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/66c761b7-56fa-1f5e-a429-fe1248ac898e.png)


### 対策2：センサをずらす
もう一つの方法として、左マーカーセンサを物理的に前に搭載する方法があります。
左マーカーセンサが**絶対先に検出できる**ようにズレていて、左マーカーセンサの検出後一定距離以内に**反応した右マーカーセンサを無視**すれば交差点とゴールマーカーのみを検出できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/45919f6a-434a-3c7a-5aaf-1270be9c9772.png)

### （追記）対策3：センサを物理的に増やしてしまう
実にシンプルな解決法があることを発見(?)しました。至極シンプルな方法ですが見逃していました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/9d8bbe94-22d9-33f4-46dc-3a2919da1730.png)
### センサの種類について
まずは大きく2種類あるセンサについてその動作を確認してみます。

#### フォトIC（デジタル）
一つ目はデジタルな検出ができるフォトIC[^S7136]です。赤外線LEDが放った赤外線が白いマーカーに当たった時は強く反射するので、それをフィルタリング・増幅して白黒を判別します[^S7136]。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/49e16f42-c673-7ece-e02b-b7682fb8f95c.png)

#### フォトトランジスタ(アナログ）
二つ目はアナログな検出が可能なフォトトランジスタ等を用いる方法です。フォトトランジスタは受け取った光の強度で流れる電流が変わります。その電流を抵抗に流すと電圧に変換でき、電圧は電流と抵抗で調整可能です。なお電圧や電流は無制限に増えるわけではなく、電源電圧やセンサの許容電流等で制限されます。

<img width="360" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/4deee91a-a627-790b-9124-1f69e6a3f9fd.png">

実際のマーカーセンサにおいては、赤外線LEDの反射光はマーカーとの距離に応じてアナログに変化し、フォトトラの電圧も位置に応じたアナログな電圧値となります。これをヒステリシスコンパレータ[^コンパレータ]でデジタルな検出結果に変えて判定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/afb90b55-994a-bb6c-f16f-6e8a4d50ee0b.png)

#### 複数のセンサを搭載した場合 
まずフォトICを用いた場合、検出範囲の抜けが生じる懸念がありました。これはフォトICの検出強度を自由に調整できないことに起因します。また、複数のセンサを隣接して使う場合に干渉[^S7136]する懸念もありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/482e22d6-9f2c-fb6a-e74a-d52caf138e90.png)

一方、フォトトラでは各フォトトラに流れる電流値の合計が電圧に変換[^キルヒホッフ]されるので、複数のセンサの間にマーカーがある場合にもアナログな値で検出が可能です。しかもICと違い感度やコンパレータのしきい値を自在に決められるため、上手く設計すれば幅広い検出範囲を作れそうです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/285fa52b-5ca0-7513-0a31-5a690700f956.png)


### 採用する対策
***マイコンを使うのは甘え***なので、回路で処理しやすい~~対策2~~対策3を選びます。ワンショットタイマー[^ワンショット]で遅延させて論理回路で処理すればゴールマーカーのみを検出できるからです。

## アナログコンピュータ部分への速度指示
[以前のロボット](https://qiita.com/tanutanup/items/8cad22d386e8295a3e84)ではSPI通信でDACと通信し、アナログコンピュータへ目標速度を電圧値で指示していました。回路のみでSPI通信させるのは面倒なので、DACの代わりにアナログ電圧を直接与えるように改造します。また、アナログコンピュータのF/Bとモータドライバの電流指示を0AにするH/L信号も(元々)あります[^アンプのONOFF]。

### 速度指示
まずは速度制御の要件を整理し、状態遷移図を作成しました。
- ボタンを押すと走行開始
    - ボタンを押すまでは勝手に走らない
- スタートマーカー検出までスロー走行
    - スタート～ゴールの間で走行を開始するため
    - スタートマーカーを見逃さないため
    - 制御安定前に最大速度で走るのはリスクが有るため
- ゴールマーカーを見つけるまで最高速度走行
    - タイムを競う競技のため速度を上げたい
    - 速度はコースに合わせて別途調整
- ゴールを通過後一定時間で停止
    - ロボットがゴールラインを完全に通過しないとゴール扱いとならないため
    - スタート～ゴール内で停止しないと失格となるため

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/041be681-fed0-0b9d-4dcd-f84869aa2df9.png)


# 実装
## ステートマシン
先程の状態遷移図は単純なのでボタン押下やマーカー検出、一定時間経過を一緒くたに4回数えれば良さそうです。
[ロジックIC](https://ja.wikipedia.org/wiki/%E6%B1%8E%E7%94%A8%E3%83%AD%E3%82%B8%E3%83%83%E3%82%AFIC)にはカウンタという、H/Lの変化回数を数えるカウンタIC[^カウンタ]があります。カウンタICは主に2進数カウンタ[^カウンタ]と10進カウンタ[^カウンタ]がありますが、0～9のカウントを各々**個別のH/L信号**で出力する10進カウンタのほうが後段の処理に使いやすいため74HC4017[^カウンタ]を採用しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/93622347-2c54-9617-35dc-cfafee5fbc24.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/19ab628f-47f2-662c-51e6-ea8cc62e4be6.png)

なお、状態遷移のトリガであるボタン押下やマーカー検出、一定時間経過は全てクロック端子(14番ピン)へ接続することになります。

## ゴールマーカー・交差点の処理
左右マーカーセンサはマーカーや交差点を検出するとLに落ちる信号を生成します。
その信号を**ワンショットタイマー**で延長することで、ゴールを誤検出する問題に[対策](###対策2：センサをずらす)します。
### ワンショットタイマー(タイマIC：555[^NE555])
タイマIC：555は外部に抵抗やコンデンサを外付けすると発振器やタイマーとして動作する超有名なICで、以下のように抵抗やコンデンサを接続するとワンショットタイマーとして動作します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/f99b5432-661e-55fb-d247-37a8beb9a9f9.png)

まず、リセット後にトリガー(L)が入力されると、出力がHになるのと同時にコンデンサCtへ充電が開始されます。Ctの電圧が電源電圧Vccの2/3に達すると出力がLになるの同時にDIS端子により放電され0Vになります。
出力がHになる時間は抵抗RtとコンデンサCtから計算でき、
```math
T_{one} \risingdotseq 1.1R_TC_T[s]
```
となります。
また、リセット端子が入力(L)されると出力が強制的にLになりコンデンサCtも放電されます。なお、トリガが入力され続けた場合はコンデンサの充電は止まらずに、出力はHを保ちます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/4184c846-e3c1-3700-e625-02d2e4acb4ab.png)

### 左マーカーセンサのマスク時間生成
ワンショットタイマーの回路のトリガに左マーカーセンサからの信号(/CORNER_WHITE)を入力し、センサが検出中orマスク時間中はHとなる出力(RESET_MODE_CLK)を生成。後段のためにデジタルトラジスタ[^デジトラ]で反転(/RESET_MODE_CLK)させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/1bc478ac-b8c4-71dd-b074-46814b210af2.png)

なお、マスク時間は速度に応じて可変させる必要があるので、写真のような2連ボリューム[^連動ボリューム]により**速度設定用可変抵抗に連動**させています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/f5620777-1821-056d-cfd8-aef1b788ecf6.png)

マスク距離を約50[mm]、設定最高速度を1.5[m/s]。最低速度を0.75[m/s]とするとマスク距離の通過時間は、
```math
\displaylines{
50 [mm]/1.5[m/s] = 33.3[ms] \\
50 [mm]/0.75[m/2] = 66.7[ms] \\
}
```
とりあえずCを4.7[μF]にしてみると、
```math
\displaylines{
1.1 \times 4.7[ \mu F] \times (6 + 0)[k \Omega] &\risingdotseq 31.02[ms]\\
&= 46.53[mm] \\
&(@1.5[m/s]) \\
1.1 \times 4.7[ \mu F] \times (6 + 6.875)[k \Omega] &\risingdotseq 66.57[ms]\\
&\risingdotseq 49.9[mm] \\
&(@0.75[m/s])
} 
``` 
6kΩの固定抵抗と6.875kΩ(22kΩと10kΩの並列抵抗)とすれば良いと計算されます。

### ゴールマーカー・ボタンの入力回路
ワンショットタイマーの回路のトリガに右マーカーセンサとボタンからの信号(/GOAL_WHITE_/PUSH)を入力[^OR]し、リセットには先程のタイマー出力/RESET_MODE_CLK)を入力しています。出力は先のカウンタにつながっています(MODE_CLOCK)。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/98375fd5-0d99-4d8d-34be-25d9448b1b9e.png)

カウンタへの入力をワンショットタイマー出力とすることで、センサやスイッチの値が暴れて誤カウントするのを防止するとともに、左マーカーセンサが検出しタイマでマスクしている間はカウントが進まないようにしています。
（リセットがLである間、出力は強制的にL）

## 目標速度の選択とスロー走行
カウンタがMODE_CLOCKを1回もしくは3回数えるとスロー走行が有効になります。2回ではファスト走行が有効になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/696532bd-1d3d-ef44-ea84-ca8dfe7fb59f.png)

なお、回路図上はフォトカプラとなっていますが、実際はフォトモス(フォトリレー）です。フォトモスはLED側への通電により出力側のMOS-FETを絶縁しながらON-OFF制御します。
これを2つ組み合わせることで、絶縁しながらアナログの目標速度指示電圧を、0[m/s]、スロー走行(0.5[m/s]、ファスト走行(可変抵抗で可変)と切り替えられるようになってます。

### ゴール後のスロー走行と停止
ゴール後のスロー走行では停止する必要もあります。そのために、ワンショットタイマーを用いてゴールマーカー検出後に遅延時間を発生させ、遅延出力(SLOW_TO)とスロー走行(GOAL_SLOW)が入っている間[^AND]だけスロー走行の指示電圧が入力されます。
遅延時間はスロー走行速度(0.5[m/s])とロボットの全長（約200[mm])から、
```math
\displaylines{
200[mm]/0.5[m/s] = 400[ms] \\
1.1 \times 47[\mu F] \times 7.74[k \Omega] \risingdotseq 400[ms]
}
```
と計算されるので、タイマーの設定値は47[μF]と7.74[kΩ]としました。

ちなみに、走行中に設定速度を0[m/s]に落としたところ完全に停止はできず、回路の微妙な誤差で少しずつ進んでしまう現象が見られた。なので速度指示が入っている時以外はアンプ毎スイッチOFFにしてしまう対策を入れました[^アンプのONOFF]。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/40825a96-af8f-74ee-c96e-05b682b386c8.png)

## 最終的な回路図
メモ書きが残ってますが、だいたいこんな感じの回路図です。
<img width="680" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/425fe86a-f3e4-3dd0-1e79-15fde26a71eb.png">


# まとめ・感想
物理的な対策とタイマー回路、カウンタ等を組み合わせることでマイコンの代替ができました。その過程でタイマー回路の動作への理解が深まりました。
大会での動作を見るにバグはほとんどなかった一方、ちょっとした***ロジック変更***で回路の修正が必要になるので、正直まあまあ面倒に感じることもあったりなかったりしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/42704b79-1cba-4903-1b83-7bd8f9aeec1a.png)
***まあ、甘えなかった結果なので受け入れています。***

[^ワンショット]:単安定マルチバイブレータ。ワンショットマルチバイブレータとも。一瞬でも入力があったら一定時間だけ出力を行う回路。
[^コンパレータ]:コンパレータはアナログ的に変化する値をHiとLoの２値に変換する回路。ノイズ等でしきい値付近で値が変化し続けるとHiとLoを繰り返してしまう。ヒステリシスコンパレータは出力を入力側に正帰還させてHiとLoのしきい値を変化させることでその対策が可能。
[^S7136]:元々使用していたフォトICは[S7136](https://www.hamamatsu.com/jp/ja/product/optical-sensors/photo-ic/light-modulation-photo-ic/S7136.html)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269597/90ca1889-9474-d3d9-e1bf-1a26135a2bc7.png)
内部に赤外線LEDの駆動回路と受光部、アンプ、フィルタを内蔵。自身が発光させた赤外線と同じタイミングの赤外線のみが受光されたかを判定してLi/Loを出力する。
コンパレータのヒステリシス値を決められず、LEDの発光周波数も変えられないため、複数のS7136を近接して使った場合に混信の可能性がある。

[^キルヒホッフ]:いわゆるキルヒホッフの第一法則。フォトトランジスタが出力した電流が合流して抵抗に流れ込むので電流を加算することになる。
[^カウンタ]:カウンタICには同期式・非同期式が存在するが、今回の用途ではデジタルなクロックは必要無いので非同期式を採用した。また、オリジナルの4000シリーズである4017ではなく74HC4017を採用したのは手持ち在庫の関係であり特に意味はない。
[^NE555]:[555タイマーIC](https://ja.wikipedia.org/wiki/555_%E3%82%BF%E3%82%A4%E3%83%9E%E3%83%BC)
[^デジトラ]:H/Lの入力によりON/OFFを行う動作に特化したトランジスタ。必要な抵抗が内蔵されており部品点数が削減できる。
[^連動ボリューム]:2つの可変抵抗の軸が内部で機械的に結合されている可変抵抗。ステレオのボリュームによく採用される。
[^OR]:いわゆるOR回路を構成。
[^AND]:いわゆるAND回路の構成。2つのデジタルトランジスタがONしてはじめてLEDへの通電が行われる。
[^アンプのONOFF]:アナログコンピュータ部の特定の入力端子にHを入力するとアナログコンピュータのF/Bやアンプが有効化される。