Skip to content

Commit 04680a6

Browse files
committed
update: 復帰動作用
1 parent 5fa1650 commit 04680a6

File tree

4 files changed

+215
-56
lines changed

4 files changed

+215
-56
lines changed

modules/MotionParser.cpp

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -434,38 +434,35 @@ vector<Motion*> MotionParser::createMotions(Robot& robot, string& commandFilePat
434434
break;
435435
}
436436

437-
// CRA: カメラ復帰動作
438-
// [1]:int 回頭角度[deg], [2]:double 回頭スピード[mm/s], [3]:string 回頭の方向(clockwise or
439-
// anticlockwise), [4-9]:int HSV値(lowerH,lowerS,lowerV,upperH,upperS,upperV), [10-13]int
440-
// ROI座標[px]
441-
// ([10]左上隅のx座標, [11]左上隅のy座標, [12]幅, [13]高さ), [14-15]int 解像度[px] ([14]幅,
442-
// [15]高さ)
437+
// CRA: カメラ検出失敗時の復帰動作
438+
// [1]:int ラインの方向角度(絶対角度)[deg], [2]:int 基準パワー値,
439+
// [3-5]:double ライン回頭用PIDゲイン(kp, ki, kd)
440+
// [6]:int 首振り角度(deg), [7]:int 最大首振り回数
441+
// [8]:double PCIDS距離[mm], [9]:double PCIDS速度[mm/s],
442+
// [10-12]:double PCIDS用PIDゲイン(kp, ki, kd)
443+
// [13-18]:int HSV値(lowerH,lowerS,lowerV,upperH,upperS,upperV), [19-22]:int ROI座標[px]
444+
// ([19]左上隅のx座標, [20]左上隅のy座標, [21]幅, [22]高さ), [23-24]:int 解像度[px] ([23]幅,
445+
// [24]高さ)
443446
// 補足:ROI(Region of Interest: ライントレース用の画像内注目領域(四角形))
444447
case COMMAND::CRA: {
445448
CameraServer::BoundingBoxDetectorRequest detectionRequest;
446449

447450
detectionRequest.command
448451
= CameraServer::Command::LINE_DETECTION; // コマンドタイプをライン検出に設定
449452

450-
detectionRequest.lowerHSV = cv::Scalar(stoi(params[4]), stoi(params[5]), stoi(params[6]));
451-
detectionRequest.upperHSV = cv::Scalar(stoi(params[7]), stoi(params[8]), stoi(params[9]));
452-
453-
// パラメータ配列のサイズによってROIと解像度を設定
454-
if(params.size() > 15) {
455-
detectionRequest.roi
456-
= cv::Rect(stoi(params[10]), stoi(params[11]), stoi(params[12]), stoi(params[13]));
457-
detectionRequest.resolution = cv::Size(stoi(params[14]), stoi(params[15]));
458-
} else if(params.size() > 13) {
459-
detectionRequest.roi
460-
= cv::Rect(stoi(params[10]), stoi(params[11]), stoi(params[12]), stoi(params[13]));
461-
detectionRequest.resolution = cv::Size(640, 480);
462-
} else {
463-
detectionRequest.roi = cv::Rect(50, 240, 540, 240);
464-
detectionRequest.resolution = cv::Size(640, 480);
465-
}
453+
detectionRequest.lowerHSV
454+
= cv::Scalar(stoi(params[13]), stoi(params[14]), stoi(params[15]));
455+
detectionRequest.upperHSV
456+
= cv::Scalar(stoi(params[16]), stoi(params[17]), stoi(params[18]));
457+
detectionRequest.roi
458+
= cv::Rect(stoi(params[19]), stoi(params[20]), stoi(params[21]), stoi(params[22]));
459+
detectionRequest.resolution = cv::Size(stoi(params[23]), stoi(params[24]));
466460

467-
auto cra = new CameraRecoveryAction(robot, stoi(params[1]), stod(params[2]),
468-
convertBool(params[0], params[3]), detectionRequest);
461+
PidGain anglePidGain(stod(params[3]), stod(params[4]), stod(params[5]));
462+
PidGain pcidsPidGain(stod(params[10]), stod(params[11]), stod(params[12]));
463+
auto cra = new CameraRecoveryAction(robot, stoi(params[1]), stoi(params[2]), anglePidGain,
464+
stoi(params[6]), stoi(params[7]), stod(params[8]),
465+
stod(params[9]), pcidsPidGain, detectionRequest);
469466
motionList.push_back(cra);
470467
break;
471468
}

modules/motions/CameraRecoveryAction.cpp

Lines changed: 108 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@
55
*/
66

77
#include "CameraRecoveryAction.h"
8-
#include <thread>
9-
#include <chrono>
10-
#include <iostream>
118

129
CameraRecoveryAction::CameraRecoveryAction(
13-
Robot& _robot, int _angle, double _speed, bool _isClockwise,
14-
const CameraServer::BoundingBoxDetectorRequest& _detectionRequest)
10+
Robot& _robot, int _lineDirectionAngle, int _basePower, const PidGain& _anglePidGain,
11+
int _swingAngle, int _maxSwingCount, double _pcidsDistance, double _pcidsSpeed,
12+
const PidGain& _pcidsPidGain, const CameraServer::BoundingBoxDetectorRequest& _detectionRequest)
1513
: CompositeMotion(_robot),
16-
recoveryAngle(_angle),
17-
speed(_speed),
18-
isClockwise(_isClockwise),
14+
lineDirectionAngle(_lineDirectionAngle),
15+
basePower(_basePower),
16+
anglePidGain(_anglePidGain),
17+
swingAngle(_swingAngle),
18+
maxSwingCount(_maxSwingCount),
19+
pcidsDistance(_pcidsDistance),
20+
pcidsSpeed(_pcidsSpeed),
21+
pcidsPidGain(_pcidsPidGain),
1922
detectionRequest(_detectionRequest)
2023
{
2124
}
@@ -38,21 +41,112 @@ void CameraRecoveryAction::run()
3841
return;
3942
}
4043

41-
AngleRotation rotation(robot, recoveryAngle, speed, isClockwise);
42-
rotation.run();
43-
std::this_thread::sleep_for(std::chrono::milliseconds(10));
44+
// 停止処理
45+
robot.getMotorControllerInstance().stopWheelsMotor();
46+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
47+
48+
// IMUの角度計算が開始されているかチェック
49+
if(!robot.getIMUControllerInstance().getShouldContinueCalculation()) {
50+
std::cerr << "IS,startで角度計算を事前に開始する必要があります。" << std::endl;
51+
return;
52+
}
53+
54+
// 現在の角度を取得
55+
double currentAngle = robot.getIMUControllerInstance().getAngle();
56+
57+
// 目標角度への最短回頭方向を決定
58+
// fmodで(目標角度 - 現在角度)を0~360度に正規化すると「時計回りで回る場合の角度」を計算
59+
// この値が180度以下なら時計回りの方が短く、180度より大きければ反時計回りの方が短い
60+
bool isClockwise = (fmod(lineDirectionAngle - currentAngle + 360.0, 360.0) <= 180.0);
61+
62+
// ラインの方向へ絶対角度モードで回頭
63+
IMUAngleRotation turnToLineDirection(robot, lineDirectionAngle, basePower, isClockwise,
64+
anglePidGain, true);
65+
turnToLineDirection.run();
66+
67+
// 最新フレームに更新するためにスナップショットを連続で取得
68+
CameraServer::SnapshotActionRequest request{};
69+
request.command = CameraServer::Command::TAKE_SNAPSHOT;
70+
std::strncpy(request.fileName, "warmup", sizeof(request.fileName));
71+
for(int i = 0; i < 5; ++i) {
72+
CameraServer::SnapshotActionResponse response{};
73+
robot.getSocketClient().executeSnapshotAction(request, response);
74+
std::this_thread::sleep_for(std::chrono::milliseconds(5));
75+
}
76+
77+
// デバッグ用に復帰動作後の画像を保存
78+
Snapshot snapshot(robot, "recovery_line_direction");
79+
snapshot.run();
80+
81+
// 動作安定のためにスリープ
82+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
4483

4584
// 再検出
4685
success = client.executeLineDetection(detectionRequest, response);
4786

4887
if(!success) {
49-
std::cerr << "通信に失敗しました" << std::endl;
88+
std::cerr << "再検出時の通信に失敗しました" << std::endl;
5089
return;
5190
}
5291

5392
if(response.result.wasDetected) {
5493
std::cout << "復帰に成功しました。" << std::endl;
55-
} else {
56-
std::cout << "復帰できませんでした。" << std::endl;
94+
return;
95+
}
96+
97+
// 復帰できなかった場合、首振り動作で検出を試みる
98+
int swingCount = 0;
99+
bool currentDirection = isClockwise; // 現在の首振り方向
100+
101+
while(true) { // ラインを検出するまで無限ループ
102+
// 首振り動作
103+
for(int i = 0; i < maxSwingCount; ++i) {
104+
// swingAngle分、現在の方向(currentDirection)に相対角度で首を振る
105+
IMUAngleRotation swing(robot, swingAngle, basePower, currentDirection, anglePidGain, false);
106+
swing.run();
107+
108+
// 最新フレームに更新するためにスナップショットを連続で取得
109+
CameraServer::SnapshotActionRequest request{};
110+
request.command = CameraServer::Command::TAKE_SNAPSHOT;
111+
std::strncpy(request.fileName, "warmup", sizeof(request.fileName));
112+
for(int j = 0; j < 5; ++j) {
113+
CameraServer::SnapshotActionResponse response{};
114+
robot.getSocketClient().executeSnapshotAction(request, response);
115+
std::this_thread::sleep_for(std::chrono::milliseconds(5));
116+
}
117+
118+
// デバッグ用に復帰動作後の画像を保存
119+
Snapshot snapshot(robot, "recovery_swing");
120+
snapshot.run();
121+
122+
// 動作安定のためにスリープ
123+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
124+
125+
// 検出を試みる
126+
success = client.executeLineDetection(detectionRequest, response);
127+
if(success && response.result.wasDetected) {
128+
std::cout << "首振りで復帰に成功しました。" << std::endl;
129+
return;
130+
}
131+
132+
swingCount++;
133+
}
134+
135+
// 首振り動作後、直進
136+
std::cout << "首振り " << swingCount << " 回実施後、直進します。" << std::endl;
137+
PictureColorDistanceStraight straightMotion(robot, pcidsDistance, pcidsSpeed, pcidsPidGain,
138+
detectionRequest);
139+
straightMotion.run();
140+
141+
// 直進後に再検出
142+
success = client.executeLineDetection(detectionRequest, response);
143+
if(success && response.result.wasDetected) {
144+
std::cout << "直進後に復帰に成功しました。" << std::endl;
145+
return;
146+
}
147+
148+
// 首振り方向を反転
149+
currentDirection = !currentDirection;
150+
std::cout << "首振り方向を反転して継続します。" << std::endl;
57151
}
58152
}

modules/motions/CameraRecoveryAction.h

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,34 @@
88
#define CAMERA_RECOVERY_ACTION_H
99

1010
#include "CompositeMotion.h"
11-
#include "AngleRotation.h"
11+
#include "IMUAngleRotation.h"
1212
#include "SocketProtocol.h"
13+
#include "Snapshot.h"
14+
#include "PictureColorDistanceStraight.h"
15+
#include "Pid.h"
16+
#include <iostream>
17+
#include <cmath>
18+
#include <thread>
19+
#include <chrono>
1320

1421
class CameraRecoveryAction : public CompositeMotion {
1522
public:
1623
/**
1724
* コンストラクタ
1825
* @param _robot ロボットインスタンス
19-
* @param _angle 回頭角度 (dig) 0~180
20-
* @param _speed 回頭速度(mm/秒)
21-
* @param _isClockwise 回頭方向(true: 右回り, false: 左回り)
26+
* @param _lineDirectionAngle ラインの方向角度(絶対角度, deg) 0~360
27+
* @param _basePower 基準パワー値
28+
* @param _anglePidGain 角度制御用PIDゲイン
29+
* @param _swingAngle 首振り角度(deg)
30+
* @param _maxSwingCount 最大首振り回数
31+
* @param _pcidsDistance PCIDS用の目標距離[mm]
32+
* @param _pcidsSpeed PCIDS用の目標速度[mm/s]
33+
* @param _pcidsPidGain PCIDS用の角度補正PIDゲイン
2234
* @param _detectionRequest 検出リクエスト
2335
*/
24-
CameraRecoveryAction(Robot& _robot, int _angle, double _speed, bool _isClockwise,
36+
CameraRecoveryAction(Robot& _robot, int _lineDirectionAngle, int _basePower,
37+
const PidGain& _anglePidGain, int _swingAngle, int _maxSwingCount,
38+
double _pcidsDistance, double _pcidsSpeed, const PidGain& _pcidsPidGain,
2539
const CameraServer::BoundingBoxDetectorRequest& _detectionRequest);
2640

2741
/**
@@ -32,10 +46,15 @@ class CameraRecoveryAction : public CompositeMotion {
3246
private:
3347
CameraServer::BoundingBoxDetectorRequest detectionRequest; // 検出リクエスト
3448
BoundingBoxDetectionResult result; // 検出結果
35-
int recoveryAngle; // 復帰回頭角度
36-
double speed; // 回頭スピード
37-
bool isClockwise; // 回頭方向
38-
static constexpr int FRAME_NUMBER = 5; // フレーム取得回数
49+
int lineDirectionAngle; // ラインの方向角度(絶対角度)
50+
int basePower; // 基準パワー値
51+
PidGain anglePidGain; // 角度制御用PIDゲイン
52+
int swingAngle; // 首振り角度
53+
int maxSwingCount; // 最大首振り回数
54+
double pcidsDistance; // PCIDS用の目標距離[mm]
55+
double pcidsSpeed; // PCIDS用の目標速度[mm/s]
56+
PidGain pcidsPidGain; // PCIDS用の角度補正PIDゲイン
57+
static constexpr int FRAME_NUMBER = 5; // フレーム取得回数
3958
};
4059

4160
#endif

tests/CameraRecoveryActionTest.cpp

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "Robot.h"
1111
#include "MockSocketClient.h"
1212
#include "SystemInfo.h"
13+
#include "IMUSetting.h"
1314

1415
using namespace std;
1516

@@ -27,7 +28,10 @@ namespace etrobocon2025_test {
2728
mockSocketClient.setNextLineDetectionResponse(successResponse);
2829

2930
CameraServer::BoundingBoxDetectorRequest dummyRequest;
30-
CameraRecoveryAction action(robot, 20, 100.0, true, dummyRequest);
31+
PidGain anglePidGain{ 0.3, 0.005, 0.15 };
32+
PidGain pcidsPidGain{ 0.5, 0.01, 0.2 };
33+
CameraRecoveryAction action(robot, 20, 100, anglePidGain, 10, 3, 100.0, 50.0, pcidsPidGain,
34+
dummyRequest);
3135

3236
testing::internal::CaptureStdout();
3337
action.run();
@@ -41,6 +45,20 @@ namespace etrobocon2025_test {
4145
MockSocketClient mockSocketClient;
4246
Robot robot(mockSocketClient);
4347

48+
// オフセット計算前に静止状態に設定
49+
IMUTestControl::rotationStateRef() = 0;
50+
51+
// オフセット計算と補正行列計算を事前実行
52+
robot.getIMUControllerInstance().initializeOffset();
53+
robot.getIMUControllerInstance().calculateCorrectionMatrix();
54+
55+
// 絶対角度モードのため角度計算を開始
56+
IMUSetting imuStart(robot, true);
57+
imuStart.run();
58+
59+
// ダミーIMUの回転状態を右回頭に設定
60+
IMUTestControl::rotationStateRef() = 1;
61+
4462
// モックを設定: 初回は失敗、2回目は成功
4563
CameraServer::BoundingBoxDetectorResponse failureResponse;
4664
failureResponse.result.wasDetected = false;
@@ -50,33 +68,64 @@ namespace etrobocon2025_test {
5068
mockSocketClient.setNextLineDetectionResponse(successResponse);
5169

5270
CameraServer::BoundingBoxDetectorRequest dummyRequest;
53-
CameraRecoveryAction action(robot, 20, 100.0, true, dummyRequest);
71+
PidGain anglePidGain{ 0.3, 0.005, 0.15 };
72+
PidGain pcidsPidGain{ 0.5, 0.01, 0.2 };
73+
CameraRecoveryAction action(robot, 15, 100, anglePidGain, 10, 3, 100.0, 50.0, pcidsPidGain,
74+
dummyRequest);
5475

5576
testing::internal::CaptureStdout();
5677
action.run();
5778
string output = testing::internal::GetCapturedStdout();
5879
ASSERT_NE(output.find("復帰に成功しました。"), string::npos);
80+
81+
// 角度計算を停止
82+
IMUSetting imuStop(robot, false);
83+
imuStop.run();
5984
}
6085

61-
// 復帰動作を行い、再検出でも失敗した場合のテスト
62-
TEST(CameraRecoveryActionTest, DetectionFailureAfterRecovery)
86+
// 復帰動作を行い、首振りで成功した場合のテスト
87+
TEST(CameraRecoveryActionTest, DetectionSuccessAfterSwing)
6388
{
6489
MockSocketClient mockSocketClient;
6590
Robot robot(mockSocketClient);
6691

67-
// モックを設定: 2回とも失敗
92+
// オフセット計算前に静止状態に設定
93+
IMUTestControl::rotationStateRef() = 0;
94+
95+
// オフセット計算と補正行列計算を事前実行
96+
robot.getIMUControllerInstance().initializeOffset();
97+
robot.getIMUControllerInstance().calculateCorrectionMatrix();
98+
99+
// 絶対角度モードのため角度計算を開始
100+
IMUSetting imuStart(robot, true);
101+
imuStart.run();
102+
103+
// ダミーIMUの回転状態を右回頭に設定
104+
IMUTestControl::rotationStateRef() = 1;
105+
106+
// モックを設定: 初回と再検出は失敗、首振り後に成功
68107
CameraServer::BoundingBoxDetectorResponse failureResponse;
69108
failureResponse.result.wasDetected = false;
70-
mockSocketClient.setNextLineDetectionResponse(failureResponse);
71-
mockSocketClient.setNextLineDetectionResponse(failureResponse);
109+
CameraServer::BoundingBoxDetectorResponse successResponse;
110+
successResponse.result.wasDetected = true;
111+
mockSocketClient.setNextLineDetectionResponse(failureResponse); // 初回失敗
112+
mockSocketClient.setNextLineDetectionResponse(failureResponse); // 再検出失敗
113+
mockSocketClient.setNextLineDetectionResponse(successResponse); // 首振り後成功
72114

73115
CameraServer::BoundingBoxDetectorRequest dummyRequest;
74-
CameraRecoveryAction action(robot, 90, 300.0, true, dummyRequest);
116+
PidGain anglePidGain{ 0.3, 0.005, 0.15 };
117+
PidGain pcidsPidGain{ 0.5, 0.01, 0.2 };
118+
CameraRecoveryAction action(robot, 15, 100, anglePidGain, 10, 3, 100.0, 50.0, pcidsPidGain,
119+
dummyRequest);
75120

76121
testing::internal::CaptureStdout();
77122
action.run();
78123
string output = testing::internal::GetCapturedStdout();
79-
ASSERT_NE(output.find("復帰できませんでした"), string::npos);
124+
ASSERT_NE(output.find("首振りで復帰に成功しました。"), string::npos);
125+
126+
// 角度計算を停止
127+
IMUSetting imuStop(robot, false);
128+
imuStop.run();
80129
}
81130

82131
} // namespace etrobocon2025_test

0 commit comments

Comments
 (0)