Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

close #KLI-80 コマンド(CSV)で動作を指定し、動作できる #19

Merged
merged 13 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions datafiles/AreaMasterLeft.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AR,20,100,clockwise,指定角度回頭
1 change: 1 addition & 0 deletions datafiles/AreaMasterRight.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
AR,20,70,anticlockwise,指定角度回頭
46 changes: 46 additions & 0 deletions module/AreaMaster.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @file AreaMaster.cpp
* @brief エリアを攻略するクラス
* @author keiya121
*/

#include "AreaMaster.h"

using namespace std;

AreaMaster::AreaMaster(Area _area, bool _isLeftCourse, bool& _isLeftEdge, int _targetBrightness)
: area(_area),
isLeftCourse(_isLeftCourse),
isLeftEdge(_isLeftEdge),
targetBrightness(_targetBrightness)
{
}

void AreaMaster::run()
{
char buf[SMALL_BUF_SIZE]; // log用にメッセージを一時保持する領域
Logger logger;

// ファイルから受け取る動作リスト
vector<Motion*> motionList;

// コマンドファイルパスを作成する
char commandFilePath[SMALL_BUF_SIZE];
snprintf(commandFilePath, SMALL_BUF_SIZE, "%s%s%s.csv", basePath,
negiuniv marked this conversation as resolved.
Show resolved Hide resolved
commandFileNames[static_cast<int>(area)], (isLeftCourse ? "Left" : "Right"));

// 動作インスタンスのリストを生成する
motionList = MotionParser::createMotions(commandFilePath, targetBrightness, isLeftEdge);

// 動作実行のメッセージログを出す
snprintf(buf, SMALL_BUF_SIZE, "\nRun the commands in '%s'\n", commandFilePath);
negiuniv marked this conversation as resolved.
Show resolved Hide resolved
logger.logHighlight(buf);

// 各動作を実行する
for(auto motion = motionList.begin(); motion != motionList.end();) {
(*motion)->logRunning();
(*motion)->run();
delete *motion; // メモリを解放
motion = motionList.erase(motion); // リストから削除
}
}
55 changes: 55 additions & 0 deletions module/AreaMaster.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @file AreaMaster.h
* @brief エリアを攻略するクラス
* @author keiya121
*/

#ifndef AREA_MASTER_H
#define AREA_MASTER_H

#include <vector>
#include <stdio.h>
#include <string.h>
#include "MotionParser.h"
#include "Logger.h"

// エリア攻略のクラスが未定義のため、仮のエリアを指定
enum Area { AreaMaster };

// エリア名を持つ列挙型変数(LineTrace = 0, DoubleLoop = 1, DebrisRemoval = 2, SmartCarry = 3)
// enum Area { LineTrace, DoubleLoop, DebrisRemoval, SmartCarry };

class AreaMaster {
public:
/**
* コンストラクタ
* @param area エリアの指定(Enum型のArea)
* @param isLeftCourse コースのLR判定(true:Lコース, false:Rコース)
* @param isLeftEdge エッジのLR判定(true:左エッジ, false:右エッジ)
* @param targetBrightness 目標輝度
*/
AreaMaster(Area area, bool isLeftCourse, bool& isLeftEdge, int targetBrightness);

/**
* @brief エリアを走行する
*/
void run();

private:
enum Area area;
bool isLeftCourse;
bool isLeftEdge;
int targetBrightness;

// 各エリアのコマンドファイルベースパス
const char* basePath = "etrobocon2024/datafiles/";

// コマンドファイル名
const char* commandFileNames[1] = { "AreaMaster" };

// TODO:今後切り替えるコマンドファイル名
// // コマンドファイル名(各エリア名)
// const char* commandFileNames[4] = { "LineTrace", "DoubleLoop", "DebrisRemoval", "SmartCarry" };
};

#endif
187 changes: 187 additions & 0 deletions module/MotionParser.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
/**
* @file MotionParser.cpp
* @brief 動作コマンドファイルを解析するクラス
* @author keiya121
*/

#include "MotionParser.h"

using namespace std;

vector<Motion*> MotionParser::createMotions(const char* commandFilePath, int targetBrightness,
bool& isLeftEdge)
{
char buf[LARGE_BUF_SIZE]; // log用にメッセージを一時保持する領域
Logger logger;
int lineNum = 1; // Warning用の行番号

vector<Motion*> motionList; // 動作インスタンスのリスト

// ファイル読み込み
FILE* fp = fopen(commandFilePath, "r");
// ファイル読み込み失敗
if(fp == NULL) {
snprintf(buf, LARGE_BUF_SIZE, "%s file not open!\n", commandFilePath);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここも

logger.logWarning(buf);
return motionList;
}

char row[READ_BUF_SIZE]; // 各行の文字を一時的に保持する領域
const char* separator = ","; // 区切り文字

// 行ごとにパラメータを読み込む
while(fgets(row, READ_BUF_SIZE, fp) != NULL) {
vector<char*> params;
// separatorを区切り文字にしてrowを分解し,paramに代入する
char* param = strtok(row, separator);
while(param != NULL) {
// paramをパラメータとして保持する
params.push_back(param);
// 次のパラメータをparamに代入する
// strtok()は第1引数にNULLを与えると、前回の続きのアドレスから処理が開始される
param = strtok(NULL, separator);
}

// 取得したパラメータから動作インスタンスを生成する
COMMAND command = convertCommand(params[0]); // 行の最初のパラメータをCOMMAND型に変換

if(command == COMMAND::AR) { // 指定角度回頭動作の生成
PwmRotation* ar = new PwmRotation(atoi(params[1]), // 目標角度
atoi(params[2]), // 目標PWM
convertBool(params[0], params[3])); // 回頭方向
motionList.push_back(ar); // 動作リストに追加
}

// TODO: 後で作成する

// else if(command == COMMAND::DL) { // 指定距離ライントレース動作の生成
// DistanceLineTracing* dl = new DistanceLineTracing(
// atof(params[1]), // 目標距離
// targetBrightness + atoi(params[2]), // 目標輝度 + 調整
// atof(params[3]), // 目標速度
// PidGain(atof(params[4]), atof(params[5]), atof(params[6])), // PIDゲイン
// isLeftEdge); // エッジ

// motionList.push_back(dl); // 動作リストに追加
// } else if(command == COMMAND::CL) { // 指定色ライントレース動作の生成
// ColorLineTracing* cl = new ColorLineTracing(
// ColorJudge::stringToColor(params[1]), // 目標色
// targetBrightness + atoi(params[2]), // 目標輝度 + 調整
// atof(params[3]), // 目標速度
// PidGain(atof(params[4]), atof(params[5]), atof(params[6])), // PIDゲイン
// isLeftEdge); // エッジ

// motionList.push_back(cl); // 動作リストに追加
// } else if(command == COMMAND::DS) { // 指定距離直進動作の生成
// DistanceStraight* ds = new DistanceStraight(atof(params[1]), // 目標距離
// atof(params[2])); // 目標速度

// motionList.push_back(ds); // 動作リストに追加
// } else if(command == COMMAND::CS) { // 指定色直進動作の生成
// ColorStraight* cs = new ColorStraight(ColorJudge::stringToColor(params[1]), // 目標色
// atof(params[2])); // 目標速度

// motionList.push_back(cs); // 動作リストに追加
// }else if(command == COMMAND::EC) { // エッジ切り替えの生成
// EdgeChanging* ec = new EdgeChanging(isLeftEdge, // エッジ
// convertBool(params[0], params[1])); //
// 切り替え後のエッジ

// motionList.push_back(ec); // 動作リストに追加
// } else if(command == COMMAND::SL) { // 自タスクスリープの生成
// Sleeping* sl = new Sleeping(atoi(params[1]));

// motionList.push_back(sl); // 動作リストに追加
// }else if(command == COMMAND::DT) { // 距離指定旋回動作の生成
// DistanceTurning* dt = new DistanceTurning(atof(params[1]), // 目標距離
// atoi(params[2]), // 左モータのPWM値
// atoi(params[3])); // 右モータのPWM値

// motionList.push_back(dt); // 動作リストに追加
// } else if(command == COMMAND::AU) { // アームを上げる
// ArmUpping* au = new ArmUpping(atoi(params[1]), atoi(params[2]));

// motionList.push_back(au); // 動作リストに追加
// } else if(command == COMMAND::AD) { // アームを下げる
// ArmDownning* ad = new ArmDownnig(atoi(params[1]), atoi(params[2]));

// motionList.push_back(ad); // 動作リストに追加
// } else if(command == COMMAND::XR) { // 角度補正回頭の追加
// CorrectingRotation* xr = new CorrectingRotation(atoi(params[1]), // 目標角度
// atoi(params[2])); // 目標速度

// motionList.push_back(xr); // 動作リストに追加
// }
bizyutyu marked this conversation as resolved.
Show resolved Hide resolved

else { // 未定義のコマンドの場合
snprintf(buf, LARGE_BUF_SIZE, "%s:%d: '%s' is undefined command", commandFilePath, lineNum,
negiuniv marked this conversation as resolved.
Show resolved Hide resolved
params[0]);
logger.logWarning(buf);
}
lineNum++; // 行番号をインクリメントする
}

// ファイルを閉じる
fclose(fp);

return motionList;
}

COMMAND MotionParser::convertCommand(char* str)
{
if(strcmp(str, "DL") == 0) { // 文字列がDLの場合
return COMMAND::DL;
} else if(strcmp(str, "CL") == 0) { // 文字列がCLの場合
return COMMAND::CL;
} else if(strcmp(str, "DS") == 0) { // 文字列がDSの場合
return COMMAND::DS;
} else if(strcmp(str, "CS") == 0) { // 文字列がCSの場合
return COMMAND::CS;
} else if(strcmp(str, "AR") == 0) { // 文字列がARの場合
return COMMAND::AR;
} else if(strcmp(str, "DT") == 0) { // 文字列がDTの場合
return COMMAND::DT;
} else if(strcmp(str, "EC") == 0) { // 文字列がECの場合
return COMMAND::EC;
} else if(strcmp(str, "SL") == 0) { // 文字列がSLの場合
return COMMAND::SL;
} else if(strcmp(str, "AU") == 0) { // 文字列がAUの場合
return COMMAND::AU;
} else if(strcmp(str, "AD") == 0) { // 文字列がADの場合
return COMMAND::AD;
} else if(strcmp(str, "XR") == 0) { // 文字列がXRの場合
return COMMAND::XR;
} else { // 想定していない文字列が来た場合
return COMMAND::NONE;
}
}

bool MotionParser::convertBool(char* command, char* stringParameter)
{
Logger logger;

// 末尾の改行を削除
char* param = StringOperator::removeEOL(stringParameter);

if(strcmp(command, "AR") == 0) { // コマンドがARの場合
if(strcmp(param, "clockwise") == 0) { // パラメータがclockwiseの場合
return true;
} else if(strcmp(param, "anticlockwise") == 0) { // パラメータがanticlockwiseの場合
return false;
} else { // 想定していないパラメータが来た場合
logger.logWarning("Parameter before conversion must be 'clockwise' or 'anticlockwise'");
return true;
}
}

if(strcmp(command, "EC") == 0) { // コマンドがECの場合
if(strcmp(param, "left") == 0) { // パラメータがleftの場合
return true;
} else if(strcmp(param, "right") == 0) { // パラメータがrightの場合
return false;
} else { // 想定していないパラメータが来た場合
logger.logWarning("Parameter before conversion must be 'left' or 'right'");
return true;
}
}
}
66 changes: 66 additions & 0 deletions module/MotionParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @file MotionParser.h
* @brief 動作コマンドファイルを解析するクラス
* @author keiya121
*/

#ifndef MOTION_PARSER_H
#define MOTION_PARSER_H

#include <vector>
#include <stdio.h>
#include <string.h>
#include "Logger.h"
#include "Motion.h"
#include "PwmRotation.h"
#include "StringOperator.h"

#define READ_BUF_SIZE 256 // コマンドのパラメータ読み込み用の領域

enum class COMMAND {
DL, // 指定距離ライントレース
CL, // 指定色ライントレース
DS, // 指定距離直進
CS, // 指定色直進
AR, // 指定角度回頭
DT, // 旋回
EC, // エッジ切り替え
SL, // 自タスクスリープ
AU, // アームを上げる
AD, // アームを下げる
XR, // 角度補正回頭
NONE
};

class MotionParser {
public:
/**
* @brief ファイルを解析して動作インスタンスのリストを生成する
* @param filePath ファイルパス
* @param targetBrightness 目標輝度
* @param isLeftEdge エッジのLR判定(true:Lコース, false:Rコース)
* @return 動作インスタンスリスト
*/
static std::vector<Motion*> createMotions(const char* filePath, int targetBrightness,
bool& isLeftEdge);

private:
MotionParser(); // インスタンス化を禁止する

/**
* @brief 文字列を列挙型COMMANDに変換する
* @param str 文字列のコマンド
* @return コマンド
*/
static COMMAND convertCommand(char* str);

/**
* @brief 文字列をbool型に変換する
* @param command 文字列のコマンド
* @param stringParameter 文字列のパラメータ
* @return bool値
*/
static bool convertBool(char* command, char* stringParameter);
};

#endif
Loading
Loading