GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
interpolated_node_creator.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 "cassert_define.h"
11#include "hexapod_const.h"
12#include "math_util.h"
13
14namespace designlab {
15
17 const std::shared_ptr<const IHexapodCoordinateConverter>& converter_ptr)
18 : converter_ptr_(converter_ptr) {}
19
21 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
22 if (IsNoChange(current_node, next_node)) {
23 return {}; // 空のvectorを返す.
24 }
25
26 if (IsBodyRot(current_node, next_node)) {
27 return CreateBodyRotInterpolatedNode(current_node, next_node);
28 }
29
30 if (IsBodyMove(current_node, next_node)) {
31 return CreateBodyMoveInterpolatedNode(current_node, next_node);
32 }
33
34 return CreateLegMoveInterpolatedNode(current_node, next_node);
35}
36
37bool InterpolatedNodeCreator::IsNoChange(
38 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
39 bool res = true;
40
41 for (int i = 0; i < HexapodConst::kLegNum; i++) {
42 if (current_node.leg_pos[i] != next_node.leg_pos[i]) {
43 res = false;
44 break;
45 }
46 }
47
48 if (current_node.center_of_mass_global_coord !=
50 res = false;
51 }
52
53 if (current_node.posture != next_node.posture) {
54 res = false;
55 }
56
57 return res;
58}
59
60bool InterpolatedNodeCreator::IsBodyMove(
61 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
62 return current_node.center_of_mass_global_coord !=
63 next_node.center_of_mass_global_coord;
64}
65
66bool InterpolatedNodeCreator::IsBodyRot(const RobotStateNode& current_node,
67 const RobotStateNode& next_node) const {
68 return current_node.posture.GetNormalized() !=
69 next_node.posture.GetNormalized();
70}
71
72std::vector<RobotStateNode>
73InterpolatedNodeCreator::CreateBodyMoveInterpolatedNode(
74 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
75 std::vector<RobotStateNode> res;
76
77 const Vector3 dif = next_node.center_of_mass_global_coord -
78 current_node.center_of_mass_global_coord;
79
80 if (dif.GetLength() < kInterpolatedDistance) {
81 return {};
82 }
83
84 if (dif.GetLength() > kBodyMoveMaxInterpolatedDistance) {
85 return {};
86 }
87
88 int cnt = 1;
89
90 while (kInterpolatedDistance * static_cast<float>(cnt) < dif.GetLength()) {
91 RobotStateNode temp_node = current_node;
92
93 temp_node.ChangeGlobalCenterOfMass(
94 temp_node.center_of_mass_global_coord + dif.GetNormalized() *
95 kInterpolatedDistance *
96 static_cast<float>(cnt),
97 true);
98
99 res.push_back(temp_node);
100
101 cnt++;
102 }
103
104 return res;
105}
106
107std::vector<RobotStateNode>
108InterpolatedNodeCreator::CreateBodyRotInterpolatedNode(
109 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
110 std::vector<RobotStateNode> res;
111
112 constexpr int kBodyMoveInterpolatedNodeNum =
113 100;
114
115 for (int i = 0; i < kBodyMoveInterpolatedNodeNum; i++) {
116 RobotStateNode temp_node = current_node;
117 const float ex = (static_cast<float>(i) + 1.0f) /
118 (static_cast<float>(kBodyMoveInterpolatedNodeNum));
119
120 const Quaternion quat =
121 SlerpQuaternion(current_node.posture, next_node.posture, ex)
122 .GetNormalized();
123
124 temp_node.ChangePosture(converter_ptr_, quat);
125
126 res.push_back(temp_node);
127 }
128
129 return res;
130}
131
132std::vector<RobotStateNode>
133InterpolatedNodeCreator::CreateLegMoveInterpolatedNode(
134 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
135 std::vector<RobotStateNode> res;
136
137 // 接地脚の平行移動,下降動作,遊脚の上昇動作,平行移動を行う.
138
139 // 接地.
140 {
141 std::vector<int> ground_move_index =
142 GetGroundMoveIndex(current_node, next_node);
143
144 // 接地脚の平行移動.
145 while (true) {
146 RobotStateNode temp_node = res.empty() ? current_node : res.back();
147
148 bool is_end = true;
149
150 for (const auto& i : ground_move_index) {
151 // 角度方向に移動.
152 const float angle_current =
153 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
154 const float angle_next =
155 atan2(next_node.leg_pos[i].y, next_node.leg_pos[i].x);
156
157 if (angle_current > angle_next + kInterpolatedAngle) {
158 const float length = temp_node.leg_pos[i].ProjectedXY().GetLength();
159 temp_node.leg_pos[i].x =
160 length * cos(angle_current - kInterpolatedAngle);
161 temp_node.leg_pos[i].y =
162 length * sin(angle_current - kInterpolatedAngle);
163 is_end = false;
164 } else if (angle_current < angle_next - kInterpolatedAngle) {
165 const float length = temp_node.leg_pos[i].ProjectedXY().GetLength();
166 temp_node.leg_pos[i].x =
167 length * cos(angle_current + kInterpolatedAngle);
168 temp_node.leg_pos[i].y =
169 length * sin(angle_current + kInterpolatedAngle);
170 is_end = false;
171 } else {
172 const float length = temp_node.leg_pos[i].ProjectedXY().GetLength();
173 temp_node.leg_pos[i].x = length * cos(angle_next);
174 temp_node.leg_pos[i].y = length * sin(angle_next);
175 }
176
177 // 半径方向に移動.
178 const float length_current =
179 temp_node.leg_pos[i].ProjectedXY().GetLength();
180 const float length_next =
181 next_node.leg_pos[i].ProjectedXY().GetLength();
182
183 if (length_current > length_next + kInterpolatedDistance) {
184 const float angle =
185 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
186 temp_node.leg_pos[i].x =
187 (length_current - kInterpolatedDistance) * cos(angle);
188 temp_node.leg_pos[i].y =
189 (length_current - kInterpolatedDistance) * sin(angle);
190 is_end = false;
191 } else if (length_current < length_next - kInterpolatedDistance) {
192 const float angle =
193 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
194 temp_node.leg_pos[i].x =
195 (length_current + kInterpolatedDistance) * cos(angle);
196 temp_node.leg_pos[i].y =
197 (length_current + kInterpolatedDistance) * sin(angle);
198 is_end = false;
199 } else {
200 const float angle =
201 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
202 temp_node.leg_pos[i].x = length_next * cos(angle);
203 temp_node.leg_pos[i].y = length_next * sin(angle);
204 }
205 }
206
207 res.push_back(temp_node);
208
209 if (is_end) {
210 break;
211 }
212 }
213
214 // 接地脚の下降.
215 // 全ての脚先を kInterpolatedDistance づつ下げていき,距離が
216 // kInterpolatedDistance 以下になったら next_node と同じz座標にする.
217 while (true) {
218 RobotStateNode temp_node = res.back();
219
220 bool is_end = true;
221
222 for (const auto& i : ground_move_index) {
223 if (temp_node.leg_pos[i].z >
224 next_node.leg_pos[i].z + kInterpolatedDistance) {
225 temp_node.leg_pos[i].z -= kInterpolatedDistance;
226 is_end = false;
227 } else if (temp_node.leg_pos[i].z <
228 next_node.leg_pos[i].z - kInterpolatedDistance) {
229 temp_node.leg_pos[i].z += kInterpolatedDistance;
230 is_end = false;
231 } else {
232 temp_node.leg_pos[i].z = next_node.leg_pos[i].z;
233 leg_func::ChangeGround(i, true, &temp_node.leg_state);
234 }
235 }
236
237 res.push_back(temp_node);
238
239 if (is_end) {
240 break;
241 }
242 }
243 }
244
245 // 遊脚.
246 {
247 std::vector<int> free_move_index =
248 GetFreeMoveIndex(current_node, next_node);
249
250 // 接地脚の下降.
251 // 全ての脚先を kInterpolatedDistance づつ下げていき,距離が
252 // kInterpolatedDistance 以下になったら next_node と同じz座標にする.
253 while (true) {
254 RobotStateNode temp_node = res.back();
255
256 bool is_end = true;
257
258 for (const auto& i : free_move_index) {
259 if (temp_node.leg_pos[i].z >
260 next_node.leg_pos[i].z + kInterpolatedDistance) {
261 temp_node.leg_pos[i].z -= kInterpolatedDistance;
262 is_end = false;
263 } else if (temp_node.leg_pos[i].z <
264 next_node.leg_pos[i].z - kInterpolatedDistance) {
265 temp_node.leg_pos[i].z += kInterpolatedDistance;
266 is_end = false;
267 } else {
268 temp_node.leg_pos[i].z = next_node.leg_pos[i].z;
269 leg_func::ChangeGround(i, false, &temp_node.leg_state);
270 }
271 }
272
273 res.push_back(temp_node);
274
275 if (is_end) {
276 break;
277 }
278 }
279
280 // 接地脚の平行移動.
281 while (true) {
282 RobotStateNode temp_node = res.empty() ? current_node : res.back();
283
284 bool is_end = true;
285
286 for (const auto& i : free_move_index) {
287 // 角度方向に移動.
288 const float angle_current =
289 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
290 const float angle_next =
291 atan2(next_node.leg_pos[i].y, next_node.leg_pos[i].x);
292
293 if (angle_current > angle_next + kInterpolatedAngle) {
294 const float length = temp_node.leg_pos[i].ProjectedXY().GetLength();
295 temp_node.leg_pos[i].x =
296 length * cos(angle_current - kInterpolatedAngle);
297 temp_node.leg_pos[i].y =
298 length * sin(angle_current - kInterpolatedAngle);
299 is_end = false;
300 } else if (angle_current < angle_next - kInterpolatedAngle) {
301 const float length = temp_node.leg_pos[i].ProjectedXY().GetLength();
302 temp_node.leg_pos[i].x =
303 length * cos(angle_current + kInterpolatedAngle);
304 temp_node.leg_pos[i].y =
305 length * sin(angle_current + kInterpolatedAngle);
306 is_end = false;
307 } else {
308 const float length = temp_node.leg_pos[i].ProjectedXY().GetLength();
309 temp_node.leg_pos[i].x = length * cos(angle_next);
310 temp_node.leg_pos[i].y = length * sin(angle_next);
311 }
312
313 // 半径方向に移動.
314 const float length_current =
315 temp_node.leg_pos[i].ProjectedXY().GetLength();
316 const float length_next =
317 next_node.leg_pos[i].ProjectedXY().GetLength();
318
319 if (length_current > length_next + kInterpolatedDistance) {
320 const float angle =
321 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
322 temp_node.leg_pos[i].x =
323 (length_current - kInterpolatedDistance) * cos(angle);
324 temp_node.leg_pos[i].y =
325 (length_current - kInterpolatedDistance) * sin(angle);
326 is_end = false;
327 } else if (length_current < length_next - kInterpolatedDistance) {
328 const float angle =
329 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
330 temp_node.leg_pos[i].x =
331 (length_current + kInterpolatedDistance) * cos(angle);
332 temp_node.leg_pos[i].y =
333 (length_current + kInterpolatedDistance) * sin(angle);
334 is_end = false;
335 } else {
336 const float angle =
337 atan2(temp_node.leg_pos[i].y, temp_node.leg_pos[i].x);
338 temp_node.leg_pos[i].x = length_next * cos(angle);
339 temp_node.leg_pos[i].y = length_next * sin(angle);
340 }
341 }
342
343 res.push_back(temp_node);
344
345 if (is_end) {
346 break;
347 }
348 }
349 }
350
351 return res;
352}
353
354std::vector<int> InterpolatedNodeCreator::GetGroundMoveIndex(
355 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
356 // 脚先座標の差分を計算.
357 std::array<Vector3, HexapodConst::kLegNum> dif;
358
359 for (int i = 0; i < HexapodConst::kLegNum; i++) {
360 dif[i] = next_node.leg_pos[i] - current_node.leg_pos[i];
361 }
362
363 // indexを返す.
364 std::vector<int> res_index;
365
366 for (int i = 0; i < HexapodConst::kLegNum; i++) {
367 if (dif[i].z < 0) {
368 res_index.push_back(i);
369 }
370 }
371
372 return res_index;
373}
374
375std::vector<int> InterpolatedNodeCreator::GetFreeMoveIndex(
376 const RobotStateNode& current_node, const RobotStateNode& next_node) const {
377 // 脚先座標の差分を計算.
378 std::array<Vector3, HexapodConst::kLegNum> dif;
379
380 for (int i = 0; i < HexapodConst::kLegNum; i++) {
381 dif[i] = next_node.leg_pos[i] - current_node.leg_pos[i];
382 }
383
384 // indexを返す.
385 std::vector<int> res_index;
386
387 for (int i = 0; i < HexapodConst::kLegNum; i++) {
388 if (dif[i].z > 0) {
389 res_index.push_back(i);
390 }
391 }
392
393 return res_index;
394}
395
396} // namespace designlab
static constexpr int kLegNum
std::vector< RobotStateNode > CreateInterpolatedNode(const RobotStateNode &node, const RobotStateNode &next_node) const
ノード間を補間する.
InterpolatedNodeCreator(const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr)
void ChangeGround(const int leg_index, const bool is_ground, LegStateBit *leg_state)
脚の接地・遊脚情報を変更する.
Quaternion SlerpQuaternion(const Quaternion &q1, const Quaternion &q2, const float t)
球面線形補間を行う.
Quaternion GetNormalized() const noexcept
正規化したクォータニオンを返す. クォータニオンの正規化とは,ノルムを1にすることを表す. クォータニオンqの正規化は,q / |q| で求められる.
グラフ構造のためのノード(頂点).
std::array< Vector3, HexapodConst::kLegNum > leg_pos
[4 * 3 * 6 = 72 byte] 脚先の座標.(coxa(脚の付け根)を原点とする)
Vector3 center_of_mass_global_coord
[4 * 3 = 12byte] グローバル座標系における重心の位置.旧名 GCOM
Quaternion posture
[4 * 4 = 16byte] 姿勢を表すクォータニオン.