GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
graph_searcher_spot_turn.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 <vector>
11
12#include "cassert_define.h"
13#include "graph_search_const.h"
14
15
16namespace designlab
17{
18
20 const std::shared_ptr<const IHexapodCoordinateConverter>& converter_ptr,
21 const std::shared_ptr<const IHexapodPostureValidator>& checker_ptr) :
22 converter_ptr_(converter_ptr),
23 checker_ptr_(checker_ptr),
24 evaluator_(InitializeEvaluator())
25{
26}
27
28std::tuple<GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode> GraphSearcherSpotTurn::SearchGraphTree(
29 const GaitPatternGraphTree& graph,
30 const RobotOperation& operation,
31 const DividedMapState& divided_map_state,
32 const int max_depth) const
33{
36
37 if (!graph.HasRoot())
38 {
39 const GraphSearchResult result = { enums::Result::kFailure, "ルートノードがありません." };
40 return { result, GraphSearchEvaluationValue{}, RobotStateNode{} };
41 }
42
43 // 初期化.
44 Quaternion target_quaternion;
45
47 {
48 target_quaternion = operation.spot_turn_last_posture;
49 }
50 else
51 {
52 // 回転軸周りに20deg回転クォータニオンを作成する.
53 const auto rot_quaternion = Quaternion::MakeByAngleAxis(math_util::ConvertDegToRad(20.0f), operation.spot_turn_rot_axis);
54 target_quaternion = rot_quaternion * graph.GetRootNode().posture;
55 }
56
57 const float target_z_value = InitTargetZValue(graph.GetRootNode(), divided_map_state, target_quaternion);
58
59
60 GraphSearchEvaluationValue max_evaluation_value = evaluator_.InitializeEvaluationValue();
61 int max_evaluation_value_index = -1;
62
63 for (int i = 0; i < graph.GetGraphSize(); i++)
64 {
65 // 最大深さのノードのみを評価する.
66 if (graph.GetNode(i).depth != max_depth)
67 {
68 continue;
69 }
70
71 // 評価値を計算する.
72 GraphSearchEvaluationValue candidate_evaluation_value = evaluator_.InitializeEvaluationValue();
73
74 candidate_evaluation_value.value.at(kTagAmountOfTurn) = GetAmountOfTurnEvaluationValue(graph.GetNode(i), target_quaternion);
75 candidate_evaluation_value.value.at(kTagLegRot) = GetLegRotEvaluationValue(graph.GetNode(i), graph.GetRootNode());
76 candidate_evaluation_value.value.at(kTagZDiff) = GetZDiffEvaluationValue(graph.GetNode(i), target_z_value);
77
78 // 評価値を比較する.
79 if (evaluator_.LeftIsBetter(candidate_evaluation_value, max_evaluation_value))
80 {
81 max_evaluation_value = candidate_evaluation_value;
82 max_evaluation_value_index = i;
83 }
84 }
85
86 // インデックスが範囲外ならば失敗.
87 if (max_evaluation_value_index < 0 || graph.GetGraphSize() <= max_evaluation_value_index)
88 {
89 const GraphSearchResult result = { enums::Result::kFailure, "最大評価値のインデックスが範囲外です." };
90 return { result, GraphSearchEvaluationValue{}, RobotStateNode{} };
91 }
92
93 const GraphSearchResult result = { enums::Result::kSuccess, "" };
94
95 return { result, max_evaluation_value, graph.GetParentNode(max_evaluation_value_index, 1), };
96}
97
98std::tuple<GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode> GraphSearcherSpotTurn::SearchGraphTreeVector(
99 const std::vector<GaitPatternGraphTree>& graph_vector,
100 const RobotOperation& operation,
101 const DividedMapState& divided_map_state,
102 int max_depth) const
103{
104 std::vector<std::tuple<GraphSearchResult, GraphSearchEvaluationValue, RobotStateNode>> result_vector;
105
106 for (const auto& graph : graph_vector)
107 {
108 const auto result = SearchGraphTree(graph, operation, divided_map_state, max_depth);
109
110 result_vector.push_back(result);
111 }
112
113 // 最大評価値を持つものを探す.
114 GraphSearchEvaluationValue max_evaluation_value = evaluator_.InitializeEvaluationValue();
115 int max_evaluation_value_index = -1;
116
117 for (int i = 0; i < result_vector.size(); i++)
118 {
119 const auto& [result, evaluation_value, _] = result_vector.at(i);
120
121 if (result.result != enums::Result::kSuccess)
122 {
123 continue;
124 }
125
126 if (evaluator_.LeftIsBetter(evaluation_value, max_evaluation_value))
127 {
128 max_evaluation_value = evaluation_value;
129 max_evaluation_value_index = i;
130 }
131 }
132
133 // インデックスが範囲外ならば失敗.
134 if (max_evaluation_value_index < 0 || max_evaluation_value_index >= result_vector.size())
135 {
136 const GraphSearchResult result = { enums::Result::kFailure, "最大評価値のインデックスが範囲外です." };
137 return { result, GraphSearchEvaluationValue{}, RobotStateNode{} };
138 }
139
140 return result_vector[max_evaluation_value_index];
141}
142
143GraphSearchEvaluator GraphSearcherSpotTurn::InitializeEvaluator() const
144{
145 GraphSearchEvaluator::EvaluationMethod amount_of_turn_method =
146 {
147 .is_lower_better = false,
148 .margin = 0.0f,
149 };
150
151 GraphSearchEvaluator::EvaluationMethod leg_rot_method =
152 {
153 .is_lower_better = false,
154 .margin = 50.0f,
155 };
156
157 GraphSearchEvaluator::EvaluationMethod z_diff_method =
158 {
159 .is_lower_better = true,
160 .margin = 1.0f,
161 };
162
163 GraphSearchEvaluator ret({ {kTagAmountOfTurn, amount_of_turn_method}, {kTagLegRot, leg_rot_method}, {kTagZDiff, z_diff_method} },
164 { kTagAmountOfTurn, kTagLegRot, kTagZDiff, });
165
166 return ret;
167}
168
169float GraphSearcherSpotTurn::InitTargetZValue(const RobotStateNode& node,
170 const DividedMapState& divided_map_state,
171 [[maybe_unused]] const Quaternion& target_quat) const
172{
173 const int div = 60;
174 const float min_z = -150.0f;
175 const float max_z = 150.0f;
176
177 for (int i = 0; i < div; i++)
178 {
179 const float z = min_z + (max_z - min_z) / static_cast<float>(div) * static_cast<float>(i);
180
181 Vector3 pos = node.center_of_mass_global_coord;
182 pos.z += z;
183
184 RobotStateNode temp_node = node;
185 temp_node.ChangeGlobalCenterOfMass(pos, false);
186 temp_node.ChangePosture(converter_ptr_, target_quat);
187
188 if (!checker_ptr_->IsBodyInterferingWithGround(temp_node, divided_map_state))
189 {
190 // std::cout << "z = " << node.center_of_mass_global_coord.z + z << std::endl;
191 return node.center_of_mass_global_coord.z + z;
192 }
193 }
194
195 return node.center_of_mass_global_coord.z;
196}
197
198float GraphSearcherSpotTurn::GetAmountOfTurnEvaluationValue(
199 const RobotStateNode& node,
200 const Quaternion& target_quat) const
201{
202 // 目標姿勢を Qt,現在の姿勢を Qc とする.
203 // Qt = Qc * Qd となるような Qd を求める.
204 // Qd = Qc^-1 * Qt となる.
205
206 // 最終姿勢を表すクォータニオンとの差分を計算する.
207 const Quaternion target_to_current = node.posture.GetConjugate() * target_quat;
208
209 return target_to_current.w;
210}
211
212float GraphSearcherSpotTurn::GetLegRotEvaluationValue(
213 const RobotStateNode& node,
214 const RobotStateNode& root_node) const
215{
216 float result = 0.0f;
217
218 for (int i = 0; i < HexapodConst::kLegNum; i++)
219 {
220 if (leg_func::IsGrounded(node.leg_state, i))
221 {
222 result += (node.leg_pos[i].ProjectedXY() -
223 root_node.leg_pos[i].ProjectedXY()).GetLength();
224 }
225 else
226 {
227 result += (node.leg_pos[i] - root_node.leg_pos[i]).GetLength();
228 }
229 }
230
231 return result;
232
233 // const float margin = 50.0f;
234}
235
236float GraphSearcherSpotTurn::GetZDiffEvaluationValue(
237 const RobotStateNode& node,
238 const float target_z_value) const
239{
240 return abs(node.center_of_mass_global_coord.z - target_z_value);
241}
242
243
244} // namespace designlab
マップを格子状に分割して管理するクラス.
RobotStateNode 構造体をノードとする木構造のグラフのクラス.
const RobotStateNode & GetRootNode() 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 > SearchGraphTree(const GaitPatternGraphTree &graph, const RobotOperation &operation, const DividedMapState &divided_map_state, int max_depth) const override
グラフを受け取り,その中から最適な次の動作を出力する.
GraphSearcherSpotTurn(const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr, const std::shared_ptr< const IHexapodPostureValidator > &checker_ptr)
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
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 T ConvertDegToRad(const T deg) noexcept
角度を [deg] から [rad] に変換する関数.
Definition math_util.h:126
@ kSpotTurnRotAxis
その場で旋回させる(回転軸を示し,その軸周りの右ねじの回転)
@ kSpotTurnLastPosture
その場で旋回させる(最終的な姿勢 Posture を示す)
グラフ探索の評価値を格納する構造体.
bool is_lower_better
評価値が小さいほど良い場合は true.
グラフ探索の結果を表す構造体.
クォータニオンを表す構造体.
static Quaternion MakeByAngleAxis(float rad_angle, const Vector3 &axis)
回転軸と回転角からクォータニオンを作成する. q = cos(θ/2) * w + sin(θ/2) * { v.x + v.y + v.z } となる. ノルムは必ず1になる.
探索において目標となる座標や角度,評価する値についてまとめた構造体.
RobotOperationType operation_type
Quaternion spot_turn_last_posture
旋回時の回転軸.右ねじの回転.
グラフ構造のためのノード(頂点).旧名 LNODE
Quaternion posture
[4 * 4 = 16byte] 姿勢を表すクォータニオン.
int depth
[4 byte] 自身の深さ.一番上の親が深さ0となる.