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-82 キャリブレーションクラスを実装する #17

Merged
merged 6 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
131 changes: 131 additions & 0 deletions module/Calibrator.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
60 changes: 60 additions & 0 deletions module/Calibrator.h
Original file line number Diff line number Diff line change
@@ -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
96 changes: 96 additions & 0 deletions test/CalibratorTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* @file CalibratorTest.cpp
* @brief Calibratorクラスのテスト
* @author takahashitom
*/

#include "Calibrator.h"
#include "DummyRobot.h"
#include <gtest/gtest.h>
#include <gtest/internal/gtest-port.h>

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
24 changes: 19 additions & 5 deletions test/dummy/ev3api_button.cpp
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
/**
* @file ev3api_button.cpp
* @brief ボタン関連のダミー
* @author keiya121
* @author keiya121 takahashitom
*/

#include "ev3api_button.h"
#include "../DummyRobot.h"

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"); // 前景色を赤に
printf("error: Variable \"button\" is an unexpected value");
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;
}
Loading