Machinekit にしたかった主な理由の一つがこれでした。事前に基板表面を一通り Probe し起伏のマトリクスを得て、これをもって補正しながら実際の切削動作を行う方法です。これにより 0.2mm ぐらいまでの細かいパターンを安定して切削できるようにできるというわけです。

# Autoleveling
software=LinuxCNC
al-back=true
al-probefeed=40
al-x=10
al-y=10

をオプションに加えるとオートレベリング用の gcode が同時に吐きだされます。この例だと 10mm ごとに Probe を行う設定です。

実際の動作

実行開始すると「Probe をつけろ」とメッセージが出て一時停止するので、Probe をつけて Resume する。

全部 Probe が終わると Probe を外せとでるので、外して Resume する。すると実際の切削が始まる。

めんどい点

一旦実行終了すると (回路が切られて各領域が絶縁されるので)、二度とオートレベリングできません。切削深さの微調整とかができないので悩ましい。

一回使った Probe データを使いまわせればよさそうですが……

備考: LinuxCNC の PROBEOPEN / PROBECLOSE

コメントのフォーマットで命令が書いてある。

(PROBEOPEN RawProbeLog.txt) と (PROBECLOSE) の間は probe 結果が指定したファイルに書き出される。

#[#101 * 3 + #102 + 500] = #5063 ( Save the probe in the correct parameter )   

が補正パラメータを変数に入れているところ。#5063 は probe の結果。#101 は X iterator / #102 は Y iterator、3 は加工範囲 / al-y - 1っぽい。500 は固定のオフセット。ということで #500 以降に補正データが入る。

なので、冒頭の probe プロセスを RawProbeLog.txt の結果を使って #500 以降への代入に置換すれば Probe データを再利用して再度切削できそう。

  1. トップ
  2. tech
  3. pcb2gcode のオートレベリングを使ってみる

これはかなり簡単な形状だと思うけど、むずかしかった。プラス端子側のモデリングのしかたがわからなくて試行錯誤したけど、あってるかよくわからない。

3D CAD で既存のをトレースするの思ったよりも面白いところがあって、例えば「ああここは面取りされてるな」みたいなのって、普段なに気なさすぎて気付かない。そういうのに気付けるのは面白い。一見しょぼい製品であっても、ちゃんと面取りされていることが多い。


いまいちわからないけど、今のところは「その部品がどういう作りかたで製造されるか」みたいなのをもっと想像したほうが良さそう。最初六角ナットの面とりのやりかたがわからなかった。正解は回転で削る、なのだけど、変なやりかたをしてしまったりした。むずかしい。

ブログに貼れる機能があって今時っぽい…… (スマフォで固まるのではずしました)

  1. トップ
  2. tech
  3. Fusion 360 の練習 RCA ジャック

USB の規格的にはダメな気はするけど ebay でしばしば売っているパネルマウント可能な USB 延長ケーブルのコネクタ部分

結構慣れてきた気がする。ノギス片手に1時間ぐらいでモデリングできた (図面がないので)。

細かい部分、微妙に角度がついて折りまげられている部分を再現してない。どうやってやるのがいいのだろう……

  1. トップ
  2. tech
  3. Fusion 360 練習 パネルマウント USB コネクタ (USB 内部延長)

オートレベリング、つまり加工前に加工対象の表面を一通り Probe して起伏のマトリックスを作る場合、Probe の速度をできるだけあげたくなります。理論的にどれぐらいまであげられるのか計算しました。

前提

  • 1066.667steps/mm
  • 1ms サンプリング (Machinekit)

計算

1066.667steps/mm なので、約937.5nmが最小ステップ(加工精度の限界)。

Probe のサンプリング頻度は 1ms ごと、つまり1kHz。これは servo-thread の実行間隔なので、実際はもう少し膨らむ(周波数は低くなる)。

1msごとに937.5nm進む速度が最も正確にProbeできる限界になるので、937.5nm * 1kHz = 937.5um/sec = 56.25mm/min。

サンプリングスピードを上げるほど速度をあげられ、精度が上がるほど速度が下がります。

  1. トップ
  2. tech
  3. 最適な Probe 速度を計算する

これが Machinekit での初切削。今まで (Grbl) と同じやりかたで gcode を生成し、そのまま実行させたもの (なので特にオートレベリングなどしてない)。

Probe のとき G91 を一緒にいれてあげないと意図しない結果になる気がする。G91 G38.2 F10 Z-1 がよさそう。

Machinekit での全体のワークフロー

  1. 起動
  2. Home All
  3. ファイルを読みこむ
  4. 設定する原点位置までジョギングで移動 (X/Y)
  5. X軸とY軸をTouch Off
  6. Probe できる範囲まで Z 軸をジョギング (1mm以内にする)
  7. Probe 端子を接続
  8. Probe (G91 G38.2 F10 Z-1)
  9. Probe 端子を外す
  10. Z軸を Touch Off
  11. (確認プロセス) Z軸を10mmあげる (G91 G0 Z10)
  12. (確認プロセス) Z軸を Touch Off
  13. (確認プロセス) 実行開始して挙動を確認して適当に停止する
  14. (確認プロセス) 本来の原点に戻す (G90 G0 X0 Y0 Z-10)
  15. (確認プロセス) Z軸を Touch Off (本来の原点設定に)
  16. 実行開始

AXIS GUI の見方

ステータスバーの「Position: Relative Actual」が地味に重要

Relative のときは (マシン座標の代わりに) オフセット座標が使われている。この場合マシン座標原点はシアンで示される。上記スクリーンショットの場合 G54 でオフセットされた座標が X/Y/Z に表示されている。G54 X/G54 Y/G54 Z はオフセットを含んだマシン座標

Actual は機械動いた結果どこにいるかを示していますよってこと。Commanded の場合、どういう指示をしたかを示していますよってこと。

  1. トップ
  2. tech
  3. Beagle Bone Black + Machinekit での PCB Milling

BBB と Machinekit (LinuxCNC/EMC2) での CNC 制御がようやく動いたので記録しておきます。

インターフェイスボードの製作

Beagle Bone Black の I/O は 3.3V かつかなり電流的に厳しいので、5V変換バッファを外部につけたほうがよさそうです。ということで、BBB とステッピングモータドライバの間にバッファをもうけました。やってることは単純で、バッファIC 74LVC541 で入出力をバッファしているだけです。5Vトレラントなバッファを使うことで電圧変換を同時に行います。

出力用に2つ、入力用に1つ使っています。入力用のICには 3.3V を供給し、入力側を5V でプルアップしています。出力用のICには5Vを供給し、BBB からは直接繋いでいます。あまり行儀良いとはいえなそうですが、これでインターフェイスは 5V に統一されています。

さらにフォトカプラとかで絶縁するとより良さそうですが、現状使っているステッピングモータドライバ (Sable-2015 付属のものです) にはフォトカプラが入っているっぽかったのでやっていません。

SOP の IC を使うつもりが、間違えて TSSOP のをいくつも買ってしまって諦めて TSSOP でなんとかしました。前に TSSOP をやったときは、かなりキツいと思いましたが、今回は思ったよりうまくできました。が、TSSOP 以外の部分で 0.25 幅の配線が2本ほど消滅してしまってリワークでなんとかしました。

というか後から調べてみたら 74*541 (非反転バッファ) で SOP の IC は秋月では取り扱いがないみたいですね。74*540 ならありました。反転でもソフト側でなんとかなるのでどっちでもいいんですが……

1608 (1.6x0.8mm) の抵抗の下を一本通すみたいなパターンにせざるを得なかったですが、なんとかなりました。といっても、特にチップ抵抗使う意味はなかったので、普通にリード部品にして安全に実装しても良かったかと思いました。今回はここの部分では特に問題が起きなくて良かったです。

(これらの切削は Grbl でやったものです)

HAL ファイルの設定

レポジトリ: https://github.com/cho45/machinekit-configs

HAL manual を一通り読んでも設定できるぐらいの知識はつかなくて、既存の他の設定ファイルや、ドライバのソースコードを読んだりしないと正確に設定することはできません……

とりあえず .hal での設定の流れですが以下のような感じです。

  1. loadusr コマンドで実行に必要な外部プログラムをロードする
    • loadusr -w だとコマンドの終了を待つ (初期設定を外部コマンドでやるために必要)
    • loadusr -W だとコマンドが起動するまで待つ
  2. loadrt コマンドで必要なコンポーネントをロード・設定する
  3. addf でコンポーネントの関数を実行スレッドに追加する
  4. setp でコンポーネントのパラメータ設定をする
  5. net でコンポーネント間を接続する

net コマンドがいちばんややこしい です。既存の設定ファイルだと、source target の形式になってないものが多いような気がするんですが、なんで動いてるんでしょうね?

基本的には既存の設定のコピペでなんとかなるのですが、自分の環境にあわせてピン名などはあわせこまないといけません。

ちなみに [xxx]foo みたいな文法は .ini ファイルの値を参照していているだけです。

BBB での設定

BBB で使う重要なモジュールはふたつあります。

hal_bb_gpio

GPIO 全般のI/Oを HAL の pin として扱うことができるようになります。外部ボタンとか、マシンステータスとか、servo-thread (遅いスレッド) でやるので十分なものはこちらで全て処理します。pin なので直接他のコンポーネントと net することができます。

loadrt hal_bb_gpio output_pins=107,115,119,126,214 input_pins=109,110,114,116,118

以上のような設定をすると。BBB のピンヘッダ8のうち 7,15,19,26、ピンヘッダ9のうち14が出力ピンに。同様にピンヘッダ8のうち9,10,14,16,18が入力ピンとして定義され、hal ファイル内で bb_gpio.p8.in-16 という形で参照できるようになります。1xx がピンヘッダ8、2xxがピンヘッダ9に対応しています。

hal_pru_generic

PRU でやることを設定します。スレッピングモーターのシグナル・PWM・エンコーダー入力など、普通の Linux だと base-thread でやることをすべてこのコンポーネントで行うようになっています。

loadrt hal_pru_generic prucode=$(HAL_RTMOD_DIR)/xenomai/pru_generic.bin pru=1 num_stepgens=3 num_pwmgens=1 halname=hpg

この例では PRU1 (BBBにはPRUが2機あるので) で stepgen を3つ、pwmgen を 1つ動かすことになります。これにより、hpg.stepgen.00, hpg.stepgen.01, hpg.stepgen.02 と hpg.pwmgen.00 が HAL に定義されます。

PRU で使うピンは hal_bb_gpio とは独立しており、setp で別途指定する必要があります。

# P9.27
setp hpg.stepgen.01.dirpin          147
# P9.28
setp hpg.stepgen.01.steppin         145

ここの数字は hal_bb_gpio とは関係ありません。上の例ではbeaglebone_pinmap.h の値をそのまま書いています。これは変換メソッドがちゃんと動いてるか不安でバイパスしたかったから以外の意味は特にありません。

ピンナンバーには hal_pru_generic.cのfixup_pin()で変換がかかるので以下のように書くことができるようです。ただ、実際には試してません。

# P9.27 GPIO
927
# P8.11 PRU OUT
1811
# P8.15 PRU IN
2815

.ini ファイルの設定

各軸の MAX_VELOCITY, MAX_ACCELERATION, SCALE, MIN_LIMIT, MAX_LIMIT はすくなくとも必ず理解して確実に設定しなければなりません。これらの項目はマシンごとに異なるのでコピペではどうにもならないからです。

参考までに自分が Grbl に設定していた項目 の一部をコピペしてくると

$0=10 (step pulse, usec)
$1=25 (step idle delay, msec)
$100=1066.667 (x, step/mm)
$101=1066.667 (y, step/mm)
$102=1066.667 (z, step/mm)
$110=800.000 (x max rate, mm/min)
$111=800.000 (y max rate, mm/min)
$112=800.000 (z max rate, mm/min)
$120=150.000 (x accel, mm/sec^2)
$121=150.000 (y accel, mm/sec^2)
$122=100.000 (z accel, mm/sec^2)
$130=200.000 (x max travel, mm)
$131=150.000 (y max travel, mm)
$132=60.000 (z max travel, mm)

としていました。この設定を Machinekit に置き換える場合、単位が全て単位時間あたりのものになっているので、そこをまず気をつける必要があります。

X軸の最大速度が 800mm/min なら [AXIS_0] で MAX_VELOCITY = 13.4 と指定する必要があります。加速度は単位が同じなのでそのまま MAX_ACCELERATION = 150。

SCALE は step/mm なのでこれもそのまま指定できます。(備考ですが、Sable-2015 のウェブの設定を見ると4マイクロステップ時のものになっています。実際には8ステップでしたので、2倍にしてあります)

自力で計算しなおす場合 200steps/rev, 8microsteps, 1.5mm/rev という環境なら

という感じで計算できます。

実行して調整する

実際設定一発で完璧に動かせるわけがないので、何度か調整する必要があります。

まず .hal の設定を変えてる場合は、意図したピンから出力がでていることをオシロで確認することが必要です。また入力も halmeter とかで必ず確認します。インターフェイス基板がちゃんと動いているかとかも含めて、動かす前に必ず電圧と波形をすべて確認します。

あとは

  • 軸の移動方向が逆
    • SCALE の符号を逆にする
  • ホーミング時に動く方向が逆
    • HOME_SEARCH_VEL の符号を逆にする
  • 原点と逆方向にホームスイッチつけてんだけど?
    • HOME_OFFSET が「原点からホームスイッチまでの距離」を表わすので、これをテーブルサイズに設定する
  • ホーミング後にものすごい動くんだけど?
    • ホーミング後は HOME で指定した座標まで移動する。HOME_OFFSET - 3 ぐらいに設定しとくのが良い

という感じで設定を詰めていきました。

備考:自分の環境 (Sable-2015)

上記設定ファイルはあくまで自分の環境用のもです。特にホーミングまわりや、軸方向などは設置状況に応じてそれぞれだと思います。

参考までにどんな環境で設定したかを書いておきます

  • リミットスイッチは Sable-2015 を正面からみて、以下のようについています。片側だけです。ホーミングとリミットのスイッチを兼ねています。
    • Xは右側
    • Yは奥側
    • Zは上側
  • X/Y 軸の原点は左手前
    • テーブルの右に行くにしたがってXが増える
    • テーブルの奥に行くにしたがってYが増える
  • Z軸
    • スピンドルが下に行くにしたがってZが減る
  • スッテピングモータードライバは付属のもの。
    • 8 マイクロステッピング設定
    • 特に改造していません

備考:内部コンポーネント

マニュアルは http://www.machinekit.io/docs/man/man9/ にありますm

ソースコードは src/hal/i_components にあります。謎のファイル形式にみえますが、instcompでコンパイル・インストールできるようになっているらしいく、実体はプリプロセッサで面倒な部分が隠してあるCのファイルです。

  1. トップ
  2. tech
  3. Beagle Bone Black + Machinekit での CNC 制御 (Sable-2015)

ジョギング用のペンダントに USB の XBox コントローラを使う話です。

基本的には LinuxCNC Documentation Wiki: Simple Remote Pendant でいいんですが、これだけだとちょっと気に入らないので、結構がんばる必要があります。

仕様

  • 左アナログパッドに X/Y軸
  • 右アナログパッドに Z軸

が割り当てられています。これが基本ですが、事故防止のため左右のトリガーを押している間しか動作しないようになっています。

  • 左トリガーを押しながら軸操作をすると低速移動
  • 右トリガーを押しながら軸操作をすると高速移動

アナログパッド自体にも傾きによって速度調節が入りますので、トリガーの役割は「最大速度の設定」です。

また、X/Y軸が同一アナログパッドにある弊害として、このままだと意図せずに移動したい軸ではない軸を動かしてしまうという問題があります。これに対処するため、

  • Xボタンを押している間はX軸のみ動く (Y軸の移動が抑制される)
  • Yボタンを押している間はY軸のみ動く(X軸の移動が抑制される)

としてあります。Z軸は独立していて問題ないので、これで意図した軸を確実に動かせます。

まだ L, R, A, B, Back, Start ボタンと十字キーとスティック押し込みが余っています。probe はどこかに入れたいですが、残りは特に思いついてません。

.hal

# X-BOX USB コントローラジョギング設定
# abs-hat0x, abs-hat0y: デジタル十字キー 1 か 0 か  -1
# abs-rx, abs-ry: 右アナログスティック
# abs-rz: 右アナログトリガー (RT)
# abs-x, abs-y: 左アナログスティック
# abs-z: 左アナログトリガー (LT)
# btn-a: Aボタン
# btn-b: Bボタン
# btn-mode: XBox ボタン
# btn-select: BACK ボタン
# btn-start: スタートボタン
# btn-thumbl: 左スティック押し込み
# btn-thumbr: 右スティック押し込み
# btn-tl: 左上側ボタン (LB)
# btn-tr: 右上側ボタン (RB)
# btn-x: Xボタン
# btn-y: Yボタン

loadusr -W hal_input -KRAL 360

loadrt deadzone count=5
loadrt scale count=2
loadrt mux2 count=3
loadrt flipflop count=1

addf flipflop.0 servo-thread
addf mux2.0 servo-thread
addf mux2.1 servo-thread
addf mux2.2 servo-thread

addf deadzone.0 servo-thread
addf deadzone.1 servo-thread
addf deadzone.2 servo-thread
addf deadzone.3 servo-thread
addf deadzone.4 servo-thread
addf scale.0 servo-thread
addf scale.1 servo-thread

setp deadzone.0.center      0.0
setp deadzone.0.threshhold  0.2
setp deadzone.1.center      0.0
setp deadzone.1.threshhold  0.2
setp deadzone.2.center      0.0
setp deadzone.2.threshhold  0.2
setp deadzone.3.center      0.0
setp deadzone.3.threshhold  0.2
setp deadzone.4.center      0.0
setp deadzone.4.threshhold  0.2


# トリガーをひかない限り動かないようにする
# また、トリガーのアナログ値によって最大スピードを制限する
# 左トリガー
setp input.0.abs-z-offset 0
setp input.0.abs-z-scale 255
net joy-speed-jog-dead-l input.0.abs-z-position   deadzone.3.in
setp scale.0.gain 80
setp scale.0.offset 0
net joy-speed-jog-scale-l deadzone.3.out scale.0.in
net joy-speed-jog-final-l scale.0.out mux2.0.in0

# 右トリガー
setp input.0.abs-rz-offset 0
setp input.0.abs-rz-scale 255
net joy-speed-jog-dead-r input.0.abs-rz-position   deadzone.4.in
setp scale.1.gain 800
setp scale.1.offset 0
net joy-speed-jog-scale-r deadzone.4.out scale.1.in
net joy-speed-jog-final-r scale.1.out mux2.0.in1

# 左か右いずれかを有効にする。ただし左が優先
net joy-flipflop-reset input.0.abs-z-is-pos flipflop.0.reset
net joy-flipflop-set input.0.abs-rz-is-pos flipflop.0.set
net joy-select-maxspeed flipflop.0.out mux2.0.sel
net joy-selected-maxspeed mux2.0.out halui.jog-speed

# X-BOX のコントローラの Scale は 127.5 ではないので気をつけよう
# 軸方向反転の設定
# setp input.0.abs-rx-scale -32767.5
setp input.0.abs-ry-scale -32767.5
setp input.0.abs-y-scale -32767.5

# 左アナログパッドはX/Y軸
# 右アナログパッドはZ軸
net joy-x-jog-dead input.0.abs-x-position  deadzone.0.in
net joy-y-jog-dead input.0.abs-y-position  deadzone.1.in
net joy-z-jog-dead input.0.abs-ry-position   deadzone.2.in

# XボタンまたはYボタンを押しているときは、それぞれX軸またはY軸のみ移動可能にする
# 予め net はしておくが、ボタンが押されたときは他軸の移動を抑制する形
net joy-x-jog-mux deadzone.0.out mux2.1.in0
setp mux2.1.in1 0
net joy-y-jog-mux deadzone.1.out mux2.2.in0
setp mux2.2.in1 0

net joy-x-brake input.0.btn-y mux2.1.sel
net joy-y-brake input.0.btn-x mux2.2.sel

net joy-x-jog mux2.1.out halui.jog.0.analog
net joy-y-jog mux2.2.out halui.jog.1.analog
net joy-z-jog deadzone.2.out halui.jog.2.analog

# X-BOX ボタンでマシンが起動するぞ
net joy-btn-xbox input.0.btn-mode halui.machine.on

備考:deadzone の設定

アナログスティックを離していてもいずれかの方向に多少傾いていて入力されてしまうので、中央付近に不感帯をつくっておく必要があります。

備考:XBox コントローラのアナログスティック類は 16bit

なので各種 scale に入ってる値が 32767.5 になっている。うっかり符号を変えようとして -127.5 とか入れると大変なことになるので注意が必要。

XBox コントローラは、2つの2軸アナログパッドと、2つのトリガーが16bitアナログなため、合計で6つのアナログ入力があります。

マイクロソフト ゲームコントローラー 有線/Xbox/Windows対応 ブラック Xbox360 Controller for Windows 52A-00006 - マイクロソフト

マイクロソフト

5.0 / 5.0

  1. トップ
  2. tech
  3. Machinekit (LinuxCNC) を XBox コントローラを使って機械を動かす。

先週は1日おきぐらいにちょいちょい調子が悪くて1日は休んだ。よくなったかと思ったら、月曜日の昼ぐらいから劇的に調子が悪くなり38.3℃ぐらいまで熱があがる。熱があがっている間って、あまりにもだるくて身体がもぞもぞとして眠れなくてとにかく辛い。上がりきったあとは暑いだけで寝れるようになるからいいんだけど、無限に疲れる。そして火曜日は会社をまた休んだ。

熱が出たときにアリナミン飲むと効く気がしていて、特に熱が上がりきってからの身体のだるさはかなり軽減される。熱があがりつつある間はロキソニンかイブプロフェン飲むと楽になるのはわかってるんだけど、手元になかったのと、治りが遅くなりそうっていうか効きすぎて熱が下がるせいで治ったのか治ってないのかよくわからないのでできれば避けたい。

特になにか不摂生なことをしているわけではないというか、何もしてないのに体調がどんどん悪くなる。こういう一時期よりも体調不良の頻度が明かに上がってるが、一つ一つの症状は一般的な風邪ぐらいしかひどくはない、みたいなのってどう対応すればいいのかわからない。内科いっても対処療法にしかならないし、根本的に体調不良の頻度を下げたいんだけど、どうやって解決できるのか全く検討もつかない。

健康のためにも多少運動したいという気持ちはあるが、そもそも運動にかけられる時間なんて捻出できないんだけど、普通の人はいったいどこからそんな時間が出てくるのだろう。というか運動すると体調不良になるしどうしようもない。

SketchUp Make を使っていたのは多少慣れていたから以外の理由は特になくて、最近だと無料版の Make の機能がヘボすぎて辛くなってきた。

そして Autodesk Fusion 360 が小規模開発者には無料で使えるのを知らなかった。(123 だけ無料だと思っていた) 普通にフル機能が使えるっぽいので使いはじめてみた。一言でいうと、普通に最高。

やってみた雰囲気

フォトカプラ的なもの (多少実際のモデルと異なります)

ロータリーエンコーダー風のもの

位置的にちゃんと光軸通るの?ってのを探ってる

周辺環境とがっちゃんこしたやつ

回るんやで

CAM まで内蔵されてるんやで

できたで (※これは3D CGではありません)

温度感

2D で「スケッチ」を描いてプッシュ/プルで形成していくので、SkechUp と比べてイメージの書き下し手順には大差なく、Fusion 360 のほうが高機能なのでかなりやりやすい。

上のように手にとれる立体をつくるまで、モデリングに3、4時間、切削の4時間ぐらい(ハマリも含めて)。

思いのほかモデリングが楽で「こうしたい」と思ったことはだいたいできた。スケッチを複製して別の面に移動するみたいなことはできない? っぽくて、プッシュプルで頑張ったけど、やりかたはありそう…

YouTube に公式の日本語チュートリアルがあるので、ぼーっと見とくだけで全能感が産まれる。

ワークフロー

スケッチと呼ばれる 2D 図面を起こしてから、3D モデルに変換していく。

図形は最初から完璧に配置する必要はない。図面に寸法を記入すると、自動的に図形の形が正しい形になる。

拘束という仕組みがあり、辺と辺・点と点の関係を定義すると、図形に他の変更を加えても、その関係が維持されるようになる。寸法も拘束の一種といえる。宣言的プログラミング (制約プログラミング) を GUI でできる感じ。

長方形などのプリミティブな図形は、簡単に図形が描けるだけではなく、自動的に拘束が定義される。

タイムライン

まず、これはアンドゥ機能ではない。

作業のある時点に遡って変更を行え、それに依存する他の作業すべてに影響を及ぼす。過去改変のコマンド。

CAM まわりの罠

Grbl な環境でめちゃくちゃな動きをしまくってハマりまくった。CAMotics とかでシミュレーションさせたりしてもおかしくなくて、実機で動かして初めて分かる不具合だったのでかなり難儀した (安いエンドミル数本と高いエンドミル1本をダメにした)

以下のようにすること

  • minimumCircularRadius を 1000 とかにする (ARC コマンドをやめて全て直線で出力)
  • 出力ファイルを nkf -Lu --overwrite 1.nc とかして改行コードを unix にすること (Fusion 360 は CRLF を吐くが、LF にしないとなんか謎のぶっこわれたパスを描いてしまうことがあった)

  1. トップ
  2. tech
  3. SketchUp Make を捨てて Autodesk Fusion 360 に移行した

久しぶりに歯医者。クリーニングといって、メンテナンスだけで虫歯というわけではない。半年毎になってるんだけど、用事が多くて前回からかなり時間が開いてる。

歯茎がさがっていて、噛み締めが多いからじゃないか。1日の終わりに反省すると寝てる間に歯ぎしりしやすいから反省するな、と言われる。無理やで

やっぱり飲み会とか好きじゃない。独りでアニメを見ながら「ひふみん可愛いデォユフフwww」とか言いながら酒を飲むのが最高であって、意識高い話をしながら酒を飲んでも特に何も産まれない。

これは切り替えの問題なのだ。酒を飲んでるとは難しいことを考えてはならない (MUST)。複雑なことをすると複雑な問題をひきおこす。

家で酒を飲んでアニメを見ていれば、酒臭くてうぜぇなみたいな話にはならないし、好きなように好きなような酒を飲んで好きなように酔っぱらって好きなようにインターネットがができる。辛い思いをする必要はどこにもない。


ツイッターとかフェイスブックとかを止めてるが、書きこみを止めているだけで、投稿はたまに見ていたりする。投稿を見た結果「やっぱ見ないほうがいいな」と思うが、投稿自体に制約を設けると「生きてる証明をなにかしらで示さなければ」と思う。そうすると (自分の中では) 価値のあるトピックでエントリーを書こうという気になる。この世界では、クソ短文で承認欲求を満たしてはならない。

何がいいたいかというと、「見ないことに価値がある」と思ってはじめてみたが、意外にも「見ても、反応・投稿しないことに価値がある」ということがわかったことだ。すべての情報は一度飲みこまなければ吐きだしてはならない、という制約をつけることによって、(自分の中では) より価値の高いものがアウトプットできる。


はてブもやっぱ見ちゃうことがあるけど、クソみたいな意識高い高いエントリについてる目線だけ高い高いブコメとか、おまえも同様にクソだろとしか思えない。クソがクソ叩いて喜んでる。クソがクソ叩いてるのを喜んでるクソがオレ。ブルーハーツって未だにテレビとかで曲がかかってすごいよなあ。弱いものたちが夕暮れ〜さらに弱いものを叩く〜。クソの連鎖。評価基準がクソなせいだと思う。ちゃんと作ってるか成長しているかが最重要。ウィーウィルベカームシルエッツ。


3D CAD をやってみて、やはりプログラミングを先にいろいろやっていて良かったと感じる。仕事で「プログラミングできて良かった」と思うことは極めて稀だが、趣味でいろんなことをしてみると全く「プログラミングをできて良かった」と思うことが多い。拘束とは制約プログラミングだと気付ければ難しいことが一切なくなり、便利さだけが理解できる。

「趣味」をバカにして「仕事こそが人生の意義だ」みたいなことを言うひとがいるが、全く間違いであり、そういう言い草は全く気にくわない。そういう人は単に仕事が趣味なのであって、趣味をバカにしている。趣味こそが全身全霊をささげるべき対象であって、仕事は単にそのために金を稼ぐ手段であるか、ないしは趣味で培った力の一部を社会に還元する行為である。


街には「地域ぐるみでなくそう路上喫煙」とか旗が立ってたりするが、喫煙者はすぐそばで路上喫煙をする。彼らは文字が読めないので仕方がない。対応策が間違っているのだ。喫煙者はなぜか人間として扱われているが、識字率99%以上のこの国で文字が読めないので、初等教育も受けていないことは明白であり、人間のような姿に見える他の生物である。JT とかいう独占企業があってモラルを啓蒙して「おれは悪くない」アピールをしているが、そもそも人間ではない生物にはモラルなどなく、判断能力のないそれに、中毒症状をいいことに薬物を売りつけるのが JT であって、今すぐにでも滅びなければならない。

不思議なのはそれのカタチが人間であるおかげで、人間として扱われれいて、人権が保証されているところである。人間は呼吸をしなければ生きていけず、空気の汚染は健康に直結する。それが環境を汚染して人間をいくら傷つけても、それが「薄く広い」殺人ならば罪にはならない。いくら薄く広く子供を殺して、あるいは子供以外の人間を殺してもそれは罪に問われない。どこから人権が生じるのだろうか? 人権のある生物から産まれれば人権があるのだろうか? 公共の福祉とはなんなのだろうか? 憲法に定められた「健康で文化的な最低限度の生活」における健康ってなんなのだろうか。「人民の健康が最高の法たるべし」ではないのだろうか? いったいそれにはいつ罰が与えられ、人間は健康に人生を過ごすことができるのであろうか?


(このエントリはクソよっぱらってクソのように世の中を思いながら書きました)

今まで SketchUp + SketchUCam で雑にポケット加工の機能を使って生成してたりしていたのですが、思うような G-Code になかなかならなくてダルくなったので自力で書くことにしました。

加工範囲ぎりぎりを動かすので、いつもリミットにあたらないか心配しながらやってたのですが、そのへんを考慮するようにしました。

今いちスタンダードなやりかたがわからないのですが、中央から削っていくようにしてみました。このほうがゴミが残りにくいかな?

あと面出しって英語でなんて言うかわからなくて検索できませんでした。

#!/usr/bin/env ruby -v

io = $stdout

=begin
使いかた:
 1. 面出し範囲のX軸幅・Y軸幅を測ってパラメータを変えておく
 2. 面出し範囲の左下に原点をあわせる
 3. G-code を生成して流す
=end

# 加工面のX軸の幅
x_size = 201
# 加工面のY軸の幅
y_size = 151
# 削る厚さ
cut_thikness = 0.1
# 使用するエンドミルの直径
tool_diameter = 6.0
# 削りのオーバーラップ割合
overwrap = 0.9
# 加工フィードレート
feed   = 500
# セーフレベル
z_safe = 1

###
io.puts "G94 ( mm/min feed rate. )"
io.puts "G21 ( Use mm )"
io.puts "G90 ( Absolute distance )"
io.puts "M3 S10000 (Start Spindle)"
io.puts

# 原点が面出し表面の左下にあること前提
# 念のためリミットにひっかからないことを確認するため、最初に外形を一周する
# この生成プログラムでは座標が加工原点からマイナスにいったり、
# 設定した x_size/y_size を超えることはない
# 一方で、加工原点や x_size/y_size からはエンドミル半径分はみだして切削する
# これは削り残しがないようにするためで意図的

io.puts "G0 Z%.5f" % [z_safe]
io.puts "G0 X%.5f Y%.5f" % [0, 0]
io.puts "F%.5f" % [feed]
io.puts "G1 Z%.5f" % [-cut_thikness]
io.puts "G1 X%.5f Y%.5f" % [0, y_size]
io.puts "G1 X%.5f Y%.5f" % [x_size, y_size]
io.puts "G1 X%.5f Y%.5f" % [x_size, 0]
io.puts "G1 X%.5f Y%.5f" % [0, 0]
io.puts "G0 Z%.5f" % [z_safe]

# 中央から外形に向かって削る
begin
	x_steps = ( x_size / (tool_diameter * overwrap) ).ceil
	y_steps = ( y_size / (tool_diameter * overwrap) ).ceil
	steps = [x_steps, y_steps].min

	# 切削中のrectサイズ
	x_center = x_size / 2.0
	y_center = y_size / 2.0
	x_current_size = 0
	y_current_size = 0

	# 削りはじめ、XとYで差があるので、まずはそれを埋める
	case
	when x_size > y_size
		x_current_size = (x_steps - y_steps - 1) * (tool_diameter * overwrap)
		x_offset = (x_size - x_current_size) / 2.0

		io.puts ""
		io.puts "(initial line)"
		io.puts "G0 Z%.5f" % [z_safe]
		io.puts "G0 X%.5f Y%.5f" % [x_offset, y_center]
		io.puts "G1 Z%.5f" % [-cut_thikness]
		io.puts "G1 X%.5f Y%.5f" % [x_offset + x_current_size, y_center]
	when y_size > x_size
		y_current_size = (y_steps - x_steps - 1) * (tool_diameter * overwrap)
		y_offset = (y_size - y_current_size) / 2.0

		io.puts ""
		io.puts "(initial line)"
		io.puts "G0 Z%.5f" % [z_safe]
		io.puts "G0 X%.5f Y%.5f" % [x_center, y_offset]
		io.puts "G1 Z%.5f" % [-cut_thikness]
		io.puts "G1 X%.5f Y%.5f" % [x_center, y_offset + y_current_size]
	else
		# nothing to do
	end

	# 少しずつ広げながら削る
	# 外形は最初に一度削っているが、内側の削りカスを除去するためにも再度削る
	steps.times do |step|
		x_current_size += (tool_diameter * overwrap)
		y_current_size += (tool_diameter * overwrap)
		xx = x_current_size / 2.0
		yy = y_current_size / 2.0
		io.puts ""
		io.puts "(step %d)" % step
		io.puts "G1 X%.5f Y%.5f" % [x_center + xx, y_center + yy]
		io.puts "G1 X%.5f Y%.5f" % [x_center - xx, y_center + yy]
		io.puts "G1 X%.5f Y%.5f" % [x_center - xx, y_center - yy]
		io.puts "G1 X%.5f Y%.5f" % [x_center + xx, y_center - yy]
		io.puts "G1 X%.5f Y%.5f" % [x_center + xx, y_center + yy]
	end
end

io.puts "G0 Z%.5f" % [z_safe]
io.puts "M5 (Stop Spindle)"
io.puts "M2 (Program End)"

% 演算子とか、もろもろが便利なので Ruby で書きましたが、再代入禁止の変数が欲しいですね。定数だとおおげさなので……

  1. トップ
  2. tech
  3. CNC フライスで加工台の面出しをするG-Codeを生成するRubyスクリプト

Universal Foldable Keyboard のレビュー

結局 amazon.com (US) から買ってみました。ちゃんと技適マーク付きのが来ました。日本で買うより安いです。

説明書が入ってなくて、なんかよくわからんイラストだけです。IKEA の説明書みたいなやつと言えばわかる人にはわかるでしょう。

配列自体は変態配列で、たとえ US 配列でも普通のキーボードと比べて打ちやすくはないです。右側はキー数が多いせいでピッチが狭かったり、中央付近で折れる構造のために中央付近のキーがなんか変な感じがします。

よくできてるなと思ったところは

  • 同時に2つペアリングができて、ボタン1発で切替えができる
  • OS切替ボタンがあって、Windows/Android/iOS でキーマップが変わるようになっている

あたりです。

同時に2つペアリングするやつは、それぞれに別々の BLE アドレスがふられているので、近くにある別々の機器に同時にペアリングして、ボタンで切替えながら入力先を変更できるので、Windows/Mac で開発しながら、Android もデスクに置いて切替えて入力するみたいなことができて便利そうです。

Universal Foldable Keyboard の仕様

まぁレビューするために買ったんじゃないんですよ。BLE キーボードの参考実装として買ったのです。ということで以下技術的な仕様をレビューします。

GATT 構造のダンプ

以下のようになっています。Device Information の Firmware Revision に CSR uEnergy SDK 2.4.2 と入っていたので、CSR のチップなのでしょう。Unknown Service が2つありますが、CSR の DFU まわりのためのサービスのようです。

HID Information の Base USB Specification Version に 0x213 が入っていて異常です。HID のスペックは 1.11 が最新のはずなので、(BCD で) 0x111 とかが正しいと思うのですが、2.13 という謎のバージョンになっています。

Device Information Service の PnP ID は source=USB VID=0x45e PID=2060 version=272 でした。

Connection Parameter は

  • 15ms - 15ms
  • Slave Latency 33
  • Supervision Timeout: 600

でした。

他には特に気になるところはありません。

Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
   Client Characteristic Configuration (0x2902)
Generic Access (0x1800)
- Device Name [R W] (0x2A00)
- Appearance [R] (0x2A01)
- Peripheral Preferred Connection Parameters [R] (0x2A04)
Human Interface Device (0x1812)
- Report Map [R] (0x2A4B)
   External Report Reference (0x2907)
- Report [N R] (0x2A4D)
   Client Characteristic Configuration (0x2902)
   Report Reference (0x2908)
- Report [N R] (0x2A4D)
   Client Characteristic Configuration (0x2902)
   Report Reference (0x2908)
- Report [R W WNR] (0x2A4D)
   Report Reference (0x2908)
- Report [R W] (0x2A4D)
   Report Reference (0x2908)
- HID Information [R] (0x2A4A)
- Boot Keyboard Input Report [N R] (0x2A22)
   Client Characteristic Configuration (0x2902)
- Boot Keyboard Output Report [R W WNR] (0x2A32)
- HID Control Point [WNR] (0x2A4C)
- Protocol Mode [R WNR] (0x2A4E)
Battery Service (0x180F)
- Battery Level [N R] (0x2A19)
   Client Characteristic Configuration (0x2902)
   Report Reference (0x2908)
Unknown Service (a74df799-13fd-4f82-a45a-0340180eac97)
- Unknown Characteristic [R W] (343f8f87-ec68-41a7-a97f-3141b2424e1d)
Unknown Service (00001016-d102-11e1-9b23-00025b00a5a5)
- Unknown Characteristic [R W] (00001013-d102-11e1-9b23-00025b00a5a5)
- Unknown Characteristic [W] (00001018-d102-11e1-9b23-00025b00a5a5)
- Unknown Characteristic [N R] (00001014-d102-11e1-9b23-00025b00a5a5)
   Client Characteristic Configuration (0x2902)
Device Information (0x180A)
- Firmware Revision String [R] (0x2A26)
- PnP ID [R] (0x2A50)
Scan Parameters (0x1813)
- Scan Interval Window [WNR] (0x2A4F)
- Scan Refresh [N] (0x2A31)
   Client Characteristic Configuration (0x2902)   

HID ReportMap

Report Map を読み出して、人力でパースしました。自動的にパースしてダンプしてくれるツールってないんですかね? おかげで人力で結構 HID Report Map が読めるようになってしまいました。

概要としては

  • report id = 1 が通常のキーボードのレポート
    • ただし feature report の定義もある (詳細は不明)
  • report id = 3 がメディアキーとかのレポート
    • 音量とか再生ボタンとか

report id = 2 が抜けてますが、Report Map Characteristics に External Report Reference Descriptor がついており、Battery Level Characteristics の UUID が入っていました。そして Battery Level Characteristics に Report Reference Descriptor がついており、report id = 2 / input report として定義されていました。これって HID の Report Map の中には定義しなくていいんでしょうか? HOGP とかの仕様書を読んでもどうしてもよくわからないのですが…… HID にもバッテリー情報を送る決まりはありますが、それは関係ないんでしょうか。(というか BLE のバッテリー情報に主要OSが対応してないのでどうしよもないです)

feature report の仕様はよくわかりません。MS 提供のツールで、言語設定を上書きできるので、これの操作に使われているような気がしています。

05-01 Usage Page (Generic Desktop)
09-06 Usage (Keyboard)
A1-01 Collection (Application)
	85-01 Report ID (0x01)
	05-07 Usage Page (Key Codes)
	19-E0 Usage Minimum (224)
	29-E7 Usage Maximum (231)
	15-00 Logical Minimum (0)
	25-01 Logical Maximum (1)
	75-01 Report Size (1)
	95-08 Report Count (8)
	81-02 Input (Data, Variable, Absolute); Modifier data

	95-05 Report Count (5)
	75-01 Report Size (1)
	05-08 Usage Page (Page# for LEDs)
	19-01 Usage Minimum (1)
	29-05 Usage Maximum (5)
	91-02 Output (Data, Variable, Absolute) ; LED report

	95-01 Report Count (1)
	75-03 Report Size (3)
	91-03 Output (Constant, Variable, Relative) ; padding

	95-07 Report Count (7)
	75-08 Report Size (8)
	16-00-00 Logical Minimum (0)
	26-FF-00 Logical Maximum (255)
	05-07 Usage Page (Key Codes)
	19-00 Usage Minimum (0)
	2A-91-00 Usage Maximum (145)
	81-00 Input (Data, Array, Absolute); Key arrays

	05-0C Usage Page (Consumer)
	0A-C0-02 Usage (0x02c0/704 ?)
	A1-02 Collection (Logical)
		85-01 Report ID (0x01)
		1A-C1-02 Usage Minimum (705)
		2A-C6-02 Usage Maximum (710)
		75-08 Report Size (8)
		95-06 Report Count (6)
		B1-03 Feature (Content, Variable, Relative)
	C0 End Collection
C0 End Collection

05-0C Usage Page (Consumer)
09-01 Usage (Consumer Control)
A1-01 Collection (Application)
	85-03 Report ID (0x03)
	75-10 Report Size (16)
	95-01 Report Count (1)
	15-01 Logical Minimum (1)
	26-FF-03 Logical Maximum (1023)
	19-01 Usage Minimum (1)
	2A-FF-03 Usage Maximum (1023)
	81-60 Input (No Preferred, Null state)
C0 End Collection

ドライバ

Windows に接続すると、専用のドライバが読みこまれることを確認しました。なんのためにそうなっているのかよくわかりませんが、明確に Windows の汎用 kbdhid ドライバとは違いがあります。

自作キーボードを Universal Foldable Keyboard に成り済まして検証する

だいぶあれ気ですが、PnP ID を偽称して Universal Foldable Keyboard に成り済まして消費電流を検証しました。Universal Foldable Keyboard を買ってやりたかった一番のことがこれです……

結果的に、汎用 kbdhid ドライバだと 800μA ぐらいの消費が、Universal Foldable Keyboard のドライバを読みこませることで 200μA まで減るということがわかりました。ドライバ内でなにかしら調節しているようです。チートかよ。

備考:Windows のドライバロード手順

デバイスが接続されると以下のディレクトリの .inf からデバイスドライバが検索される。BLE 接続後、しばらくプログレスバーが表示されるが、これを検索している時間分待たされるっぽい。

C:\Windows\System32\DriverStore\FileRepository

.inf の中に以下のような行がある。

%UniversalFoldableKeyboard.DeviceDesc% = UniversalFoldableKeyboard, HID\{00001812-0000-1000-8000-00805f9b34fb}_Dev_VID&02045e_PID&080c&Col01


ここのやつがデバイスとマッチするとドライバがロードされる。VID/PID は PnP ID、Col01 は HID の Report Map の中のコレクションの Report ID ?っぽいがよくわからない。Collection もうまく一致していないとロードされない。

一致するドライバがみつかると C:\Windows\INF 以下に oemNN.inf oemNN.PNF としてコピーされる。次回からはここの .inf が読まれるのですぐ接続される。

  1. トップ
  2. tech
  3. Microsoft Universal Foldable Keyboard (US版) を買ってみたら辛い事実がわかった

背景

現在は CNC のコントローラとして Grbl + 自作のインターフェイスを使っています。Grbl の G-code インタプリタは必要な機能はほとんどどありますが、凝ったことをしようと思うと少し困ることがでてきます。

ということで、Beagle Bone Black と Machinekit (Linux CNC) での環境構築をぼちぼちはじめています (まだある程度設定しただけで動かせてませんが)。その過程で結局コードを読むハメになってるので覚書を残しておきます。

Machinekit とは何か

Machinekit は Linux CNC (EMC2) からの fork プロジェクトです。Linux CNC は x86 しかサポートしていませんが、Machinekit は ARM もサポートしています。細かい違いがいろいろあるみたいですが、実のところよくわかってません。

OSSのG-code実行機だと Linux CNC が最も高機能なようなので、これが動く環境がうまく作れれば、機能で困ることはなくなるはずです。

Machinekit / Linux CNC はどのようにして GPIO を操作するか

名前の通りなのですが、これらは Linux 上で動きます。Linux CNC の典型的な実行環境は、普通の x86 コンピュータにパラレルポートを付けたマシンです。パラレルポートをGPIOとして使用し、ステッピングモータドライバなどに送る信号を出力します。

全てソフトウェアで制御信号を生成するため、Xenomai という Linux カーネルにリアルタイム拡張を行うものを組込み、複数のリアルタイムスレッドを協調して動かすことでスムーズに実行できるようにしてあります。

具体的には

  • base-thread
    • 25μs ごとに起動
    • 最小の実行単位を扱うスレッドで、GPIO の実際の操作を行う
  • servo-thread
    • 1ms ごとに起動
    • 入力などを処理して base-thread で行う操作を決めるスレッド

という2つのスレッドがあります。実行間隔を書きましたが、実際には Xenomai を組み込んだ状態でも各スレッドが起動される間隔にはばらつきがあり、正確に起動されるわけではありません。「リアルタイム」はあくまで最悪の応答時間を保証しているだけです。十分余裕を持って行動するために処理の重さに応じて実行スレッドが分けられているわけです。

Machinekit と Beagle Bone Black

Beagle Bone Black は TI の ARM SoC である AM3359AZCZ100 がメインCPUの、Raspberry Pi に似たカードサイズ Linux コンピュータです。GPIO が豊富にあり、これに Machinekit をインストールすることで、単体でCNCコントローラにできます。

パラレルポートに依存した環境構築というのは今時ちょっとやる気が起きませんし、パラレルポートが増設可能なフル装備の Linux コンピュータを組み立てようと思うと結構コストがかかります。Beagle Bone だと単体で役目を果たすことができます。

Raspberry Pi ではダメなのか? という疑問があるかと思いますが、実は BBB にあって Raspberry Pi にはない重要な機能があります。それが PRU (Programmable Real-time Unit) です。

PRU は要するにメインのCPUと独立して動作できるマイコンです。メインCPUは1GHzですが、PRU は 200MHz の独自クロックで、メインCPUとは独立して動作します。

PRU の実装自体は独自の命令セットのアセンブリを書いて、TI 提供のツールでコンパイルして実行バイナリを得ます。なので、あまり高度なことをやるのは難しいですが、CNC の制御信号を出すというような用途にはまさにうってつけです。

フツーのPCと何が変わるか

Machinekit のリアルタイム処理は base-thread と servo-thread に分かれていると書きましたが、BBB の場合は base-thread は存在せず、servo-thread だけがあります。base-thread 相当の処理が PRU で独立して行われます。

Machinekit の hal_pru_generic ドライバにおいて PRU が GPIO を操作する間隔はデフォルトでは10μsとなっています。これは普通のPCのデフォルトの2倍以上の速度ですが、内部的には PRU 内でビジーループでえ 10μs を待つように実装されています。GPIO まわりのタスク処理が 10μs すなわち 2000 CPUサイクル以内ならば遅延することがありません。

現状では

  • stepgen
    • ステッピングモータの駆動パルス生成
  • pwmgen
    • ソフトウェア PWM
  • encoder
    • エンコーダーパルスをなんかするやつ(使ったことないです)

を PRU 内で実行できます。

PRU と PRU Low Latency I/O

AM3359AZCZ100 にはPRU Low Latency I/O というのがあり、複数の特定ピンの GPIO を PRU 内から r30/r31 レジスタへの読みかきによって1サイクルで行えるというものすごいものがあります。

一方で、PRU 内からだからといって PRU Low Latency I/O しか使えないというわけでもなく。普通の GPIO もそれよりはレイテンシがありますが読み書き可能です。

Machinekit の実装でもいずれのピン設定も利用可能です。前述の通り 10μs ごとの操作になるので、特に Low Latency ピンにこだわる必要はなく、この場合特にメリットもありません。

このへんは HAL の設定まわりになるので、ちゃんと動かせてからそのうち書きたいと思います。

  1. トップ
  2. tech
  3. Machinekit (Linux CNC) のアーキテクチャと、BeagleBone Black での動作

HID Proxy機能のあるドングルを使うとOSを介さずUSB HIDキーボードとしてBIOS起動時に認識させることができます。(BIOSというか、近年だと UEFI ですが)

 -

5.0 / 5.0

MM-BTUD43 (CSR8510 A10)

一部の BLE USB アダプタには HID Proxy モードが結構前から実装されているようです。これは CSR 社製のものです。たまたま手元にあったのですが、どうやらこれも HID Proxy モードをそなえいるようです。

経緯

BIOS 画面で BLE キーボードを使うため、HID Proxy モードのあるアダプタを探していました。当初そんなものはなさそうと思ってたのですが、最近になって以下のようなページを見つけました。

How to put CSR8510 A10 into HID Proxy Mode?

Switching Boot Modes
The initial boot mode is set by PSKEY_INITIAL_BOOTMODE. If this PS Key is set to 2 (HID proxy mode), CSR8510 A10 enumerates as USB HID device.

When the PC boots with its operating system and Bluetooth host stack, the Bluetooth host stack may reboot the CSR8510 A10 in mode 0 (standard HCI operation).
In this mode, the Bluetooth Host Stack handles the HID device functions.

Note:
Switching from HID to HCI is allowed in both HID Boot Protocol Mode and HID Report Protocol Mode configuration. In HID Report Protocol Mode, the USB report descriptors should include the feature report to accept the USB Set Feature request to accept the command from the host.

This report is defined as:
/* Feature report to enable Host Communications */
0x06, 0x00, 0xff, /* USAGE PAGE (Vendor 0xFF00) */
0x09, 0x01, /* USAGE (Vendor Page 1) */
0x95, 0x08, /* REPORT COUNT (8) */
0x75, 0x08, /* REPORT SIZE (8) */
0xB1, 0x02, /* FEATURE (Var) */


When in HCI mode - it is basically a 'pass-through' mode - no profiles, can with any Bluetooth 'flavour'.

When in HID Proxy mode - it is indeed meant for BLE only - using 2 instances of HID over GATT, one for keyboard and one for mouse.

対象は BLE デバイスのみです。もちろん事前にOSを起動した状態でペアリング(正確にはボンディング)してある必要があります。これによってデバイスに情報が保存され、HID Proxy モードでも通信が可能になります。

しかし、デフォルトでは PSKEY_INITIAL_BOOTMODE は 0x0000 のようで、HID Proxy として働きません。本来メーカーで設定する項目で、ユーザが書きかえられる部分ではありません。ただ、ちょっと面倒ですがデバイスを再設定することができました。

bccmd

Linux の bluez に CSR のデバイスを設定するためのコマンドが含まれており、これを使って HID Proxy モードを有効にします。

手元にさっと利用できる Linux が Raspberry Pi しかなかったので、Raspberry Pi で行いました。bluez が入ってさえいればなんでもいいはずです。おそらく VM 上で起動しても一時的にデバイスを VM 側に接続するようにすれば動くはずです。

USB にデバイスを接続した上で以下のコマンドを実行していきます。

# 現在のブートモードを確認
$ sudo bccmd psget bootmode
Initial device bootmode: 0x0000 (0)

# アドレスを確認
$ sudo bccmd psread -s 0
...
0x03cd - Initial device bootmode (2 bytes)
...

# アドレスにブートモードを書きこむ 0x0002 が HID Proxy モードらしい
$ sudo bccmd psset -s 0 0x03cd 0x0002

# 確認
$ sudo bccmd psget bootmode
Initial device bootmode: 0x0002 (2)

しかしどうも、OS起動後は HCI モードに移行というのは全くうまく動きません。HID Proxy から抜けられない。そして、 HID Proxy から抜けられないと bccmd がデバイスを認識しません (productId も変化するんですが、bccmd がそれに対応してないのでUSBデバイスを見付けられない)

ってことで、試したはいいけど戻せなくなってあせりました。

bluez の tools をコンパイル

bluez のツールとして /lib/udev/hid2hci という hid から hci に移行させるツールがあって、これで強制的に HCI にできるかと思いきや、できませんでした。調べているとシステムにインストールされているやつが古かったので、自力でコンパイルします。

http://www.bluez.org/download/

 sudo apt-get install libglib2.0-dev
 sudo apt-get install libdbus-1-dev
 sudo apt-get install libudev-dev
 sudo apt-get install libical-dev
 sudo apt-get install libreadline-dev
 sudo apt-get install libbluetooth-dev

本来必要ない依存もあるかと思いますが、これらを入れないと configure が通らず Makefile が生成されないので全て入れています。

wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.41.tar.xz
tar xJvf bluez-5.41.tar.xz
cd bluez-5.41
 ./configure
 make tools/hid2hci

全部ビルドする必要はないので hid2hci のみビルドしました。これで以下のように戻します。

sudo ./tools/hid2hci --method=csr2 --devpath=$(udevadm trigger  --subsystem-match=usb --attr-match=idVendor=0a12 --attr-match=idProduct=100b --verbose | cut -d '/' -f 3-)
# HCI モードに戻ったので bccmd が普通に使えるように
sudo bccmd psget bootmode

method=csr2 がポイントです。最新だとこのメソッドが使えるようになっていて、HCI モードに移行できます。

なお、このコマンドでやっていることは冒頭で引用した中にある feature report を送っているだけです。なので HID のレポートを送れさえすれば bluez をコンパイルする必要はないはずです…… が、さくっと feature report 送るみたいなのもなかなか難しいのでコンパイルしてみました。

HID Proxy モードを活用するためには…

ペアリングするときだけ HCI として起動してくれればいいので、基本的には HID モードでも良いかという気はします。ただ、キーボード1つにつき1つのBLEドングルが必要になりますので、Bluetooth デバイスが他にもあるなら OS 起動中はちゃんと HCI モードになってほしいところです。

ということで、OS起動時にhid2hci相当のことをやるコマンドを起動すれば問題なさそうです。しかしWindows でこれをやるのは若干面倒です。検索すると hid2hci.exe という CSR のツールがあることはわかるのですが、公式に入手する方法が見つけられませんでした (デバイススタックと一緒にインストールされるのかもしれませんが、OS 標準のスタックを使ってるのでインストールしたくありません)。他のところから怪しい .exe なんてダウンロードして実行するのは愚かなことなので、自分でなんとかします。

hid2hcix.exe

結局、自分で書くのが一番てっとり早いので、hidapi を使って書いてみました。mingw でクロスコンパイル環境にして OS X でコンパイルしています。

Linux には hid2hci があるのでいいとして、OSX でも無駄にコンパイルできるので、主要OSで HCI モードにできる安心感が生まれます。

hidapi がそのままだとキーボードのHIDデバイスに対して使えないので、1行だけ修正をいれてあります。キーボード・マウスのようなHIDデバイスはWindowsがOSレベルで握ってしまっていて、デバイスファイルを CreateFile できないという問題があるようです。また、キーボードやマウスには Feature Report のやりとりしかできません。

Linux の hid2hci をまるまる再実装したほうが便利かもしれませんが、HCI から HID に戻す実装は HCI にアクセスする必要があって面倒ですし、自分の環境だと CSR の CSR8510 A10 以外に入手できるものがないので、決め打ちの実装になっています。

レポジトリ内のコードだけでコンパイルも簡単だしこれで必要十分でしょう。これをOS起動時に自動実行するようにすれば、OS起動前はHID Proxy、OS起動後は Bluetooth ドングルとして働くことになります。

国内販売で CSR8510 A10 を使ってると確認できるもの

レビューとかを見るとプロトコルスタックをインストールしている記述が多かったりしますが、Windows 10 なら OS にプロトコルスタックがあるので不要です。自分ではインストールしたことありません。かなり古いレビューがずっと残ってるので注意が必要です。

 -

5.0 / 5.0

上にも書きましたが MM-BTUD43 は手元にあって、確認済みです。

プラネックス PLANEX Bluetooth USBアダプター Ver.4.0+EDR/LE(省エネ設計)対応 BT-Micro4 - プラネックス

プラネックス

4.0 / 5.0

PLANEX BT-Micro4 は公式に技術情報を公開していて、CSR 8510A10 であることを表記しています。これも手元にあって、確認済みです。

 -

3.0 / 5.0

ロジテック LBT-UAN04C1BK も CSR 8510A10 のようです。これは持ってないので確認してません。高いので特にこれを選ぶ理由はなさそうです。

ref

  1. トップ
  2. tech
  3. BIOS 画面でもBluetooth LE な無線キーボードを使いたい

BLE Nano に載ってる MDBT40 モジュールの認証情報: MDBT40

  • F1D 2402-2480MHz(40ch) 3.0mW/MHz
  • F1D 2405-2480MHz(16ch) 3.0mW

MDBT40 の最大出力は +4dBm。W換算すると2.5mW。少し余裕があるのは mW 単位での承認なんだろうか?

MDBT40P

Seeed Studio が MDBT40P を販売している。けど、メモリサイズが16KBなのか32KBなのか書いてなくて定かではない (たぶん16KB)

MDBT40P と MDBT40 の違いはアンテナで、P は Printed Circuit Antenna のことで、よくあるトレースアンテナ。MDBT40 のほうは積層チップアンテナ。

メーカー仕様書を見ると、積層チップアンテナでは Over 80mm、トレースアンテナでは Up to 60m と書いてあり、あきらかに電波の飛びは違うみたい。アンテナの性能が良いということは、同じ距離飛ばすために必要な送信出力が低いということですから、低消費電力に繋がります。

BLE Nano には MDBT40 が使われているけど、MDBT40の単体販売は ebay で多少あるぐらい。

MDBT40 シリーズはスペック違いがいくつかあるけど、BLE Nano に使われているような、チップアンテナ+256KB Flash+32KB RAM というモデルの単品販売は見つけられなかった。BLE Nano を買うしかない。

MDBT40P の技適は?

アンテナも含めての技適なので、アンテナが変わってる場合、技適が適用されているか改めて注意する必要がある。

メーカー仕様を見る限り、MDBT40P も、あるいは他の多少違うモデルに関しても「MDBT40」という統一モデルとして工事設計認証番号を取得しており、製品にマークと刻印があるので問題なさそう。

  1. トップ
  2. tech
  3. BLE Nano に載ってる MDBT40 モジュールのメモ

PowerShell がダメだったので、素直に Visual Studio 入れて C# 書くぞと思ったわけです。そしたらハマらず書けるだろと。検索したらいかにも動きそうなサンプルコードでてくるしね。

で2時間ぐらい試行錯誤したけど、ダメでした。

References に Windows.Devices を入れたりいろいろして、うまくいきそうだなと思ったけど、結局 await が動かない。Console Application で作ろうとしてるのが悪いのかなんなのかわからないけど、

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.HumanInterfaceDevice;
using Windows.Devices.Enumeration;
// WindowsRuntimeSystemExtensions could not be found
// using WindowsRuntimeSystemExtensions.AsTask;

namespace Foo
{

    class Program
    {
        const UInt16 USAGE_PAGE = 0x01; // Generic Desktop Ctrls
        const UInt16 USAGE_ID = 0x06; // Keyboard

        static void Main(string[] args)
        {
            Task.Factory.StartNew(async () =>
            {
                await new Program().run();
            })
            .Unwrap()
            .Wait();
        }

        private async Task run()
        {
            var selector = HidDevice.GetDeviceSelector(USAGE_PAGE, USAGE_ID);
            var devices = await DeviceInformation.FindAllAsync(selector);
            Console.WriteLine("%s", devices);
        }
    }
}

が書けないんですよ。IAsyncOperation に GetAwaitor がないから await できないって怒られる。よくわからんけど .AsTask() とインスタンスメソッド形式で WindowsRuntimeSystemExtensions を読んでみるけど、これがそもそもできない。

References に WindowsRuntime がないせいか?と思ったけど、Add References... には WindowsRuntime なんで微塵も出てこないんですよ。

で、そういや NuGet とかいう臭そうな名前のパッケージマネージャがあったなと思って、 Manage NuGet Packages... から WindowsRuntime を検索すると、あるわけですね。

ははーん。ようやく辿りついたぞ、って思うじゃないですか。意気揚々と Install ボタンをクリックします。Output を見てるとなんとなくインストールすすんでいる様子がみえます。で、画面の表示が更新されて Output が表示から消えたんで、インストール終わったんだなと思いました。しかしそこには何の変化もない Solution Explorer さんの姿がありました。References にも何も増えてない。一体何をインストールしたんだ?と思ったら、NuGet の画面をもう一度見ると、まだ「Install」のままなんですよ。

そこでまぁ1回ぐらいは失敗するよなと思ってもっかい Install をしました。また Output にインストールがすすむ様子がうかがえました。画面が更新されました。インストールされたはずですが何も変化がありません。もしやと思って、インストール終了と共に自動的に非表示になった Output 画面を見ると、最後の最後で

Could not install package 'System.Runtime.WindowsRuntime 4.0.11'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.6.1', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
========== Finished ==========

とか出てるんです。エラーメッセージもお世辞にも親切ではない。意味がわかりません。どうしようもないので諦めました。

さようなら Visual Studio。

いくつかのメモ

普段 IntelliJ IDEA を使ってるので、Visual Studio を使ってみると???ってなるところがかなりある。一言でいうと「おもてなし感がない」

  • using を手動で書かなければいけない? いきなりクラス名と書きはじめても一切補完されないし、自動的に using が書かれたりもしない。何かやりかたがある?
  • using を書いても References に自動的に依存が追加されたりはしない。その using がどのアセンブリに入ってるか把握して References に追加しないといけない。
  • using を書いても反映されるまで数秒かかり (別に低スペックマシンってわけじゃないのに)、赤い警告が消えないので「え? これ間違えてるの?」ってしばらく思うハメになる
  • ググって出てくる情報が大抵古い。Windows8 とかいう古代のOSの時代の情報がでてくる。WindowsRuntime を使うときに「このdllを追加しろ!」と「ほげほげを追加しろ!」とかひっかかってくれるんだけど、全部情報が古いので使えない。
  • エディタ上に赤線で警告がでるけど、キーボード操作で見ることができない?? マウスポインタをかざさないと見れなくて何がおかしいのがさっぱりわからない。

フツーにちょろっと、うまくいけば10分〜20分ぐらいで書けるコードのはずだったのに、時間を無駄にしたなあという感じで満足度が極めて低い…… 前向きに考えると、自分の技術力が低すぎて Windows アプリケーション作るのは不可能ってことがわかって良かった。

  1. トップ
  2. tech
  3. Visual Studio Community で Console Application を書こうとして挫折した