見出し画像

自作チップマウンタの記録

(2022/1/28追記)この内容をまとめて薄い本を書きました!→https://www.amazon.co.jp/dp/B09MDXVLVL/

ふと思い立って、勢いではじめてしまったチップマウンター製作。先人もたくさんおられるけど、なるべく既製品・標準部品を使って作る、という方針で。
https://github.com/openpnp/openpnp-openbuilds/wiki/Build-Instructions
https://cronos.kibe.la/shared/entries/02da22b6-3af8-4fed-b5a0-82a5204c0a3f
http://koibo.blog.fc2.com/blog-category-7.html
http://mechanic.pilotz.jp/2017/07/diy-pnp-progress-report/

21/06/27

TwitterTLで、チップマウンタ用のピックアップヘッドを動かしている人をみかけて(出典が見つからない・・・ピックアップヘッドを動かして「チップマウンターの鼓動を感じている」みたいなツイート)、深夜(早朝)のテンションでピックアップヘッドを衝動買い
→(21/08/28追記)こちらだ。「チップマウンタ作ろうとしてる学生がいるけど相談にのって」と高須さんから紹介された学生さんだった。世の中狭すぎる。

21/07/01

XYZ移動できればチップマウンタが作れるような気がして、改造用の3Dプリンタを衝動買い。Tronxy 3D、2.5万円ほど。https://twitter.com/akita11/status/1410560442317955075

ピックアップヘッドはいろいろあるようなので、とりあえず何個かポチる。

21/07/02

ピックアップヘッドの空気系統の制御を調べる。ピックアップヘッドと並んで売っていたバルブの商品写真をみながら(いっしょに買えばよかった)。

画像4

右上のパーツは、真空イジェクタで、左から空気を送ると、下から空気を吸い込む。つまり左上のチューブから空気を送ると、パーツが吸着される。左中のチューブから空気を送ると、パーツが離れる。

21/07/03

せっかくならフィーダーもつくりたい。ステッピングモータでチップ部品のテープを送る機構を考える。3Dプリンタのエクストルーダを送るギアが使えそうと考え、バネで押すローラーではさんでテープを送る。

画像2とりあえずそのパーツを設計
https://twitter.com/akita11/status/1411201397438095361

画像3

ついでにステッピングモータについて調べてまとめRepRap用のフィラメント送りのギアと、ステッピングモータ用のコネクタ付きけーケーブルを購入。

この3Dプリンタの制御ボードはRepRapでよく使われるMarlin互換(クローン?)とのこと。https://twitter.com/akita11/status/1411251221021696000

RepRapのWiKiに制御コードの情報がのっている。

PCとUSBでつないでCOMポートをTeraTermで開き(通信速度は115200bps)、とりあえずGコードを送って、制御できた。常時、ヘッドとベッドの温度が送られてくる。
https://twitter.com/akita11/status/1411184308136550403

機構のほうは、迷わずに分解してXYZ機構だけにする。

https://twitter.com/akita11/status/1411243874312359939

21/07/06

Z軸のリミッタについて調べる。最初ついていたのは近接スイッチ。

https://www.banggood.com/TRONXY-6-38V-Auto-Leveling-Heated-Bed-Sensor-For-Tronxy-P802M-P802E-3D-Printer-p-1160586.html?cur_warehouse=CN

RepRapの規格として、リミッタスイッチはぜんぶXH3pコネクタで、マイクロスイッチでも、近接スイッチでもピン互換。標準規格、ばんざい。ちなみにTronxy3Dには予備(?)のリミットスイッチ(マイクロスイッチ)がついている。

手持ちのNEMA17モータだとフィーダーで大きすぎそうなので、比較検討用にNEMA17で薄いのと、NEMA8で小さいのをポチる。

21/07/07

ピックアップヘッドが届く。すごくよくできてる。ステッピングモータでピックアップ部が回転(部品を回転できる)、押し付けてもバネが押し込まれる。なおステッピングモータは1辺20mmのNEMA8という規格。

21/07/08

フィーダーのテープの固定を引きバネ(ホームセンターで売ってるもの)を使うように変更。

画像2

あわせて、ピックアップヘッドの製品ページに載っているマウント(固定具)の図面をみながら、レーザーカッターでカット。
https://twitter.com/akita11/status/1412921012321062913

21/07/09

制御ボードについて調べる。よく使われるGRBL型のステッピングモータ制御ボードは、M5Stack用モジュールがあるのでこれを使う。M5StackからI2C接続、アドレス切り替えで2台までつなげるので、ステッピングモータを合計6台まで制御できる。XYZとピックアップヘッドの回転で4軸なので、あと2軸使えるのでフィーダーに使おう。はじめてM5Stackを「スタック」して使う。https://twitter.com/akita11/status/1413396166364975106

Z軸ヘッド部分にピックアップヘッドを装着
https://twitter.com/akita11/status/1413396496704106498

フィーダーの構造として、テープのフィルムを巻き取る方法のほうがいいような気がして構造を考える。しかし巻取り部にフィルムを固定するいい方法が思いつかないので、たぶんボツ。

画像5

21/07/11

テープのフィルム巻取り機構の案。エクストルーダ送りのギアを2つ噛ませて、そこで巻き取る。こんな構造。

画像6

あわせて、この機構でフィルムを巻き取りながらテープを送る動作のテストのため、フィルムにはがしたテープに、再度フィルムを貼る。スティックのりを塗って貼り、押し付けたらけっこうOK。https://twitter.com/akita11/status/1414108050944716802

答え合わせというわけではないけど、業務用のフィーダーの構造を調べる。そんなに大きく違わないような気がする。送ったあとのテープ部を下に送る部分の構造が不安なので、試作してためす。
https://twitter.com/akita11/status/1414192054255505410

画像7

X軸のリミットスイッチを押せるように治具を追加。

21/07/12

ピックアップする部品を、テープから剥がした状態で使う方法を考える。チップ抵抗・コンデンサなら、トレイに並べればピックアップはできそう。こんな構造で、チップ抵抗が並んだ状態にできそうなので、これも並行して試す。ただしこの状態だと、並んだあとトレイを取り出しにくいので、構造を改良する。
https://twitter.com/akita11/status/1414368206421041152
https://twitter.com/akita11/status/1414383981747834880

画像8

Z軸のリミットスイッチは、フレームにマイクロスイッチを固定することにし、その位置調整の治具。ちょっと左過ぎたので13mm短くする。

21/07/13

フィーダーの、テープのフィルムを巻き取る機構。ちょっとギアの間隔が広すぎて、噛まないので、1mm縮める。

画像9

画像10

エア系統のパーツが届いた。左側からのエア2系統は外径6mmのチューブで、これは熱帯魚用エアポンプに付いてるのと同じ。上のバルブの右側出口は6mm、それ以外はぜんぶ外径4mmのチューブ。Amazonで4mmのチューブを買ってあるので、それを使う。動作テストは後日。

画像11

エアのバルブのソレノイドは定格24V。

画像12

フィーダーのテープ送り機構(テープを押し出す方)はとりあえず形になった。思ったより空送りが多いかもしれない。

画像13

21/07/14

フィルムを巻き取るフィーダー。ギアのかみ合わせOK、フィルムも巻き取れる。次は実際のフィルム付きテープからの巻取り。

画像14

Z軸リミットスイッチの位置調整・固定治具、OK

画像15

ピックアップのエア系統として買った熱帯魚用ポンプ(5W)は、さすがにエアが弱すぎて、かすかに吸引している気もするけど、1608サイズチップ抵抗も吸着できない。ポンプを増強するまえに、吸引用のポンプを買ってあってあるので、それが届いてから試す。

画像16

21/07/16

Z軸リミットスイッチの固定治具の改良。ネジの数を増やして斜めになりにくいように。とはいえレールの溝がネジ(M4)より広くて、あまり効果がない。

画像17

真空イジェクタに空気を送り込んでのピックアップでの吸着、かなり空気圧が必要そう。口で思いっきり息を吹き込んでも、ぜんぜん吸い付かない。代わりに、Hozanのバキュームピックのポンプ(もともと吸引)をつないでみたら、1608のチップ抵抗があっさり吸着した。これでいいんじゃないか。

画像19

画像18

フィーダーの代わりにチップ抵抗を並べておくトレイも、フィーダーと並行して。こんな構造で、チップ抵抗を入れて、とんとんすると、かなりきれいに並ぶ。壁を取り外してトレイを取り出せる。ちょっと支柱のネジの穴が大きすぎたので調整する。

画像20

画像21

21/07/17

エア系統。バルブのソレノイドは24V用で、grblをつけてあるM5Stackからどう制御しようか、と思ったが、自分でつくってたんだった。USB-PDで20V供給だと、ちょっと弱いかもだけど、開閉はOKそう。

画像22

ポンプの調査。熱帯魚エア供給用の5Wポンプはこんな構造。AC電源の周波数で振動し、空気を押し出す。吸込口は明示的にはないので、そっちから吸い込む、という使い方は無理そう。

画像23

HOZANのバキュームピックは、吸い込みと吸い出しの口がわかれてるポンプ。INの口にチューブがつながっていて、そこから空気を吸い込む。このタイプのポンプなら吸引できそう。

画像24

21/07/17

↑のHOZANバキュームピックに入っているポンプは,ダイヤフラムポンプ,という名称。とりあえずAmazonで売ってる小型のものを購入。

21/07/18

エア制御のバルブを手動で動かしてみたが,どうもエアが入っていかない。このPのところに口で息を吹き込んで,ソレノイドをON/OFFしても,ぜんぜん出てこないor止まらない(どちらか)。分解してみたが,仕組みがよくわからないので,このバルブのデータシートをみて,なんとなくわかった。Pから加圧空気を送り込み(その圧力も使ってバルブが動く=圧力が弱いとバルブは動かない),ソレノイドのON/OFFにあわせて,AまたはBに出ていく,という構図。S/Rについている金色のパーツは,排気口。動作圧力の範囲の下限が21PSI(1.4気圧くらい)なので,そりゃ口で息を吹き込むぐらいじゃびくともしないはずだ。そもそもチップ部品を吸着するのにそんなに圧力いらないんじゃという気がする。

画像25

21/07/19

ためしにコンプレッサーで圧力の高い(たぶん21PSI以上)空気をつないでソレノイドをON/OFFすると,たしかにBの出口からエアの出る/止まるを制御できる。しかしこんなに圧力はいらないよなあ。

画像26

もう少し調べてみると,最低圧力0PSI(つまり真空),というバルブもあるようだ。こういうのでいいんじゃ,という気がするので,とりあえずAmazonで購入

21/07/20

昨日Amazonでポチったバルブが届いたので、とりあえず通電。口から息を吹き込むくらいでも、エアの閉(非通電時)、開(通電時)ができる。これでイケそう。あとはチューブをつなぐ金具は、前のを流用しよう。

画像27

21/07/22

届いたバルブに,チューブの接続部(クイックコンタクト)をつなごうしたら,径があわない。買ったのは1/4インチ(ネジの部分が直径11mmくらい),前に買ったのは1/8インチ(ネジの部分が直径8mmくらい)。直径のインチ表記というわけではないんだけど,こういう規格らしい。あと買ったバルブのソレノイドが12V用だったので,改めて1/8インチ・24V用のをAmazonでポチってみた。

21/07/23

念のため、Tronxy3Dの電源の電圧を確認したら、24V(だけ)だった。

画像28

CNC.jpで、Tronxy3DのX/Y/Z軸を手動で制御できた(コントローラはmarlinを選択)。これで手動動作チェックが捗りそう。

ソレノイド(24V,1/4in)が届いたので、吸引テスト。吸引用とは離脱用で別のポンプ。
https://twitter.com/akita11/status/1418491540905742336?s=20
https://twitter.com/akita11/status/1418491641132847107?s=20

21/07/27

ベースの台をcut。一応X/Y軸のリミッタをもとに原点の位置を計測して、ステージのネジ穴の位置から原点を決定。
https://twitter.com/akita11/status/1419445450914947073

21/07/28

Z軸リミッタを、台にあわせて長さを合わせて治具を製作。Z軸原点の位置は調整できるように長穴で。

画像29

エア系統の電磁バルブとM5Stack(ステッピングモータ用制御用のGRBLモジュールつき)を固定できる板を製作。

画像30

21/07/31

M5grblにTronxyのステッピングモータをつないでCNC.jsから動かしてみるが、脱調している。いろいろ原因を調べた結果、モータのXH6pコネクタの結線が、一般的なNEMA17モータとは異なるのが原因だった。一般的なNEMA17モータは、こちらに書いたように、A-*-B-A'-*-B'、だが、このモータは、A-*-A'-B-*-B'(つまりA'とBが入れ替わっている)という配線だった(Tronxyにもともとつながっていたケーブルもこの結線)。

21/08/01

Tronxyのモータはこれ。コネクタのピン配置などの情報は載ってない。1ステップ1.8度、のようだ。

エア制御系統のチューブを6mmに揃えようと、ソレノイドバルブの1/8インチ-6mmコンタクトと6mmのT字継ぎ手を購入。継ぎ手が先に届いたので、T字の出力側に6mmの短いチューブの内側に、ピックアップヘッドへの4mmチューブをしっかりと差し込めばエア漏れはなさそう。ソレノイドバルブがOFFのときは、ピックアップヘッド側のチューブから息を吹き込んでも漏れはないはずだが、4mmのほうのバルブの出口の差し込みがあまく、エアが漏れていた。奥までしっかり差し込めばエア漏れはなくなり、2つのソレノイドバルブのON/OFFで、1608チップ抵抗の吸着と離脱ができた。

21/08/02

M5StackのGRBLの挙動がよくわからなくなってきたので、改めて整理。
grblのGコードからポイントを整理。
・G0 : 位置決め用送り(F無効)
・G1 : 加工用用送り(F有効)
・G21 ; ミリ系
・G90 ; 絶対座標系
・G91 ; 相対座標系 

 _GRBL0.Init(XY_STEP_PER_MM, XY_STEP_PER_MM, Z_STEP_PER_MM, ACC);

こんな感じで、GRBLボードの初期化時に、X/Y/Z方向の移動量1mmあたりのステップ数と、移動時の加速度を指定できる。ACCの値は、GRBLのファームウエアのソースコードでは以下のように定義されていて、単位は[mm/min^2]のように読めるが、実はファームウエアの内部で、この値(内部変数としてはsettings.acceleration)が(60*60)倍されて使われているので、10[mm/min^2]に設定すならば、ここでは"10"を指定しなければならない(これはバグだと思われるのでプルリク送っておこうか)

defaults.h
#define DEFAULT_ACCELERATION (10.0*60*60) // 10 mm/min^2
settings.cpp:
    case 8: settings.acceleration = value*60*60; break; // Convert to mm/min^2 for grbl internal use.

使っているステッピングモータは1.8[deg/step]、つまり200パルスで1回転。X/Y軸モータについているギヤの溝を数えたら1回転20個。つまりギヤの溝1つあたり10パルス。あとはX/Y軸の移動ベルトの溝の間隔から、「移動量1mmあたりのパルス数」が決まることになる。

21/08/02

どこまでできるかわからないけど、USB顕微鏡を固定できるようにしてみた。

画像31

背景を原色にすれば色抜きはできそうで、パターンマッチングとかで中心座標と角度は、OpenCVあたりでなんとかなるんじゃないかな(希望的観測)。

画像32

21/08/07

M5Stack GRBLの挙動の理解にだいぶ時間がかかってしまったので、まとめ。結局、ソースコードを読んでだいぶいろいろわかった。

・$で指定できる変数の一覧(settings.cppのsettings_store_global_setting()内):GRBLの標準(?)と異なるものがけっこうある。
$0 = 400.0 (steps/mm x)
$1 = 400.0 (steps/mm y)
$2 = 400.0 (steps/mm z)
$3 = 30 (microseconds step pulse)
$4 = 480.0 (mm/sec default feed rate)
$5 = 480.0 (mm/sec default seek rate)
$11 = 0.100 (mm/arc segment) <----- GRBL標準だと$6
$6 = 0 (step port invert mask. binary = 0) <----- GRBL標準だと$7
$8 = 25 (acceleration in mm/sec^2)
$9 = 0.05 (cornering junction deviation in mm)
$10 : settings.mm_per_arc_segment = value;
$11 : settings.n_arc_correction = round(value);
$12 : settings.decimal_places = round(value);
$13 : REPORT_INCHES
$14 : BITFLAG_AUTO_START
$15 : invert ST
$16 : enable hard limit
$17 : enable homing
$18 : settings.homing_dir_mask = trunc(value);
$19 : settings.homing_feed_rate = value;
$20 : settings.homing_seek_rate = value;
$21 : settings.homing_debounce_delay = round(value);
$22 : settings.homing_pulloff = value;

・settings.invert_maskで、各軸の正の向きを指定できる。defaults.hでは以下のようにすべて0だが、?_DIRECTION_BITのビットで反転を指定可能。

#define DEFAULT_STEPPING_INVERT_MASK (0)
// #define DEFAULT_STEPPING_INVERT_MASK ((1<<X_DIRECTION_BIT) | (1<<Y_DIRECTION_BIT) | (1<<Z_DIRECTION_BIT))

config.hで、各軸のビットが指定されている。

#define X_DIRECTION_BIT    5  // Uno Digital Pin 5
#define Y_DIRECTION_BIT    6  // Uno Digital Pin 6
#define Z_DIRECTION_BIT    7  // Uno Digital Pin 7

つまりX軸の正の向きを反転させるのは、これを2^5=32とすればよく、XY軸をともに反転させるには、両者のORをとって32+64=96とすればよい。(Tronxy3DはXYを反転させる必要がある)

・リミットスイッチ
LIMIT_PORT = PORTC
PORTC.0=X, PORTC.1=Y, PORTC.0=Z

・ホーミング動作
$17=1とすると、起動時に以下のメッセージが出る。

'$H'|'$X' to unlock"

これは、ユーザがまずは最初に、ホーミング($H)か意図的なロック解除($X)を行わせる(それに気づかせる)ためのもの、つまり原点を初期化せずに使い始めないように、ということののようだ。デフォルトでは、この設定はOFFになっている。ちなみに$で変数を設定すると、毎回EEPROMに保存される(settings.cppにそう書いてある)

・I2Cバッファ
$$で設定変数の内容を見ようとすると、どうも後半が文字化けする。GRBLのソースを読むと、I2Cのバッファが128バイトしかなく、しかも終端コード'\0'を入れていない、ようだ。(これはバグのような気がする:プルリクを送っておこう)終端コードを入れてバッファを256バイトぐらいまで増量すると、だいぶ文字化けが減るが、それでも$$で表示される変数一覧は380バイトくらいあるので、バッファが足りない。これは仕様と考えたほうがいいのかもしれない。

・$Hでのホーミング動作
limits_go_home()では、以下のように順にhomingを実行。config.hで、CYCLE0はXY軸、CYCLE1はZ軸、と定義されている。ホーミング動作に関連する変数は以下。
$18 : X/Y/Z各軸のホーミング動作の向きを逆にするかの指定(X/Y/Z_DIRECTION_BITの論理和)。XYZ軸すべて反転させるので0xe0=224
$19 : ホーミング時のフィード速度。800くらいか。
$20 : ホーミング時のシーク速度。これも800くらいか。
$22 : 1だと、ホーミング後にちょっと戻る

なお$4/$5で指定するフィード速度・シーク速度が、X/Y軸とZ軸で挙動が違うっぽい。例えばこれらを8000にすると、Z軸が速すぎて脱調orオーバーフローする(リセットがかかる)。これはバグなんだろうか(もうちょっとソースを読まないといけない:本来はここで指定したシーク速度と、各軸のstep/mmからパルスの速度が変わるはず)

なおこのままだと、ホーミング動作が、Z軸→XY軸、の順になるので、ステージの原点付近になにかあると、ヘッドがぶつかってしまう。そのため、先にZ方向の+方向に移動させてからXY軸を先にホーミングするか、原点付近にはものをおかないようにしないといけない。

21/08/18

認識用のカメラにUSB顕微鏡を使っていたけど、倍率が高すぎる(カメラをかなり高い位置に置かないといけない=振動でブレやすい&被写界深度が浅くてピントが合わせにくい&照明が届きにくい)ので、以前AliExpで買ったUSBカメラを使うように変更。ピントはレンズを回して調節するタイプで、これくらいの位置でも十分ピントは合うし、倍率もちょうどいいくらい。

画像33

画像34

照明は白色LEDを6個直列にし、秋月のLEDドライバで24V電源で駆動。これだとエアのバルブのソレノイドと同じ電圧なので電源を共通化できるし、ソレノイド駆動系の余ったチャネルでON/OFFもできる。

画像35

画像36

21/08/20

エアバルブのソレノイドとポンプ(吸気と排気の2個のダイアフラムポンプ:AliExpで発注中)を、ステージの下に収めるように床板を作ってみた。ついでに、M5Stackもそちらに固定。もしかしたらポンプの振動が本体に伝わっちゃうかもしれないので、そのときは防振ゴムをはさむことにする。

画像37

21/08/21

エアのチューブの系が、ばらばらになりそう。そもそも内径表示と外径表示があって、混乱する。
・ダイアフラムポンプ(熱帯魚用):内径8mm
・ソレノイドバルブ:外径6mm or 外径4mm(バルブ側あ1/8 NPT規格で、それにはまるアタッチメントが2種類用意してある)
・ピックアップヘッド:外径4mm
これに対して、バルブに内径8mmチューブをはめるアタッチメントをAliExpでみつけたので発注。あわせて、内径4mmと内径8mmを変換するジョイントもAliExpで見つけたので発注。(外径6mmのチューブの内径はほぼ4mm)
これらが届くまでのつなぎとして、「内径8mmチューブを外径6mmチューブにつなぐ治具」を3Dプリントしてみた。既製品にならってぎざぎざをつければ、エアの漏れは大丈夫そう。外径6mmチューブ側は直径6mmの穴で設計したら、ちょうどいぴったりはまってエアの漏れもなさそう。

画像38

21/08/22

Python+OpenCVで抽出したチップ抵抗の(カメラ座標系の)位置をステージ座標系に変換して、カメラ取り付け治具の位置ズレを補正して、求めた座標にむけてヘッドを移動。だいたい大丈夫そう。
https://twitter.com/akita11/status/1429278797119905798

チップ抵抗だと、表は黒、裏は白なので、うまくやれば表を向いてるやつだけ座標を求める、ということができそうだけど、端子の銀色と裏面の白色が思ったより区別しにくいっぽい。照明を変えてみるか。

XY軸とZ軸の移動1mmあたりのモータのステップ数が違うが、どうもGRBLのバグなのか、指定した移動速度が、XY軸とZ軸で異なる速度になるっぽい。XY軸をそこそこの移動速度にすると、Z軸が速すぎて脱調してしまう。そこで、ちょっと不本意ではあるけど、Z軸のステップ数をXY軸にあわせて(1/5倍にする)、移動速度をXY軸でそこそこ、にあわせることにした。(G1で移動速度を個別に指定する方法もあるけど、まあこの方法でいこう)

その後、バルブを手動でON/OFFして、ピックアップはできた。
https://twitter.com/akita11/status/1429278797119905798?s=20
ただ、2個のGRBLとソレノイド制御ボードの間で同期はとれてない。具体的には、M5Stackから各GRBLへ移動のG0などを送ったあと、その動作が終わったかどうかをチェックしていないので、すぐ次の動作へ行ってしまう。各GRBLやソレノイドON/OFFをまたがる連続動作だと、動作のタイミングがあわない。
解決策としては、制御側(M5Stack上でもいいし、シリアルでコマンドを送るPC側でもいい)で、GRBLの'@'コマンドで動作状態(BUSY/IDLE)をチェックしてBUSYの間は待つ、というのが現実的か。PCでやるほうがスマートだな。

21/08/24

押し出しのエアが強すぎるので、流量を調節するバルブ。売ってるものもあるんだけど、大した構造でもなし、正確に密閉しなければいけないわけでもないので、チューブ径変換をかねたものを成形。M6ネジで流路をしめるだけ。エアの漏れも大丈夫そう。

画像39

21/08/27

XY方向にうごかすと、どうも位置がずれる。具体的には、左下隅(ホームポジション)を(0,0)として、(100,100)に動かすと、(98,102)あたりに来る。ということは、ステージ板が回転している、ということ。まあY軸自動部に4ヶ所のネジで、高さ調整のバネを通して固定しているから、多少回転してしまうのはしょうがないか。これを根本的に補正するのは難しそうなので、標準添付のステージ板(裏にヒーターがあるが使わない)に、座標軸や基板・部品トレイ位置を決める補助板をつけた台紙を、クリップ等で、位置をあわせて固定することにする。(0, 0), (200, 0), (0, 200), (200, 200)の4点に移動させて、それぞれの位置が台紙の対応点に来るように調整して固定。これで(200, 200)でも誤差0.5mmくらいで位置決めができそう。高さ(Z軸の原点)も、この4点で、ステージ板のネジで調整できる。ただ、これは厚紙なんだけど、反ったりしがちなので、アクリル板のほうがよさそう。

画像40

21/08/28

Amazonで発注してあったポンプ(熱帯魚水槽用)が届いた。ネジ穴つき防振台がついていたので、これにあわせて固定板をカットし直し。念のためバンドでも固定。これで固定は大丈夫そう。

画像41

このポンプのモータは定格DC12Vなので、モータ/ソレノイド系の24Vとあわない。モータを2個(吸引・排気)使うので、直列につなげばモータ1個あたり12Vになるから、ちょうどいいんじゃ?とつないでみるが、どうもおかしい。具体的には、片方しか回転せず、そこの排気口を指で抑えてモータに負荷をかけると、そのモータが止まってもう片方のモータが回転する。つまり片方しか回転しない。ちょっと理解に苦しむ現象だけど、モータの始動電流・電圧の関係のように思える。
とりあえず、PWMでも駆動できるので、デューティー比を50%にして、2個のモータを並列につないだら、ちょうどよさそう。モータのPWM駆動と駆動電圧の定量的な解析はこのあたりを参考に。またM5Stack(ESP32)のPWM出力はこのあたりを参考に。

画像42

画像43

画像44

内径8mmのホースを買ってきて、ポンプにぴったりはまる。ソレノイドバルブへの外形6mmチューブへの変換は、押出エアは3Dプリントした調圧器をはさむ(かなり絞らないとエアが強すぎる)。吸引エアは、以前3Dプリントしたアタッチメントで。エアの漏れがないようにちゃんとチューブを差し込まないと、エアが漏れてうまく吸引できないので、注意しながらチューブをセットしてOK。

チップLEDのマークの認識もいずれはやりたいので、高解像のUSBカメラを手配しておく。こいつをポチる。8Mpixelと書いてあるけど、書いてある最大解像度が2048x1536@15fpsということは、3Mpixelじゃないのかなあ。まあそれでもいまのVGA(640x480)よりは十分解像度が高い。

カメラの座標の補正は、カメラをちゃんと調整して固定すれば、しなくてもいいかな、と思ってたけど、実際に撮ってみると、カメラがちょっと傾いているのをなかなか直せない。まあそりゃあそうだよね、というわけで、キャリブレーション画像を撮って、そこからカメラ座標→物理座標への変換をするべき。というわけで、アフィン変換とOpenCVでのやりかたについて復習う。カメラ座標は、トレイを撮って、その四隅の点を、手動でいいので求めればいい。物理座標は、上記のように台紙の座標がCNC機構の座標系似一致するように調整して置いてあるので、そのトレイの四隅の点の座標は計算上求まる。したがって、この両者の関係をアフィン変換の係数として求めておいて、求まったカメラ座標での位置から物理座標への位置にアフィン変換すればよい。いや、アフィン変換は平行四辺形→平行四辺形の変換だから、この場合は、任意四角形→任意四角形の変換なので、射影変換、か。

21/08/29

射影変換は、OpenCVのライブラリで、四隅の点の座標(変換元、変換先)を与えれば変換行列を求める関数があるので、それを使う(ためしにその行列で変換元座標を変換した結果は、変換先座標とちょっとずれるけど、まあこれぐらいは数値計算の誤差か)。カメラ上の四隅の点は、一応ハフ変換で求める方法が使えるが、四辺の直線の検出がどうも安定しない(複数検出されることのほうがお多い)ので、ハフ変換の結果と、カメラ画像保存→目視座標を求める、のを、併用するのが現実的か。

なお、この射影変換のための四隅の点の座標と、色抽出用のHSV範囲は、基本的にはキャリブレーション後は変わらない数値になるので、ファイルに保存しておいて、それを読み出して使うようにした。これで、色調整などをしたら、その結果をそこに保存しておけば、各実行ソースに個別にかかなくていい。

カメラで位置・角度を計測→それに基づいて指定位置に置く、とう一連の動作がOKそう。ピックアップ時にすこし部品が動いて(回転して)しまっているが、これはピックアップ位置の高さの調整でなんとかなるか?(あるいは回転のモータをピックアップ時には励磁して固定すれば大丈夫なんか?
https://twitter.com/akita11/status/1431867054949224455?s=20

なおトレイは、現状でも6種類はおけるので、6種類の部品までは、この延長でできる(位置計測時のカメラの位置を変えるだけ)。増やそうと思えば、もっと種類は増やせる(ただしその分、基板を置くワークエリアが小さくなる)。あとはCADのposファイルから、部品の位置をもらって、そこに置くだけ、か。

21/08/30

あまり効率のいい方法ではないけど、求まった矩形に対して、距離が近い黒抜き領域があるか、を全探索で調べて、表を向いている抵抗だけを検出できた。これで表向きの抵抗だけピックアップできる。
https://twitter.com/akita11/status/1432168943880261638

21/08/31

ベースが紙だと、湿気を吸うからか、たわんだりすることがあるようなので、やはり剛体がいい。というわけでMDF板(2.5mm厚)でつくってみた。底板の固定は円形マグネットを、やや小さな穴のバネっぽい構造で挟んで固定するスタイル。トレイの下にもマグネットを配置したら、抵抗がマグネットに引かれて立ってしまう・・・ので、そこはマグネットを回避。

画像45

21/08/31

どうもピックアップ座標がずれる原因が、OpenCVの射影変換の誤差っぽい。カメラ座標-物理座標の組から射影変換行列を求め、それを使って、その点のカメラ座標→物理座標を求めると、Y方向で2mmくらいずれる。実物でもそれぐらいずれてる。原点から離れると誤差が大きくなるんだろうか。トレイの左隅を仮の原点として求めるようにしてみるか
https://twitter.com/akita11/status/1432630324140265472?s=20

→この方法を使うと、かなり精度がよくなって、誤差が0.1mmくらいにできそう。
https://twitter.com/akita11/status/1432654982688305162?s=20

PythonのPySerialでシリアルポートを開くと、そのたびにM5Stackがリセットされるので、$Hからはじめないといけない。
そこで、UDP受信→シリアル送信、のサーバをlocalhostに動かして、動作させたい側はUDPでコマンド(Gコード)を送る、という構成にした。

21/09/02

各種設定を、JSON形式で保存するようにした。また、設定の読み書きやUDPコマンド送信、カメラ取り込みなどは、いろいろなプログラムで使うので、picker.pyというモジュールにまとめて、importして使うようにした。

部品を置くときの押し出しエアが、どうも強すぎて、部品が吹っ飛んでしまう。3Dプリンタでつくったバルブだと、完全にはエアを止められず、けっこう止めるぎりぎりぐらいの微調整が大事そう。そこで、ちょっと高価だが、ちゃんとしたバルブ(コントロールバルブ、ニードルバルブ)をポチってみた。
https://www.amazon.co.jp/gp/product/B08LKTK1XN/

あと、使っているカメラが、実はFHD(1280x1024)だった。OpenCVのデフォルト設定でcaptureするとVGA(640x480)だったから、てっきりVGA解像度のカメラかと思っていた。OpenCVで解像度をしていてキャプチャもできる。
https://qiita.com/sowd0726/items/8a6e9ae53378141e64a0

21/09/03

いろいろライブラリ化して抽象化して、ここまでシンプルに書けるようになった。カメラの色抜きやトレイの座標(カメラ→実座標への補正に使う)などのパラメータは設定ファイルにJSON形式で保存しておく。それをもとに、トレイ番号を指定して、そこにある部品の座標と向きと表面/裏面のリストをつくる。そして、これはデモ用に、トレイにある部品を順番にpickして、並べてplaceしていく、というスクリプト。
https://twitter.com/akita11/status/1433798319520698379?s=20

21/09/04

よく考えたら、補正前のカメラ画像から部品の向きを求めていて、それを補正せずに使っている(位置だけ補正している)。これだと誤差が生じるので、カメラ画像→矩形、の射影変換をまずやって、それに対して位置と向きの検出を行い、それを実座標への射影変換、という2段階の射影変換を行うことにした。

もしかして、と思って、照明とカメラに偏光板をつけてみた。思ったより金属端子の反射が抑えられそう。
https://twitter.com/akita11/status/1434017735604781056?s=20

排気側のニードルバルブが届いたので、フレームの下側に固定(ちょうど4mmの穴があいていた)。完全に閉めるのから、ほんのちょっとだけ開ける、くらいがちょうどよさそう。だけどこれは実物で試行錯誤を繰り返しそうだから、やっぱり、こういう微調整できるやつを買っておいてよかった。またこうやってフレームに固定しておいてよかった。

画像46

カメラ周りのキャリブレーションはGUIでパラメータをいじれるようにしたいけど、OpenCVのGUIはどうもオマケみたいな感じで、あまり自由がきかなさそうなので、このまえ使ってだいたい勝手がわかってきたQtを使ってみようと思う。
https://www.qt.io/ja-jp/qt-for-python
こちらの「インストールはこんなに簡単!」が、それなりにアレでちょっとひるんだけど、python -m pip install pyside6 でインストールすればOKそう。
Python+OpenCV+Qtというビンゴな例もあるので、こちらも参考に。
https://takacity.blog.fc2.com/blog-entry-338.html
→PyQt5のほうがよさそう。先人(その1その2その3)を参考にしつつ、バージョン違いがけっこうある(Qtあるある)ので、いろいろ調整して、なんとかなりそう。
https://twitter.com/akita11/status/1434134100663623681?s=20

21/09/05

Python+OpenCV+QtでつくるキャリブレーションのGUIアプリ、大枠はこんなもんかなあ。

画像47

21/09/10

M2スタンドオフ(結局Amazonで購入)が届いたので、カメラを交換(それにあわせて固定具をつくりなおし)。4Kに近い8M画素(3264x2448)のカメラ。ついでにリング照明も基板を起こして12灯に。これでチップLEDの向きの検出を目指す。
https://twitter.com/akita11/status/1436306291387822084?s=20

21/09/13

いくつか並行して進めてる。

まずベースの板をMDFでつくってたけど、湿度のせいか、微妙に反ってしまうようなので、アクリル板でつくりなおし。あわせて、位置合わせを、まずベース板を置く前にヘッドを指定位置(4箇所)に移動させ、そこにこの紙を貼り、その紙の位置を、ベース板(透明アクリルなので、この紙が見える)の指定位置をあわせる、という手順でやってみようと思う。

画像48

また、カメラを後付だと、どうも直角がでないようなので、ピックアップヘッド固定具と一体化してみた。

画像49

調子に乗って、はんだペーストのディスペンサも作ってみようかと思う。エア送り出しもいいんだけど(@ichirowo さんがやってる)、せっかくなのでVoletaOneの構造をならって、ネジで送り出す、というので、どこまでいけるかやってみようと思う。
https://twitter.com/akita11/status/1436115698485391378?s=20

キャリブレーション用のソフトは、Python+Qtでかいていて、だいたいできた。

画像50

21/09/15

クリーム半田ディスペンサ、だいたいめどがたった。結局、送りのネジは6mmで、M6x45mmの高ナット(Amazonで売ってる)を使うことにした。中の高ナットがまわらないようにするガイド(5mm厚アクリルを六角形の穴がある円筒形にカットして、それを積んでアクリルサンデーで融着)の六角形の穴は、かなり試行錯誤した。大きすぎるとぶかぶか、小さすぎるとキツくて動かない。
https://twitter.com/akita11/status/1438105821850714114?s=20

マウンターの方は、結局、ヘッドの位置が基準なので、ヘッドの位置がベース板上でどこかがわかればよい、ということで、ヘッドに「筆記具」をもたせて、それでベース板にマークを描くのが一番正確そう。で、その「筆記具」をいくつかトライアル中。
・アクリル板で十字マークのハンコをカットし、それを押す→さすがにアクリル板だとうまくインクが写らない。
・ピックアップヘッドの先端部をボールペン軸に交換→ボールペン軸が長すぎて入らない https://twitter.com/akita11/status/1437927312670875648?s=20
・シャーペンの芯(0.5mm)が、ちょうどピックアップヘッドの先端に入るおのがありそうなので、これにシャーペンの芯を差し込む→いまのところこれが一番よさそう。ただ、つまると除去が難しそう。0.5mmピアノ線で押し出せるか?
・シャーペンの芯は悪くなさそうなので、↑↑のアクリル板ハンコのところにシャーペン芯をセットできないかやってみる

21/09/16

ピックアップヘッドの先端に筆記具を付ける方法、試行錯誤の結果、この構造が一番シンプルでよさそう。
https://twitter.com/akita11/status/1438426229967777797?s=20

それとあわせて、ベース板の細かいところをちゃんとつくりなおし。両側のステンレス定規(マグネットを貼り付ける用)の隙間を、ちゃんと長さを測って厚紙を貼り、その上に、基準点をマークするための薄い色画用紙を貼る。ここにCNC座標系の基準点に、↑のシャーペンで印をつけ、そこにアクリル板のベース板を、基準点をあわせてマグネットで固定する。

画像51

画像52

21/09/18

十字マークを描くのは大丈夫そう。ただ、シャー芯が奥に押し込まれちゃうので、押し込まれないように、穴が貫通してない治具をつくりなおしてみることにする。
https://twitter.com/akita11/status/1439000519964454912?s=20

先端部分は、注意してアクリル融着すれば、中心は十分出せそう。
https://twitter.com/akita11/status/1439044429269008385?s=20

十字マークを基準にした位置合わせは、だいぶ精度よくいけそう。
https://twitter.com/akita11/status/1439024870226993152?s=20

KiCADから吐いたPOSファイルを読み込んで、部品配置のシミュレーションも大丈夫そう。
https://twitter.com/akita11/status/1439019813884416005?s=20

8M画素カメラのレンズが、思ったより画角が広く、また被写界深度が浅いので、別のレンズをaitendoとAliExpでポチってみる。M12P0.5というメジャーな規格のボードレンズなので、選択肢は多い。

クリーム半田ディスペンサの方も、だいたいめどはたった。ホルダの採寸に使っていたシリンジと、クリーム半田のシリンジが、微妙にサイズが違う(2mm太い、など)ので、ホルダを微調整。
https://twitter.com/akita11/status/1439098337211273217?s=20

21/09/20

微妙にベース板が左右にブレるのが気になって、はずしてみたら、固定のネジ(ナット)が少し緩んでいた。こりゃブレるはずだ。というわけでしっかりしめなおし。バネで上下の緩衝をしているのが原因かと思ったけど、そこじゃなかった。なおY軸の移動機構自体も、手で押すとちょっと左右にブレるんだけど、ベルトで引っ張る分には大丈夫そう。

あと、前から微妙に気になってたZ軸の挙動を詳しく分析。どうも上下を繰り返すと、徐々に位置が下にズレてくる。ベース板の四隅にヘッドを移動させて、ベース板の高さを調整(ネジ)していて、どんどん高さが低くなっていくことに気づいた。Z軸だけ、上下を繰り返すと(例えばZ10→Z50→Z10...と繰り返す)、徐々に下にズレていく。ホーミングして原点調整すると、もとに戻るので、原点がずれているわけではない。XY軸ではおこらない。
一番ありえそうな現象として、Z軸の脱調を疑って、移動速度を十分に遅くしてみたが、現象は変わらない。ケーブルの断線もありうるけど、それもなさそう。ちょっと原因がわからず、詰みぎみ。困ったな。
https://twitter.com/akita11/status/1439827558665633795?s=20

→Z軸のモータのカプラの緩みかも?とその付近をチェックしていて、原因を見つけた。上昇の停止後、ちょっと戻っちゃってる。励磁を切るのが早すぎるんだな。
https://twitter.com/akita11/status/1439848357447438340?s=20

M5GRBLだと、$7で設定できる。これを最大(254)にしても、ちょい戻りが起こっちゃう。255(常時励磁に)にしたら、起こらなくなった。やっぱ位置決めは常時励磁のほうがいいんかな。
https://twitter.com/akita11/status/1439852173001588741?s=20

21/09/26

ちょっとまだツメがあまいけど、だいたい行そうな目処はたった。トレイにチップ抵抗を置いておいて、カメラで位置・向きを認識し、基板CADから出力した部品位置にしたがって配置していく。あとは精度だな。
https://twitter.com/akita11/status/1441956199503568901?s=20
配置結果はこんな感じ。向きがズレてるのは、どちらかというと画像認識誤差よりも、置くときにズレる、というのが多い印象。
https://twitter.com/akita11/status/1441956296383553542?s=20

クリーム半田塗布も、意外といけそう。
https://twitter.com/akita11/status/1441988209869688834?s=20

ベース板の位置合わせ、別の方法を試す。これが一番簡単で精度よさそう。
https://twitter.com/akita11/status/1442050729338818560?s=20

21/10/02

実戦投入テスト。クリーム半田塗布→抵抗を配置(USBコネクタは今回は手置き)。思ったよりいけそう。
https://twitter.com/akita11/status/1444102947369934853?s=20

クリーム半田はマスクで塗布してから、84個のチップ抵抗をマウント。思ったよりカメラの位置検知も、配置も、精度も安定度も思ったよりいい印象。
https://twitter.com/akita11/status/1444126250432229385?s=20

トレイ2個に別々の部品を入れておいてのテストもOKそう。
https://twitter.com/akita11/status/1444196014345244673?s=20

21/10/03

パラメータを調整して、移動を3倍速にしてみた。これでも大丈夫そう。(軸の移動停止の検出が時々失敗していたので、2回チェックするようにしたら、大丈夫そう)あと、カメラのまわりに、簡易に黒い覆いをつけてみた。これである程度は外来光の影響は除外できそう。
https://twitter.com/akita11/status/1444469340946923526?s=20

昨日の84個連続実装のときのカメラ画像を保存していたので、つなげてみた。XYのばらつきがあるように見えるけど、画像サイズもバラついているのでZ移動時の揺れ(片持ち構造のため)に伴うものか?
https://twitter.com/akita11/status/1444575868244791298?s=20

21/10/09

クリーム半田ディスペンサの送り機構、長ナット(M6x45mm)のガイドを、5mm厚アクリルを10個積んでアクリルサンデーで固定する。ちょっとでもズレると動きがスムーズでなくなるので、両側にポッチをつけ、MDF板でそのポッチを含めて固定し(本体とはネジで固定)、隙間からアクリルサンデーを流して固定したあとはずす。かなりスムーズに動くようになった。

画像53

21/10/8

半田ペースト塗布の座標をガーバーから抜き出すのに、KiCADだと四角パッドど角丸パッドで描き方が違うので、ガーバー形式のフォーマットを読みながら、スクリプトを修正。
https://twitter.com/akita11/status/1446281624287539201

クリーム半田が、ニードルを下にして置いておくと、ぽたぽた垂れてくる。necobitさんに相談してみたら、中のフラックスが分離して垂れてきているのでは、とのことで、経験上、室温保管すると分離しやすい、クリーム半田部を握ってあたためると、クリーム半田が柔らかくなってフラックスが戻りやすくなる気がする、とのこと。ちょっと試してみよう。

21/10/09

向きがある部品のカメラ検出はいったん保留して、テープを手動で送ってピックアップするようにしてみた。
https://twitter.com/akita11/status/1446643688503865353

21/10/11

テープを送る機構、こんな感じで歯車で送る方法をちょっと試してみた。
https://twitter.com/akita11/status/1447338220262342657

金本さんから、ピックアップヘッドを送り穴にひっかけて送る方法もあるよ、という情報をいただいたので、これも並行して試してみようと思う。

21/10/17

LED照明が円形だとトレイの隅の照度が不足してしまうので、なるべく均等に照らすようにLEDを配置してみた。
https://twitter.com/akita11/status/1449538267070681096

ディスペンサの先端が、機能・構造上、ピックアップヘッドより下に来ないといけないので、装着したままでもZ軸の原点出しのときに先端がベース板に接触しても折れないように、バネで戻る機構に。
https://twitter.com/akita11/status/1449538730184699907

基板をベース板に置いたときにズレないように、クルマのダッシュボード用滑り止めのシリコーン樹脂を使った固定具。かなりしっかり密着してズレない。
https://twitter.com/akita11/status/1449539192011165696

テープを扱うトレイ(その1)。ピックアップヘッドorディスペンサの針で、テープ送り穴をひっかけて送るタイプ。送り穴の部分に穴を開けて逃し。また幅の違うテープも使えるようにテープを左右にズレなくするガイドは差し替えが効くように。
https://twitter.com/akita11/status/1449540602408833027

テープを扱うトレイ(その2)。超小型ステッピングモータでまわす歯車(?)でテープを送る機構。この歯車は直径15mmあればスムーズに送れる(それ以下だと隣の歯がぶつかる)。あとはモータあわせだな
https://twitter.com/akita11/status/1449540602408833027

21/10/21

そういえばM5Stack UnitV2はOpenCVも使えるということに気づいて、これで部品検知ができないか、下調べをはじめてみる。フォーカス合わせもだいたい大丈夫そう。
https://twitter.com/akita11/status/1450347933367369728
https://twitter.com/akita11/status/1450969843910414344

21/10/26

M5Stack UnitV2をカメラ部に固定する治具。試行錯誤の結果、この形に。
https://twitter.com/akita11/status/1453137115617763331

AliExpでポチってあった小型ステッピングモータが届いたので、テープ送り機構に組み込む。このモータのコネクタは1.25mmピッチのMolexのPicoBladeシリーズの4p。ただ受け側のコネクタがぜんぜん買えない。なんとかDigiKeyに在庫があったSMDコネクタをポチる。
https://twitter.com/akita11/status/1453137619462676485

21/11/04

テープの送り穴にヘッドを差し込んでテープを4mmずつ送る。この方法、けっこういけるんじゃないか。
https://twitter.com/akita11/status/1456157772978933760?s=20

21/11/07

テープのホルダ、何回かの試行錯誤を経て、だんだんクリスタルパズルみたいになってきた。テープの幅・厚みに応じて保持部分を交換できるスタイル。
https://twitter.com/akita11/status/1457115143888781312

ディスペンサの先端部分を固定したほうがいいだろう、ということで、セットしたあと手前側からロックする機構の試作。
https://twitter.com/akita11/status/1458580673371918336

21/11/12

自作チップマウンタのテープ送り、クリーム半田ディスペンサに使うシリンジの先のニードルの先端をカットして、代わりに古くなったボールペンの先をはめてみた。長さもぴったりで、先端のテーパー具合もテープの送り穴にぴったりはまる。
https://twitter.com/akita11/status/1458982822316675073

21/11/23

久しぶりに実稼働。↑の先端具で位置を調整し、pick&placeの素振り。だいたい大丈夫そうだけど、ピックアップヘッドが擦っちゃってるから、もう少し先端具を長くしたほうがいいな。
https://twitter.com/akita11/status/1463009091438084099?s=20

21/12/08

どうも連続運転していると、どれかの軸のモータが脱調することがある。以前、ディスペンサでハンダを送り出すとY軸が脱調することがある、というのがあったけど、それも電源容量が足りないような気がしてきた。というわけで、つよつよの電源をAliExpでポチってみた。24Vで25Aくらいまでとれるやつ。
https://ja.aliexpress.com/item/1005002843829663.html


この記事が気に入ったらサポートをしてみませんか?