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