2020年3月16日月曜日

tf.kerasの自作モデルをNNCase v0.2.0 (kmodel V4)に対応させ、M5StickV(K210)上で動かす(2)



 卒業式が吹き飛んだ中の人です。今回も前回前々回に引き続き、NNCaseの話です。前回まででモデルの作成が終了し、変換の話になります。
2020/3/21 追記:Windows 10でもNNCaseが動きました!





2-1.NNCaseのダウンロード


 前回作成した.tfliteのモデルの変換には、kendryte提供のNNCaseを使用します。というわけでまずはダウンロードしましょう。
 今回使用する kmodel V4に対応するNNCaseはV0.2.0以降なので、最新版(2020/3/26現在)であるNNCase v0.2.0から各OS版の圧縮ファイルをダウンロードします。中の人はUbuntuを使用しているので、ncc_linux_x86_64.tar.xzを落としてきました。

2-2.NNCaseのインストール(?)

 落としてきたファイルをどこでもいいので解凍します。解凍した中にnccという名前のフォルダnccという名前のファイルが存在するはずです(おそらく./ncc/nccという形)。
 このフォルダごとトレーニング済みの.tfliteがあるフォルダに投げ込みましょう。これでインストール(?)は終わりです。

2-2-1.(補足)

 実はフォルダを移動させることなく、tfliteのパスと出力先のパスをファイル名とともにに指定してあげれば問題なく動きます(Linuxなら相対パスでも動作確認済み)。

2-3.コンパイルオプション

 モデルを変換する際のオプションは、以下のようになっています。(2020/5/31更新)

DESCRIPTION
NNCASE model compiler and inference tool.

SYNOPSIS
    ncc compile <input file> <output file> -i <input format> [-o <output
        format>] [-t <target>] [--dataset <dataset path>] [--dataset-format
        <dataset format>] [--inference-type <inference type>] [--input-mean
        <input mean>] [--input-std <input std>] [--dump-ir] [--input-type <input
        type>] [--max-allocator-solve-secs <max allocator solve secs>]
        [--calibrate-method <calibrate method>] [-v]

    ncc infer <input file> <output path> --dataset <dataset path>
        [--dataset-format <dataset format>] [--input-mean <input mean>]
        [--input-std <input std>] [-v]

OPTIONS
    ncc compile <input file> <output file> -i <input format> [-o <output
        format>] [-t <target>] [--dataset <dataset path>] [--dataset-format
        <dataset format>] [--inference-type <inference type>] [--input-mean
        <input mean>] [--input-std <input std>] [--dump-ir]
        [--dump-weights-range] [--input-type <input type>]
        [--max-allocator-solve-secs <max allocator solve secs>]
        [--calibrate-method <calibrate method>] [--weights-quantize-threshold
        <weights quantize threshold>] [--no-quantized-binary] [-v]

    ncc infer <input file> <output path> --dataset <dataset path>
        [--dataset-format <dataset format>] [--input-mean <input mean>]
        [--input-std <input std>] [-v]

    ncc -h [-v]

OPTIONS
    compile
        <input file>        input file
        <output file>       output file
        -i, --input-format  input file format: e.g. tflite, caffe, onnx
        -o, --output-format output file format: e.g. kmodel, default is kmodel
        -t, --target        target arch: e.g. cpu, k210, default is k210
        --dataset           calibration dataset, used in post quantization
        --dataset-format    datset format: e.g. image, raw default is image
        --inference-type    inference type: e.g. float, uint8 default is uint8
        --input-mean        input mean, default is 0.000000
        --input-std         input std, default is 1.000000
        --dump-ir           dump nncase ir to .dot files
        --dump-weights-range
                            dump weights range

        --input-type        input type: e.g. default, float, uint8, default
                            means equal to inference type

        --max-allocator-solve-secs
                            max optimal layout solve time in secs used by
                            allocators, 0 means don't use solver, default is 60

        --calibrate-method  calibrate method: e.g. no_clip, l2, default is
                            no_clip

        --weights-quantize-threshold
                            the threshold to control quantizing op or not
                            according to it's weigths range, default is
                            32.000000

        --output-quantize-threshold
                            the threshold to control quantizing op or not
                            according to it's output size, default is 1024

        --no-quantized-binary
                            don't quantize binary ops

    infer
        <input file>        input kmodel
        <output path>       inference result output directory
        --dataset           input dataset to inference
        --dataset-format    datset format: e.g. image, raw default is image
        --input-mean        input mean, default is 0.000000
        --input-std         input std, default is 1.000000

    -h, --help              show help
    -v, --version           show version
(https://github.com/kendryte/nncase/blob/master/docs/USAGE_EN.mdより引用)

 V0.1.0の頃とは異なり、compileとinferを指定する必要があります。inferはコンパイル済みのkmodelを実行するモードなので今回はパス。

2-3-1.ファイル・ファイルフォーマット・ターゲット

コンパイルオプションの<input flie>は入力ファイルなので、(入力ファイル名).tflite、<output file>は出力ファイルなので、(出力ファイル名).kmodelと入れておきます。
 同様に、-i(--input-format)には tflite、-o(--output-format)には kmodel としておきます。V0.1.0では-oには k210model と指定していたので注意してください。
 -t(--target)は指定しなくても大丈夫です。勝手にK210向けになります。(cpuに指定したときの挙動は未確認)

2-3-2.データセット・データセットフォーマット

--datasetは、データセット内の画像の入ったフォルダを指定しておきます。特には解説していなかったのですが、モデルのテスト用コードとtfliteへの変換用コード内で、テスト画像と出力画像を指定のフォルダ(./Img)に吐き出すようにしていました。今回はここを指定しておきます。これはパラメータの量子化で使っているようです。データ数が増えるほどよい性能になるかもしれませんが、コンパイルに時間がかかります。
 --dataset-formatは入力データがどのようなデータなのかを指定します。といっても、画像orその他の選択肢しかないです。今回は画像が入力なので image を選択しました。音声などの信号データや、2dデータだけどチャンネル数が3(もしかしたらor 1)ではないデータを使う際は raw にしてください。

2-3-3.インターフェース・入力データ

 --interface-typeは内部処理のデータ型を指定します。精度重視の場合には float を選択しますが、メモリの使用率が上がりKPUのアクセラレーションが受けられなくなります。
KPUを使用する場合は、uint8 一択になります。
 --input-meanと--input-stdは入力データの範囲調整に使われます。トレーニング時の入力データと同じ範囲になるようにしましょう。変換式は
y = (x - mean) / std
となっています。
(参考:https://github.com/kendryte/nncase/blob/master/docs/USAGE_EN.md)
NNCaseでは、最初に入力データを[0, 1]に変換してから上記の変換式を使うそうです。
0~1、-1~1、0~255の場合については、上記の参考URL内に値が出ています。

2-3-4.中間生成データ

 --dump-irはNNCase IRが生成する中間生成データを.dot形式でファイルにするかどうかのオプションです。

2-3-5.入力データ型

 --input-typeは入力データのデータ型を指定します。MaixPyで画像データを使う場合は、デフォルトの uint8 にしておきましょう。もし浮動小数点型の場合は float を指定しましょう。

2-3-6.その他

--max-allocator-solve-secsは最適な量子化のレンジの探索にかかる時間を指定します。デフォルトは60sですが、個人的に120sにしています(特に意味はない)。
 --calibrate-methodは最適な量子化のレンジの探索方法を指定します。デフォルトだと全レンジを使う no_clip になっていますが、 l2 を指定すると、時間はかかりますがよい量子化レンジを得られるようです。

2-3-7.2020/05/31追記

NNCase V0.2.0 Beta4の登場により,オプションが追加されています.
--dump-weights-rangeは,conv2dの重みパラメータの範囲を表示します.
--weights-quantize-thresholdは,conv2dとmatmulの重みパラメータの量子化をするための重みパラメータのしきい値を指定します.デフォルトは32です.これよりも大きい場合は,量子化しません.
--output-quantize-thresholdは,conv2dとmatmulの重みパラメータの量子化をするための出力要素数の閾値を指定します.デフォルトは1024です.これより小さい場合量子化しません.
--no-quantize-binaryは,すべての計算を量子化せずにfloatで行うオプションです.

2-4.コンパイルの例

 コンパイル例です(解説文書くの疲れた)。


./ncc/ncc compile Model.tflite Model.kmodel -i tflite -o kmodel --dataset ./Img/ -- dataset-format image --inference-type uint8 --input-mean 0 --input-std 1 --dump-ir --input-type uint8 --max-allocator-solve-secs 120 --calibrate-method l2

 Tensorflowでトレーニング・変換したModel.tfliteをModel.kmodelに変換しています。
 --dataset用のデータを./Imgに入れて置きました。.jpgや.pngのファイルをそのまま./Imgに入れるだけでよく、データセットの画像は0-1に正規化する必要はないです。
 トレーニング時には0-1に正規化していたので、--input-meanと--input-stdを合わせておきます。

2-5.次回予告

 次回は本編最終回で、M5StickVに実装していきます。
 MaixPyやKflashGUIのインストール・使い方は飛ばすので、ほかのところで探しておいてください。
ついに手に入れた、精密ナットドライバー
アキバとかではお目にかかれず、新宿のハンズで購入


©2020 shts All Right Reserved.

2020年3月12日木曜日

tf.kerasの自作モデルをNNCase v0.2.0 (kmodel V4)に対応させ、M5StickV(K210)上で動かす(1)



 最近は特に何もない中の人です。前回からの続きで、今回はM5StickV向けのモデルを作っていきます。
 コードについてはこちらから:https://github.com/shtsno24/DAE_for_M5StickV



1-1.ターゲットモデル

M5Stack+KPUの作例で多く出ているのがYOLOなどを使用した物体検出です。まあ同じものをやっても面白みに欠けるので、今回はCNNを用いたDeep Autoencoderを作成していきます。Autoencoderを端的に言えば、入力データと同じ出力データを得られるようにトレーニングしたモデルです。一見無駄に見えますが、モデル構造を工夫することで、画像圧縮・復元ができるようになります(特に意味はない)(セマンティックセグメンテーションや超解像のモデルに結構近いので応用重視で選んだ側面が大きい)。

 もう少し話すと、tf.kerasで容易にデータセットが構築できるCIFAR-10の入力画像をそのまま復元することにしました。モデルの入出力は32x32x3(トレーニング時は1x32x32x3)の画像になります(入出力のデータは0-1に正規化する)。

1-2.ライブラリ

 M5StickV向けのモデル作成にはTensorflowまたはCaffeが対応しているようです。今回は対応しているレイヤの多いTensorflowを使います。Tensorflowによる開発の場合、Tensorflow ->Tensorflow Lite -> Kmodelとなるので、Tensorflow Liteへの対応がカギになります。

NNCaseのアーキテクチャ。
資料は見当たらないが、ONNX・PaddlePaddle(百度のDLフレームワーク)も対応しているらしい。
(NNCase/README.mdより)

1-3.モデル作成前の準備

 Tensorflowをpipでインストールすればモデルの作成・推論はできます。トレーニングに関してはGPUが欲しいので、Google Colabを使うか、自前でGPU付きのマシンを準備したほうがよいでしょう。中の人は、ラボのUbuntuマシンにDocker環境を作りました。

1-4.モデル

 今回作成するCNNベースのDeep Autoencoderは、全層CNNで構成します。これはKPU
がCNN向けに最適化されているためであり(もっと言えば1x1 or 3x3カーネル、ストライド=1 or 2)、また全結合を使うよりもパラメータ数を削減し、小メモリ化を図るためです。(参考:NNCase/FAQ_EN.md)

今回作成したモデル全体図(tflite)。レイヤが確認できないほど長くてもメモリに載るのはありがたい。

今回のモデルはほぼオリジナルでNNCase/KPUのテストもかねて、必要以上に分岐・結合させたり、レイヤを増やしたりしています(そもそも無意味なタスクなので関係なし)。
 モデルを確認する際にはnetronを使いました。tf.kerasの.h5や.tfliteを読み込めるので、レイヤの種類の確認にはうってつけでした。

 モデルの作成で注意したいのが、使用できるレイヤの種類です。今回はtf.kerasを使用したので、kerasのレイヤからTensorflow Liteのレイヤに変換できるかが第一関門となります。このページを参考にしながら、対応するkerasのレイヤと紐づけていくのが楽でした。YOLO、UNetあたりなら、ほぼそのまま変換ができそうです。
 第二関門はTensorflow Liteのレイヤからkmodelのレイヤに変換できるかです。こちらはNNCaseのGitHubに一覧があるので、そこから対応するレイヤを確認しましょう。

コード:https://github.com/shtsno24/DAE_for_M5StickV/blob/master/Model.py

1-5.トレーニング

入力画像。実際は32x32の画像なのでものすごく小さい

 トレーニングは通常のtf.kerasを使った場合と同じです。今回は、訓練データ50000枚、検証データ10000枚で、100epoch回しました。バッチサイズは100枚とし、lossはMSE、OptimizerはAdamを使用しました。

tf.kerasモデルのトレーニング結果。輪郭がぼやけているが、雰囲気はとらえられている。

コード:https://github.com/shtsno24/DAE_for_M5StickV/blob/master/Train.py

1-6.TFLiteへの変換

 tf.kerasに変換したモデルを今度は.tfliteに変換します。このやり方は、ここを参考にするとわかりやすいです。参考例ではkeras付属のMobilenetを読み出して変換していますが、今回は自作のモデルを読み込んだうえで変換するので、書き方が少し変わってきます。

.tfliteの推論結果。tf.kerasの結果と大差ない。

コード:https://github.com/shtsno24/DAE_for_M5StickV/blob/master/Convert_to_tflite.py

1-7.次回予告

 .tfliteまで変換できたので、次回はkmodelへの変換となります(前回と今回でまだ本題に入っていない...)。



©2020 shts All Right Reserved.

2020年3月9日月曜日

tf.kerasの自作モデルをNNCase v0.2.0 (kmodel V4)に対応させ、M5StickV(K210)上で動かす(0)




 卒業も決定し、無事週5で研究室にこもっている中の人です。3月に予定されていた各種イベントが軒並み流れたため、研究もバイトもそっちのけでM5StickVで遊んでいました。(教授からオーバーワークかもよって言われました)。
 M5StickVで何をしていたかといえば、独自に作成したDNNモデルをK210内のKPU上で動かそうと悪戦苦闘していました。その時の苦労も含めて話していきたいと思います。


0-1.K210とKPU

 K210は、Kendryteが開発したデュアルコアRISC-Vチップです。内部構成はこんな感じ。

K210の概略。アクセラレータはKPU以外にもオーディオとFFT用が載る。(Image:Kendryte)

 このプロセッサの注目すべき(?)点としてKPUがあげられます。KPUはニューラルネット(おそらくCNNの演算をメインにしている)のアクセラレータであり、0.8TOPSの性能があるらしいです(参考:M5Stack - A series of modular stackable development devices)。
 今回はこいつを使っていきます。


0-2.KPUを開発する

 KPUはGPUなどと同じく、CPUのコードとは別の実行バイナリを作ってやる必要があります。そのためのツールとしてkendryteからNNCaseが提供されています。NNCase自体では学習モデルの作成は行わず、量子化とKPU向けの変換に特化しています。(PC向けのバイナリも吐き出せるようだが、今回は動作未確認)
 そのため、大元のモデルは自前で開発する必要があります。NNCaseの場合、Tensorflow/Tensorflow LiteまたはCaffeを使う必要があります(.tfliteが吐き出せればよいので、Torch->ONNX->tfliteとかでもできるはず)。


0-3.NNCase V0.1.0とV0.2.0

 NNCase V0.1.0からV0.2.0にかけての主な変更点は、GitHubのリリースを見てね(出落ち)。
 対応しているレイヤが増えたことや、コンパイルオプションが変わったことがあります。特にコンパイルオプションの違いはMaix Toolboxでのバグの原因になったりしてるようです。開発の最初、Maix Toolboxを入れていたのですが、結局tfliteの変換コードを作成し、直接NNCaseを使うことで解決しました。(一度作ればそこまで苦ではない)


0-4.開発環境

 リリースの内容的には、Win/Mac/Linuxがサポートされているようです。今回はTensorflow/Kerasによるトレーニング、Kmodelの生成をLinux(Ubuntu 18.04.3)、MaixPyによる開発をWindows 10で行いました。


0-5.次回予告?

 とりあえず導入は(中の人が力尽きたので)終わりで、次回はTensorflowによるモデル作成とTensorflow Liteへの変換の話の予定です。(ターゲットモデルは未定Deep Autoencoderになりました。)

 今回の一連の投稿は、モデル作成からM5StickVへの実装までの備忘録的なものにしていく予定です。
(V0.1.0の方は偉大なる先人のおかげで使用例や日本語資料も出ているのですが、V0.2.0の資料が少ない(日本語資料はほぼ皆無)という裏事情も。)

 この投稿ですくわれる方が一人でもいれば幸いです。
 


©2020 shts All Right Reserved.

2020年2月16日日曜日

MTOF171000C0使ってみた




 卒論も提出し終わったにもかかわらず,研究室にこもって何かしている中の人です.研究室ので使っているマシンでデータセット作成とかをやっているのですが,メモリを大量に使い果たすのでVPNでつなげず,結局来ないといけなくなっています.OTL

 さて,今回は秋月で売っているToFセンサの話です.ToFセンサといえばSTMicroelectronicsのこちらが有名?ですが,少しお高めかつ情報が出回っているのでパスです.(レジスタマップは果たして公開されたのだろうか)

1.仕様的なもの

センサ裏面


 今回使用するモジュールはFOXCONNが製造しており,SHARP製GP2AP01VT10F ToFセンサと謎マイコンが載っています.Arduino UNO向けサンプルコードモジュールのアプリケーションノートが公開されています.
 アプリケーションノートによれば,距離レンジ10cm-120cm(白壁),10cm-70cm(灰色壁)で,120cm±4%,70cm±7%となっています.
 通信方式は,UART/I2Cですが,I2Cで通信する際には電源,SCL,SDAのほかにCS代わりにTXDピン(センサ側の)を使用します(アプリケーションノートだと,RXDにつなげって書いてあるが,マイコン側って意味なのか?).今回はI2Cの方のみテストしました.
モジュール付属のケーブル.一回装着すると取りにくいらしい

 モジュールのピンアサインは,

  1. VDD(赤)
  2. GND(黒)
  3. TXD(白)
  4. RXD(茶)
  5. SCL(緑)
  6. SDA(黄色)

となっています.注意点として,付属のケーブルをモジュールにつけると抜けにくいらしく,無理やり抜こうとしてモジュールごと破損する可能性があるらしいです.

2.I2Cでおしゃべり

距離測定の図.M5StickVはただの壁

 ESP32でMTOF171000C0を使ってみましょう.何も考えずにピンを割り当てました.
  • VDD(赤) <-> 3V3
  • GND(黒) <-> GND
  • TXD(白) <-> IO25
  • RXD(茶) <-> 未接続
  • SCL(緑) <-> IO21
  • SDA(黄) <-> IO22
最初,TXDをIO12につないでいたのですが,うまく書き込めなくなりました(ESP32の仕様で,ブート時のモード決めとかで使うらしいです).IO25であれば問題なく動きました.
 アプリケーションノートに従うと,通信の流れは以下のようになります.

  1. TXD(CS)をLowにする
  2. センサのアドレスを送る(0x52)
  3. 距離データのはいっているレジスタを指定する(0xD3)
  4. センサのアドレスからデータが送られてくるのを待つ(2Bytes,上位8bitから送信)
  5. CSをHighにする

 距離が測定できない場合には,出力結果が"8888"になります.そうでない場合は,レジスタの値がそのまま距離(mm)になります.コードはこちらに上げておきました.

3.まとめ


 モジュール内でmmに直してくれるのはありがたい...のだろうか.マイナス点はSTMicroelectronicsのToFシリーズより性能が低いこととセンサ自体のデータシートが出回っていないことでしょうか.(未公開コマンドで精度や速度に関する設定ができるのかも)
 VL53L0Xに対しては,秋月価格で\2-300安いので少しお手軽です.(\1080->\780)
何も考えずにcmオーダで正確に測れることを考えると,こっちでもいいかもしれないです.

4.その他

  • データシートが英語・中国語(繁体字)併記.繁体字なので,雰囲気はつかめる.
  • SHARPからではなくFOXCONNから出ているのはなんでだろ(親会社一緒だけど)
  • UARTではオフセットの設定もできるらしい.I2Cは知らないけど,同じレジスタにアクセスすれば設定できる気がする.
  • 精度はまあまあ.20cmぐらいなら±3mm切ってくるレベル.
  • 距離が8888になる現象は,距離が遠すぎる場合にもなる.
  • センサ自体のレジスタマップはこちらも未公開.公開してほしい.

©2020 shts All Right Reserved.

2020年1月31日金曜日

DRV8830をESP32-DevKitCで動かした話




 卒論発表が終わった日にモータ回してる中の人です.発表自体は特に問題なく終わったので,あとは卒論を提出するのみです.ヤッタネ.
 今回はESP32でDRV8830を動かした話です.I2Cで制御できるMDとしては一番ポピュラーなICで中の人も何度か使っていますが,ESP32と一緒に使ったことがありませんでした.復習もかねて動かしてみましょう.



1.回路回り

 IC自体は絶対最大定格が7Vとなっていますが,実際は5Vあたりが上限になります(実はDACの関係で5V一択になります).ICの裏面にはGNDパッドがあるため,回路設計やはんだ付けの際には十分気を付けてください.
 VCCが1つだけなので,ロジック電圧とモータ電源電圧が一致するはず(と思いたい)です.ロジック電圧とモータ電源電圧が違う場合は,レベル変換のICや回路をロジック側に追加します.
 モータにかける電圧はDACで生成しており,0.48[V]から5.06[V]のまで57段階で調整できます.昇圧回路などはないので,この範囲をフルに使う場合は電源電圧を5V以上になります.フルにしないとあまり使えないので,結局モータ電源電圧は5V一択になります.(6Vとかを生成しても結局5.06Vで頭打ちになる)
 パスコンは0.1uFが最低になっていますが,10uFを突っ込んだ方が安定します.あとはモータの端子にセラコン直付けがでどうにかなります.
 I2C線のプルアップは様子を見つつやってください.単体で動かすならSCL/SDAともに10kで動きました.
 ISENSEの抵抗は適宜付けますが,電流制限がいらない場合はGNDに落としておきましょう.
A0/A1はアドレスの設定に使います.各ピンをGND/未接続/VCCのどれかに設定することで変えられます.
 FAULTnはレジスタ1(FAULT)と同期する形で,障害を通知します.使わないときは未接続にするか,抵抗を介してVCCにつないでおきましょう.障害が発生したときにはLowになるので,LED(と電流制限抵抗)をつけておくことでレジスタを読まなくても障害発生がわかります.

参考:シリアル・インターフェイス内蔵、低電圧モータ・ドライバ 日本TI

2.I2C

 ユーザが叩くI2Cのレジスタはわずか2本と,わかりやすい構造です.

2.1アドレス

 A1/A0ピンでアドレスを指定するのですが,データシート上ではアドレス(書き込み)とアドレス(読み込み)とありますが,DRV8830は7bitアドレスのはずです.
 これは,I2Cの仕様として,7bitのアドレスの後に読み込みか書き込みかを示すビットを付与する仕組みになっているためです.よくよく見てみると,同じピンの状態における読み込み/書き込みアドレスは1つ違いになっています.
 ArduinoのWire.hでは,最後の1bitを自動付与するので,アドレスはデータシートにあるものの上位7bitを書き込むことになります.(A1=A0=0だと0xC0>>1 = 0x60)

2.2レジスタ0(0x00)

 出力電圧や回転方向の指定はここで行います.
 ┌────┬──┬──┐
|D7- D2  |D1 | D0 |
 ├────┼──┼──┤
 |VSET    |IN2 |IN1|
 └────┴──┴──┘
 VSETがモータの電圧,D1/D0で回転の仕方を決めます.
 VSETは0x06から0x3Fまでの整数を設定します.もし電源電圧が0x3F(=5.06[V])より低い場合は,電源電圧以上の電圧を指定しても出力されません.
 D1/D0=0で惰性,1で逆転,2で正転,3でブレーキと,普通のMDの方向指定とあまり変わりません.

2.3レジスタ1(0x01)

 障害通知用です.
 ┌────┬────┬───┬──┬───┬──┬────┐
|D7        | D6-D5 | D4    | D3 | D2   | D1 | D0       |
 ├────┼────┼───┼──┼───┼──┼────┤
 | CLEAR |未使用 |ILIMIT|OTS|UVLO|OCP| FAULT  |
 └────┴────┴───┴──┴───┴──┴────┘
 D7に1を書き込むときは,D0が0になっていることを確認しましょう.障害が発生している状態でやっても意味ないですからね.

参考:シリアル・インターフェイス内蔵、低電圧モータ・ドライバ 日本TI
   I2Cの基本データフォーマット 電子工作室

3.動かしてみた


 とりあえず動かしてみました.昔作った基板にたまたまDRV8830が載っていたので,使いまわしてます.秋月で売っているDRV8830のブレークアウトボードレベル変換IC10uFセラミックコンデンサ10k抵抗x2,5Vレギュレータ9V電池あたりで代用ができそうです.
ソースコードはこちらから.

4.まとめ

 ロジック電源とモータ電源が分離していないなど電源回りに癖がありますが,それを除けば扱いやすいMDです.



©2020 shts All Right Reserved.

2020年1月25日土曜日

GS1502動かしてみた


 卒論発表の資料作っているはずの中の人です.最近はスライドの作成に手間取っております,はい. 今回は自宅で熟成を重ねたサーボモータの話です.

 サーボモータでよく使われているのはRCサーボ(SG90とその無限回転Ver.)とかだと思います.ですが,今回使ったサーボモータはリニアサーボモータという,別の種類のサーボモータになります.RCサーボモータは回転運動をしますが,リニアサーボモータは直線方向の運動をするものです.

1.とりあえずGS1502を眺める


GS1502.1円玉はデカいだけ(すっとぼけ)
 この手のサーボは2010年ごろには存在したようで,小さなRC飛行機やRCヘリ向けなようです.
 パットコネクタ周りを見た感じだと,SG90あたりとあまり変わらない制御ができるのではないかなぁと思いました.赤が+Vcc,黒がGND,白がPWMだと考え,動かしてみることにしました.


2.眺めたので端子を交換する

 一通り眺めたので,ここから作業開始です.手始めに,ESP32-DevKitCには使いにくそうなコネクタをQiに交換しましょう(2550とQiってどっちがメジャーな呼び方なんだろうか).
とりあえずぶった切る
Qi圧着して終わり
 交換自体はさほど時間はかかりませんでした.PA-09いいね.

3.動かす

 交換も終わったのでマイコン(ESP32を使用)とつないで動作確認です...

仕様一切知らんのだが

 ええ,仕様が全く分かりません.とりあえずCR1630ってICが乗っていたので調べたのですが,データシートが見当たらない...
 まあ最初の方でSG90と同じ制御だろって考えたので,そのままの方法で動かしてみました.とりあえずコードの方はこちらから.


なんもしてないのに

動きました


 これはブログを書けとの思し召しなのだろうかって思いましたが,おそらくRCサーボと同じ規格で使うことを想定しているため動いたと思います.あくまで推測ですが.
 となると,パルス幅は700[us]-2300[us]で,1500[us]に設定すると真ん中で停止する感じですね.ArduinoのServoライブラリでいえば700[us]が0[deg],2300[us]が180[deg],1500[us]は90[deg]に相当するので,今回作ったコードよりもライブラリを使った方が楽に動作確認できそうです.

4.最後に

 意外とすんなり動きました.やっぱり(仕様ががっちり決まってる)共通規格は偉大.あと,ホビーラジコン系の部品は精度がいい上に小さい部品もあるので,物理的に動くものを作るときは有力な選択肢になりそうです.

©2020 shts All Right Reserved.

2019年12月31日火曜日

M5StickVとESP32-DevKitC-32Dで双方向UARTやってみた



 大晦日も自宅にこもって高位合成している中の人です.PYNQ-Z2からUltra96 V2に乗り換えれば,簡単に速くなりそうなんですけどねぇ. さて,今回は積み基板になっていたM5StickVESP32-DevKitC-32Dを使って,UART通信してみた話です.



配線的なもの

 とりあえずピンアサイン的なもの.
────────────
 ESP32  M5StickV
━━━━━━━━━━━━
 GPIO16  GPIO35
────────────
 GPIO17  GPIO34
────────────
 GND    GND
────────────
 M5StickVの方はFPIOAの仕組みがあるので,UARTピンのアサインを間違えても入れ替えれば動くのですが,とりあえずこんな感じにしておきます.
 ESP32の方はUART2を使っていますが,UART0やUART1でも設定すれば使える気がします.

参考:SwitchScience ESP32-WROOM-32に関するTIPS


プログラム的なもの

 今回,ESP32はArduino IDE,M5StickVはMaixPyを使いました.まあUARTのテストだけなのでこれでいいかなって感じです.

コード全体はGitHubに上げておきます.最新版のArduinoでESP32のUART2を使うときは,何も宣言することなくSerial2を使うだけで,OKなようです.

 

結果

 115200bpsで動いた.
左:M5StickV,右:ESP32
参考:Wi-FiがないM5StickVを、M5StickCと繋ぎLINEに投稿してみるまでの手順

今年最後の投稿がこんな感じでいいものなのだろうか...

©2018 shts All Right Reserved.

2019年12月8日日曜日

にゃーん(異常検知しようとしてできたのか出来なかったのかよくわからない話)


0.初めに

 この投稿はMice Advent Calendar 2019の8日目の記事です.7日目はコヒロさんの2019年全日本大会で人権を取り戻した話でした.人権...僕も欲しい....



卒論のファイルの存在が虚無な中の人です.こんな時期にブログを書くなんて思っていなかったのですが,現役からの熱い圧力強い要望により書いています.今回は異常検知したかった話です.

1.異常検知とは

 異常検知(anomaly detection)は,"通常の動作として明確に定義された概念に準拠しないデータパターン"(wikiより)を検出することで,いろいろな分野で使われています.
 まあいつもの動き(狙った動き)と違うぞってことを見つけるって話です.

2.PID制御ぶるぶる問題

  マウスに限らず,限界感度法とかでPID制御のパラメータを決めている場合,パラメータを上げすぎると出力が発散(振動)することがあります.
見事に発散

別に適切なパラメータであれば問題はないのですが,どんな環境でも動くパラメータを見つけ出すのは至難の業.なので少し高めのパラメータをデフォルトに設定し,出力が発振しかかったらパラメータを下げるようにしてみました.

3.そうだ,検出しよう

さて,出力の発振を検出して...ってどうやって?ここで出力データをよーく見てみましょう.

出力とにらめっこ

何となくですが,比例制御で使う偏差の絶対値をとって,その値をテキトーな区間(半周期あたり)で積分すればいい気がしてきました.制御が荒ぶっているときは値が大きくなって,安定しているときは値が小さくなりそうです.あとはしきい値決めてぶった切れば勝ち確かな?

検出できた???

4.わたし,(誤検知)気になります!

3.で考えた検出方法にはある問題があります.アンダーシュート/オーバーシュートして安定している場合です.元データでは,加速度がノンゼロの区間の遅れが誤検知されています.勝ち確#とは.(※実はこの方法でもどうにか検出することもできたりできなかったり)

やっぱり駄目だったよ


 となると方針変更です.偏差を何か,入力データの変動のみを表すものに置き換えてやればできそうです.
 ある関数の変動を見るとすれば...ああ,微分なんてあったなぁ.まあ厳密に数値微分なんてする必要はないので,もういっそ引き算だけすればいいでしょう(やけくそ).

5.そして,よくわからないものへ

 さて,結果です.

さっきよりイケそう

差分だけならよさげなので,最初のデータと合わせて確認してみましょう.

イケたのでは
 
   とりあえず,誤検知が無くなりました.めでたしめでたし...なんてことにはならない.
実機にぶち込んで動いたら完全なる勝利です.さて,やってみましょう.

 
 あれ,思ったよりも誤検知多いのでは?とりあえずは安定して動いているので,良しとします.

結論.

 異常検知は難しい...が,マウス君はちょっとだけ安定するようになった.このやり方であってるかどうかは知らないです.もっといい方法があったら教えてください.

 Mice Advent Calendar 2019の9日目はべし先輩の未定です.""未定""です.(大事なことなので2回言いました)











おまけ : 偏差だけで異常検知はできるのか?

 3.で作った偏差だけを使うやり方では誤検知が多いという話をしました.が,実はそこで議論していないことがありました.しきい値です.
 具体的な値を言えば,3.の場合0.1をしきい値としていました.ここでしきい値を0.5に上げて比べてみましょう.

あれ,こっちもできてる

 どうやらうまく検出出来ているようです.ですが,4.の方法のほうがパラメータがテキトーでも成功しやすいと感じました.この辺の話はリソースとかの問題もあるので,一概にどちらのアルゴリズムがいいかを決めることはできませんが,まあ好きな方を選んでください.

おまけ2 : タイトルと内容について

タイトルと内容の決定のながれはこちらのツイート及びコヒロさんの2019年全日本大会で人権を取り戻した話の最後のほうを参照のこと.


©2019 shts All Right Reserved.

2019年9月17日火曜日

TinyFPGA BXをVSCode(+PowerShell)で開発する



 ブログのネタを探してさまよっていた中の人です。夏休みはマウスのコーディングやらバイトやらで忙しい毎日を送ってました。(今夏はアキバへ2桁回買い出しに行ってました。定期がなかったらヤバかった)
 今はこの記事を書きながら環境構築研究を始めています。圧倒的進捗のNASA。



 さて、今回のネタはちっちゃいFPGAをVSCode上で開発する話です。タイトルには(+PowerShell)って入ってますが、pipが入ってる(入る)ターミナルなら何でも大丈夫です。

0.TinyFPGA BXについて&開発の動機

 TinyFPGA BXはLattice Semiconductor Corporation製ICE40LP8Kを使ったFPGAボードで、その名の通り小さいのが特徴です。(AX2っていうもっと小さいのもある)

 サイズ感はArduino nanoやNucleo F303に近いです。
 このボードGUI環境でも開発ができるのですが、なんとPython2.xを使用しているのです!(インストールしようとしたら2.7.11を突っ込もうとしてきた)
 よって今回はPython3.x系で開発環境を整えようとした感じです。

1.今回の環境及び使うもの

  • VSCode 1.38.1
  • Python 3.7.4
  • pip 19.2.3
  • TinyFPGA BX
  • USB micro B ケーブル
今回はVHDLではなくverilogを使用します。(ビルドツールがVHDL未対応らしい)

2.インストール

最初は、TinyFPGA BX User Guideに従ってインストールを進めましょう。私が環境構築をしていて詰まったところは、

apio drivers --serial-enable

の前に

apio install drivers

をすることでしょうか。この辺りはそこまで難しくないはずです。
この時、一緒にverilogのExtensionをVSCodeに入れておくと.vが読みやすくなります。

Atomを入れろとなっていますが、今回は無視します。


3.実機実装

 FPGAの開発では、大体の場合シミュレーションを走らせてから実機実装しますが、面倒なので飛ばします。
とりあえず、サンプルコードを使いたいので、TinyFPGA BXのリポジトリをどうにかこうにかして落としましょう。落として来たら、apio_templateをフォルダコピーしておきます。(書き換えると面倒なので)

 コピーしたフォルダをVSCodeで開いたら、ターミナルを出して、

apio build

と打ちましょう。.vが間違っていなければビルドが通り、hardware.binが生成されているはずです。(ほかのファイルも同時に生成)



 ボードへの書き込みは、ケーブルでPCとつなぎ、リセットボタンを一回押した状態で、

tinyprog -p .\hardware.bin

と打てば書き込まれます。


書き込みがうまくいかないときは、User Guideの下の方に書いてあるブートローダのアップデートをやってみましょう。

参考:tinyFPGA-BX boardにTerminalのみでbuildとボードへの書き込みを行った




©2018 shts All Right Reserved.

2019年7月23日火曜日

matplotlibでマウスやらキーボードのイベントを取得する


 ブログ更新をさぼりにサボっていた中の人です.研究室とバイトとマウスに明け暮れたら,いつの間にか金と時間が溶けていました.
 私事ではございますが,大学院に進学することが決まりもう少しだけ学生でいられそうです.やったね(白目)

 それはさておき,今回はmatplotlibでマウスやらキーボードのイベントを取得する話です.

概略
 みんな大好きmatplotlibなのですが,実はマウスやキーボード,その他もろもろのイベントを拾うことができます.これによってグラフに表示されているデータをいじったりすることが可能です.

イベントの種類
 トリガとして扱えるイベントは以下の通り.
  1. button_press_event       : マウスのボタンが押されたら
  2. button_release_event    : マウスのボタンが離されたら
  3. draw_event                   : キャンバスが更新されたら
  4. key_press_event           : キーボードのボタンが押されたら
  5. key_press_event           : キーボードのボタンが離されたら
  6. motion_notify_event      : カーソルが動いたら
  7. pick_event                    : キャンバス内のオブジェクトが選択されたら
  8. resize_event                 : figureキャンバスがリサイズされたら
  9. scroll_event                  : マウスホイールが回ったら
  10. figure_enter_event        : カーソルがfigureの中に入ったら
  11. figure_leave_event        : カーソルがfigureの中から出たら
  12. axis_enter_event           : カーソルがaxisの中に入ったら
  13. axis_leave_event           : カーソルがaxisの中から出たら
参考:https://matplotlib.org/users/event_handling.html?highlight=event%20handling%20picking

使い方
 イベント発生時に動かしたい関数を事前に準備しておき,canvasに紐づける感じです.

#クリック時にカーソルの座標を取得する
def Click(event):
    print("x=%d, y=%d" % (event.x, event.y))

#紐づける
fig.canvas.mpl_connect("button_press_event", Click)

2020/8/17 追記:上記のmplの部分がmlpだったのを修正

eventはマウスカーソルの位置や選択したデータの値,マウスやキーボードの押したボタンなどを取得するために使うやつです.取得できるのは以下の通り

  1. x, y : canvas内のピクセル
  2. inaxis : カーネルがaxisを超えたかどうか(True/False)
  3. xdata, ydata : 選択されたデータ
  4. button : 押されていたマウスのボタン(None, 1, 2, 3, 'up', 'down')
  5. key : 押されていたキーボードのボタン(None, すべての文字,'shift', 'win', 'ctrl')


最後に
 便利機能が結構仕込まれているmatplotlibです.公式のサンプル等もあるので,そちらも参考にするといいと思います.


©2018 shts All Right Reserved.