Maix Bitで製品検査システムを作ったおはなし


#１．事の始まり

日々の業務に疲れ、消耗したとある技術屋さんのところに、アッシーされた樹脂部品に紛れ込んだ未アッシー品を検出したいという相談が舞い込みました。
その技術屋さんの本業は樹脂部品の開発ですが、「~~仕事中にも趣味で遊べる~~趣味で磨いた技術を仕事に生かせる！」と喜び「そんなの簡単だよと」安請け合いしました。

正しいアッシー品は、直径φ40程度の小さなお釜形状のアウター部品の中に、φ35程度のインナー部品が入っている２重構造。今後「お釜」と称します。
![2020_12_14 19_07 Office Lens (3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/2de67b0e-4e2b-3fcf-1446-c18eacded06c.jpeg)
検出したいNG品はアウターのみもしくはインナーのみとなっている未アッシー品。大至急（ざっくり納期）ウン百万個（数もざっくり）の製品を検査しないといけないそうです。うすうす気づいてはいましたが、結構危険な香りが漂っています。予算も時間もないということで、手元にある部品を使って検査装置を作るというのが今回のミッション。（マクガイバーかよ。。。）

アドベントカレンダーへの参加を勧めていただきましたので、お言葉に甘えて記事化しました。
お仕事周りに迷惑が掛からない様、最低限の写真、動画とポンチ絵でお届けしますがご了承ください。
また、DEMO以外でMaix系を使うのは初めてでしたので、覚書がわりにこまごま書き残します。

#２．作ったもの

何がしかのセンサーで良否判定を行う、人よりも早く、価格はキー○ンスより安くというのがざっくりした達成目標でした。
検出方法としては重量測定、厚み測定（重ねると見かけの厚みが増える）、画像判定などの方式が考えられますが、納期の面で画像処理系がもっともはやく対応可能。私が大風呂敷広げたこともあり、画像処理ができるDevボードを利用しようという流れに。
M5系、Maix系、raspi系どれにしようかな、と私物のDEVボード在庫を眺めながら一人会議を開催。フルサイズのOV2640の見栄えが良くIOも使いやすいMaix Bitで画像処理することにしました。（見栄え大事）

##２－１．装置の概要

お釜の供給には滑り台を組んで、整列して滑らせカメラ前に送ります。
![2020_12_14 19_09 Office Lens (5).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/d57b2495-d7c5-150d-5030-3a565f0bf826.jpeg)

滑り台下端部では、
![2020_12_14 19_09 Office Lens (6).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/32f469fa-8348-0bb7-9218-fae7d90743f6.jpeg)
①の穴からLED照明を照射。
②の穴からカメラ撮影して良否判定。
③の穴からエアシリンダで突っつき棒を押し出してオカマを排出。
という流れで処理します。

##２－２．検出方法

最初に考えたのはどのようにして未アッシー品を検出させるか。
せっかくAI画像認識できる能力があるのだからOK品とNG品の画像を学習させて分類したかった。したかったのだけど、最終的にはお釜の向こうからLEDライトで照らし、透過光の明るさが閾値より明るければ未アッシー品（NG品）、暗ければアッシー品（OK品）として判断しました。
フィルターをかけて識別精度の変化等みましたが、生のRGB565イメージを用いてLABカラースペースのL値の閾値のみで識別できそうでした。

判定はimage.find_blobsを用いています。カラーの閾値と、領域の最小サイズの両者で判定します。
NG判定の際には別途用意したサインポールに表示するほか、LCD画面全周の赤枠で注意喚起します。

```python

    blobs = img.find_blobs([NG_threshold], x_stride = 2, y_stride = 2, pixels_threshold = 100, merge = True, margin = 20)
    if blobs:

#blob枠表示処理
        max_area = 0
        target = blobs[0]
        for b in blobs:
            if b.area() > max_area:
                max_area = b.area()
                target = b

        img.draw_rectangle(target[0:4])                 #blob枠表示
        img.draw_cross(target[5], target[6])          #blobセンター表示

    #赤枠表示
        img.draw_rectangle(0,0,320,240,[255,0,0],50)  #NG赤枠表示
        lcd.display(img) 
```

##２－３．撮影方法

上記の判定はMaix Bitのカメラ(OV2640)で撮影します。
いくつかの光源を試しましたが最終的に、私物のジェントス閃のLEDが安定かつ高収束かつ取付用意なサイズ/形状であったため、電源直結に改造して採用しました。
![201214-DSC_2280.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/fc644573-0124-eab5-19f0-41772b63f200.jpeg)
撮影条件調整に便利そうだったので、調光機能付きのLEDランプも試してみましたが、PWM制御だったらしく撮影画像に干渉したので不採用としました。

後述の問題対策のため、LEDもMaix Bitから制御してフラッシュ撮影できる様にしました。
PIN10から信号出力してトランジスタでオンオフ制御しています。
![2020_12_14 14_51 Office Lens (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/a55777d4-66e1-151b-8f13-39699c411751.jpeg)
回路はこんな感じ。LED照明用の電源は当初別回路化していましたが、消費電力小さそうだったので今はMaix Bitの5Vからとって、システムへの電源供給をMaix BitへのUSB一本にまとめました。ボードの5V出力端子はK210を通ってなさそうなのでおそらく大丈夫でしょう。
御覧の通りのシンプル回路です。突入電流が発生するのなら5V側にコンデンサー→GNDのラインを加えた方がLEDには優しいのかな？　電気回路はズブズブの素人なのでアドバイスは随時受付中ですmm
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Maix Bitによるフラッシュ撮影テスト <a href="https://t.co/Vhp6vMt1Wy">pic.twitter.com/Vhp6vMt1Wy</a></p>&mdash; AIRPOCKET＠rastaman vibration (@AirpocketRobot) <a href="https://twitter.com/AirpocketRobot/status/1338671606768435201?ref_src=twsrc%5Etfw">December 15, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

##２－４．排出方法

OK品は滑り台の一番下から小さなエアシリンダーで突き出して排出します。エアシリンダーは12V駆動の電磁バルブで駆動させますので、いつか使うだろうと~~死蔵~~在庫していた安価な[中国製リレー](https://ja.aliexpress.com/item/32971704441.html?spm=a2g0s.9042311.0.0.27424c4dsJiQyW)にも登場願いました。
![H98aeb39a84b447a8a28b09a1a7f4ddf37.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/c6ba3b4b-9a30-361d-89c5-7e24a88d48f0.jpeg)
また、NG品検出を作業者に知らせるためにサインポールを光らせますので、これもリレーを介して制御します。今回利用したリレーは制御信号5Vタイプですが、Maix Bitの3.3V信号でも問題なく動作しました（動作不良起こしても自己責任です）

ちなみにこのリレーは基板にビス穴付いてないし、DINレールにもはまらないので固定できません。よって、宙ぶらりん配置となっています。電源と動作表示のLEDがついているのはとても便利なだけに残念です。

MaixBitのfpioって初見ではとっつきにくかったのですが、こんなかんじにPIN定義したら動きました。

```python

from Maix import GPIO
from board import board_info
from fpioa_manager import fm

fm.register(board_info.PIN9,fm.fpioa.GPIOHS9)
fm.register(board_info.PIN15,fm.fpioa.GPIOHS15)

PUSH = GPIO(board_info.PIN9,GPIO.OUT)
SIGN = GPIO(board_info.PIN15,GPIO.OUT)
```

PUSHはイジェクト用のシリンダ操作、SIGNはサインポールの操作です。

##２－５．制御ボタン

入力装置はボタン一つのシンプル構造です。
初回スタート、不良排出後再スタート、一時停止、再開、すべて１ボタンで操作してます。
Maixpyのdigitalreadはこんな感じ。

```python
fm.register(board_info.PIN10,fm.fpioa.GPIOHS17)
BUTTON = GPIO(board_info.PIN17,GPIO.IN,GPIO.PULL_UP)
```
あとは、

```python
BUTTON.value()
```
を覗いてやれば、随時入力状況を確認できます。

##２－６．IOまとめ

Maix Bitは小さいながらもフリーのIOが4本(PIN9,10,15,17)有ります。
今回はこれらのPINを使用して、リレー制御×2、LED制御×1、ボタン入力×1としています。
さらにfpioを駆使すれば使っていない機能（mic arrayなど）のPINも横取りして使える（はず）など、AIボードとしてだけでなく制御もこなす便利なDEVボードでした。筐体に入れて必要なラインを引き出しています。
![201214-DSC_2278.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496179/3bd33d53-2382-b643-3554-ba3b0c830946.jpeg)

##２－７．完成品チラ見せ
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Maix Bitで製品検査 <a href="https://t.co/nIHDFF5osq">pic.twitter.com/nIHDFF5osq</a></p>&mdash; AIRPOCKET＠rastaman vibration (@AirpocketRobot) <a href="https://twitter.com/AirpocketRobot/status/1338685155624415234?ref_src=twsrc%5Etfw">December 15, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
ポンチ絵だけでは伝わらないと思うので、動画チラ見せです。製品形状を伏せるため、排出部分は黒塗りしています。
滑り台部は天井を付けてトンネル状にしているため分かりにくいですが、黄色いボタンを押すと製品表面の透過光を撮影してLCDに表示しています。LCDが切り替わるたびに最下段からOK品を排出し、一個づつ製品が送られています。
OK品の暗い画像が続きオカマを連続的に排出したあと、NG品の明るい画像を検出してストップしているのがわかります。

開発初期の仕様なのでフラッシュ化されておらず、ライトの種類が違います。
画像処理は15~20fps程度の速度が出ますが、オカマ排出と滑り台の安定待ち時間がボトルネックとなり3個/sec程度が実用最高速度となりました。

#３．制作上の課題など

当たり前のことも含めて制作上のポイントや課題解決方法、未解決課題など。

##３－１．撮影環境を整える必要がある
###・カメラはオートホワイトバランス、オートゲインを切る。
今回は画像の明るさパラメータを評価しているためオフにします。AIで画像認識するならONの方が良いと思います。
###・撮影環境は外乱光が入らない様に囲う
安定した判定を行うためには、安定した画像が重要です。外乱光は撮像に影響を与えますので天敵です。基本トンネル内や暗箱で囲って撮影します。どうしても囲えない場合は、外乱光の誤差が十分小さくなるくらい照明を強くするのもあり。
今回は透過光を使うので、光源の光が回り込まないことも重要。
AI画像認識であれば、外乱光にも強くなると思われます。

##３－２．本当にゲイン、ホワイトバランスは安定しているか問題
###・システム立上げ時の光量により、カメラのゲインが変わる。
原因不明。
LED照明を先に点灯してからカメラを起動すると、ゲインが下がり、逆の場合はゲインが上がります。
ファームのOV2640の項目をあさったのですが、よくわかりませんでした。
おそらくセンサー初期化の際に、ゲインを自動設定しているのではないかと思うのですが。
ゲインを数値設定できるコマンドが欲しいところです。（あるけど知らないだけ？）
対策として光源用LEDライトをMaix Bitから制御して、立上げ時は確実に照明オフとしました。

###・オートホワイトバランスを切っても、ホワイトバランスが変わる。
原因不明。
オートWBオフ状態でも、色の違う背景を撮影すると、WB調整が入ったように画像の色目が変わります。なぜ？
判定精度に致命的な影響がないため放置しています。気持ち悪いけど。

###・長時間LEDを直射すると取得画像が暗くなる。
ソフト的な問題じゃなくて、ハード的にセンサー感度が徐々に落ちている気がします。
一度LEDを切って再稼働するとある程度復帰している気がします。
ソフト原因か、ハード原因か確定できませんでした。強い光をセンサー素子に当て続ける弊害かな？と想像。
対策としては、LEDをフラッシュライト化し、センサー素子への負荷を軽減しました。

##３－３．LEDの光量は安定しているか問題
###・LEDは連続使用で光量が変化する？
カメラのゲインが徐々に落ちる様に感じる件、LED照明の光量が落ちている可能性もありますが、特定できていません。耐久性がありそうななLEDライトに変更し、フラッシュライト化しました。（LEDにとってはフラッシュの方が負荷になる可能性もありますが）
###・購入初期の（安い）LED照明は光量が大きく落ちる？
最初に使ったLED照明は光量が落ちてしまいました。
「慣らし」で安定するのかもしれませんが、未確認。
LED照明を変更して対策。

##３－４．滑り台は安定しない問題
オカマの送りには滑り台を使いました。滑り落ちる衝撃で転がり落ちたり、落ち着いた場所がずれていたり、引っかかったり、早かったり遅かったり、安定させるのにそれなりに苦労しました。重力と摩擦力と静電気力は侮れません。
コンベア使用案もあり制御は容易になりそうですが、製品送りスピードは滑り台の方が勝っており、どちらが良いかはケースバイケースですね。確実なワークの取り回し用に[myCobot](https://twitter.com/cobotmy)が欲しくなりました。

##３－５．リレーの耐久性は足りるのか問題
オムロンのリレーが30万回耐久と聞きました。約100円/個の格安品はどの程度耐えられるのでしょうか？興味の絶えない問題です。

##３－６．QIコネクタ（dupontピン）は使うな!!!
リレーの入力側のPINがQIコネクタでしたが、接点不良がぽろぽろ発生。
また、ユニバーサル基盤に乗せるときは、[JSTのPHコネクタ](https://ja.aliexpress.com/item/32836912971.html?spm=a2g0o.cart.0.0.33f23c00MHaVI9&mp=1)？を使用するのですが、ケーブル同士の接続にちょうど良いコネクタを持っていないことに気づきました。良いコネクタキットがあったら教えてください。できれば2pin~5pinくらいの雄雌セットで安いのがあれば便利なんですが。。。

#４．顛末とまとめ

開発期間1週間、実働約24時間ででっち上げたシステムですが、結論から申し上げますと仕様は満足したもののあえなく不採用と相成りました。
最終的に、3個/secの処理能力は人力の3倍以上、部品代は約5000円（キーエンスの1/100）という高パフォーマンスを実現したのですが。。。開示できないとある事情によりお蔵入り。
各部品の耐久性や判別精度、安定性など、実地で試してみたかった信頼性にかかわる諸々のデータは採取できず残念な結果となってしまいました。同様のニーズは今後も出てくると思われるため、どこかで活用したいと思います。
ウン百万個の検査がどうなったのかは神の世界のまた別のお話です。

ライバル視していたキーエン○等の高級システムは、耐久性、動作の安定性はもとより、幅広い画像処理や形状認識機能が操作性の高いUIで簡単に実現できます。また、多彩な付属部品で拡張性が高いなど素晴らしい装置であることに疑念の余地はありません。
一方、使い切れない多彩な機能（と宣伝広告費と人件費）が高コストを招いているのも確かです。今回のような限定的な用途であれば、Maix Bitなどの安価な機材を組み合わせても同等の結果を得られる。かもしれません。