先日書いた記事から、実際に配置してみようという段になったとき、配置するのめんどいなと思ったので、自動化したくなった。ので、kicadのpython APIを使った。その記録
罠たち
- Python 2.7.18が使われてる
- Kicad 6.0のRelease noteで、現在あるAPIが置き換わることが明言されているため、今から学ぶのは微妙
- 公式APIノートが息してない。
- 説明がないのはいい方で、そもそもAPIのドキュメントに名前が載ってないメソッドの方がおおい。
dir()
を使って生えてるメソッド確認したり、先駆者のブログ、フォーラムのお世話にならないとお話にならない。
動作確認
一通り罠にはまってから、実際に動かしてちゃんと動いたコードをコピペする。以下のコードは次のような機能を持つ。
- pcbnewに配置されているすべてのスイッチの位置座標を(x, y) -> (x + 1, y + 3)する。
途中でダイオードの情報も取得しているけれど、最後のコードブロックでスイッチだけアップデートしている。特に理由はない。
import pcbnew
import re
import operator
def main(prefix_switch="SW", prefix_diode="D"):
"""Align switches and diodes
Args:
prefix_switch (str, optional): Prefix of reference of switch. Defaults to "SW".
prefix_diode (str, optional): Prefix of reference of switch. Defaults to "D".
"""
board = pcbnew.GetBoard()
switches = []
diodes = []
name_pattern = re.compile("^[^0-9]*")
number_pattern = re.compile("[0-9]*$")
for module in board.GetModules():
ref = module.Reference().GetText()
dict_ = {
"number": int(number_pattern.search(ref).group()),
"module": module
}
name = name_pattern.search(ref).group()
if name == prefix_switch:
switches.append(dict_)
elif name == prefix_diode:
diodes.append(dict_)
switches.sort(key=operator.itemgetter("number"))
diodes.sort(key=operator.itemgetter("number"))
for s, d in zip(switches, diodes):
old_position_x, old_position_y = pcbnew.ToMM(s["module"].GetPosition())
new_position_x, new_position_y = (pcbnew.FromMM(old_position_x + 1), pcbnew.FromMM(old_position_y + 3))
s["module"].SetPosition(pcbnew.wxPoint(new_position_x, new_position_y))
pcbnew.Refresh()
これを書く上でハマったこと。
- 書く前に、
GetPosition()
で取れる値がmm
単位でないことは把握していたが、SetPosition()
には、GetPosition()
で得た値と同じように入れては設定できないこと。pcbnew.FromMM()
で処理した上で、pcbnew.wxPoint()
で処理しないといけない。 - Pythonのインタープリター上での変更は、
pcbnew.Refresh()
を叩かないと反映されない。
これを書いてて気づいたことなど。
- フットプリントの名前を取得したいとき、フットプリントで分類したいときは、
Module.GetFPID().GetLibItemName()
で取得できるとフォーラムに書いてあった。確かにできた。 GetPosition()
はModuleの中心座標を返す。
個人的に、sortしたときにオブジェクトがコピーされたりして、参照がうまくいかず、編集が反映されないのではないかと危惧していたが、これは杞憂だった。途中でList.sort()
を叩いているけど問題なくpcbnewで反映された。copy()
なんかを使うと、もしかしたら変なことになるかもしれない。
実際のコード
ここまでかなりめんどかったけれど、取得と更新の仕方のお作法を押さえれば後はなんてことないはず。
スイッチの大きさ、ダイオードの大きさは、本当はプログラムが認識するべきなんだろうけど、ここは人間のために人間が教えてあげることにした。
- SwitchとDiodeの縦、横の長さ
- クリアランス
- Between switches
- Between switches and diodes
- Between groups of switches and diodes
- Diodeの上下方向のズレ距離
- Diode間の中心座標間の距離
スイッチの回転角は入力パラメータから計算できそうなので計算させる。
スイッチの高さを$h$, $\theta$回転後のスイッチとスイッチのクリアランスを$d_c$としたとき、各スイッチ間の距離$d$は
$$ d = \frac{h}{\cos{\theta}} - d_c $$
となる。
できたスクリプトがここに入る予定だった…