MIRS1302 管理台帳へ戻る
名称 MIRS1302 ソフト詳細設計書
番号 MIRS1302-SOFT-0001

最終更新日:2013.12.17

版数 最終更新日 作成 承認 改訂記事
A01 2013.12.18 山田,泉谷 初版

目次

1.本ドキュメントについて

本ドキュメントは、MIRS1302のオリジナルシステムにおける、ソフトの詳細設計についてのドキュメントである。

2.ファイル構成

Makefile,*.o,*.aは省略した。
srcc++/
-Mirs/ メインプログラム(巡回、探索、追跡、補正)
	Mirs.cpp
	Mirs.h
-Motor/ モーターとの通信を行う
	Motor.cpp
	Motor.h
-MotorController/ 走行を制御する
	MotorController.cpp
	MotorController.h
-Uss/ 超音波距離センサを扱う
	Uss.cpp
	Uss.h
-FpgaIO/ FPGAを介した入出力を扱う
	FpgaIO.cpp
	FpgaIO.h
-Img/ 画像処理を扱うスレッドを管理する
	Img.cpp
	Img.h
-BallDetector/ ボールの認識を行う
	BallDetector.cpp
	BallDetector.h
-NumberDetector/ 数字の認識を行う
	NumberDetector.cpp
	NumberDetector.h
-Field/ 地図情報を扱う
	Field.cpp
	Field.h
-Route/ 経路情報を扱う
	Route.cpp
	Route.h
-Debug/ デバッグ用マクロの定義
	Debug.h
-Test/ テスト用のプログラム(端末のコマンドのように、対話しながらテストを行う)
	TestTalk.cpp
	TestTalk.h
-Data/ 入力するデータと、出力したデータを置く。また、地図情報と経路情報を簡単に作るためのスクリプトを置く
	routemake.py
	fieldmake.py
	PatrolRoute.dat
	SearchRoute.dat
	Field.dat

3.クラス図



[各クラス説明]
Route 経路情報をファイルから読み込み、扱うクラス
Field 地図情報をファイルから読み込み、扱うクラス
Motor モータ制御ボードと通信を行うクラス
VMotor モータ制御ボードと通信を行っている振りをして、シミュレーションを行うためのクラス
Motors モータ2つをまとめて操作するためのクラス
MotorControllerBase 直進、回転など、移動を制御するための基礎的なクラス(機能は標準のものとほぼ同じ)
Position 位置情報を扱うクラス
MotorController 移動の制御と自己位置推定を行うクラス
NumberDetector 数字認識を行うクラス
BallDetector ボールの認識を行うクラス
ImageThread 画像処理スレッドを扱うクラス
UssThread 超音波距離センサ用のスレッドを扱うクラス
FpgaIO FPGAの入出力を扱うクラス
Mirs 行動の制御を行う。メインのクラス

4.スレッド・状態遷移図

まず、スレッドについて以下の表に示す。
メインスレッド 初期化、スレッドの生成、終了処理を行う。
画像処理スレッド 画像処理を行う。
USSスレッド 超音波距離センサによる計測を行う。
コントローラスレッド 行動の制御を行う。
以下に(コントローラスレッド)状態遷移図を示す。

5.フローチャート

メインループのフローチャートを以下に示す。

巡回のフローチャートを以下に示す。

探索のフローチャートを以下に示す。

追跡のフローチャートを以下に示す。

補正のフローチャートを以下に示す。

ボールの画像処理は実効速度が必要なため、複数のパターンを実験して、速いものを選んで採用する。
ボールの画像処理のフローチャート(パターン1)

ボールの画像処理のフローチャート(パターン2)

ボールの画像処理のフローチャート(パターン3)


6.関数・データ定義

特に指定がない限り、長さの単位はmm、角度の単位はradを使用する。
スピードは必ずcm/sとする。

地図ファイルについて、
座標系はシステム設計書の絶対座標系の定義に従う。
地図ファイルの書式を以下に示す。
object parameter parameter ...
この文を何行も記述することによって、競技場の地図情報を表す。 objectと指定できるparameterは、以下の表で定義される。
(競技内容次第では、追加、削除の可能性がある)
object_name parameter 説明
wall parameter1 : 始点のX座標を表す整数
parameter2 : 始点のY座標を表す整数
parameter3 : 終点のX座標を表す整数
parameter4 : 終点のY座標を表す整数
始点から終点までの壁を表す。
column parameter1 : 中心のX座標を表す整数
parameter2 : 中心のY座標を表す整数
parameter3 : 半径を表す整数
円柱を表す。
checkpoint parameter1 : 撮影ポイントのX座標を表す整数
parameter2 : 撮影ポイントのY座標を表す整数
parameter3 : 撮影対象のX座標を表す整数
parameter4 : 撮影対象のY座標を表す整数
カメラによる撮影ポイント・撮影対象を表す
経路ファイルについて、
書式を以下に示す。
toX toY
この文を何行も繰り返すことによって、移動経路を表す。ただし、開始地点は座標(0,0)であるものとして、記述しない。
例えば、
100 100
400 300
ならば、(100,100)の地点に移動し、その後(400,300)の地点に移動することを表す。

以下に、関数を示す。(VMotorはMotorをオーバーライドしてMotorのシミュレーションをするだけなので省略した。)
宣言 概要
int main() 初期化と終了処理を行う。srcc++/Mirs.cppの中で定義される。
Mirs::Mirs(MotorController& mc, UssThread& uss, ImageThread& imagethread, FpgaIO& fpgaio, Field& field, Route& route) Mirsクラスのコンストラクタ
void Mirs::start() 巡回を開始する
void Mirs::controllerThread(MotorController& mc, UssThread& uss, ImageThread& imagethread, FpgaIO& fpgaio, Field& field, Route& route) 行動決定を行う。
Motor::Motor(const char* fd_path,double tire_radius=57.0,double axis_radius=5.5,double rotaryencoder_pulley_radius_ratio=3.85,double rotaryencoder_resolvingpower_deg=1,char kp=55,char ki=5) Motorクラスのコンストラクタ。ファイルディスクリプタのパスを引数にとる
void Motor::update() ロータリーエンコーダの値を取得して進んだ距離に換算したものをメンバ変数(distance)に保存する
void Motor::clear() ロータリーエンコーダの値(総回転角度)をクリアする
int Motor::control(uint8_t speed) モータのスピードを指定する。
bool Motor::isComplete(int dest, int complete=5) 進んだ距離が、dest±completeの範囲に収まっているかを判定する
void Motor::brake() モータを停止状態(スピードを0)にする。
double getDistance() メンバ変数distanceの値を返す
Motors::Motors(const char* fd_path_l,const char* fd_path_r,const char* mode) Motorsクラスのコンストラクタ。modeによってVMotorかMotorのどちらを持つか決定する。modeは、"virtual"または"real"を指定する。
void Motors::update() ロータリーエンコーダの値を取得して進んだ距離に換算したものをメンバ変数(distance)に保存する
void Motors::clear() ロータリーエンコーダの値(総回転角度)をクリアする
int Motors::control(uint8_t speed_l,uint8_t speed_r) モータのスピードを指定する。
bool Motors::isComplete(int dest_l,int dest_r, int complete=5) 進んだ距離が、dest_r±complete,dest_l±completeの範囲に収まっているかを判定する
void Motors::brake() モータを停止する。
MotorControllerBase::MotorControllerBase(const char* l_motor_fd_path, const char* r_motor_fd_path, double two_tires_distance=304.0, int maxspeed=100) MotorControllerBaseクラスのコンストラクタ。左右のモーターのファイルディスクリプタのパスと2つのタイヤ間の距離、指定できる最大のスピードを引数にとる。
int MotorControllerBase::straight(double speed,double dest,int accomplishment=20,double kd=0,double kp=0,double ki=0) 直進走行(左右のスピードを一定に保つ)。while(!mc.straight(...));のようにして呼ぶ。D制御のみを行う。kp、kiはサブクラスのメソッドと同じ引数で利用できるようにするためにとってある。
int MotorControllerBase::rotate(double speed,double deg,accomplishment_deg=10,kd=0,kp=0,ki=0) 回転する。accomplishment_degに角度を指定して、その角度以内であることを終了条件とする。
Position::Position(double x,double y,double theta) Positionクラスのコンストラクタ
double Position::getX() xの値を得る
double Position::getY() yの値を得る
double Position::getThetaRad() thetaの値を得る[rad]
double Position::getThetaDeg() thetaの値を得る[deg]
int MotorController::straight(double speed,double dest,int accomplishment=20,double kd=0,double kp=0,double ki=0) MotorControllerBaseのメソッドのオーバーライド。開始点から、角度を指定することで決まる直線に沿って、直進走行する。
void MotorController::update() Motorsのメソッドのオーバーライド。位置情報の更新も行うようにする。
void MotorController::setStartPos(Position pos) straightのための開始点の設定をする。
UssThread::UssThread(const char *serialport,char uss_count) UssThreadのコンストラクタ,ファイルディスクリプタのパスとUSSの個数を引数にとる
void Uss::startThread() スレッドを開始する
void Uss::stopThread() スレッドを終了する
int* Uss::getValues() 距離計測の結果を要素数がuss_countとなる配列の先頭のポインタとして返す。エラー値は標準のプログラムと同じである
FpgaIO::FpgaIO(const char *fd_path) FpgaIOのコンストラクタ
int FpgaIO::get(unsigned char num) 指定した識別番号のセンサの値を得る
int FpgaIO::put(unsigned char* values) 出力をvaluesにセットする。valuesは要素が4つの配列
ImageThread::ImageThread() ImageThreadのコンストラクタ。
void ImageThread::startThread() 画像処理を行うスレッドを開始する。画像処理の結果は、値取得用のメンバ関数を呼び出して、値を得る
void ImageThread::stopThread() スレッドの終了処理を行う
void ImageThread::start(int mode) スレッドが画像処理を行い始める。modeで"ball"か"number"を指定する。
番号はシステム基本設計書の定義に従う。
void ImageThread::stop(int mode) スレッドが画像処理を行うのを止める。modeで"ball"か"number"を指定する。
番号はシステム基本設計書の定義に従う。
Position ImageThread::getBallPosFromMirs() MIRSを原点としてMIRSの右方向をX軸正にとって、前方にy軸正をとったとき(相対座標系)の、ボールの座標を得る。
ボールが大きく異なる位置に複数存在した場合にはエラーとして、(0,0)を返す。
char ImageThread::getNumber() 数字認識の結果を得る。認識出来なかった場合には-1を返す。
BallDetector::BallDetector() BallDetectorのコンストラクタ。
Position BallDetector::getPosFromMirs() MIRSを原点としてMIRSの右方向をX軸正にとって、前方にy軸正をとったとき(相対座標系)の、ボールの座標を得る。
void BallDetector::update() ボールの認識を行って値を更新する。
NumberDetector::NumberDetector() NumberDetectorのコンストラクタ。
char NumberDetector::get() 数字認識の結果を得る。認識出来なかった場合には-1を返す。
void BallDetector::update() 数字の認識を行って値を更新する。
Field::Field() Fieldのコンストラクタ。
int* Field::getObjectNear(const char* object_name, int x, int y, threshold_radius) 半径threshold_radius以内でもっとも近い、名前がobject_nameであるデータを配列の先頭のポインタとして返す。なければNULLポインタを返す
Route::Route() Routeのコンストラクタ。
int* Route::get() 次の行き先を得る。
int* Route::next() 経路情報を参照している行を1つ進める。
int* Route::previous() 経路情報を参照している行を1つ戻す。
int* Route::getAndNext() 次の行き先を得ると同時に経路情報を参照している行を1つ進める
int* Route::seek(int index) 経路情報を参照している行を任意の行に移す。
int* Route::searchNear(int x, int y) 最も近い経路上の点を返す。
また、マクロとして、
#ifdef NDEBUG
#define debug_printf(...)
#else
#define debug_printf(...) printf(__VA_ARGS__)
#endif
を定義する。これは、デバッグ時以外はプログラムから削除される出力として使うことができる。

画像の撮影は、motionというアプリケーションを利用して、別プロセスで行う。
(追記 OpenCVの機能を用いたほうが簡単で十分高速だったため、そちらを使用した。)
motionの詳細・motion単体のテスト仕様については、調査・文書化を行う。
環境構築手順書

7.テスト仕様

Talk.cppを使用してテストを行う。
以下の動作をすることを仕様とする。
プログラムは、'>'とプロンプトを表示して、コマンドの入力を受け付け始める
以下にコマンドを示す。日本語でかかれている部分は、整数を入力する。
[タッチセンサの確認]
> view touch
[USSの確認]
> view uss
[左右のスピードを一定に保つ直進 straight]
> run st 直進距離
[角度を一定に保つ直進 straightKeepDeg]
> run skd 開始X 開始Y 開始角度 直進距離
[回転]
> run rot 角度
[現在位置,現在角度の取得]
> view pos
[画像処理(ball) ボールの相対座標を出力]
> detect ball
[画像処理(number) 数字認識を行って、数字を出力]
> detect number
[巡回指定経路に従った移動]
> run patrolroute
[探索指定経路に従った移動]
> run searchroute
[パフォーマンス用ボードへのデータ出力]
> output fpga 状態番号

テスト項目と判定基準を以下に示す。

[タッチセンサの確認] [USSの確認] [左右のスピードを一定に保つ直進 straight] [角度を一定に保つ直進 straightKeepDeg]
 動作について説明するための図を下に示す。

[回転]
[現在位置,現在角度の取得] [画像処理(ball) ボールの相対座標を出力] [画像処理(number)] [指定経路に従った移動]
[パフォーマンス用ボードへのデータ出力]
flex 10kのデータシートのURLを示す。
http://www.altera.com/literature/ds/archives/dsf10k.pdf


___________________________最終的なプログラムたち___________________________





沼津工業高等専門学校 電子制御工学科