GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
graph_searcher_straight_move.cpp
[詳解]
1
3
4// Copyright(c) 2023-2025 Design Engineering Laboratory, Saitama University
5// Released under the MIT license
6// https://opensource.org/licenses/mit-license.php
7
9
10#include <functional>
11#include <vector>
12
13#include "cassert_define.h"
14#include "cmdio_util.h"
15#include "math_util.h"
16#include "graph_search_const.h"
17#include "leg_state.h"
18
19
20namespace designlab
21{
22
24 const std::shared_ptr<const IHexapodPostureValidator>& checker_ptr) :
25 checker_ptr_(checker_ptr),
26 evaluator_(InitializeEvaluator())
27{
28}
29
30std::tuple<GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode> GraphSearcherStraightMove::SearchGraphTree(
31 const GaitPatternGraphTree& graph,
32 const RobotOperation& operation,
33 const DividedMapState& divided_map_state,
34 const int max_depth) const
35{
36 // ターゲットモードは直進である.
39
40 if (!graph.HasRoot())
41 {
42 const GraphSearchResult result = { enums::Result::kFailure, "ルートノードがありません." };
43 return { result, GraphSearchEvaluationValue{}, RobotStateNode{} };
44 }
45
46 // 初期化.
47 Vector3 normalized_move_direction;
48
50 {
51 normalized_move_direction = (operation.straight_move_position -
53 normalized_move_direction.z = 0.0f;
54 normalized_move_direction = normalized_move_direction.GetNormalized();
55 }
56 else
57 {
58 normalized_move_direction = operation.straight_move_vector;
59 normalized_move_direction.z = 0.0f;
60 normalized_move_direction = normalized_move_direction.GetNormalized();
61 normalized_move_direction = normalized_move_direction.GetLength() == 0.0f ? Vector3::GetFrontVec() : normalized_move_direction;
62 }
63
64 const float target_z_value = InitTargetZValue(graph.GetRootNode(), divided_map_state, normalized_move_direction);
65
66 CmdIOUtil::FormatOutput(OutputDetail::kDebug, "target_z_value = {}", target_z_value);
67
68 GraphSearchEvaluationValue max_evaluation_value = evaluator_.InitializeEvaluationValue();
69 int max_evaluation_value_index = -1;
70 int log_depth = 0;
72
73 GraphSearchEvaluationValue candidate_evaluation_value = evaluator_.InitializeEvaluationValue();
74
75 for (int i = 0; i < graph.GetGraphSize(); i++)
76 {
77 log_depth = log_depth < graph.GetNode(i).depth ? graph.GetNode(i).depth : log_depth;
78 log_move = log_depth == graph.GetNode(i).depth ? graph.GetNode(i).next_move : log_move;
79
80 // 最大深さのノードのみを評価する.
81 if (graph.GetNode(i).depth != max_depth) { continue; }
82
83 // 評価値を計算する.
84 candidate_evaluation_value.value.at(kTagMoveForward) = GetMoveForwardEvaluationValue(graph.GetNode(i), graph.GetRootNode(), normalized_move_direction);
85 // if (!evaluator_.LeftIsBetterWithTag(candidate_evaluation_value, max_evaluation_value, kTagMoveForward)) { continue; }
86
87 candidate_evaluation_value.value.at(kTagLegRot) = GetLegRotEvaluationValue(graph.GetNode(i), graph.GetRootNode());
88 // if (!evaluator_.LeftIsBetterWithTag(candidate_evaluation_value, max_evaluation_value, kTagLegRot)) { continue; }
89
90 candidate_evaluation_value.value.at(kTagZDiff) = GetZDiffEvaluationValue(graph.GetCoMVerticalTrajectory(i), target_z_value);
91 //candidate_evaluation_value.value.at(kTagZDiff) = GetZDiffEvaluationValue({ graph.GetNode(i).center_of_mass_global_coord.z }, target_z_value);
92
93 // 評価値を比較する.
94 if (evaluator_.LeftIsBetter(candidate_evaluation_value, max_evaluation_value))
95 {
96 // 上回っている場合は更新する.
97 CmdIOUtil::FormatOutput(OutputDetail::kDebug, "max_evaluation_value = {}", max_evaluation_value.value[kTagZDiff]);
98 max_evaluation_value = candidate_evaluation_value;
99 max_evaluation_value_index = i;
100 }
101 }
102
103 // インデックスが範囲外ならば失敗.
104 if (graph.GetGraphSize() <= max_evaluation_value_index)
105 {
106 const GraphSearchResult result = { enums::Result::kFailure, "最大評価値のインデックスが範囲外です." };
107 return { result, GraphSearchEvaluationValue{}, RobotStateNode{} };
108 }
109
110 if (max_evaluation_value_index < 0)
111 {
112 const GraphSearchResult result =
113 {
115 std::format("葉ノードが存在しません.最大深さ : {},動作 : {}", log_depth, string_util::EnumToStringRemoveTopK(log_move))
116 };
117
118 return { result, GraphSearchEvaluationValue{}, RobotStateNode{} };
119 }
120
121 const GraphSearchResult result = { enums::Result::kSuccess, "" };
122
123 return { result, max_evaluation_value, graph.GetParentNode(max_evaluation_value_index, 1) };
124}
125
126std::tuple<GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode> GraphSearcherStraightMove::SearchGraphTreeVector(
127 const std::vector<GaitPatternGraphTree>& graph_vector,
128 const RobotOperation& operation,
129 const DividedMapState& divided_map_state,
130 int max_depth) const
131{
132 std::vector<std::tuple<GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode>> result_vector;
133 result_vector.resize(graph_vector.size());
134
135 for (size_t i = 0; i < graph_vector.size(); i++)
136 {
137 // グラフ探索の結果を格納する.
138 result_vector[i] = SearchGraphTree(graph_vector[i], operation, divided_map_state, max_depth);
139 }
140
141 // 最大評価値を持つものを探す.
142 GraphSearchEvaluationValue max_evaluation_value = evaluator_.InitializeEvaluationValue();
143 int max_evaluation_value_index = -1;
144
145 for (int i = 0; i < result_vector.size(); i++)
146 {
147 const auto& [result, evaluation_value, _] = result_vector[i];
148
149 // 失敗しているものは無視する.
150 if (result.result != enums::Result::kSuccess)
151 {
152 continue;
153 }
154
155 // 評価値を比較する.
156 if (evaluator_.LeftIsBetter(evaluation_value, max_evaluation_value))
157 {
158 // 上回っている場合は更新する.
159 max_evaluation_value = evaluation_value;
160 max_evaluation_value_index = i;
161 }
162 }
163
164 // インデックスが範囲外ならば失敗.
165 if (max_evaluation_value_index < 0 || result_vector.size() <= max_evaluation_value_index)
166 {
167 const GraphSearchResult result = { enums::Result::kFailure, "最大評価値のインデックスが範囲外です." };
168 return { result, GraphSearchEvaluationValue{}, RobotStateNode{} };
169 }
170
171 return result_vector[max_evaluation_value_index];
172}
173
174GraphSearchEvaluator GraphSearcherStraightMove::InitializeEvaluator() const
175{
176 GraphSearchEvaluator::EvaluationMethod move_forward_method =
177 {
178 .is_lower_better = false,
179 .margin = 0.0f,
180 };
181
182 GraphSearchEvaluator::EvaluationMethod leg_rot_method =
183 {
184 .is_lower_better = false,
185 .margin = 0.0f,
186 };
187
188 GraphSearchEvaluator::EvaluationMethod z_diff_method =
189 {
190 .is_lower_better = true,
191 .margin = 0.f,
192 };
193
194 GraphSearchEvaluator ret({ {kTagMoveForward, move_forward_method}, {kTagLegRot, leg_rot_method}, {kTagZDiff, z_diff_method} },
195 { kTagZDiff, kTagMoveForward, kTagLegRot });
196
197 return ret;
198}
199
200float GraphSearcherStraightMove::InitTargetZValue(
201 const RobotStateNode& node,
202 const DividedMapState& divided_map_state,
203 const Vector3& move_direction) const
204{
205 const float move_length = 100.0f;
206
207 const Vector3 target_position = move_direction * move_length;
208
209 const int div = 300;
210 const float min_z = -150.0f;
211 const float max_z = 150.0f;
212
213 for (int i = 0; i < div; i++)
214 {
215 const float z = min_z + (max_z - min_z) / static_cast<float>(div) * static_cast<float>(i);
216
217 Vector3 pos = node.center_of_mass_global_coord;
218 pos += target_position;
219 pos.z += z;
220
221 RobotStateNode temp_node = node;
222 temp_node.ChangeGlobalCenterOfMass(pos, false);
223
224 if (!checker_ptr_->IsBodyInterferingWithGround(temp_node, divided_map_state))
225 {
226 return node.center_of_mass_global_coord.z + z;
227 }
228 }
229
230 return node.center_of_mass_global_coord.z;
231}
232
233float GraphSearcherStraightMove::GetMoveForwardEvaluationValue(
234 const RobotStateNode& node,
235 const RobotStateNode& root_node,
236 const Vector3& normalized_move_direction) const
237{
238 // 正規化されていることを確認する.
239 assert(math_util::IsEqual(normalized_move_direction.GetSquaredLength(), 1.f));
240
241 const Vector3 root_to_current = node.center_of_mass_global_coord - root_node.center_of_mass_global_coord;
242
243 // root_to_current の normalized_move_direction 方向の成分を取り出す.
244 const float result = root_to_current.Dot(normalized_move_direction);
245
246 return result;
247
248 // const float margin = 7.5f;
249}
250
251float GraphSearcherStraightMove::GetLegRotEvaluationValue(
252 const RobotStateNode& node,
253 const RobotStateNode& root_node) const
254{
255 float result = 0.0f;
256
257 for (int i = 0; i < HexapodConst::kLegNum; i++)
258 {
259 if (leg_func::IsGrounded(node.leg_state, i))
260 {
261 result += (node.leg_pos[i].ProjectedXY() -
262 root_node.leg_pos[i].ProjectedXY()).GetLength();
263 }
264 else
265 {
266 result += (node.leg_pos[i] - root_node.leg_pos[i]).GetLength();
267 }
268 }
269
270 return result;
271
272 // const float margin = 10.0f;
273}
274
275float GraphSearcherStraightMove::GetZDiffEvaluationValue(
276 const std::vector<float>& com_trajectory,
277 const float target_z_value) const
278{
279 float result = abs(com_trajectory.back() - target_z_value);
280
281 if (com_trajectory.size() == 3)
282 {
283 if ((com_trajectory[0] - com_trajectory[1]) * (com_trajectory[0] - com_trajectory[2]) <= 0)
284 {
285 result += abs(com_trajectory[0] - com_trajectory[1]);
286 }
287 }
288
289 return result;
290}
291
292} // namespace designlab
static void FormatOutput(OutputDetail detail, const std::format_string< Args... > str, Args &&... args)
コマンドラインに文字を出力する関数. SetOutputLimit() で設定した出力の許可範囲内であれば出力される. 必ず SetOutputLimit() を呼び出してから使うこと.
Definition cmdio_util.h:117
マップを格子状に分割して管理するクラス.
RobotStateNode 構造体をノードとする木構造のグラフのクラス.
const RobotStateNode & GetRootNode() const
グラフの根ノードの参照を返す.
std::vector< float > GetCoMVerticalTrajectory(const int index) const
指定したノードの重心の上下移動軌跡を返す.
const RobotStateNode & GetParentNode(const int index, const int depth) const
指定したノードの親ノードの参照を返す.depthは親ノードの深さを指定する.
const RobotStateNode & GetNode(const int index) const
グラフのノードの参照を返す.
constexpr bool HasRoot() const
グラフが根ノードを持つかどうかを返す. 根ノードとは,親を持たないノードのこと. 一番最初に追加するノードは必ず根になるため, 根を持つかどうかはノードの総数が0でないかどうかで判定できる.
constexpr int GetGraphSize() const
グラフのノードの総数を返す.
グラフ探索の評価値を評価するクラス.
bool LeftIsBetter(const GraphSearchEvaluationValue &left, const GraphSearchEvaluationValue &right, bool return_true_case_of_equal=true) const
2つの評価値を比較する.左側の評価値が良い場合は true を返す.
GraphSearchEvaluationValue InitializeEvaluationValue() const
評価値を初期化する. 自身の持つ評価方法を用いて,評価値を初期化する.
std::tuple< GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode > SearchGraphTreeVector(const std::vector< GaitPatternGraphTree > &graph_vector, const RobotOperation &operation, const DividedMapState &divided_map_state, int max_depth) const override
std::tuple< GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode > SearchGraphTree(const GaitPatternGraphTree &graph, const RobotOperation &operation, const DividedMapState &divided_map_state, int max_depth) const override
グラフを受け取り,その中から最適な次の動作を出力する.
GraphSearcherStraightMove(const std::shared_ptr< const IHexapodPostureValidator > &checker_ptr)
static constexpr int kLegNum
bool IsGrounded(const LegStateBit &leg_state, const int leg_index)
脚番号 leg_index 0 ~ 5 に応じて,その脚が接地しているかを調べる. 脚は右前脚を0番として,時計回りに0,1,2,3,4,5となる.左前足が5番.
Definition leg_state.cpp:43
constexpr bool IsEqual(const T num1, const T num2) noexcept
C++において,小数同士の計算は誤差が出てしまう. 誤差込みで値が等しいか調べる.
Definition math_util.h:45
std::string EnumToStringRemoveTopK(const T &enum_value)
enumを文字列に変換する関数. Google C++ coding style だと enumの要素は 先頭にkをつけてキャメルケースで書くことが推奨されている. 例えば,
Definition string_util.h:54
@ kStraightMoveVector
直線移動をさせる(移動したい方向をベクトルで示す)
@ kStraightMovePosition
直線移動をさせる(移動したい座標を示す)
@ kDebug
デバッグ時のみ出力,一番優先度が低い.
HexapodMove
ロボットが次にどの動作をするのかを表す列挙体.
@ kNone
何も動作をしない.
グラフ探索の評価値を格納する構造体.
bool is_lower_better
評価値が小さいほど良い場合は true.
グラフ探索の結果を表す構造体.
探索において目標となる座標や角度,評価する値についてまとめた構造体.
Vector3 straight_move_vector
< 目標方向.正規化されたベクトル.
RobotOperationType operation_type
Vector3 straight_move_position
目標姿勢 ( posture )
グラフ構造のためのノード(頂点).旧名 LNODE
Vector3 center_of_mass_global_coord
[4 * 3 = 12byte] グローバル座標系における重心の位置.旧名 GCOM
int depth
[4 byte] 自身の深さ.一番上の親が深さ0となる.
3次元の位置ベクトルを表す構造体.
Vector3 GetNormalized() const noexcept
単位ベクトルを返す. normalizeとは,ベクトルを正規化(単位ベクトルに変換)する操作を表す. 絶対値が0のベクトルの場合,そのまま0ベクトルを返す.
float z
ロボットの上向きに正.
static constexpr Vector3 GetFrontVec() noexcept
正面に進む単位ベクトルを返す. 静的な関数なので,Vector3::GetFrontVec() と呼び出せる.
float GetLength() const noexcept
ベクトルの長さを返す.