ろこらぼ

僕の開発の手順とか実験結果とか感想とかをつらつら書き込んでいくお墓.僕の魂を成仏させるためのお墓です.いいね・ブクマ・コメント待ってます

TensorFlowの導入について

f:id:ryuga13tk:20190118172339j:plain

TensorFlowとは,Googleが中心に開発している機械学習を行うためのライブラリです.

今日はそれの導入について書いておきます.

 

 

(追記)すでにTensorFlowが導入してある人はこの記事へ

 

www.nekorokomemordm.info

 

 

 

 

TensorFlowとは

TensorFlowとは,テンソル(多次元配列)の処理のフロー(流れ)を記述して,最後にまとめて実行することができるライブラリです.

 

具体的には,変数や定数などを宣言した後に,それらを用いて計算をすると宣言をします.そして,最後に計算を実行しろと命令を出すと,宣言したとおりに計算を行います.
最後に計算をするというのが特徴ですね.

これを用いて,深層学習をします.

まずは導入から.

 

 

導入(Windows)

 Windowsの場合は,Anacondaを使います.

www.anaconda.com

 

Anacondaは2019/01/18時点では,Python3.7を選びます.

インストールは特に書くことがないです.

 

次にGUIで仮想環境を構築します.

「Anaconda Navigator」を起動して,[Environments]→[Create]→[Create new environment]で,[Name]はすきにしてください.
[Packages]は[3.5]で,[Create]を押せばそのうちできます.

 

次に,右向きの▲を押して,[Open Terminal]をクリックします.

すると,コマンドプロンプトが起動するので,

CPU版のTensorFlowなら[pip install --upgrade tensorflow]

GPU版のTensorFlowなら[pip install --upgrade tensorflow-gpu]

でインストールができる.ただし,GPU版なら,CUDAとcuDNNが必要になるので,自分で調べてね.

次は,Jupyter Notebookとその他のライブラリをインストールします.

[conda install jupyter]

[conda install -c conda-forge opencv]

 

これで,Jupyterが動いて,PythonでTensorFlowがインポートできれば導入完了.

インポートはCPU,GPU関係なく,[import tensorflow as tf]

とかで.

 

ちなみに簡単な計算をさせてみたいなら,

import tensorflow as tf

a = tf.Variable(1, name = 'a')
b = tf.constant(1, name = 'b')
c = tf.assign(a, a + b)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run([c, a]))
    print(sess.run([c, a]))

 

 で動かせる.

 

導入(Ubuntu)

Ubuntu使ってる人は,やり方わかるだろうし,頑張って.

 

 

なんて冗談で,Ubuntuは基本的に流れが同じで,Pythonのバージョンを合わせて,TensorFlowをインストールして,必要ならJupyter Notebookをインストールすればすぐにできそう(やってない).

 

 

 

実際に動かしていくのはまた今度やっていきます.

現場で使える! TensorFlow開発入門 Kerasによる深層学習モデル構築手法 (AI & TECHNOLOGY)

現場で使える! TensorFlow開発入門 Kerasによる深層学習モデル構築手法 (AI & TECHNOLOGY)

 

 

STM導入からLチカまで

 

1 STM32マイコンとは

STM32マイコンとは,ARMのコアを積んだとっても賢いマイコン.

また,ARM-Cortex-M3を積んでいて,自分たちに最も近いものがNucleoシリーズ.これが,STM32マイコン.今回は,NucleoをMbedとしての開発ではなくて,HALでSTM32としての開発をまとめる.エンコーダを読み,それをUARTで吐き出すなどである.

2 対象ソフトインストール

開発手順としては,STM32CubeMXというソフトで,対象マイコンとそのマイコンで使用するペリフェラルの設定を行い,そこからコードを排出する.そのコードの中をTrueStudioで編集・実行・デバッグをする.STMStudioというものも用いてデバッグを行う.



◆下記サイトより,STM32CubeMXをダウンロードする.

https://www.st.com/ja/development-tools/stm32cubemx.html

 

先に,ほかのソフトウェアもダウンロードしておく.

◆TrueStudioをダウンロード.

https://www.st.com/ja/development-tools/truestudio.html

 

◆STMStudioをダウンロード.

https://www.st.com/ja/development-tools/stm-studio-stm32.html

 

すべて要会員登録である.

インストールに際して,注意点などは特にない.

しいて言うならば,TrueStudioをインストール中に,ドライバのインストールが割り込んでくるので,OKしておくこと.

f:id:ryuga13tk:20190107091223p:plain

関連付けるかどうかは,任意でOK.

 

3 プロジェクトの作り方

STM32CubeMXとは,STM32はレジスタをユーザが操作して,制御することができるが,その設定部分を代わりにやってくれるもの.

STM32CubeMXを起動すれば”New Project”をクリックして,ウィンドウを呼び出す.その際に,初回もしくは環境によってはダウロードが発生する.

f:id:ryuga13tk:20190107091311p:plain

画面左上に”MCU Selector”と”Board Selector”があるので,”Board Selector”を選択.”MCU Selector”では,マイコンではなくCPU単体での開発になる.”Board Selector”であれば,ボードが使用しているST-LINKやLED,PCとのSerial部分のペリフェラルを事前に設定してくれているので,明示的にどのピンがデフォルトで使用中であるかがわかる.

今回は,諸事情によりNucle-F411REを用いた開発手順をまとめる.

まず,”Board Selector”で,F411REと入力.

f:id:ryuga13tk:20190107091322p:plain

出てきたボードをダブルクリックしてプロジェクトを作成する.その際に,ボードにデフォルトでついているペリフェラルを使うかどうかと聞かれるのでYesと回答しておく.

f:id:ryuga13tk:20190107091340p:plain

まずはLチカから.出てきた画面は,CPUの各ピンに役割を設定するためのツール.左側からいじれば,ペリフェラルごとに設定ができる.

それじゃ,まずは下のほうにあるPA5がGPIOに設定されていることを確認する.

f:id:ryuga13tk:20190107091353p:plain

普通にGPIOを設定するだけではなく,右クリックして”Enter user label”を選べば,ユーザでピンの名前を設定することができる.

なので今回は,以下のように設定してやってみる.

f:id:ryuga13tk:20190107091406p:plain

今回はボード上についているブルーボタンも使う.CPUの左側一番上にあるB!~~を使うが,GPIO_Inputに,名前もB1_Blueに変更しておく.

f:id:ryuga13tk:20190107091418p:plain

 

f:id:ryuga13tk:20190107091440p:plain

これは,CPUや各ペリフェラルのクロック数を設定する画面であるが,まあ,設定できるところは最大にしちゃってもいいが,大人になったら消費電力のことも考えて,最適な値になるようにしなくちゃいけない.今回はデフォルトのままで行う.

 

Configratinoでは,各ペリフェラルの詳細設定を行うが,今回は何もいじらないのでパスしておく.エンコーダを読むときになれば,設定することになるので,その時に細かく書いておく.

f:id:ryuga13tk:20190107091458p:plain

 

 

最後の画面である.ここでは,実際に生成するコードに関しての設定を行うことができる.

その前準備としてメニュータブのProjectから設定を呼び出す.

f:id:ryuga13tk:20190107091536p:plain

 

Project NameをEX1GPIOにしておく.Project Locationは任意の場所でOK.

Toolchain/IDEをTrueStudioで設定する.

f:id:ryuga13tk:20190107091601p:plain

 

ここで,もしもTrueStudio以外の状態でコードを生成した場合,不具合だと思うが,STM32CubeMXのプロジェクトも最初からやらないと行けなくなる.

f:id:ryuga13tk:20190107091620p:plain

 

Code Generationで.このようにチェックを付けておく(なんとなく便利だから).

こうすることで,本来だとmain.cに書かれるペリフェラルのinit関数をペリフェラルごとに分散してくれる.

f:id:ryuga13tk:20190107091639p:plain




最後にこれをクリックすることで,任意のディレクトリにコードを生成する.

 

そうしたら,TrueStudioを起動する.

 

 

4 コーディングの方法(Lチカを行う)

1 TrueStudioの使い方

TrueStudioを起動すれば,メニュータブのファイルをクリックして”Open project from filesystem”をクリックして,ディレクトリ-(D)をクリックして,STM32CubeMXで作成したプロジェクトのディレクトリへ移動する.

f:id:ryuga13tk:20190107091658p:plain

 

プロジェクトの名前がEX1GPIOなので,そのフォルダをクリックしてひらく.

この時にそのプロジェクトがあり,チェックが入っていることを確認したら終了をクリックする.

そしたら,プロジェクトが追加されるので,EX1GPIOの中のsrc直下のmain.cを開く.

f:id:ryuga13tk:20190107091718p:plain

 

あとは,whileの中のUSERCODEBEGIN~USERCODEENDまでにコードを書く.こういったものがいくつかあるが,範囲外に書くと,STM32CubeMXで再びコードを排出したときに,書いたコードが消えるので注意を.



main関数の外にグローバル関数として,ButtonStatusを宣言しておく.

/* USER CODE BEGIN 0*/
int ButtonStatus;
/* USER CODE END 0*/

 

while内にこのように書く.

 while (1)
 {
 /* USER CODE END WHILE */
 /* USER CODE BEGIN 3 */
 ButtonStatus = HAL_GPIO_ReadPin(B1_Blue_GPIO_Port, B1_Blue_Pin);
 }
 /* USER CODE END 3 */



実行してみる.

トンカチマークでBuildして,虫のマークでデバッグを開始できる.

f:id:ryuga13tk:20190107091745p:plain

デバッグを開始して,デバッグを切って.

デバッグを押して,次はSTMStudioを使う.

 

2 STMStudioの使い方

STMTStudioを起動して,下記マークをクリックして,プロジェクトの.elfファイルを読み込む.

任意のディレクトリの中のDebugフォルダに.elfがあるので,それを読み込む.

f:id:ryuga13tk:20190107091808p:plain

するとこのように,出てくるので,この中からButtonStatusを探し出す.

ButtonStatusを見つけたらクリックして,右側のImportをクリックする.

ここに表示される変数は,すべてグローバル変数なので,モニタリングしたい関数はグローバルで宣言すること.また,宣言時に以下のように宣言すると,アドレスがおかしくなる.

int a, b, c;
------------------
int a = 0;
int b = 0;

f:id:ryuga13tk:20190107091834p:plain

 

Importすると,このようにButtonStatusが移動する.

これを,ドラッグアンドドロップする.

f:id:ryuga13tk:20190107091848p:plain

すると下のほうにButtonStatusと出てくる.ここまで終われば,

f:id:ryuga13tk:20190107091903p:plain

これをクリックしてデバッグを開始する.

そして,ボードのボタンを押すと・・・

f:id:ryuga13tk:20190107091919p:plain

このように値が動いているのがわかる.



これで,STMStuioはいったん終了する.エンコーダを読むときにもう一度扱う.

f:id:ryuga13tk:20190107091932p:plain

また,ここのVar Viewew 1 asを設定すれば,Curb以外にbar graphとtableで値を視認することが可能である.

では次にGPIOをいじるので,TrueStudioに戻り,whileの中をこのようにする.

 

 while (1)
 {
 /* USER CODE END WHILE */

 /* USER CODE BEGIN 3 */
 ButtonStatus = HAL_GPIO_ReadPin(B1_Blue_GPIO_Port, B1_Blue_Pin);
 HAL_GPIO_WritePin(GreenLED_GPIO_Port, GreenLED_Pin, !ButtonStatus);
 }
 /* USER CODE END 3 */



もう一度Buildして実行をする.

これでボタンを押すとボード上のLD2がボタンに合わせて点滅することが分かる.

基板をElecrowで発注した話

どうもこんにちは.

今日の内容は僕の魂を成仏させるための活動の一環です

 

タイトルの通りですがまあ.
実は個人的な話ですが,基板の設計が趣味なんです.
言葉の通りの意味で,大意はありません.
つまるところどういう意味かというと,設計して満足しておしまいなんですよね.

 

ただ,今回は,ある方とお話しして,Elecrowでの発注方法を教えていただいたので,せっかくだから発注してみようかな・・・?ってことで・・・・・・

発注するために基板を設計して発注しました(わーい).

 

(11月28日現在,基板の外形データに初歩的なミスがあり,しょんぼりしていますが...)

 

 

 

これが,今回設計した基板です.ちなみにKiCADです.

f:id:ryuga13tk:20181128143527p:plain

青地の部分には僕の名前と,バージョンが書いてあるので伏せてます.
これは,I2Cマルチプレクサで,同じアドレスのセンサー5つと通信するためのモジュール基板です.


今回は発注するための設計なので,表面実装とか,普段なかなかできないような設計をこれでもかっていうぐらいにしました(ふーふー)
ビアとか,表面,裏面,表面実装がおおいので,一般家庭じゃ難しいのですよね.なので,外注!

 

サイズとしては,50x80ぐらいです.
KiCADだとガーバーデータの拡張子を変更する必要があったので,今後もElecrowを使うならスクリプト組んでもよさそうだなっていう気持ち.

 

一応提出した段階で,すぐに発注して,現在制作中らしいので,待っているところです.
ちゃんと実物ができるのか不安ではあります・・・.配線ミスとか,なければいいのですが...(ないはず)
ただ,外形データで,まさかの設計ミスがあり,そのミスが,配線が重なってるっていうもので,KiCADの3Dビューアーでは,外形認識されず,外形が生成されなかったので....製造されるか心配です...

 

個人的にはElecrowもしくはPCBGOGOを使っていこうかなって思った次第です.
一個人としては,PCBGOGOは少し高いので,手が出ないなぁっていう気持ちです

 

 

提出後のサポートがしっかりしているところがいいですね.

 

 

11/30日現在追記
昨日製造した基板の写真を送ってもらい,ちゃんと基板が製造されていることを見ることができ,とりあえず一安心といったところです

 

12/22日現在追記

基板が届いて(2週間ぐらい前?),部品の実装,一部動作確認完了といったところです.

 

エンコーダについて

PPR(plus per rotation)が100のエンコーダがあるのですが,
ppr100だと,400パルスだお.と言われ「へっ!?」ってなったことがあって調べてみたのですが,
A相,B相は回転の方向を調べるためのものだと思っていたら,それ以外にも分解能が上がるっていう特徴があるみたいで.

sm_201204avago_encoder-6.jpg


A,B相の信号を1と0で表すとその表し方が

enc1-240x300.jpg
この図より4通りあることがわかります.
そうすると,A相B相の1パルスで4パルス分と言えるので,
PPRをKとすると4Kになるわけです.


そのことを考慮してmbedで書いてみました.

まず,ヘッダーファイルが

#ifdef __encoder_h__
#define __encoder_h__
 
#include "mbed.h"
 
class encoder{
public:
    encoder(PinName A1, PinName B1, int ppr);
    void getSetEncoder();//** mainのループで必ず毎回呼び出す!!!! **
    int getPpr();
    int getRotation();
    int getResolution();
private:
    int _ppr;
    int _resolution;
    int _rotation;
    };
 
#endif



cppファイルが

#include "encoder.h"
 
void encoder::encoder(PinName A1, PinName B1, int ppr){
    DigitalIn A(A1);
    DigitalIn B(B1);
    _ppr = ppr;
    _resolution = 0;
    _rotation = 0;
    A.mode(PullUp);
    B.mode(PullUp);
    i = 0;
    }
    
void encoder::getSetEncoder(){
    if(A == 1 && B == 1){ a = 0; }
    else if(A == 0 && B == 1){ a = 1; }
    else if(A == 0 && B == 0){ a = 3; }
    else if(A == 1 && B == 0){ a = 2; }
 
    if(b == 0 && a == 0){}
    else if(b == 0 && a == 1){ k++; }
    else if(b == 0 && a == 2){ l++; }
    else if(b == 0 && a == 3){ }
    else if(b == 1 && a == 0){ l++; }
    else if(b == 1 && a == 1){ }
    else if(b == 1 && a == 2){ }
    else if(b == 1 && a == 3){ k++; }
    else if(b == 2 && a == 0){ k++; }
    else if(b == 2 && a == 1){ }
    else if(b == 2 && a == 2){ }
    else if(b == 2 && a == 3){ l++; }
    else if(b == 3 && a == 0){ }
    else if(b == 3 && a == 1){ l++; }
    else if(b == 3 && a == 2){ k++; }
    else if(b == 3 && a == 3){ }
    b = a;
    _resolution++;
    i++;
    if(_resolution % _ppr == 0){ rotation++; }
    }
int getRotation(){
    return rotation;
    }
int getResolution(){
    return resolution;
    }

というようになっています.
パルスを4Kとした時,パルスの合計を返す関数と,
回転数を返す関数を書いてみましたが,
正直使うというよりエンコーダのことを深く知るのに書いてみただけなので,効率の良し悪しについてはまあ知らん.
もっといい書き方があるのは知ってるけど,まあいいかって感じで.

STM32の開発中に困ったんやけど・・・

どうもこんにちは.

この記事は二言三言だけ言って速攻終わるので,ふーん,ほーんって感じで見てください.

 

僕個人の開発環境が,家のデスクトップPCと持ち運び用のラップトップなのですが,特にGitで連携しているわけでもなくて(していた時期もあります),今までそれぞれその都度プロジェクト作ってコードを切り貼りしていたんですよね.

それで同じようにやったら,TrueStudioでコンパイルができても書き込み,デバッグができなくて頭抱えてたんです.

それでよく見てみたら,プロジェクトのディレクトリが記号と数字のエンコードされた状態になっていたんですよね.
それでああ,これ見たことあるなぁ・・・って思って,気づいたんですけど,ディレクトリが漢字だったんですね.

どおりでおかしいわけですよねぇ.


はい,締めです.


アプリケーションによっては,日本語に対応していないもの(少し前のKicadもそうでしたね)があるので,
ディレクトリ名はできるだけ英語にしましょうっていうことですね(◍•ᴗ•◍)

STM32F303K8T6とHALのSPIでL3GD20を動かした

どうもこんにちは.

今日はSTM32とHALのSPIを使ってジャイロセンサL3GD20を動かしてみましたので,それのまとめをします.

コードに関しては,諸事情により,パブリックに公開するわけにはいかないので,もしもほしければTwitterでDMください.

  1. 開発環境
    ・Windows10.
    ・System WorkBench for stm32.
     stm32のコーディングを行い,書き込む.
    ・CubeMX.
     GUIでできるあれ
    ・Arduino IDE.
     これはセンサデータを可視化するツールです.
    ・STM32F303K8T6が乗っているNucleo.
     スペックはググって.
    ・L3GD20.
     ・XYZ軸ジャイロセンサ
     ・分解能は16ビット
     ・2.4V~3.6V動作.
     ・IO電圧は1.8~電源電圧まで
     ・測定範囲は±250/500/2000dps(°/sec)
     ・インターフェースはI2CまたはSPI.
    以下画像の緑色の基板がL3GD20です.
    f:id:ryuga13tk:20180907044004j:image
    これは僕が設計したセンサ開発評価ボードです.
    おいおいは表面実装のSTM32F303K8T6を乗せるつもりです.Nucleo君とはおさらばの予定です.

    スペックとしては,ジャイロセンサL3GD20,CANのレシーバでMPU2515,エンコーダを読むためのピンを用意してあります.
    USBは100円ショップに売っている光るあれです(データ通信できるものこれしかなかった...).

  2. 開発手順
    まずはCubeMXの画面で以下のようにSPIとUARTの設定をしています.

    f:id:ryuga13tk:20180907042753p:plain


    CANとか関係ないやつも含まれていますが,まあ今後開発していきますよ.
    今回使うのは,下部のSPIの設定とUARTの設定.
    ちなみにSTM32とTeratermを使ってprintfを実装しているのですが,順序が逆転しますが今度投稿します.気になる人は調べてください.

    SPIの設定はこんな感じ

    f:id:ryuga13tk:20180907043011p:plain



    これをworkbenchへコード化して,SPIの実装をすれば完成です(パブリックに公開できない部分です).

  3. 結果
    動かしてみた結果が

    f:id:ryuga13tk:20180907043242p:plain

    これです.
    この画面はArduino IDEというツールを用いてセンサデータをグラフ化しています.
    ちゃんとジャイロが取れていますね.ちなみにセンサは各速度を出力しますが,角度になるようにしています.また,移動平均フィルタをかけています.

  4. 考察
    センサとしては応答性もそれなりに良くて,きれいな値を出すなっていうイメージでした.

    f:id:ryuga13tk:20180907043630p:plain
    これが各速度の生データです.0の時はきれいに0を出すので,大人しい子ですね.
    ただまあ,このセンサも例に漏れず,ドリフト角がそれなりにあることがわかったので,カルマンフィルタあたりを実装する必要があるなっていう感じです.
    元々カルマンフィルタ実装のために作ったセンサ基板だったので,やっと本題に入れるなって感じですが.
    まあ,簡単に角度を算出できるとは思ってなかったので,センサの動作確認とセンサデータの確認ができて満足です.


    次回からはカルマンフィルタの実装をしていくつもり(つもりはつもり)です.

ROSの開発を通して

ROS1を使ってて,ROS2も同じように使えるっていう話だけど,何がどう違うのかわからなくて,とりあえず自分の学んだ限りでの知識でROS1の部分についてまとめてみる.

  1. 概要
    使ってみた実感でのROSをまとめてみる.まずROSはロボットを制御するためのツールで,一部しかないがユーザーに対してサポートしてくれるものであるなっていう感じ.
    ROSはノード間の通信やセンサーのドライバーとか,ほかの機器との通信(センサ含むカメラとかDepthカメラLRF)をサポートしている.

  2. 開発の順序
    まず環境はLinuxであること.OS Xは知らん.
    今自分の環境はUbuntu 16.04(LTS)にROS Kineticを乗せてる.Lunarとかでもいいけれど,ネットにある記事数が違ったり,センサーによってはROSのバージョンに対応していなかったりするから,ダウングレードも必要.
    インストールはROS Wikiか過去記事から

    英語->kinetic/Installation/Ubuntu - ROS Wiki

    日本語->ja/kinetic/Installation/Ubuntu - ROS Wiki

     

    www.nekorokomemordm.info

     

     


    インストールすれば,あとは自分でパッケージ(ロボット等を制御するためのメインブレイン部分)を作っていく.

    開発ではcatkinを用いていて,コーディング後,ビルドの対象をCMakelistに書き込んで,ビルドしてマスターを起動して各ノードを実行する.

    ノードひとつひとつにセンサー・機器に対しての通信とか,データ処理とかを担当させてる.
    各ノードはmessage, service, actionで通信ができる.通信に用いるデータ型はユーザー自身で定義することも可能.
    実行しなければならないノードが増えてくれば,launchを使って幾つものノードを一度に実行して楽に行う.

  3. 使ってみた感想
    開発において作成したプログラムはもちろん,通信に用いるデータ型などはCMakelistに書き込む必要があり,それをいちいちするのも面倒くさいなっていう風に感じた.githubで他人のコードを使いまわすことができるので,楽に開発できるらしいが・・・そこまでじっくり開発した経験がないので知らん.

    あと去年(NHK学生ロボコン2018に向けてのロボット)の開発中,ロボットのセンサデータをフィードバックする必要があった時に,基本的にC++でコードを書くのだが,センサデータを可視化するツールでPythonのMatplotlibがどうしても使いたいときがあった.その時は,簡単にノード間の通信ができて,簡単にセンサデータを可視化できた.楽ちんだった.
    今なら,C++でRvizとかなりなんなりを使って,もっと楽に簡単に実装する.