2018年12月11日火曜日

MatplotlibにGUI(Tkinter)を組み合わせる話




 本記事はMice Advent Calendar 2018の11日目の記事です.昨日の記事はNse先輩のブラウザ上で動く無償3D-CAD「Onshape」を使おうでした.データの引継ぎをしなくてもいいのはなかなか魅力的ですね.しゅごい.

 紹介遅れました,全日本終わったのにブログすら書いていなかった中の人です.ステッパーマウスで40位という順位をどう見るかは人によって変わるかと思いますが,5本中4本完走したんでまあ悪くはないかなって感じです.



 さてさて本題に戻りまして,Matplotlibのそこそこ楽な描画機能があるのでシミュレータとして扱うのは楽なのですが,GUI機能が限られているためボタンを追加して再描画するといったことはMatplotlibだけでは出来ません.
 そこでMatplotlibの拡張機能を使用してPythonのGUIライブラリであるTkinterと連携し自分でGUI機能を追加しようというのがテーマです.連携もなにもMatplotlibがTkinter使ってるんだからできるに決まってるなんて思うんじゃないゾ

一応本記事中のコードはGitHubに上がっているので参考にしてください.

1.基本となるコード


 この記事ではこのコードを基本にやっていきます.

#-*-coding:utf-8-*-
"""
参考 http://b4rracud4.hatenadiary.jp/entry/20181207/1544129263
"""

import numpy as np
import matplotlib.pyplot as plt

gridSize = 2 #マスの数を指定

if __name__ == "__main__":
    try:
        plt.gca().set_aspect('equal', adjustable='box')
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出t


        #区画の描画
        for i in np.array(range(gridSize)) * 90.0:
            plt.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
            plt.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color="gray", linestyle="dashed")

            #斜めの線の描画
            if (i / 90.0) % 2 == 1:
                plt.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                plt.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color="gray", linestyle="dashed")

                plt.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                plt.plot(np.array([i, 0.0]), np.array([0.0, i]), color="gray", linestyle="dashed")
       
        plt.show()
    except:
        import traceback
        traceback.print_exc()
    finally:
        input(">>")#エラー吐き出したときの表示待ち

このコード自体はMice Advent Calendar 2018の7日目の記事の迷路の描画をnマス対応にしたものです.今回はこの"nマス"をGUIから指定して描画できるようにします.(わからなかったらリンク先を見よう!)

2.Tkinterにグラフを載せる


 まずはグラフをTkinterの描画機能で表示させます.Matplotlibの開発元が公開しているコードに従っていじっていきます.流れとして,TkinterのGUIクラス(つまりGUIの部品を載せる台みたいなやつ)を作成してその上に描画したいグラフを載せる感じです.
 先ほどのコードにライブラリを追加していきます.必要なものは

import numpy as np
import tkinter
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg  import FigureCanvasTkAgg

です.先ほど使用していたnumpyとmatplotlibにTkinterと連携用のライブラリを追加しました.次にtry文の中にGUIに関する諸々の設定を書いていきます.まずはGUIの要素を載せる"台"改めウィンドウを宣言します.

if __name__ == "__main__":
    try:
        #GUIの生成
        root = tkinter.Tk()
        root.title("にゃーん")

はい,たったこれだけです.最初の2行はただのおまじないGUIの生成には関係ない部分なので下2行がGUIの生成に関与しています.titleはウィンドウの名前になります.


次にグラフの設定を行います.これは先ほどと同じです.

        #グラフの設定
        fig,ax = plt.subplots()
        fig.gca().set_aspect('equal', adjustable='box')#グラフ領域の調整
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出t

そしてこのグラフを台に乗るような部品へ変換するための設定を行います.

        #キャンバスの生成
        Canvas = FigureCanvasTkAgg(fig, master=root)
        Canvas.get_tk_widget().grid(row=0, column=0, rowspan=10)

FigureCanvasTkAggによってGUIの部品へ変換し,その下の行でウィンドウ内の位置を決めています.そうしたら線を引いていきましょう.

        #区画の線を引く
        for i in np.array(range(gridSize)) * 90.0:
            ax.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
            ax.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color="gray", linestyle="dashed")

            #斜めの線を引く
            if (i / 90.0) % 2 == 1:
                ax.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color="gray", linestyle="dashed")

                ax.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([i, 0.0]), np.array([0.0, i]), color="gray", linestyle="dashed")
        
        Canvas.draw()  #キャンバスの描画
        root.mainloop()#描画し続ける

ここで重要なのが最後の2行で,Matplotlibにおいてグラフの描画はplt.show()で行っていたかと思いますが,Tkinterを使用した場合はGUIの部品へ変換したものにある.draw()を実行して描画を行ってください.また最後の行がないと一瞬でGUIの表示が消えます.
 後は諸々の処理を付け加えれば完成です.

#-*-coding:utf-8-*-
"""
参考
    http://b4rracud4.hatenadiary.jp/entry/20181207/1544129263
    https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html
"""

import numpy as np
import tkinter
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg  import FigureCanvasTkAgg

gridSize = 2 #マスの数を指定

if __name__ == "__main__":
    try:
        #GUIの生成
        root = tkinter.Tk()
        root.title("にゃーん")

        #グラフの設定
        fig,ax = plt.subplots()
        fig.gca().set_aspect('equal', adjustable='box')#グラフ領域の調整
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出

        #キャンバスの生成
        Canvas = FigureCanvasTkAgg(fig, master=root)
        Canvas.get_tk_widget().grid(row=0, column=0, rowspan=10)

        #区画の線を引く
        for i in np.array(range(gridSize)) * 90.0:
            ax.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
            ax.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color="gray", linestyle="dashed")

            #斜めの線を引く
            if (i / 90.0) % 2 == 1:
                ax.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color="gray", linestyle="dashed")

                ax.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color="gray", linestyle="dashed")
                ax.plot(np.array([i, 0.0]), np.array([0.0, i]), color="gray", linestyle="dashed")
        
        Canvas.draw()  #キャンバスの描画
        root.mainloop()#描画し続ける
    except:
        import traceback
        traceback.print_exc()
    finally:
        input(">>")#エラー吐き出したときの表示待ち

 とりあえずTkinter上で表示できたかと思います.(Matplotlibとの違いは下のボタンとウィンドウの名前ぐらいかと思いますが)
ただ×ボタンを押しても消えない症状が出ました.(Ctrl+Cもうまく動かないのなんだろ)

3.終了ボタンとかをつける



 ここまでやってきて強制終了しかできないのは悲しいです.というわけで終了ボタンを付けましょう....といきたかったのですが,説明するのだるいぉ.実は実装を大きく変えたためコードの説明に追加で1記事ぐらい費やしそうなのです.(とはいえコピペして改変するだけなので解読は可能かと思います)とりあえずコードだけ置いときます.

#-*-coding:utf-8-*-
"""
参考
    http://b4rracud4.hatenadiary.jp/entry/20181207/1544129263
    https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html
    https://pg-chain.com/python-tkinter-entry
"""
import numpy as np

import tkinter
import tkinter.messagebox as tkmsg

import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg  import FigureCanvasTkAgg

from functools import partial

def Quit():
       root.quit()
       root.destroy()

def DrawCanvas(canvas, ax, colors = "gray"):
    value = EditBox.get()
    if value != '':
        EditBox.delete(0, tkinter.END)
        ax.cla()#前の描画データの消去
        gridSize = int(value)
        gridSize = (gridSize * 2 + 1) #半区画の区切りを算出
        
        #区画の線を引く
        for i in np.array(range(gridSize)) * 90.0:
            ax.plot(np.array([i, i]), np.array([0.0, (gridSize - 1) * 90]), color=colors, linestyle="dashed")
            ax.plot(np.array([0.0, (gridSize - 1) * 90]), np.array([i, i]), color=colors, linestyle="dashed")

            #斜めの線を引く
            if (i / 90.0) % 2 == 1:
                ax.plot(np.array([0.0, i]), np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), color=colors, linestyle="dashed")
                ax.plot(np.array([(gridSize - 1) * 90 - i, (gridSize - 1) * 90]), np.array([0.0, i]), color=colors, linestyle="dashed")

                ax.plot(np.array([(gridSize - 1) * 90, i]), np.array([i, (gridSize - 1) * 90]), color=colors, linestyle="dashed")
                ax.plot(np.array([i, 0.0]), np.array([0.0, i]), color=colors, linestyle="dashed")
           
        canvas.draw()  #キャンバスの描画

if __name__ == "__main__":
    try:
        #GUIの生成
        root = tkinter.Tk()
        root.title("あー、てすてす")

        #グラフの設定
        fig,ax1 = plt.subplots()
        fig.gca().set_aspect('equal', adjustable='box')#グラフ領域の調整

        #キャンバスの生成
        Canvas = FigureCanvasTkAgg(fig, master=root)
        Canvas.get_tk_widget().grid(row=0, column=0, rowspan=10)

        #テキストボックスに関する諸々の設定
        EditBox = tkinter.Entry(width=5)#テキストボックスの生成
        EditBox.grid(row=1, column=2)

        #ラベルに関する諸々の設定
        GridLabel = tkinter.Label(text="ますめ")
        GridLabel.grid(row=1, column=1)

        #ボタンに関する諸々の設定
        ReDrawButton = tkinter.Button(text="こうしん", width=15, command=partial(DrawCanvas, Canvas, ax1))#ボタンの生成
        ReDrawButton.grid(row=2, column=1, columnspan=2)#描画位置(テキトー)

        QuitButton = tkinter.Button(text="やめる", width=15, command=Quit)#ボタンの生成
        QuitButton.grid(row=7, column=1, columnspan=2)#描画位置(テキトー)
        
        DrawCanvas(Canvas,ax1)
        root.mainloop()#描画し続ける
    except:
        import traceback
        traceback.print_exc()
    finally:
        input(">>")#エラー吐き出したときの表示待ち


追加した部分はボタン周りやテキストボックスなどです.ボタンによるアクションは先に関数として宣言したうえで各ボタンに登録しておきます(コールバック関数).引数等の問題はfunctoolsライブラリのpartialを引っ張てきて解決しました.×ボタンに関してはQuitButtonのコールバック関数としてQuit()を登録しておきました.

 まあいろいろいじって自分好みにカスタムしてみてください.次回はnorthernfox2先輩の「今年のマウスと教訓」です.そういえば今年の反省してなかったなぁ(れぽーよしか思い浮かばない...).
©2018 shts All Right Reserved.

2018年10月21日日曜日

OpenCV(Python版)で作るペイントツール



全日本学生完走した後マウス君とほとんど戯れていない中の人です。 今回はFCN用のデータセット作成ツールをPython-OpenCVで作ったのでその解説。 FCNに関してはこちらをみてください。
1.データのフォーマット
FCNの訓練データはこんな感じのものを使用しています。(オレオレデータセットってやつです)

入力画像はそのまま使用しますが、出力画像はこんな感じで変換しています。

入力画像からエッジを検出したのち、領域にタグをつける(≒色ぬりぬり)作業を行って出力画像を得ます。 で、この色ぬりぬり作業が相当めんどくさいんです。
エッジを得る段階で、適切なエッジを得られない、不必要なエッジが含まれる、領域が閉じていないなど様々な問題が出てくるので、実際には入力画像と見比べて手作業で補正します。この補正がずれまくる...。

ということでこの手作業をそこそこ楽にするツールを作成しました。...といってもトレース台みたいなツールです。
機能としては
・透かし
・点を書く
・塗りつぶし
です。とりあえず次回から機能の解説をしていきたいと思います。
ちなみに,コードはこちらから
©2018 shts All Right Reserved.

2018年9月16日日曜日

SH7125の割り込み優先度について



夏休みが終わって虚無感に襲われてる中の人です。
私事ではございますが、東日本大会をなぜか完走したため晴れてクラシックマウサーになってしまいました。よく完走したな

東日本が終了しインターンシップの関係で1週間気絶した後、かねてより懸案だったマウス君の速度があってない問題の解決を図ったのでその時のメモ。


1.どんな問題だったか
私のマウス君はステッピングモータを使用しているのですが、指定したモータ速ではない、より低い速度(100mm/sぐらい低い)で速度が上がらなくなる症状が発生していました。目標速設定周り、パルス周波数導出式にはバグはないようだったので何か別の部分に原因がありそうでした。

2.原因(と思しきもの)
速度導出系・速度代入系に異常がなかったので、割り込み周りの設定を確認しました。
まずはCMTやMTU2の割り込み内部で処理落ちしていないかどうかを確認しましたが、問題はなさそうでした。
そこでCMTやMTU2の設定を見直すことにしました。そしてMTU2の割り込み優先度をCMTのそれより上げた結果、目標回転速に達することが判明しました。

SH7125の場合、割り込み優先度の処理は以下の手順を踏んでいるようです。

・事前に設定された割り込み優先度に応じて処理を始める(割り込み優先度の設定レジスタは分かれているが、すべての割り込みの優先度を一括で決めている)
 ↓
・設定された割り込み優先度が同じとき、元々の優先度(データシート参照)に応じて割り込み処理を行う

また、割り込み実行時に別の優先度が低い割り込みが入ろうとしたときの挙動は調査中ですが、今回の問題から恐らく、あとから来た割り込みは破棄されるか待ちぼうけを食わされるようです。

つまりCMTの割り込みが走っている状態で優先度が低いMTU2が割り込もうとして失敗したため、MTU側の出力パルスの周期が長くなり、結果としてモータが遅く回ることになったと考えられます。

マイコン難しすぎ...にゃーん


©2018 shts All Right Reserved.

2018年7月4日水曜日

FP16とFP32で重みの型を変えた話



実験がツラい中の人です.

今回は前々から組んでいたFCNの高速化に関するネタ.
Chainerで何も設定せずにモデルを作成すると重みやバイアスのデータはfloat32で作られるのですが,設定を変更することで重みやバイアスのデータ型をfloat16に変更することができます.今回はデータ型を変更した時の推論にかかる時間への影響について考えてみます.





FP16 : 0.096[sec]
FP32 : 0.069[sec]
(30回平均)
あれ,FP16のほうが遅い...
FP16とFP32が同じぐらい時間がかかるなら,SIMDとかやらずに単純に計算しただけって解釈できるのですが,FP16が遅いってことは...

高速化もされていないなら...命令セット周りか...
どうやらFP16から型変換して演算→結果をFP16に直すってことらしい.

..FP16サポートしてよ...

おまけ モデルのサイズ
Chainerではモデルの保存ができますが,この時のデータサイズを比較すると...
FP32 : 12KB
FP16 : 7KB
こちらは至極当然といった感じ.
(NPZ形式での値,モデルの構成を変えるといろいろ変わると思われます.)



2018年6月20日水曜日

Matplotlibで明朝体を使えるか

はい,中の人です.
今回はMatplotlibの軸ラベルに明朝体を使おうとした話です.



0.今回使うグラフ
今回は以下のコードを改造しながら進めていきます.(詳しい説明はmatplotlibを紹介しているページへ)

import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(-2 * np.pi,2 * np.pi,num=101)
y = np.sin(t)
plt.plot(t,y)

plt.xlabel(u"時間$t$")
plt.ylabel(u"変位$y$")

plt.show()




1.概要
Matplotlibでは軸ラベルの設定ができますが,初期設定のフォントでは日本語を入れると変な文字が出てくるはずです.
そこでこの"変な文字"を回避するため,日本語対応フォントを導入して日本語を表示させてみましょう.

2.やってみた
Matplotlibだとフォント変更は以下の二通りがあります.
①rcParamsでフォントを変える
②font_managerで"なんとか.ttc"を直接参照する

①rcParamsを使ってフォントを変える.
rcParamsを使う場合,最初のコードは以下のようになります.


#-*-coding:utf-8-*-
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams["font.family"] = "Yu Mincho"
plt.rcParams["mathtext.fontset"] = "cm"

t = np.linspace(-2 * np.pi,2 * np.pi,num=101)
y = np.sin(t)
plt.plot(t,y)

plt.xlabel(u"時間$t$")
plt.ylabel(u"変位$y$")

plt.show()

これはmatplotlibの設定ファイル(matplotlibrc)を書き換えることでフォントを読み込ませる方式です.この場合,数式フォントと普通の文字のフォントを別々に設定できます.
しかし設定できるフォントに限りがあり,以下のコードで調べられます.


#-*-coding:utf-8-*-
import matplotlib.font_manager as fm

fonts = fm.findSystemFonts()
for f in fonts:
    font = fm.FontProperties(fname=f)
    print(font.get_name())
input(">")


②font_managerで"なんとか.ttc"を直接参照する
font_managerを使う場合は以下のようになります.


#-*-coding:utf-8-*-
import matplotlib.pyplot as plt
import matplotlib.font_manager
import numpy as np

fp = matplotlib.font_manager.FontProperties(fname="C:\Windows\Fonts\msmincho.ttc")

t = np.linspace(-2 * np.pi,2 * np.pi,num=101)
y = np.sin(t)
plt.plot(t,y)

plt.xlabel(u"時間$t$", fontproperties=fp)
plt.ylabel(u"変位$y$", fontproperties=fp)

plt.show()

この場合,"なんとか.ttc"さえ参照できればフォントを適用できることができます..ttcファイルであればフォントの制限もありませんが,数式はデフォルトのフォントが当てられます.

3.完走した感想
もう英語でいいや




©2018 shts All Right Reserved.

2018年6月10日日曜日

Raspberry Pi 向けモータ制御基板を作ってみた


レポートに発狂しながら生きている中の人です。

少し前にラズパイ向け(というよりArduino Pro Micro向け)の拡張ボード的なものを作ったのですが、その紹介。






1.そもそもの作成理由
Raspberry Piで生成できるPWMの精度があまり良くなかったので、よりきれいなPWMが作れお手軽にコードが書けそうなArduinoを使ってサーボとかモータードライバとかの制御をやってみたかった。
ついでにプリント基板化もしておこうと思った次第です。

2.設計
今回、ArduinoとRaspberry Piの通信部分はUSB経由のUARTにしたので、そこの配線は不要でした。(というよりArduino Pro MicroのUARTピンがうまく使いこなせなかったOTL。)
モータードライバは、i2Cでモータの電流が制御できるDRV8830を二つ使用しました。秋月で取り扱っているのもよかったですね。モータドライバを二つ乗せたのは、今後別のことにも転用できるようにするためです。

RaspberryPiからはi2cで使えるキャラクタ液晶とUARTのピンを引き出しています。液晶はIPアドレス確認用で、UARTはSSHがうまくいかないときのバックアップとしてPCとの通信に使います。

電源ボードはAdafruitのPowerBoost 1000 basicを使用し、1SのLi-poから5Vに昇圧しています。5V1Aぐらいあっても、モータの駆動は若干厳しいです。
電源回りでいえば、Raspberry Piの電源も一緒にしたかったのですが、電源が足りなくなるのとGPIOからの給電がうまくいかなかった関係で別系統にしました。

3.作成

今回もE社に投げ込みました。DRV8830のパッド-パッド間が12milより狭かったので、怒られるのではないかと思っていましたが、難なく仕上げてきました。(恐ろしい)
初めてヒートパッドのついたICのはんだをしたのですが、
①パッドにスルーホールを設けておく。
②パッドが薄くはんだでコーティングされる程度にパッドと穴にはんだを流し込む。(穴は埋める)
③パッドにフラックスを塗り、ICの位置を決め、マスキングテープで固定。
④裏返しにしてスルーホールにはんだごてをあて、固定する。
⑤固定されたら再度ひっくり返して、マスキングを外し、フラックスをICの足に塗る。
⑥ICの足をはんだ付けする。
ってやったら一応ついたようでした。(正しい手順が知りたい)

4.動作確認
正常に動いたので一安心です。

5.改善点
とりあえずヒートパッドの裏の穴はもっと小さくてよかったことと、DRV8830だったらRaspberry Piからi2Cを使って叩けるので、i2CかSPIのPWM生成ICかなんかがあればArduinoが不要なる点でしょうかね。
Arduinoを使うなら、アナログピンやデジタルピンを引き出して、センサなどをさらに追加できたらよりよかったですね。
あっ,i2C線にプルダウン抵抗入れ忘れてました...OTL

6.まとめ
ソフト、ハードともに基礎研究は終了したので、今度は実際に組立てて走らせ、データ収集とデータ加工をしないといけないですね...
©2018 shts All Right Reserved.

2018年5月27日日曜日

Arduinoのシリアル通信で、カンマ区切りの文字列を読ませる

突然ですが、今回はArduinoのシリアル通信でカンマ区切りの文字列を扱う話です。

パラメータの送信とかで使いたくなるカンマ区切りのデータですが、意外とお手軽に実装できたので紹介したいと思います。





1.解読の流れ
解読の流れとしてはこんな感じ
①シリアル入力をバッファに突っ込む
②strtok関数でトークンに分解して、各変数に読み込む
③atoi関数で数値に変換


2.実装
int angle = 0, mot_sta = 0, power = 0, i = 0;
char buff[30];

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    buff[i] = Serial.read();
    if (buff[i] == 'e') {
      buff[i] == '\0';
      angle = atoi(strtok(buff, ","));
      mot_sta = atoi(strtok(NULL, ","));
      power = atoi(strtok(NULL, ","));

      Serial.println(angle);
      Serial.println(mot_sta);
      Serial.println(power);
      i = 0;
    } else {
      i += 1;
    }
  }
}

今回のプログラムはangle、mot_sta、powerの3つの変数に値を代入するモノです。
Arduino側に送られてくるフォーマットはこんな感じ

10,20,30,e

末尾の"e"はデータの終端を表す信号で、こいつが出るまでバッファに送られてきたデータを書き出します。
そのあと、strtok関数でバッファの中身を解読します。この関数は一回文字列に対して実行するごとに1つずつトークン(のポインタ)を返します。また2回目以降は対象の文字列を"NULL"にしてあげる必要があります。
それと並行してトークン(のポインタ)をatoi関数に入れることでint型の数値が得られます。atofを使えばfloat型として数値が得られるようです。



今回はここを参考にしました。
http://www9.plala.or.jp/sgwr-t/lib/strtok.html


©2018 shts All Right Reserved.

2018年5月23日水曜日

draw.ioで数式を打ち込む

れぽーよ地獄にサヨナラしたい中の人です。
今回はれぽーよで図を描くときによく使っているdraw.ioの話。

2018/5/23 22時 追記





0.draw.ioとは
多種多様な図を書くことができるオンライン上のツールです。
(e.g.回路図、フローチャート、家の図面的なもの)

1.何がしたいか
今回のれぽーよ課題で図を描いたのですが、同時に数式を入れないといけなくなりました。というわけで、draw.io内での数式の書き方を書いていきます。

2.やり方
1)draw.ioを開く
    とりあえず、ここからdraw.ioを開きましょう。

    最初にこんな画面が出ると思うので、"新規ファイルを作成する"を選択。

    次にこの画面になるはずです。いくつかのテンプレートが用意されていますが、
    今回は"白紙ファイル"で行きます。
    名前はここで決めても、後からxmlファイルで出力するときに決めてもよいので、
    とりあえず"名称未設定ファイル"行きます。
    そして、右下の作成するボタンを押してください。

2)数式入力を有効にする

    多分こんな画面になったはずです。
    そうしたらどこでもいいので右クリックしてメニューを出しましょう。

    メニューの一番下のオプションから数式組版にチェックを入れることで数式入力ができるようになります。

3)数式を書く
    実際に数式を書いてみます。上の"図形"のボタンをクリックするとテキストボックスがあるのでそれを使います。

    draw.ioで数式を書くには、数式を"`"(バッククオート)で囲む必要があります。
    また書き方はTeXと同じものを使用します。


    そしてこんな感じになるはずです。
4)追記:保存方法
    draw.ioで作ったものはxml形式のほか種々の画像ファイルなどで保存できます。
 
    この画像の左上のほう、"ダイアグラム"をクリックするとこんなのが出てくるはず。
    ここで"保存"を選ぶと、xmlファイルで保存できます。
    このxmlがあればdraw.ioから開いて修正などもできます。
    "形式を指定してエクスポート"を選ぶと、pngなどの各種ファイルで出力できます。



©2018 shts All Right Reserved.

2018年5月20日日曜日

SH7125でsqrtを動かしたかったけどできなかった話

れぽーよに追われ、何もできてない中の人です。(テストが迫ってきたぁぁぁぁぁあああ)

少し前にSH7125でsqrt関数を動かそうとして詰まったのでその話をします。





0.要約
SH7125上でsqrt関数を動かすことは、
とてつもなく重い(中の人の感想です。個人差があります。)

1.何がしたかったか
今となってはよくわからないが、とりあえず何かの距離とか速度を算出したかったらしい。

2.どこに実装したか
最初は1[ms]の割り込み関数の内部で、次は車体を動かす距離を決める関数で。

3.結果
どちらも計算が追い付かず、モータは正常に動作しませんでした。
割り込み内部で実行したときは1[ms]以内に計算が出来なかったのであっさり轟沈しました。もう一つの時は、車体速度が上がるとうまくモータが回らなくなっていきました。

4.もしsqrtを使いたくなってしまったら
どうしてもsqrtを使いたいそこのあなたにこんな情報を差し上げます。
車体速度を上げた時のパルス周期から、SH7125だとsqrtの実行には3[ms]ぐらいを見積もったほうが良いことが判明しました。
(CPUのクロック数を50[MHz]した時の値。1[ms]で割り込みを走らせ、迷路探索アルゴリズムを走らせながら実行する条件だったので、単純な実行時間ではないことにご注意。)
本当にsqrtが必要かどうか、もう一度検討しましょう。後戻りできるうちに...


©2018 shts All Right Reserved.

2018年5月7日月曜日

加速テーブルを使わずにステッピングモータで台形加速する

Mice入って早1年たった中の人です。

ステッピングモーターを回すのに加速テーブルを使う例は多々ありますが、テーブルなしで回す例は意外とないのでメモ。





まずはステッピングモーター(のドライバIC)送るパルス周期を出してみましょう。

①1ステップで動く距離を出す
 ステッピングモータは励磁する磁石を次々に変えながら回します。そのため1ステップで回る角度が定義できます。オリエンタルモーター様の無償提供モーターPKE-243A-Lの場合、1相励磁でのステップ角は1.8°で、1-2相励磁はその半分で0.9°となります。
 ここからタイヤ直径51[mm]の場合、1ステップで"車体"が進む距離d[mm]は
となります。

②単位時間に何ステップ進めるかを決める
 1ステップでどれぐらい"車体"が進むかがわかったところで、モーターを単位時間に何ステップ分回すか、つまりステップ速度を決めましょう。
 単位ステップ距離が出ているので、これを使って求めることを考えます。1ステップで進む"車体"の距離が出ているので、"車体"の動きを記述するパラメータであり、かつ単位時間が絡むものが良いですね。例えば車体が単位時間に進む距離とか...








そう、車体速度です!
具体的には、"車体"速度をステップ距離で割るだけです。まあ、単位時間に進む距離を1ステップで進む距離で割れば、距離が消えて単位時間当たりのステップ数が出るって落ちです。
③ステップ周期を出す
 単位時間に何ステップ出すかが決まったので、1ステップにかかる時間を求めます。まあ、1[s]で何ステップ出すかが決まっているので、逆数を取れば1ステップにかかる秒数がわかります。
 では何故ステップ周期を出すかといえば、マイコンのタイマを使うためです。タイマで半周期と1周期を計って出力のHIGH-LOWを切り替えます。

④回転を加減速させる
 加減速するとき、ステップ周期を変更しながら回すのですが、ステッピングモータ特有の問題として、"脱調"があります。
 脱調とは、入力パルス周波数が大きすぎたり、小さすぎたり、変化が大きすぎるためにうまく回らなくなることです。僕の場合、200[mm/s]-1000[mm/s]、2000[mm/s^2]くらいで今のところやっています。
 
 最初に回すのなら、現在速度と目標速度の差分を取り、目標速度より速かったら、(割り込み時間x設定した加速度)を現在速度から差し引き、目標速度より遅かったら(割り込み時間x設定した加速度)を現在速度に加算するやり方で十分かと思います。


今回はこの辺を参考にしました

JASALMAのプログラム解読Part1 走行系1



それでは良きマウスライフを!
 

©2018 shts All Right Reserved.

2018年5月3日木曜日

matplotlibって使いやすいよねって話

実験も始まり、レポーヨに追われまくってる中の人です。

この前大学の課題でレポートが出たのですが、グラフの作成に戸惑っている人たちにいろいろ質問されたので僕がやってる方法を少し公開します。





1.グラフ作成に使う言語
 個人的によくPythonを使っています。最近はPython3.6をVS2017環境で動かしています。ライブラリの管理が意外とやりやすいことには驚きました。Pythonはいいゾ

2.ライブラリ
 ライブラリはnumpyで計算を行い、matplotlibでグラフの描画を行います。matplotlibは最新版(2.2.2)がおすすめ。

3.使い方
 とりあえずsinカーブを作ってみましょう。
①numpyとmatplotlibをimportする。
import numpy as np
import matplotlib.pyplot as plt
②numpyで独立変数の配列を作る。
x = np.linespace(-3.14,3.14,0.01)
③numpyのsin関数にさっきの配列を入れる。
y=np.sin(x)
④matplotlibで関数の出力と独立変数の配列を組みにして表示する。
plt.plot(x,y)
⑤表示
plt.show()
4.総論
 ここまで書いたのをまとめると
#-*- coding:utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt

x = np.linespace(-3.14,3.14,0.01)
y=np.sin(x)

plt.plot(x,y)
plt.show()
これでサインカーブが表示できたはず。できない場合は頑張って調べてネ。そして...













































Pythonはいいゾ
異論は認める。



©2018 shts All Right Reserved.

2018年4月9日月曜日

ChainerでFCNやってみた(完成版)


教習所地獄から生還した中の人です。
今日はこの前作ったFCNもどきを完成させたので、その報告。





この前作ったやつは、誤差関数を平均二乗誤差にして連続値をそのまま出力する形になっていました。(分類問題なのにね)

なんでこうなったかといえば、ChainerのSoftmaxCrossEntropyの仕様を理解せずに使おうとしていたからでして、最初から読んでいればこんなことにならなかった...。

とりあえず、こちらで公開しておきます。今後の開発としては、分類数をもっと増やして、より実践的なやつを作る予定です。(ハードについては今後公開予定)

2018年2月11日日曜日

Raspberry PiでFully Convolutional Networks(もどき)を走らせる

テストが終わったと思ったら教習所通いの中の人です。
今回はchainerを使用してFCNもどきを構築してみたので、少しご紹介。

1.目的
    今回これを作った理由は、この車の改良版を作成するためです。

2.改良手法
    Fully Convolutional Networks(FCN)を使って道路を見分け、道路の面積から操作角      を判断する。FCNについてはこちらから

    https://people.eecs.berkeley.edu/~jonlong/long_shelhamer_fcn.pdf

    そもそもFCNを使う理由としては、どのようにして道を判断したかがパッと見てわかり      やすいためです。(計算量は度外視)
3.結果
  3.1 精度
      こんな感じです。



    道(3段目の白い部分)がしっかり取れていました。(まだ荒いけど)
  3.2 処理速度

  想定より遅い...。大体10fpsは超えるぐらいですかね。もっと速くしたいです。

4.考察
    重かった原因として、①FCN自体が重い、②無駄な処理が走ってるといったことがあげ    られます。ここからさらに高速化しようと思ったら、この辺とか試してみたいですね。

5.その他
    今回のコードはこちらにあります。



©2018 shts All Right Reserved.

2017年12月10日日曜日

ビット演算の初歩の初歩の初歩

この記事はMice Advent Calendar 10日目の記事です。
========================================

東工大杯の準備は着々と進んでおらず、テスト対策もしていない中の人です。
Miceの先輩方からの有形無形の圧力により、Mice Advent Calendarなるものに参加しています。ほかの方々の有用な情報のほうがこの記事よりためになるので、どうぞご覧ください。

=========================================

話は変わりまして、ビット演算の話。
そもそもこんな記事を書いたのは趣味で少しかじったからであって、別段他人に見せるほどでもないんですが、とりあえず書いときます。

ビット演算とは何かという話は他の人に譲るとして、実際の演算子を紹介していきます。

1.NOT
Cでの記号(演算子): ~ (チルダ)
論理演算のNOTに相当。数字をビット毎に反転させる。
例:
a : 0101 0101
b ~= a : 1010 1010

2.AND
Cでの記号(演算子): &
論理演算のANDに相当。2つの数字のビット毎にANDをとる。
例:
a : 0101 0101
b : 1111 0000
a & b : 0101 0000

3.OR
Cでの記号(演算子): | (バーティカルバー)
論理演算のORに相当。2つの数字のビット毎にORをとる。
例:
a : 0101 0101
b : 1111 0000
a | b : 0101 0000

4.XOR
Cでの記号(演算子): ^ (キャレット)
論理演算のXORに相当。2つの数字のビット毎にXORをとる。
例:
a : 0101 0101
b : 1111 0000
a | b : 0101 0000

ちなみにXORは以下の通り
X Y | Z
----+--
0 0 | 0
1 0 | 1
0 1 | 1
1 1 | 0


さてここからビット演算特有のビットシフトの話。ビットシフト自体はそこまで難しくはない(ずらすだけ)が、ビットシフトの種類で空いたところに何が入るかが変わるの(特に右シフト)で注意。

5.論理左シフト
Cでの記号(演算子): << ("Double less-than sign" とか言うらしい)
n-bit分左にずらし、空いたbitには"0"を入れる。
例:
a          : 0101 0101
a << 3 : 1010 1000

6.算術左シフト
記号も動作も5.論理左シフトと同じなので割愛

ここからがわけわからん右シフトの世界

7.論理右シフト
Cでの記号(演算子): >> ("Double greater-than sign" とか言うらしい)
n-bit分右にずらし、空いたbitには"0"を入れる。
例:
a          : 0101 0101
a >> 3 : 0001 0101


8.算術右シフト
Cでの記号(演算子): >>
n-bit分右にずらし、空いたbitには..."1"か"0"を入れる
例①:
a         : 0101 0101
a >> 3 : 0001 0101

例②:
b         : 1010 0101
b >> 3 : 1111 0100


さて算術右シフトの例が二つ出てきましたが、①では"0"、②では"1"が入っています。これは

"算術右シフトでは、操作する前の一番上のbitを空いたところに入れる"

というルールがあるためです。(理由はGoogle先生に聞いてみよう!!!!!!!)

ここまでで、Cで使えるすべてのビット演算が出てきました。
























全部の演算子が出てきたんだし、C言語だったらビット演算できる...なんて思ってませんよね?




ここである記号についてみてみましょう

5.論理左シフト
Cでの記号(演算子): <<

6.算術左シフト
Cでの記号(演算子): <<

5.論理右シフト
Cでの記号(演算子): >>

5.算術右シフト
Cでの記号(演算子): >>



あれ、記号が同じだ...。


そうです、C言語ではシフトの記号が論理と算術とで分けられていません!!!!!!!!!!!!!!!!!!

何たる失態。
ところでC言語の規格書(日本語で書かれたものだとJIS X 3010:2003)というものが世の中には存在しまして、こいつの中にはビットシフトについてこう書いてあります。

E1<<E2の結果は,E1 を E2 ビット分左にシフトした値とする。空いたビットには 0 を詰める。
E1 が符号無し整数型をもつ場合,結果の値は,E1×2^E2の,結果の型で表現可能な最大値より 1 大きい値を法とする剰余とする。
E1 が符号付き整数型と非負の値をもち,E1×2^E2が結果の型で表現可能である場合,それが結果の値となる。
それ以外の場合,その動作は未定義とする。

E1>>E2の結果は,E1 を E2 ビット分右にシフトした値とする。
E1 が符号無し整数型をもつ場合,又はE1が符号付き整数型と非負の値をもつ場合,結果の値は,E1/2^E2の商の整数部分とする。
E1 が符号付き整数型と負の値をもつ場合,結果の値は処理系定義とする


つまり左シフトは算術でも論理でも空いたビットには"0"が入るが、
右シフトは動作している環境で違うってこのらしい。







(´・ω・`)


環境依存である以上算術シフトと論理シフトについて議論してもあまり意味がないのですが、例えばGCCだとビットシフトする方の型をunsignedにしておくと論理シフトで、signedにしておくと算術シフトになったりします。



こんな感じで最後にトラップがありましたが、とりあえずビット演算の初歩の初歩の初歩はクリアできそうですね!












©2017 shts All Right Reserved.

2017年12月9日土曜日

PiZeroのOTGモードでネットにつなぐ(Windows10)

Raspberry Pi ZeroのOTGモードでのネットワーク接続に手間取ったのでメモ。

前提としてOTGモードでログインできている状態である必要があります。



①Pi Zeroと母艦とを接続し、コントロールパネル→ネットワークとインターネット→ネットワーク接続を開く

②ネットワークにつながっているアダプタを右クリックし、プロパティを開く

③共有タブを開いて、"ネットワークのほかのユーザーに、このコンピュータのインターネット接続をとおしての接続を許可する(N)"の欄にチェックを入れる。

④Pi Zeroを再起動するとつながるはず

うまくつながらないこともあるので、ほんとのやり方はほかにあるのかも知れないです。


©2017 shts All Right Reserved.

2017年10月20日金曜日

SH7125でリセット同期PWMモードを使う


センサ周りのポート接続の関係でセンサLEDをリセット同期PWMで動かすことになったのでメモ。
基本的にデータシート通りに設定し、割り込みに関する部分を追加して動かす感じ。
割り込み条件は周期を決める関係上MTU23のTGRAのコンペアマッチを使う。ついでに割り込み許可もこいつだけに出しとけばOKなようだ。

©2017 shts All Right Reserved.

2017年10月16日月曜日

kicadでプリント基板作ってみた


完全にレポーヨに時間を取られ、何もできていなかった中の人です。
少し前になりますが、ひょんな事からプリント基板を作ることになったので少しその話を

今回作った基板は、3cellのlipo からステッピングモーター用の電源とマイコン用の5Vを取り出す電源回路です。

取り敢えず3端子レギュレータを使った降圧回路にしました。保護用のダイオードをつけたのに、100μFのコンデンサのパッドを片方だけ消したのはなんでだろ?
ロゴとビアはやり直したいなぁ


秋月でAZ1086-5.0Hの取り扱いを終了したっぽいのでどうしようかなぁ?

©2017 shts All Right Reserved.

2017年10月9日月曜日

ソフト構成


今回はマイクロマウスソフト構成の話。

とりあえず全体を見通しやすくするために、レイヤーをなるべく少なくする方針で設計を進めてます。
Application layerとController / Driver layerを分けたのは、App layerでなるべくハードを意識せずにプログラムしたいためです。またControllerとDriverは一体にして、プログラムのサイズを小さくする狙いがあります。


構築はまだ全部の動作確認を終えてないのでそちらが優先ですね...

©2017 shts All Right Reserved.

2016年10月15日土曜日

Raspberry Pi Autonomous Car - ソフトウエア

今回はソフトウエア編です。いろいろ試してたら最初4つだったのが6つになってました...。




画像収集

NNのトレーニング用の画像データを収集します。出力するデータは9600次元のベクトルにしました。(160*60)
機械学習
さっきの画像データを元にPybrainを使ってトレーニングさせます。ちなみにNNは9600x32x32x4の4層にしました。(Win10のみ動作確認)
自律運転(白線検知)
先ほどのNNを使って白線を検知し、走らせます。

このほかに、カメラとモータとNNのテスト用のスクリプトを作りました。

大体10Hzぐらいで処理できているので、移動速度がそこそこ遅ければしっかり白線トレースできます。カメラからのデータ読み込みさえ速ければ、もっと処理速度あげられるのに...

©2017 shts All Right Reserved.

2016年9月11日日曜日

Raspberry Pi Autonomous Car - ハードウエア2

前回問題に上がっていた電源周りのハナシ。電源の要求は以下の通り。
  • モータ側に1A
  • raspberry pi 側に0.5A
  • lipoを使えるようにする
この条件を満たすため電源ボードとしてadafruitから出ているこれを2つ積むことにしました。
またモータ制御用にTA7291Pを、サーボにSG90を使うことにしました。あとはzeroにサイズの合うユニバーサル基板に実装して制御ユニットの完成。
ただ、この基板が仕上がったあたりで2つ使うはずだったlipoバッテリーのうち1つのケーブルが外れ、使えなくなるトラブルが発生。急遽raspberry pi 用に小型のモバイルバッテリーを調達することに...。



©2017 shts All Right Reserved.

2016年9月10日土曜日

Raspberry Pi Autonomous Car - ハードウエア1

前回から唐突に始まった謎のハナシ、今回はハード編1です。
ハードウエアに対する要求は以下の通り。
  • ステアリングの機構を備えること
  • FA-130が使えること
  • そこそこのペイロードがあること
  • 改造がしやすいこと
  • Amazonで入手できること
  • 改造事例が多いこと
これを満たしたのがタミヤのバギー工作基本セットでした。最初はこれをベースにarduinoとraspberry piを使って制御しようと考えてました。

©2017 shts All Right Reserved.