GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
node_creator_leg_up_down_radius.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 <algorithm>
11
12#include <boost/dynamic_bitset.hpp>
13
14#include "com_type.h"
15#include "math_const.h"
16#include "math_util.h"
17#include "graph_search_const.h"
18#include "leg_state.h"
19
20
21namespace designlab
22{
23
25 const DividedMapState& divided_map,
26 const std::shared_ptr<const IHexapodCoordinateConverter>& converter_ptr,
27 const std::shared_ptr<const IHexapodStatePresenter>& presenter_ptr,
28 const std::shared_ptr<const IHexapodPostureValidator>& checker_ptr,
29 HexapodMove next_move
30) :
31 kLegMargin(10),
32 map_(divided_map),
33 converter_ptr_(converter_ptr),
34 presenter_ptr_(presenter_ptr),
35 checker_ptr_(checker_ptr),
36 next_move_(next_move)
37{
38};
39
40
41
42void NodeCreatorLegUpDownRadius::Create(const RobotStateNode& current_node, const int current_num,
43 std::vector<RobotStateNode>* output_graph) const
44{
45 // 脚の遊脚・接地によって生じるとりうる重心を com type として仕分けている.
46 // (詳しくは com_type.h を参照).
47 // vector<bool>を使用したいが,vector<bool>はテンプレートの特殊化で,
48 // 通常の vector とは違う挙動をするので,boost::dynamic_bitset<>を使用する.
49 boost::dynamic_bitset<> is_able_leg_ground_pattern(com_func::GetLegGroundPatternNum());
50
51 is_able_leg_ground_pattern.set(); // 全て true にする.
52
53
54 // まず離散化された重心位置から取り得ない接地パターンを除外する.
56 leg_func::GetDiscreteComPos(current_node.leg_state), &is_able_leg_ground_pattern);
57
58
59 // 次に脚が地面に接地可能か調べる.
60
61 // 脚が設置可能ならば true になる.既に接地しているならば true になる.
62 bool is_groundable_leg[HexapodConst::kLegNum];
63 Vector3 ground_pos[HexapodConst::kLegNum]; // 脚が接地する座標.
64
65 for (int i = 0; i < HexapodConst::kLegNum; i++)
66 {
67 ground_pos[i] = current_node.leg_pos[i];
68 }
69
70 for (int i = 0; i < HexapodConst::kLegNum; i++)
71 {
72 if (leg_func::IsGrounded(current_node.leg_state, i))
73 {
74 // すでに接地している脚は接地可能に決まっているので true にする.
75 is_groundable_leg[i] = true;
76 ground_pos[i] = current_node.leg_pos[i];
77 }
78 else
79 {
80 // 現在遊脚中の脚は自身の脚状態で接地できるか検討する.
81 Vector3 res_ground_pos;
82
83 if (IsGroundableLeg(i, current_node, &res_ground_pos))
84 {
85 is_groundable_leg[i] = true; // 接地可能にする.
86 ground_pos[i] = res_ground_pos;
87 }
88 else
89 {
90 is_groundable_leg[i] = false; // 接地不可能にする.
91 com_func::RemoveLegGroundPatternFromNotGroundableLeg(i, &is_able_leg_ground_pattern);
92 }
93 }
94 }
95
96
97 // 子ノードを生成する.
98 for (int i = 0; i < com_func::GetLegGroundPatternNum(); i++)
99 {
100 // その重心タイプが可能であれば,追加する
101 if (is_able_leg_ground_pattern[i])
102 {
103 RobotStateNode res_node = current_node;
104
105 res_node.ChangeToNextNode(current_num, next_move_);
106
107
108 // 遊脚・接地を書き換える.
109 leg_func::LegGroundedBit new_is_ground =
111
112 leg_func::ChangeAllLegGround(new_is_ground, &res_node.leg_state);
113
114
115 // 脚位置を書き換える.
116 for (int j = 0; j < HexapodConst::kLegNum; j++)
117 {
118 if (new_is_ground[j])
119 {
120 res_node.leg_pos[j] = ground_pos[j];
121
122 res_node.leg_reference_pos[j] = ground_pos[j];
123 }
124 else
125 {
126 res_node.leg_pos[j].z = presenter_ptr_->GetFreeLegPosLegCoordinate(j).z;
127
128 res_node.leg_reference_pos[j].x = presenter_ptr_->GetFreeLegPosLegCoordinate(j).x;
129 res_node.leg_reference_pos[j].y = presenter_ptr_->GetFreeLegPosLegCoordinate(j).y;
130 }
131 }
132
133 if (checker_ptr_->IsStable(res_node.leg_state, res_node.leg_pos))
134 {
135 (*output_graph).push_back(res_node);
136 }
137 } // if is_able_leg_ground_pattern[i]
138 } // for i
139}
140
141
142bool NodeCreatorLegUpDownRadius::IsGroundableLeg(const int now_leg_num,
143 const RobotStateNode& current_node,
144 Vector3* output_ground_pos) const
145{
146 // 脚座標がマップのどこに当たるか調べて,そのマスの2つ上と2つ下の範囲内を全て探索する.
147 const Vector3 global_leg_base_pos = converter_ptr_->ConvertLegToGlobalCoordinate(
148 current_node.leg_reference_pos[now_leg_num],
149 now_leg_num,
150 current_node.center_of_mass_global_coord,
151 current_node.posture,
152 true);
153
154
155 int max_x_dev = map_.GetDividedMapIndexX(global_leg_base_pos.x) + 2;
156 int min_x_dev = map_.GetDividedMapIndexX(global_leg_base_pos.x) - 2;
157 int max_y_dev = map_.GetDividedMapIndexY(global_leg_base_pos.y) + 2;
158 int min_y_dev = map_.GetDividedMapIndexY(global_leg_base_pos.y) - 2;
159
160 // 値がマップの範囲外にあるときは丸める.
161 max_x_dev = DividedMapState::ClampDividedMapIndex(max_x_dev);
162 min_x_dev = DividedMapState::ClampDividedMapIndex(min_x_dev);
163 max_y_dev = DividedMapState::ClampDividedMapIndex(max_y_dev);
164 min_y_dev = DividedMapState::ClampDividedMapIndex(min_y_dev);
165
166 // マップ内を全探索して,現在の脚位置(離散化した物)に適した脚設置可能点が存在するか調べる.
167
168 Vector3 candidate_pos; // 現在の脚位置に合致する候補座標群.
169 bool is_candidate_pos = false; // 候補座標が存在するかどうか.
170
171 // 範囲内の点を全て調べる.
172 for (int x = min_x_dev; x < max_x_dev; x++)
173 {
174 for (int y = min_y_dev; y < max_y_dev; y++)
175 {
176 const int kPosNum = map_.GetPointNum(x, y);
177
178 for (int n = 0; n < kPosNum; n++)
179 {
180 // 脚設置可能点の座標を取り出す.
181 Vector3 map_point_pos = map_.GetPointPos(x, y, n);
182 map_point_pos = converter_ptr_->ConvertGlobalToLegCoordinate(
183 map_point_pos,
184 now_leg_num,
185 current_node.center_of_mass_global_coord,
186 current_node.posture,
187 true);
188
189 // 脚位置を更新したノードを作成する.
190 RobotStateNode new_node = current_node;
191
192 new_node.leg_pos[now_leg_num] = map_point_pos;
193
194
195 // 前の候補地点と比較して,より良い候補地点の時のみ実行すする
196 if (is_candidate_pos)
197 {
198 // 反対方向をむいている場合は候補地点として採用しない.
199 if (new_node.leg_reference_pos[now_leg_num].ProjectedXY().Cross(
200 candidate_pos.ProjectedXY()) *
201 new_node.leg_reference_pos[now_leg_num].ProjectedXY().Cross(
202 map_point_pos.ProjectedXY()) < 0 - MathConst<float>::kAllowableError)
203 {
204 continue;
205 }
206
207 // 現在の脚位置と候補地点の間に障害物がある場合は候補地点として採用しない.
208 if (map_point_pos.ProjectedXY().Cross(
209 candidate_pos.ProjectedXY()) *
210 map_point_pos.ProjectedXY().Cross(
211 new_node.leg_reference_pos[now_leg_num].ProjectedXY()) < 0 - MathConst<float>::kAllowableError)
212 {
213 continue;
214 }
215 }
216
217 leg_func::ChangeGround(now_leg_num, true, &new_node.leg_state);
218
219 // 脚が範囲外ならば追加せずに続行.
220 if (!checker_ptr_->IsLegInRange(now_leg_num, new_node.leg_pos[now_leg_num]))
221 {
222 continue;
223 }
224
225 // 候補座標として,適していないならば追加せずに続行.
226 if (!IsAbleLegPos(new_node, now_leg_num)) { continue; }
227
228 // 脚先が干渉しないか調べる.
229 if (checker_ptr_->IsLegInterfering(new_node.leg_pos))
230 {
231 continue;
232 }
233
234 is_candidate_pos = true;
235 candidate_pos = map_point_pos;
236 }
237 }
238 }
239
240
241 // 候補点を全列挙したのち,候補点が一つもなければ false.
242 if (!is_candidate_pos) { return false; }
243
244 // 存在するなら,その中で最も適したものを結果として返し,true.
245 (*output_ground_pos) = candidate_pos;
246
247 return true;
248}
249
250bool NodeCreatorLegUpDownRadius::IsAbleLegPos(const RobotStateNode& _node, const int leg_index) const
251{
252 const enums::DiscreteLegPos discrete_leg_pos =
253 leg_func::GetDiscreteLegPos(_node.leg_state, leg_index); // 脚位置を取得(1~7)
254
255 // まず最初に脚位置4のところにないか確かめる.
256 if ((_node.leg_reference_pos[leg_index].ProjectedXY() - _node.leg_pos[leg_index].ProjectedXY()).GetSquaredLength() <
257 math_util::Squared(kLegMargin))
258 {
259 if (discrete_leg_pos == enums::DiscreteLegPos::kCenter)
260 {
261 return true;
262 }
263 else
264 {
265 return false;
266 }
267 }
268 else
269 {
270 if (discrete_leg_pos == enums::DiscreteLegPos::kCenter)
271 {
272 return false;
273 }
274 }
275
276 // 脚位置4と比較して前か後ろか.
277 if (_node.leg_reference_pos[leg_index].ProjectedXY()
278 .Cross(_node.leg_pos[leg_index].ProjectedXY()) *
279 _node.leg_pos[leg_index].ProjectedXY().Cross({ 1, 0 }) > 0)
280 {
281 // 前.
282 if (discrete_leg_pos == enums::DiscreteLegPos::kLowerBack ||
283 discrete_leg_pos == enums::DiscreteLegPos::kBack ||
284 discrete_leg_pos == enums::DiscreteLegPos::kUpperBack)
285 {
286 return false;
287 }
288 }
289 else
290 {
291 // 後ろ.
292 if (discrete_leg_pos == enums::DiscreteLegPos::kLowerFront ||
293 discrete_leg_pos == enums::DiscreteLegPos::kFront ||
294 discrete_leg_pos == enums::DiscreteLegPos::kUpperFront)
295 {
296 return false;
297 }
298 }
299
300
301 // 脚位置4と半径を比較して上か下か.
302 if (discrete_leg_pos == enums::DiscreteLegPos::kLowerFront ||
303 discrete_leg_pos == enums::DiscreteLegPos::kLowerBack)
304 {
305 // 脚位置4と比較して下.
306 if (_node.leg_reference_pos[leg_index].ProjectedXY().GetSquaredLength() -
307 _node.leg_pos[leg_index].ProjectedXY().GetSquaredLength() - kLegMargin > 0)
308 {
309 return true;
310 }
311 }
312 else if (discrete_leg_pos == enums::DiscreteLegPos::kUpperFront ||
313 discrete_leg_pos == enums::DiscreteLegPos::kUpperBack)
314 {
315 // 脚位置4と比較して上.
316 if (_node.leg_pos[leg_index].ProjectedXY().GetSquaredLength() -
317 _node.leg_reference_pos[leg_index].ProjectedXY().GetSquaredLength() - kLegMargin > 0)
318 {
319 return true;
320 }
321 }
322 else
323 {
324 // 脚位置4と同じくらい.
325 if (std::abs(_node.leg_reference_pos[leg_index].ProjectedXY().GetSquaredLength() -
326 _node.leg_pos[leg_index].ProjectedXY().GetSquaredLength()) < kLegMargin)
327 {
328 return true;
329 }
330 }
331
332 return false;
333}
334
335} // namespace designlab
マップを格子状に分割して管理するクラス.
constexpr int GetDividedMapIndexX(const float pos_x) const noexcept
指定した座標を DividedMap のインデックスに変換する. 範囲外の値を指定した場合でも,値を丸めずに返す. そのため,IsInMap で範囲内に存在するかどうかを確認する必要がある.
Vector3 GetPointPos(int x_index, int y_index, int divided_map_index) const
格子状に切り分けられたマップから,脚設置可能点の実際の座標を取得する. 範囲外の値を指定した場合は,(0,0,0)を返す.
constexpr int GetDividedMapIndexY(const float pos_y) const noexcept
指定した座標を DividedMap のインデックスに変換する. 範囲外の値を指定した場合でも,値を丸めずに返す. そのため,IsInMap で範囲内に存在するかどうかを確認する必要がある.
int GetPointNum(int x_index, int y_index) const
格子状に切り分けられたマップから,脚設置可能点の数を取得する. 範囲外の値を指定した場合は,0を返す.
static constexpr int ClampDividedMapIndex(const int index) noexcept
指定した座標がマップのインデックスの範囲内になるように丸める.
static constexpr int kLegNum
NodeCreatorLegUpDownRadius(const DividedMapState &devide_map, const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr, const std::shared_ptr< const IHexapodStatePresenter > &presenter_ptr, const std::shared_ptr< const IHexapodPostureValidator > &checker_ptr, HexapodMove next_move)
void Create(const RobotStateNode &current_node, int current_node_index, std::vector< RobotStateNode > *output_graph) const override
現在のノードから次のノード群を生成する.
void RemoveLegGroundPatternFromCom(enums::DiscreteComPos discrete_com_pos, boost::dynamic_bitset<> *output)
離散化された重心位置から,その重心位置では取り得ない脚接地パターンを falseにする.
Definition com_type.cpp:246
int GetLegGroundPatternNum()
脚の接地パターンの総数を返す.
Definition com_type.cpp:229
leg_func::LegGroundedBit GetLegGroundedBitFromLegGroundPatternIndex(const int leg_ground_pattern_index)
脚の接地パターンの番号から,その番号に該当する接地パターンを返す.
Definition com_type.cpp:234
void RemoveLegGroundPatternFromNotGroundableLeg(int not_groundable_leg_index, boost::dynamic_bitset<> *output)
接地できない脚番号から, その脚が接地できない場合に取り得ない接地パターンを falseにする.
Definition com_type.cpp:261
DiscreteLegPos
離散化された脚位置を表す列挙体. 先行研究では 1~7の int型の数値で表現されているが, 可読性を上げるために列挙体にした. 離散化された脚位置は 3bit (0 ~ 7)の範囲で表現される...
@ kUpperBack
現在の位置より後方かつ上方にある.
@ kBack
現在の位置より後方にある.
@ kCenter
現在の位置にある.
@ kUpperFront
現在の位置より前方かつ上方にある.
@ kFront
現在の位置より前方にある.
@ kLowerBack
現在の位置より後方かつ下方にある.
@ kLowerFront
現在の位置より前方かつ下方にある.
std::bitset< HexapodConst::kLegNum > LegGroundedBit
脚の遊脚・接地を表す型.6bitのビット型.接地が 1 遊脚が 0.
Definition leg_state.h:59
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
enums::DiscreteComPos GetDiscreteComPos(const LegStateBit &leg_state)
現在の脚状態から重心パターンを取得する.
void ChangeGround(const int leg_index, const bool is_ground, LegStateBit *leg_state)
脚の接地・遊脚情報を変更する.
enums::DiscreteLegPos GetDiscreteLegPos(const LegStateBit &leg_state, const int leg_index)
脚状態を取得する.
void ChangeAllLegGround(const LegGroundedBit &is_ground_list, LegStateBit *leg_state)
全ての脚の接地・遊脚情報を変更する.
constexpr T Squared(const T num) noexcept
2乗した値を返す関数.
Definition math_util.h:59
HexapodMove
ロボットが次にどの動作をするのかを表す列挙体.
float 型と double 型の定数を提供するクラス.
Definition math_const.h:25
グラフ構造のためのノード(頂点).旧名 LNODE
std::array< Vector3, HexapodConst::kLegNum > leg_pos
[4 * 3 * 6 = 72 byte] 脚先の座標.(coxa(脚の付け根)を原点とする)
leg_func::LegStateBit leg_state
[4 byte] 脚状態,重心パターンを bitで表す.旧名 leg_con.
constexpr void ChangeToNextNode(const int parent_index_, const HexapodMove next_move_)
次の動作を設定する関数. 深さを一つ深くして,親と次の動作を設定する.
Vector3 center_of_mass_global_coord
[4 * 3 = 12byte] グローバル座標系における重心の位置.旧名 GCOM
Quaternion posture
[4 * 4 = 16byte] 姿勢を表すクォータニオン.
std::array< Vector3, HexapodConst::kLegNum > leg_reference_pos
constexpr float Cross(const Vector2 &other) const noexcept
自分×引数 の外積の結果を返す.
3次元の位置ベクトルを表す構造体.
float x
ロボットの正面方向に正.
constexpr Vector2 ProjectedXY() const noexcept
XY平面に射影したベクトルを返す.
float y
ロボットの左向きに正.