diff --git a/module/Calibrator.cpp b/module/Calibrator.cpp new file mode 100644 index 0000000..3a5ab39 --- /dev/null +++ b/module/Calibrator.cpp @@ -0,0 +1,131 @@ +/** + * @file Calibrator.cpp + * @brief キャリブレーションからスタートまでを担当するクラス + * @author takahashitom + */ + +#include "Calibrator.h" + +Calibrator::Calibrator() : isLeftCourse(true), targetBrightness(50) {} + +void Calibrator::run() +{ + // まだ画像に関する処理が実装されていないためコメントアウト + // // 画像の削除 + // char cmd[LARGE_BUF_SIZE]; + // snprintf(cmd, LARGE_BUF_SIZE, "cd etrobocon2024/rear_camera_py && make rm-img && cd ../.."); + // system(cmd); + + // 左右ボタンでコースのLRを選択する + selectAndSetCourse(); + + // 目標輝度を測定する + measureAndSetTargetBrightness(); +} + +void Calibrator::selectAndSetCourse() +{ + char buf[SMALL_BUF_SIZE]; // log用にメッセージを一時保持する領域 + Logger logger; + bool _isLeftCourse = true; + + logger.log("Select a Course"); + logger.log(">> Set Left Course"); + // 右ボタンが押されたら確定する + while(!measurer.getRightButton()) { + if(measurer.getLeftButton() && !_isLeftCourse) { + // 左ボタンが押されたときRコースがセットされていれば、Lコースをセットする + _isLeftCourse = true; + logger.log(">> Set Left Course"); + timer.sleep(500); // 500ミリ秒スリープ + } else if(measurer.getLeftButton() && _isLeftCourse) { + // 左ボタンが押されたときLコースがセットされていれば、Rコースをセットする + _isLeftCourse = false; + logger.log(">> Set Right Course"); + timer.sleep(500); // 500ミリ秒スリープ + } else { + timer.sleep(); // 10ミリ秒スリープ + } + } + + isLeftCourse = _isLeftCourse; + const char* course = isLeftCourse ? "Left" : "Right"; + snprintf(buf, SMALL_BUF_SIZE, "\nWill Run on the %s Course\n", course); + logger.logHighlight(buf); + + timer.sleep(1000); // 1秒スリープ +} + +void Calibrator::measureAndSetTargetBrightness() +{ + char buf[SMALL_BUF_SIZE]; // log用にメッセージを一時保持する領域 + Logger logger; + int whiteBrightness = -1; + int blackBrightness = -1; + targetBrightness = -1; + + // 黒線上で左ボタンを押して黒の輝度を取得し、右ボタンで決定する + logger.log("Press the Left Button on the Black"); + + // 黒 + // 左ボタンで輝度を取得し、右ボタンで黒の輝度を決定する + while(blackBrightness < 0 || !measurer.getRightButton()) { + // 左ボタンが押されるまで待機 + while(blackBrightness < 0 && !measurer.getLeftButton()) { + timer.sleep(); // 10ミリ秒スリープ + } + // 輝度取得 + blackBrightness = measurer.getBrightness(); + snprintf(buf, SMALL_BUF_SIZE, ">> Black Brightness Value is %d", blackBrightness); + logger.log(buf); + timer.sleep(); // 10ミリ秒スリープ + } + + // 白線上で左ボタンを押して白の輝度を取得し、右ボタンで決定する + logger.log("Press the Left Button on the White"); + + // 白 + // 左ボタンで輝度を取得し、右ボタンで白の輝度を決定する + while(whiteBrightness < 0 || !measurer.getRightButton()) { + // 左ボタンが押されるまで待機 + while(whiteBrightness < 0 && !measurer.getLeftButton()) { + timer.sleep(); // 10ミリ秒スリープ + } + // 輝度取得 + whiteBrightness = measurer.getBrightness(); + snprintf(buf, SMALL_BUF_SIZE, ">> White Brightness Value is %d", whiteBrightness); + logger.log(buf); + timer.sleep(); // 10ミリ秒スリープ + } + + targetBrightness = (whiteBrightness + blackBrightness) / 2; + snprintf(buf, SMALL_BUF_SIZE, ">> Target Brightness Value is %d", targetBrightness); + logger.log(buf); +} + +void Calibrator::waitForStart() +{ + char buf[SMALL_BUF_SIZE]; // log用にメッセージを一時保持する領域 + Logger logger; + constexpr int startDistance = 5; // 手などでスタート合図を出す距離[cm] + + logger.log("On standby.\n"); + snprintf(buf, SMALL_BUF_SIZE, "On standby.\n\nSignal within %dcm from Sonar Sensor.", + startDistance); + logger.log(buf); + + // startDistance以内の距離に物体がない間待機する + while(measurer.getForwardDistance() > startDistance) { + timer.sleep(); // 10ミリ秒スリープ + } +} + +bool Calibrator::getIsLeftCourse() +{ + return isLeftCourse; +} + +int Calibrator::getTargetBrightness() +{ + return targetBrightness; +} \ No newline at end of file diff --git a/module/Calibrator.h b/module/Calibrator.h new file mode 100644 index 0000000..6a95849 --- /dev/null +++ b/module/Calibrator.h @@ -0,0 +1,60 @@ +/** + * @file Calibrator.h + * @brief キャリブレーションからスタートまでを担当するクラス + * @author takahashitom + */ + +#ifndef CALIBRATOR_H +#define CALIBRATOR_H + +#include "Measurer.h" +#include "Timer.h" +#include "Logger.h" + +class Calibrator { + public: + /** + * コンストラクタ + */ + Calibrator(); + + /** + * @brief キャリブレーション処理(入力系)をまとめて実行する + */ + void run(); + + /** + * @brief スタート合図が出るまで待機状態にする + */ + void waitForStart(); + + /** + * @brief isLeftCourseのゲッター + * @return true:Lコース, false:Rコース + */ + bool getIsLeftCourse(); + + /** + * @brief targetBrightnessのゲッター + * @return 目標輝度 + */ + int getTargetBrightness(); + + private: + bool isLeftCourse; // true:Lコース, false: Rコース + int targetBrightness; // 目標輝度 + Timer timer; + Measurer measurer; + + /** + * @brief 左右ボタンでLRコースを選択してisLeftCourseをセットする + */ + void selectAndSetCourse(); + + /** + * @brief 黒と白の輝度を測定して目標輝度を求めtargetBrightnessをセットする + */ + void measureAndSetTargetBrightness(); +}; + +#endif \ No newline at end of file diff --git a/test/CalibratorTest.cpp b/test/CalibratorTest.cpp new file mode 100644 index 0000000..8f62b04 --- /dev/null +++ b/test/CalibratorTest.cpp @@ -0,0 +1,96 @@ +/** + * @file CalibratorTest.cpp + * @brief Calibratorクラスのテスト + * @author takahashitom + */ + +#include "Calibrator.h" +#include "DummyRobot.h" +#include +#include + +using namespace std; + +namespace etrobocon2024_test { + + // run()において期待した出力がされており,WarningやErrorが出ていないかテスト + TEST(CalibratorTest, run) + { + Calibrator calibrator; + DummyRobot::setButtonState( + DummyRobot::ButtonState::right); // 実機のボタン押下状態を「右」に設定 + testing::internal::CaptureStdout(); // 標準出力キャプチャ開始 + calibrator.run(); + string output = testing::internal::GetCapturedStdout(); // キャプチャ終了 + + // find("str")はstrが見つからない場合string::nposを返す + bool actual = output.find("Will Run on the Left Course") != string::npos + && output.find("Warning") == string::npos // Warningがない + && output.find("Error") == string::npos; // Errorがない + + EXPECT_TRUE(actual); + } + + // waitForStart()において期待した出力がされており,WarningやErrorが出ていないかテスト + TEST(CalibratorTest, waitForStart) + { + Calibrator calibrator; + testing::internal::CaptureStdout(); // 標準出力キャプチャ開始 + calibrator.waitForStart(); + string output = testing::internal::GetCapturedStdout(); // キャプチャ終了 + + // find("str")はstrが見つからない場合string::nposを返す + bool actual = output.find("On standby.\n\nSignal within 5cm from Sonar Sensor.") != string::npos + && output.find("Warning") == string::npos // Warningがない + && output.find("Error") == string::npos; // Errorがない + + EXPECT_TRUE(actual); + } + + // getIsLeftCourse()により、isLeftCourseの値を取得できるかのテスト + TEST(CalibratorTest, getIsLeftCourse) + { + Calibrator calibrator; + testing::internal::CaptureStdout(); // 標準出力キャプチャ開始 + calibrator.run(); + string output = testing::internal::GetCapturedStdout(); // キャプチャ終了 + bool expected; + + // Leftコースと出力されていた場合 + if(output.find("Will Run on the Left Course") != string::npos) { + expected = true; // Lコース + } + // Rightコースと出力されていた場合 + else if(output.find("Will Run on the Right Course") != string::npos) { + expected = false; // Rコース + } + // 想定していない状況 + else { + expected = NULL; + } + + bool actual = calibrator.getIsLeftCourse(); // 実際のisLeftCourseを取得 + + EXPECT_EQ(expected, actual); // 出力とゲッタの値が等しいかテスト + } + + // getTargetBrightness()により、targetBrightnessの値を取得できるかのテスト + TEST(CalibratorTest, getTargetBrightness) + { + Calibrator calibrator; + testing::internal::CaptureStdout(); // 標準出力キャプチャ開始 + calibrator.run(); + string output = testing::internal::GetCapturedStdout(); // キャプチャ終了 + + string targetString = "Target Brightness Value is "; // 目標輝度値の直前に書かれている文字列 + + // 出力された目標輝度値を取得 + int index = output.find(targetString) + targetString.length(); + string expectedStr = output.substr(index); // 輝度値を取得(文字列) + int expected = stoi(expectedStr); // 文字列を整数値に変換 + + int actual = calibrator.getTargetBrightness(); // 実際の輝度値を取得 + + EXPECT_EQ(expected, actual); // 出力とゲッタの値が等しいかテスト + } +} // namespace etrobocon2024_test \ No newline at end of file diff --git a/test/dummy/ev3api_button.cpp b/test/dummy/ev3api_button.cpp index 3dfbef3..ec3751e 100644 --- a/test/dummy/ev3api_button.cpp +++ b/test/dummy/ev3api_button.cpp @@ -1,7 +1,7 @@ /** * @file ev3api_button.cpp * @brief ボタン関連のダミー - * @author keiya121 + * @author keiya121 takahashitom */ #include "ev3api_button.h" @@ -9,16 +9,18 @@ bool ev3_button_is_pressed(button_t button) { + bool judge = false; + DummyRobot::ButtonState currentButtonState = DummyRobot::getButtonState(); // 左ボタンが押された時 - if(button == LEFT_BUTTON && currentButtonState == DummyRobot::ButtonState::left) return true; + if(button == LEFT_BUTTON && currentButtonState == DummyRobot::ButtonState::left) judge = true; // 右ボタンが押された時 - if(button == RIGHT_BUTTON && currentButtonState == DummyRobot::ButtonState::right) return true; + if(button == RIGHT_BUTTON && currentButtonState == DummyRobot::ButtonState::right) judge = true; // 中央ボタンが押された時 - if(button == ENTER_BUTTON && currentButtonState == DummyRobot::ButtonState::enter) return true; + if(button == ENTER_BUTTON && currentButtonState == DummyRobot::ButtonState::enter) judge = true; if(button != LEFT_BUTTON && button != RIGHT_BUTTON && button != ENTER_BUTTON) { printf("\x1b[31m"); // 前景色を赤に @@ -26,5 +28,17 @@ bool ev3_button_is_pressed(button_t button) printf("\x1b[39m\n"); // 前景色をデフォルトに戻す } - return false; + // 次のボタンの状態を設定する + int nextButtonState = rand() % 4; + if(nextButtonState == 0) { + DummyRobot::setButtonState(DummyRobot::ButtonState::left); + } else if(nextButtonState == 1) { + DummyRobot::setButtonState(DummyRobot::ButtonState::enter); + } else if(nextButtonState == 2) { + DummyRobot::setButtonState(DummyRobot::ButtonState::right); + } else if(nextButtonState == 3) { + DummyRobot::setButtonState(DummyRobot::ButtonState::none); + } + + return judge; } \ No newline at end of file