マイクロマウスのソフト設計の話 番外編 PlantUMLの紹介

こんにちは。そらです。
マイクロマウスのソフト設計の話の番外編として、その2~その5のアクティビティ図等の図の作成に使用したソフトの紹介をしたいと思います。テキストから図を作ってくれるので、GUIでやるよりも楽だと使用しながら思いました。
PlantUMLの公式サイトはこちらです。
この記事では、詳しく説明は書かないため各自で使用するときに確認をしていただければと思います。また、VisualStudioCodeはVSCodeと省略して書かせていただきます。環境構築はVSCodeのプラグインを使用することとします。




VSCodeをインストール/PlantUMLの拡張機能をインストール

MicroSoftのVSCodeの公式サイトからインストールをしましょう。
VSCodeをインストールしたら、左側のバーから拡張機能のインストールをクリックしてPlantUMLを検索してREADMEを読んで行きます。すると、How to Installに以下のソフトを要求すると書いてあったため、それらをインストールします。必要なソフトはJavaとGraphvizになります。Windowsの場合はネットでインストーラーを探してインストール、またはQuick Install For Windowsで紹介されているコマンドを使用するかだと思います。私は、前者の方法を使用しました。
これらの必要なソフトをインストールしたら、拡張機能をインストールした後、VSCodeを再起動しましょう。
便利なショートカットキーとしてAlt + Dがあります。これをPlantUMLに対応したファイル編集中に押すことでPreview(作成中の図)が見れるようになります。

PlantUMLのソースの公開

その3~その5で図のソースコードを紹介していきたいと思います。

その3のソース(アクティビティ図)

操作者が使用するシステムのメインルーチンを考える

@startuml
|Operator|
start
:電源を入れる;

|#AntiqueWhite|MCU|

:初期化処理を行う;

if(初期化処理に成功したかどうか) then (success)
:モード選択に移動する;
else (false)
:問題を表示する;
:電源が切られるのをまつ;
stop
endif

|Operator|
while(メインルーチンスタート)

:変数等の初期化(必要に応じて);

if(バッテリ電圧をチェック) then (電圧が異常の場合)
:電圧が異常であることを表示;
:電源が切られるのをまつ;
stop
endif

fork
|Operator|
:モードを選択する;
fork again
|MCU|
:現在のモードをUIなどを用いて表示する;
:モード決定の入力を受け付ける;
end fork

:モードを決定する;
:モードを決定したことをUIなどを用いて表示する;

fork
|Operator|
:選択したモードに対してマシンをおくなど物理的な処理をする;
fork again
|MCU|
:処理のスタートの入力を受け付ける;
:行う処理によってUIの表示等を変更する;
end fork

:実行;

endwhile

|Operator|
:電源を切る;
stop
@enduml

迷路探索の流れを考える

@startuml

|#CCCCEE|Main Process|
|#LightSkyBlue|Maze Algorithm|
|#AAFFFF|Controller|

|Main Process|
start
:モード選択で探索モードが選択された;
:マシンの座標情報を初期化;
:迷路アルゴリズムに使用する変数等の初期化を指示;

|Maze Algorithm|

:迷路アルゴリズムに使用する変数を初期化;

|Main Process|

:制御を有効にするよう指示;

|Controller|

:制御を有効にする;

|Main Process|

:区画の中心まで進むことを指示する;

|Controller|

:目標値等の生成を行う;
:目標値の更新
目標値に追従を行う;

|Main Process|
:動作が終了するのをまつ;
note right
センサの取得等も含め、
制御のプログラムは
割り込み処理で実行する
end note

|Main Process|

while(ゴール座標につくまで)
:壁情報を取得;
:足立法の歩数マップの更新を指示;
|Maze Algorithm|
:足立法で歩数マップを更新;
:次の動作を決定して動作の情報を返す;
|Main Process|
:動作に合わせてマシンの座標を更新する;
:次の動作を指示する;
|Controller|
:目標値等の生成を行う;
:目標値の更新
目標値に追従をする;
|Main Process|
:動作が終了するのをまつ;
endwhile

:停止の処理を指示;

|Main Process|

if(ゴール座標にいるかどうか) then (ゴール座標にいるとき)
:迷路情報を保存;
else (ゴール座標にいないとき)
:迷路情報を保存しない;
endif

stop
@enduml

最短走行のときの流れを考える

@startuml

|#CCCCEE|Main Process|
|#LightSkyBlue|Maze Algorithm|
|#AAFFFF|Controller|

|Main Process|
start
:モード選択で探索モードが選択された;
:マシンの座標情報を初期化;
:迷路情報を読み込む;
:最短経路を導出するように指示を出す;

|Maze Algorithm|

:最短経路導出問題を解く;

note right
ダイクストラ法やA*などが
最短経路導出問題の例。
足立法を使用してもできる
斜めの場合は拡張足立法って呼ばれる
ことがあるみたいです。
end note

:迷路の経路を取得;
:動作の速度を設定する;
:経路情報等を返す;

|Main Process|

:動作、速度情報を取得;
:制御を有効にするよう指示;

|Controller|

:制御を有効にする;

|Main Process|

while(動作がなくなるまで)
|Main Process|
note right
最短走行が速い人たちは、
最短走行中に壁や柱を見て
距離補正をしているという
噂があります。
end note

:動作の指示を出す;
|Controller|
:目標値等の生成を行う;
:目標値の更新
目標値に追従をする;
|Main Process|
:動作が終了するのをまつ;
endwhile

:停止の処理を指示;

stop
@enduml

その4

割り込み処理の流れを検討していく

@startuml

|#LightSkyBlue|Interrupt|
|#CCCCEE|Peripheral|

|Interrupt|
start

:壁センサ情報の取得を指示;

|Peripheral|
:センサ取得の処理を行う;
:センサの情報を返す;

|Interrupt|
:エンコーダの情報の取得を指示;

|Peripheral|
:エンコーダのデータの取得;
:エンコーダの情報を返す;

|Interrupt|
:IMUの情報の取得を指示;

|Peripheral|
:IMUのデータの取得;
:IMUの情報を返す;

|Interrupt|
if(制御が有効かどうか) then(true)
:制御に使用する目標値を更新;
:目標値と現在値から制御量を計算;
:モーターに出力を指示;
|Peripheral|
:出力値をマイコンが扱えるものに変換する;
:PWMを出力をする;
|Interrupt|
stop
else (false)
:モーターの出力は0にしておく;
stop
endif

@enduml

ジャイロセンサの流れを検討する

@startuml

|#LightSkyBlue|Main Process|
|#CCCCEE|IMU Process|

|Main Process|
start

:初期化の指示をする;

|IMU Process|

:SPIの初期化をする;
if(初期化を失敗したとき) then(true)
:失敗したことを通知する;
|Main Process|
:失敗したというデータを
受け取り処理を終了する;
stop
endif

|IMU Process|
if(MPU6500のWHO_AM_Iを確認する) then(データがおかしいとき)
:失敗したことを通知する;
|Main Process|
:失敗したというデータを
受け取り処理を終了する;
stop
endif

|IMU Process|
:MPU6500の初期化処理をする;
:データが要求されたら
MPU6500からデータを取得
して物理情報に変換して返す;
stop
@enduml

エンコーダの処理の流れを検討する

@startuml

|#LightSkyBlue|Main Process|
|#CCCCEE|Encoder Process|

|Main Process|
start

:初期化の指示をする;

|Encoder Process|

:SPIの初期化をする;
if(初期化を失敗したとき) then(true)
:失敗したことを通知する;
|Main Process|
:失敗したというデータを
受け取り処理を終了する;
stop
endif

|Encoder Process|
if(NOPを確認する) then(データがおかしいとき)
:失敗したことを通知する;
|Main Process|
:失敗したというデータを
受け取り処理を終了する;
stop
endif

|Encoder Process|
:AS5047Pの初期化処理を行う;
:データが要求されたらAS5047P
からデータを取得して、物理情報
に変換をして返す;

stop
@enduml

その5

クラス図を考える

@startuml

Peripheral --> Machine
Controller --> Machine
MazeAlgorithm --> Machine

package Machine {
class System {
bool init()
void testCase()
}

class Mode {
void select()
void execute()
}

class Interrupt {
void process()
void enableControl()
void disableControl()
}

class Runnning {
void search()
void fast()
}
}

package Peripheral {
class Machine_IO{
bool init()
bool getSW()
void setFrontUI()
void setBackUI()
}

class Sensor {
bool init()
void updateSensor()
void sensing()
void start()
void stop()
float getBattery()
}

class IMU {
bool init()
float getGyroX()
float getGyroY()
float getGyroZ()
float getAccelX()
float getAccelY()
float getAccelZ()
}

class Motor {
bool init()
void controlMotor()
void controlFunMotor()
}

class Encoder {
bool init()
float getLeftVel()
float getRightVel()
}

}

package Controller {
class Trapezoid {
float 必要な変数
void make()
float update()
bool isend()
}
class Motion {
void straight()
voud turn()
}

note bottom
trapezoidを上手く使用して
実装できたらいいなぁと
思っています
end note

class PID {
float kp
float kd
float ki
float previous
float integral
void setPIDParameter()
float update()
}
}

package MazeAlgorithm {
class Adachi {
uint16_t step[32][32]
void init()
void updateStepMap()
uint8_t getNextAction()
}
class Map {
/*壁情報を保持する変数等が必要*/
void init()
void addWall()
}
}

@enduml 

さいごに

マイクロマウスのソフト設計の時に使ってみましたが、使いやすく図も綺麗にできているので今後使っていこうかなと思いました。ソフト設計等をするときの参考になれば幸いです。