GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
phantomx_mk2.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
8#include "phantomx_mk2.h"
9
10#include <numbers>
11
12#include <cmath>
13
14#include "cassert_define.h"
15#include "math_line_segment2.h"
16#include "math_util.h"
17#include "leg_state.h"
18#include "phantomx_mk2_const.h"
19
20
21namespace designlab
22{
23
25 kBodyLiftingHeightMin(parameter_record.body_lifting_height_min),
26 kBodyLiftingHeightMax(parameter_record.body_lifting_height_max),
27 kMovableCoxaAngleMin(math_util::ConvertDegToRad(parameter_record.movable_coxa_angle_min_deg)),
28 kMovableCoxaAngleMax(math_util::ConvertDegToRad(parameter_record.movable_coxa_angle_max_deg)),
29 kMinLegR(parameter_record.min_leg_range),
30 kMaxLegR(parameter_record.max_leg_range),
31 kFreeLegHeight(parameter_record.free_leg_height),
32 kStableMargin(parameter_record.stable_margin),
33 free_leg_pos_leg_coordinate_({ {
34 {160 * cos(PhantomXMkIIConst::kCoxaDefaultAngle[0]), 160 * sin(PhantomXMkIIConst::kCoxaDefaultAngle[0]), kFreeLegHeight},
35 {160 * cos(PhantomXMkIIConst::kCoxaDefaultAngle[1]), 160 * sin(PhantomXMkIIConst::kCoxaDefaultAngle[1]), kFreeLegHeight},
36 {160 * cos(PhantomXMkIIConst::kCoxaDefaultAngle[2]), 160 * sin(PhantomXMkIIConst::kCoxaDefaultAngle[2]), kFreeLegHeight},
37 {160 * cos(PhantomXMkIIConst::kCoxaDefaultAngle[3]), 160 * sin(PhantomXMkIIConst::kCoxaDefaultAngle[3]), kFreeLegHeight},
38 {160 * cos(PhantomXMkIIConst::kCoxaDefaultAngle[4]), 160 * sin(PhantomXMkIIConst::kCoxaDefaultAngle[4]), kFreeLegHeight},
39 {160 * cos(PhantomXMkIIConst::kCoxaDefaultAngle[5]), 160 * sin(PhantomXMkIIConst::kCoxaDefaultAngle[5]), kFreeLegHeight},
40 } }),
41 leg_base_pos_robot_coordinate_({ {
48 } }),
49 kMaxLegRArray(InitMaxLegR()),
50 kMinLegPosXY(InitMinLegPosXY()),
51 kMaxLegPosXY(InitMaxLegPosXY()),
52 kMinLegDistance(50.0)
53{
54}
55
57 const int leg_index, const Vector3& leg_pos) const noexcept
58{
59 // leg_indexは 0~5 である.
60 assert(0 <= leg_index);
61 assert(leg_index < HexapodConst::kLegNum);
62
63 // 各パラメータを初期化する.
65
66 const int kJointNum = 4;
67 const int kJointAngleNum = kJointNum - 1;
68
69 res.joint_pos_leg_coordinate.clear();
70 res.joint_angle.clear();
71
72 res.joint_pos_leg_coordinate.resize(kJointNum);
73 res.joint_angle.resize(kJointAngleNum);
74
75
76 // coxa jointの計算.脚座標系では coxa joint は原点にある.
77 res.joint_pos_leg_coordinate[0] = Vector3{ 0, 0, 0 };
78
79 // 脚先の追加.
80 res.joint_pos_leg_coordinate[3] = leg_pos;
81
82 // coxa angleの計算.
83 {
84 float coxa_joint_angle = std::atan2f(leg_pos.y, leg_pos.x);
85
86 if (leg_pos.y == 0 && leg_pos.x == 0)
87 {
88 coxa_joint_angle = PhantomXMkIIConst::kCoxaDefaultAngle[leg_index];
89 }
90
91 if (!PhantomXMkIIConst::IsValidCoxaAngle(leg_index, coxa_joint_angle))
92 {
93 // 範囲外ならば,180度回転させた時に範囲内にあるかを調べる.
95 leg_index, coxa_joint_angle + std::numbers::pi_v<float>))
96 {
97 coxa_joint_angle += std::numbers::pi_v<float>;
98 }
100 leg_index, coxa_joint_angle - std::numbers::pi_v<float>))
101 {
102 coxa_joint_angle -= std::numbers::pi_v<float>;
103 }
104 }
105
106 res.joint_angle[0] = coxa_joint_angle;
107 }
108
109 // femur jointの計算.
110 {
111 const Vector3 femur_joint_pos = Vector3{
114 0
115 };
116
117 res.joint_pos_leg_coordinate[1] = femur_joint_pos;
118
119 if (!math_util::CanMakeTriangle((leg_pos - femur_joint_pos).GetLength(),
122 {
123 // そもそも脚先が脚の付け根から届かない場合,一番近い位置まで脚を伸ばす.
124
125 const float angle_ft = std::atan2(
126 leg_pos.z - femur_joint_pos.z,
127 (leg_pos.ProjectedXY() - femur_joint_pos.ProjectedXY()).GetLength());
128
129 // angle_ftの位相を180度回転する.-180度~180度の範囲にする.
130 float angle_ft_phase = angle_ft + std::numbers::pi_v<float>;
131 angle_ft_phase = (angle_ft_phase > std::numbers::pi_v<float>) ?
132 angle_ft_phase - std::numbers::pi_v<float> : angle_ft_phase;
133
134 const Vector3 candidate_leg_pos = femur_joint_pos + Vector3{
136 std::cos(res.joint_angle[0]) * std::cos(angle_ft),
137
139 std::sin(res.joint_angle[0]) * std::cos(angle_ft),
140
142 std::sin(angle_ft)
143 };
144
145 const Vector3 candidate_leg_pos_phase = femur_joint_pos + Vector3{
146 (PhantomXMkIIConst::kFemurLength * std::cos(angle_ft_phase) +
147 PhantomXMkIIConst::kTibiaLength * std::cos(angle_ft)) *
148 std::cos(res.joint_angle[0]),
149
150 (PhantomXMkIIConst::kFemurLength * std::cos(angle_ft_phase) +
151 PhantomXMkIIConst::kTibiaLength * std::cos(angle_ft)) *
152 std::sin(res.joint_angle[0]),
153
154 PhantomXMkIIConst::kFemurLength * std::sin(angle_ft_phase) +
155 PhantomXMkIIConst::kTibiaLength * std::sin(angle_ft)
156 };
157
158 const float distance = (leg_pos - candidate_leg_pos).GetLength();
159 const float distance_phase = (leg_pos - candidate_leg_pos_phase).GetLength();
160
161 float angle_f = 0, angle_t = 0;
162
163 if (distance < distance_phase)
164 {
165 angle_f = angle_ft;
166 angle_t = 0;
167 }
168 else
169 {
170 angle_f = angle_ft_phase;
171 angle_t = -std::numbers::pi_v<float>;
172 }
173
174 res.joint_angle[1] = angle_f;
175 res.joint_angle[2] = angle_t;
176
177 res.joint_pos_leg_coordinate[2] = femur_joint_pos + Vector3{
178 PhantomXMkIIConst::kFemurLength * std::cos(angle_f) *
179 std::cos(res.joint_angle[0]),
180
181 PhantomXMkIIConst::kFemurLength * std::cos(angle_f) *
182 std::sin(res.joint_angle[0]),
183
184 PhantomXMkIIConst::kFemurLength * std::sin(angle_f)
185 };
186
188 PhantomXMkIIConst::kTibiaLength * std::cos(angle_f + angle_t) *
189 std::cos(res.joint_angle[0]),
190
191 PhantomXMkIIConst::kTibiaLength * std::cos(angle_f + angle_t) *
192 std::sin(res.joint_angle[0]),
193
194 PhantomXMkIIConst::kTibiaLength * std::sin(angle_f + angle_t)
195 };
196
197 res.is_in_range = false; // 範囲外であることを示す.
198
199 return res;
200 }
201 }
202
203
204 // femur angle の計算.
205
206 // 脚先から第一関節までの長さ.
207 const Vector3 femur_to_leg = leg_pos - res.joint_pos_leg_coordinate[1];
208
209 // 脚先へ向かう方向をxの正方向にする座標系に置き換える.
210 // 脚先が第一関節よりも近い場合は正の方向にする.
211 const float femur_to_leg_x =
212 femur_to_leg.ProjectedXY().GetLength() *
213 ((leg_pos.ProjectedXY().GetSquaredLength() >
214 res.joint_pos_leg_coordinate[1].ProjectedXY().GetSquaredLength()) ? 1.f : -1.f);
215
216 const float femur_to_leg_z = femur_to_leg.z;
217
218 {
219 const float arc_cos_upper =
220 femur_to_leg.GetSquaredLength() +
223
224 const float arc_cos_lower = 2 * PhantomXMkIIConst::kFemurLength *
225 femur_to_leg.GetLength();
226
227 const float arc_cos_arg = arc_cos_upper / arc_cos_lower;
228
229
230 const float femur_joint_angle =
231 std::acos(arc_cos_arg) +
232 std::atan2(femur_to_leg_z, femur_to_leg_x);
233
234 res.joint_angle[1] = femur_joint_angle;
235 }
236
237 // tibia jointの計算.
238 {
239 const Vector3 femur_to_tibia = Vector3{
241 std::cos(res.joint_angle[1]),
242
244 std::cos(res.joint_angle[1]),
245
247 };
248
249 const Vector3 tibia_joint_pos = res.joint_pos_leg_coordinate[1] + femur_to_tibia;
250
251 res.joint_pos_leg_coordinate[2] = tibia_joint_pos;
252 }
253
254
255 // tibia angleの計算.
256 {
257 const float tibia_angle = std::atan2(
258 (femur_to_leg_z - PhantomXMkIIConst::kFemurLength * std::sin(res.joint_angle[1])),
259 (femur_to_leg_x - PhantomXMkIIConst::kFemurLength * std::cos(res.joint_angle[1]))) -
260 res.joint_angle[1];
261
262 res.joint_angle[2] = tibia_angle;
263 }
264
265 res.is_in_range = true;
266
267 return res;
268}
269
270bool PhantomXMkII::IsValidJointState(const int leg_index,
271 const Vector3& leg_pos,
272 const HexapodJointState& joint_state) const noexcept
273{
274 assert(joint_state.joint_pos_leg_coordinate.size() == 4);
275 assert(joint_state.joint_angle.size() == 3);
276
277 // coxa関節の範囲内に存在しているかを確認する.
278 if (!PhantomXMkIIConst::IsValidCoxaAngle(leg_index, joint_state.joint_angle[0]))
279 {
280 return false;
281 }
282
283 // femur関節の範囲内に存在しているかを確認する.
284 if (!PhantomXMkIIConst::IsValidFemurAngle(joint_state.joint_angle[1]))
285 {
286 return false;
287 }
288
289 // tibia関節の範囲内に存在しているかを確認する.
290 if (!PhantomXMkIIConst::IsValidTibiaAngle(joint_state.joint_angle[2]))
291 {
292 return false;
293 }
294
295 // リンクの長さを確認する.
296 if (!math_util::IsEqual((joint_state.joint_pos_leg_coordinate[0] -
297 joint_state.joint_pos_leg_coordinate[1]).GetLength(), PhantomXMkIIConst::kCoxaLength))
298 {
299 return false;
300 }
301
302 if (!math_util::IsEqual((joint_state.joint_pos_leg_coordinate[1] -
303 joint_state.joint_pos_leg_coordinate[2]).GetLength(), PhantomXMkIIConst::kFemurLength))
304 {
305 return false;
306 }
307
308 if (!math_util::IsEqual((joint_state.joint_pos_leg_coordinate[2] -
309 joint_state.joint_pos_leg_coordinate[3]).GetLength(), PhantomXMkIIConst::kTibiaLength))
310 {
311 return false;
312 }
313
314 // 脚位置と脚先座標が一致しているかを確認する.
315 if (joint_state.joint_pos_leg_coordinate[3] != leg_pos) { return false; }
316
317 return true;
318}
319
320
322 const Vector3& converted_position,
323 const int leg_index,
324 const Vector3& center_of_mass_global,
325 const Quaternion& robot_quat,
326 const bool consider_rot) const
327{
328 // leg_indexは 0~5 である.
329 assert(0 <= leg_index);
330 assert(leg_index < HexapodConst::kLegNum);
331
332 if (consider_rot)
333 {
334 return RotateVector3(converted_position - center_of_mass_global,
335 robot_quat.GetConjugate()) -
337 }
338 else
339 {
340 return converted_position -
341 center_of_mass_global -
343 }
344}
345
347 const Vector3& converted_position,
348 int leg_index,
349 const Vector3& center_of_mass_global,
350 const Quaternion& robot_quat,
351 const bool consider_rot) const
352{
353 // leg_indexは 0~5 である.
354 assert(0 <= leg_index);
355 assert(leg_index < HexapodConst::kLegNum);
356
357 if (consider_rot)
358 {
359 return RotateVector3(converted_position + GetLegBasePosRobotCoordinate(leg_index),
360 robot_quat) + center_of_mass_global;
361 }
362 else
363 {
364 return converted_position +
365 GetLegBasePosRobotCoordinate(leg_index) + center_of_mass_global;
366 }
367}
368
370 const Vector3& converted_position,
371 const Vector3& center_of_mass_global,
372 const Quaternion& robot_quat,
373 const bool consider_rot) const
374{
375 if (consider_rot)
376 {
377 return RotateVector3(converted_position, robot_quat) + center_of_mass_global;
378 }
379 else
380 {
381 return converted_position + center_of_mass_global;
382 }
383}
384
386 const int leg_index) const
387{
388 return converted_position - GetLegBasePosRobotCoordinate(leg_index);
389}
390
392 const int leg_index) const
393{
394 return converted_position + GetLegBasePosRobotCoordinate(leg_index);
395}
396
397
398Vector3 PhantomXMkII::GetFreeLegPosLegCoordinate(const int leg_index) const noexcept
399{
400 // leg_indexは 0~5 である.
401 assert(0 <= leg_index);
402 assert(leg_index < HexapodConst::kLegNum);
403
404 return free_leg_pos_leg_coordinate_[leg_index];
405}
406
407Vector3 PhantomXMkII::GetLegBasePosRobotCoordinate(const int leg_index) const noexcept
408{
409 // leg_indexは 0~5 である.
410 assert(0 <= leg_index);
411 assert(leg_index < HexapodConst::kLegNum);
412
413 return leg_base_pos_robot_coordinate_[leg_index];
414}
415
416
417bool PhantomXMkII::IsLegInRange(const int leg_index, const Vector3& leg_pos) const
418{
419 // leg_indexは 0~5 である.
420 assert(0 <= leg_index);
421 assert(leg_index < HexapodConst::kLegNum);
422
423 if (GetFreeLegPosLegCoordinate(leg_index).z < leg_pos.z)
424 {
425 return false;
426 }
427
428 const Vector2 leg_pos_xy = leg_pos.ProjectedXY(); // 投射した脚先座標をえる.
429
430 // 脚の角度が範囲内にあるか調べる.外積計算で間にあるか調べる
431 if (kMinLegPosXY[leg_index].Cross(leg_pos_xy) < 0.0f)
432 {
433 return false;
434 }
435 if (kMaxLegPosXY[leg_index].Cross(leg_pos_xy) > 0.0f)
436 {
437 return false;
438 }
439
440
441 // 脚を伸ばすことのできない範囲に伸ばしていないか調べる.
442 if (static_cast<int>(leg_pos.z) < -kMaxLegRSize || 0 < static_cast<int>(leg_pos.z))
443 {
444 return false;
445 }
446
447 if (leg_pos_xy.GetSquaredLength() < math_util::Squared(kMinLegR))
448 {
449 return false;
450 }
451
452 if (math_util::Squared(kMaxLegR) < leg_pos_xy.GetSquaredLength())
453 {
454 return false;
455 }
456
457 if (math_util::Squared(kMaxLegRArray[-static_cast<int>(leg_pos.z)]) <
458 leg_pos_xy.GetSquaredLength())
459 {
460 return false;
461 }
462
463 return true;
464}
465
467 const std::array<Vector3, HexapodConst::kLegNum>& leg_pos) const
468{
469 // 重心を原点とした,座標系において,脚の干渉を調べる.
470
471 // 脚の干渉を調べる.
472 Vector2 leg_pos_xy[HexapodConst::kLegNum]; // 脚先の座標(ロボット座標系).
473 Vector2 joint_pos_xy[HexapodConst::kLegNum]; // 脚の根元の座標(ロボット座標系).
474
475 // 脚の根元の座標(ロボット座標系)を取得する.
476 for (int i = 0; i < HexapodConst::kLegNum; i++)
477 {
478 joint_pos_xy[i] = GetLegBasePosRobotCoordinate(i).ProjectedXY();
479 leg_pos_xy[i] = ConvertLegToRobotCoordinate(leg_pos[i], i).ProjectedXY();
480 }
481
482 // 隣の脚との干渉を調べる.
483 for (int i = 0; i < HexapodConst::kLegNum; i++)
484 {
485 // 脚が交差しているか調べる.
486 LineSegment2 line1(joint_pos_xy[i], leg_pos_xy[i]);
487 LineSegment2 line2(joint_pos_xy[(i + 1) % HexapodConst::kLegNum],
488 leg_pos_xy[(i + 1) % HexapodConst::kLegNum]);
489
490 if (line1.HasIntersection(line2)) { return true; }
491
492 // 脚先の距離を確認する.
493 if (leg_pos_xy[i].GetDistanceFrom(leg_pos_xy[(i + 1) % HexapodConst::kLegNum]) < kMinLegDistance)
494 {
495 return true;
496 }
497 }
498
499 return false;
500}
501
503{
504 return kBodyLiftingHeightMin;
505}
506
508{
509 return kBodyLiftingHeightMax;
510}
511
513 const leg_func::LegStateBit& leg_state,
514 const std::array<Vector3, HexapodConst::kLegNum>& leg_pos) const
515{
516 // std::min をカッコで囲んでいるのは,マクロの min と被るため.
517 // (std::min) と書くと名前が衝突しない
518
519 // xy平面に投射した,重心を原点としたローカル(ロボット)座標系で,脚の位置を計算する.
520 std::array<Vector2, HexapodConst::kLegNum> ground_leg_pos;
521
522 // 速度の関係上 vectorでなく array を使う.
523 int ground_leg_pos_num = 0;
524
525
526 // 接地脚のみ追加する.
527 for (int i = 0; i < HexapodConst::kLegNum; i++)
528 {
529 if (leg_func::IsGrounded(leg_state, i))
530 {
531 ground_leg_pos[ground_leg_pos_num] = leg_pos[i].ProjectedXY() +
533
534 ground_leg_pos_num++;
535 }
536 }
537
538
539 float min_margin = 0; // 多角形の辺と重心の距離の最小値
540 bool is_first = true; // 初回かどうか,最初は必ず値を更新する
541
542 for (int i = 0; i < ground_leg_pos_num; i++)
543 {
544 Vector2 i_to_i_plus_1 = ground_leg_pos[(i + 1) % ground_leg_pos_num] -
545 ground_leg_pos[i];
546 Vector2 i_to_com = Vector2{ 0, 0 } - ground_leg_pos[i];
547
548 // 多角形の辺と重心の距離(静的安定余裕)
549 float margin = i_to_com.Cross(i_to_i_plus_1.GetNormalized());
550
551 if (is_first)
552 {
553 min_margin = margin;
554 is_first = false;
555 }
556 else
557 {
558 min_margin = (std::min)(min_margin, margin);
559 }
560 }
561
562 return min_margin;
563}
564
566 const std::array<Vector3, HexapodConst::kLegNum>& leg_pos) const
567{
568 // kStableMargin 以上の余裕があるか調べる.
569 return CalculateStabilityMargin(leg_state, leg_pos) > kStableMargin;
570}
571
573 const DividedMapState& devide_map) const
574{
575 // 重心の干渉を調べる.
576 {
577 const float top_z = (std::max)(
578 devide_map.GetMapMinZ(),
579 devide_map.GetTopZ(
582
583 if (top_z != devide_map.GetMapMinZ() &&
585 {
586 return true;
587 }
588 }
589
590 for (int i = 0; i < HexapodConst::kLegNum; i++)
591 {
592 // 脚の根元の座標(グローバル)を取得する.
593 const Vector3 coxa_pos_global_coord = ConvertRobotToGlobalCoordinate(
596 node.posture,
597 true);
598
599 if (devide_map.IsInMap(coxa_pos_global_coord))
600 {
601 const float coxa_top_z = (std::max)(
602 devide_map.GetTopZ(devide_map.GetDividedMapIndexX(coxa_pos_global_coord.x), devide_map.GetDividedMapIndexY(coxa_pos_global_coord.y)),
603 devide_map.GetMapMinZ());
604
605 if (coxa_top_z != devide_map.GetMapMinZ() &&
606 coxa_top_z + GetGroundHeightMarginMin() - MathConst<float>::kAllowableError > coxa_pos_global_coord.z)
607 {
608 return true;
609 }
610 }
611
612 // 脚先の座標(グローバル)を取得する.
613 const Vector3 leg_pos_global_coord = leg_func::IsGrounded(node.leg_state, i) ?
616
617 if (devide_map.IsInMap(leg_pos_global_coord))
618 {
619 const float leg_top_z = (std::max)(
620 devide_map.GetTopZ(devide_map.GetDividedMapIndexX(leg_pos_global_coord.x), devide_map.GetDividedMapIndexY(leg_pos_global_coord.y)),
621 devide_map.GetMapMinZ());
622
623 if (leg_top_z != devide_map.GetMapMinZ() &&
625 {
626 return true;
627 }
628 }
629 }
630
631 return false;
632}
633
634
635std::array<float, PhantomXMkII::kMaxLegRSize> PhantomXMkII::InitMaxLegR() const
636{
637 // 2019年度の先行研究のコードそのまま.
638
639 // 逆運動学 coxaなしの計算結果を用いて準運動学を計算する.
640 std::array <float, kMaxLegRSize> res;
641
642 for (auto i : res)
643 {
644 i = 0;
645 }
646
647 // 逆運動学と運動学を行った結果が半径 Permission ^ 0.5 の円の中なら等しいと考える.
648 const float PERMISSION = 0.5f;
649
650
651 // 脚可動範囲 おそらく rad 変換したやつ(-81.8° -101.98° -68.41°) 190527
652 const float mins[3] = { -1.428f, -1.780f, -1.194f };
653
654 // 左から coxa, femur, tibia (80.32° 99.92° 101.36°)
655 const float maxes[3] = { 1.402f, 1.744f, 1.769f };
656
657 // ans of kinematics use solution of i_kinematics.
658
659 // zは最大196.ixは最大248.
660 for (int iz = 0; iz < 200; iz++)
661 {
662 for (int ix = 53; ix < 248; ix++)
663 {
664 // 脚先座標(ローカル)
665 const Vector3 line_end(static_cast<float>(ix), 0.0f, static_cast<float>(iz));
666
667 // 逆運動学 coxa なし.
668
669 // const float _coxa_angle = atan2(line_end.x, line_end.y); // coxa角度.
670
671 // femurから足先までを結ぶベクトルをxy平面に投影したときのベクトルの大きさ.
672 const float _IK_trueX = sqrt(math_util::Squared(line_end.x) +
673 math_util::Squared(line_end.y)) -
675
676 // 絶対に正.
677 float _im = sqrt(math_util::Squared(_IK_trueX) + math_util::Squared(line_end.z));
678
679 if (_im == 0.0f)
680 {
681 // 0割り対策.
682 _im += 0.01f;
683 }
684
685 // マイナスでおk座標系的にq1自体は常に負.xがゼロだと定義域エラー.
686 const float _q1 = -atan2(line_end.z, _IK_trueX);
687
688 // im = 0 だと定義域エラー.
689 const float _q2 = acos(
692 (2.0f * PhantomXMkIIConst::kFemurLength * _im));
693
694 const float _femur_angle = _q1 + _q2;
695 const float _tibia_angle = acos(
698 math_util::Squared(_im)) /
700 std::numbers::pi_v<float> / 2.0f;
701
702 // 運動学
703 const float _K_trueX = PhantomXMkIIConst::kFemurLength * cos(_femur_angle) +
705 cos(_femur_angle + _tibia_angle - std::numbers::pi_v<float> / 2.0f);
706
707 Vector3 _kinematics;
708 _kinematics.x = _K_trueX + PhantomXMkIIConst::kCoxaLength;
709 _kinematics.y = 0.0f;
710 _kinematics.z =
711 -(PhantomXMkIIConst::kFemurLength * sin(_femur_angle) +
713 sin(_femur_angle + _tibia_angle - std::numbers::pi_v<float> / 2.0f));
714
715 const float _Permission = (_kinematics - line_end).GetSquaredLength();
716
717 if (PERMISSION > _Permission)
718 {
719 constexpr float kLegRom_RMargin = 2.f;
720
721 // y = 0のとき,脚高さzのときのx方向の最大の範囲.
722 res[iz] = static_cast<float>(ix) - kLegRom_RMargin;
723
724#ifdef MAX_LEG_RADIUS
725 // 脚を置く位置が遠すぎるとトルクが足りなくて
726 // 沈み込みが激しいから200までにした2020/11/09 Hato
727 if (iz <= 115)
728 {
729 res[iz] = MAX_LEG_RADIUS;
730 }
731#endif
732 }
733 }
734 }
735
736 return res;
737}
738
739std::array<Vector2, HexapodConst::kLegNum> PhantomXMkII::InitMinLegPosXY() const
740{
741 std::array<Vector2, HexapodConst::kLegNum> res;
742
743 for (int i = 0; i < HexapodConst::kLegNum; i++)
744 {
745 const float angle = kMovableCoxaAngleMin + PhantomXMkIIConst::kCoxaDefaultAngle[i];
746 res[i] = Vector2(cos(angle), sin(angle)).GetNormalized();
747 }
748
749 return res;
750}
751
752std::array<Vector2, HexapodConst::kLegNum> PhantomXMkII::InitMaxLegPosXY() const
753{
754 std::array<Vector2, HexapodConst::kLegNum> res;
755
756 for (int i = 0; i < HexapodConst::kLegNum; i++)
757 {
758 const float angle = kMovableCoxaAngleMax + PhantomXMkIIConst::kCoxaDefaultAngle[i];
759 res[i] = Vector2(cos(angle), sin(angle)).GetNormalized();
760 }
761
762 return res;
763}
764
765} // namespace designlab
マップを格子状に分割して管理するクラス.
constexpr int GetDividedMapIndexX(const float pos_x) const noexcept
指定した座標を DividedMap のインデックスに変換する. 範囲外の値を指定した場合でも,値を丸めずに返す. そのため,IsInMap で範囲内に存在するかどうかを確認する必要がある.
constexpr bool IsInMap(const float x, const float y) const
指定した座標がマップの範囲内に存在するかどうかを返す.
constexpr int GetDividedMapIndexY(const float pos_y) const noexcept
指定した座標を DividedMap のインデックスに変換する. 範囲外の値を指定した場合でも,値を丸めずに返す. そのため,IsInMap で範囲内に存在するかどうかを確認する必要がある.
float GetTopZ(int x_index, int y_index) const
格子状に切り分けられたマップから,最も高いZ座標を返す.
float GetMapMinZ() const noexcept
static constexpr int kLegNum
static constexpr float kFemurLength
第2関節部の長さ[mm].
static constexpr bool IsValidCoxaAngle(const int leg_index, const float angle)
第1関節の角度が有効な範囲内かどうかを判定する.
static constexpr float kCoxaBaseOffsetY
coxa linkの付け根(中央)までの長さ[mm].
static constexpr float kCenterCoxaBaseOffsetY
coxa linkの付け根(前方・後方)までの長さ[mm].
static constexpr float kCoxaLength
第1関節部の長さ[mm].
static constexpr float kTibiaLength
第3関節部の長さ[mm].
static constexpr std::array< float, kPhantomXLegNum > kCoxaDefaultAngle
第1関節の初期角度[rad]
static constexpr bool IsValidFemurAngle(const float angle)
第2関節の角度が有効な範囲内かどうかを判定する.
static constexpr bool IsValidTibiaAngle(const float angle)
第3関節の角度が有効な範囲内かどうかを判定する.
static constexpr float kCoxaBaseOffsetX
coxa linkの付け根までの長さ(上方向)[mm].
static constexpr float kCoxaBaseOffsetZ
胴体の高さ[mm].
Vector3 ConvertLegToGlobalCoordinate(const Vector3 &converted_position, int leg_index, const Vector3 &center_of_mass_global, const Quaternion &robot_quat, const bool consider_rot) const override
脚座標系で表現されている座標を,グローバル座標系に変換する.
Vector3 ConvertGlobalToLegCoordinate(const Vector3 &converted_position, int leg_index, const Vector3 &center_of_mass_global, const Quaternion &robot_quat, const bool consider_rot) const override
グローバル座標系で表現されている座標を,脚座標系に変換する.
Vector3 ConvertRobotToLegCoordinate(const Vector3 &converted_position, int leg_index) const
ロボット座標系で表現されている座標を,脚座標系に変換する.
PhantomXMkII(const PhantomXMkIIParameterRecord &parameter_record)
Vector3 ConvertLegToRobotCoordinate(const Vector3 &converted_position, int leg_index) const
脚座標系で表現されている座標を,ロボット座標系に変換する.
bool IsBodyInterferingWithGround(const RobotStateNode &node, const DividedMapState &devide_map) const override
胴体が地面と干渉しているかどうかを判定する.
float GetGroundHeightMarginMax() const noexcept override
地面の最大高さと重心位置を最大どれだけ離すかを返す.
float GetGroundHeightMarginMin() const noexcept override
地面の最大高さと重心位置を最小どれだけ離すかを返す.
float CalculateStabilityMargin(const leg_func::LegStateBit &leg_state, const std::array< Vector3, HexapodConst::kLegNum > &leg_pos) const override
安定余裕(Stability Margin)を計算する. 詳しくは「不整地における歩行機械の静的安定性評価基準」 という論文を読んで欲しい. 接地脚を繋いで作られる多角形の辺と重心の距離の最小値を計...
bool IsLegInRange(int leg_index, const Vector3 &leg_pos) const override
脚が可動範囲内にあるかどうかを判定する.
HexapodJointState CalculateJointState(const int leg_index, const Vector3 &leg_pos) const noexcept override
指定した脚の関節のグローバル座標と,角度を計算する. 重たいのでグラフ探索や,描画処理中にループで使用することは推奨しない. 間接の可動範囲外まで動いてしまう場合でも,答えを返す. 目標座標...
Vector3 GetFreeLegPosLegCoordinate(int leg_index) const noexcept override
遊脚する位置を返す,脚座標系.
bool IsValidJointState(const int leg_index, const Vector3 &leg_pos, const HexapodJointState &joint_state) const noexcept override
指定した脚のHexapodJointStateが正しく計算できているかを調べる. 目標座標に届かない場合や,間接の可動範囲外まで動いてしまう場合, 戻り値は false になる.
Vector3 ConvertRobotToGlobalCoordinate(const Vector3 &converted_position, const Vector3 &center_of_mass_global, const Quaternion &robot_quat, const bool consider_rot) const override
ロボット座標系で表現されている座標を,グローバル座標系に変換する.
bool IsStable(const leg_func::LegStateBit &leg_state, const std::array< Vector3, HexapodConst::kLegNum > &leg_pos) const override
安定余裕を用いて,静的に安定しているかどうかを判定する.
bool IsLegInterfering(const std::array< Vector3, HexapodConst::kLegNum > &leg_pos) const override
脚が他の脚と干渉しているかどうかを判定する.
Vector3 GetLegBasePosRobotCoordinate(int leg_index) const noexcept override
脚の付け根の座標(leg base position )を取得する.ロボット座標系.
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
std::bitset< kLegStateBitNum > LegStateBit
脚状態を保存する型.28bitのビット型.
Definition leg_state.h:56
constexpr bool CanMakeTriangle(const T a, const T b, const T c) noexcept
3辺で三角形が作れるか調べる関数.
Definition math_util.h:68
constexpr bool IsEqual(const T num1, const T num2) noexcept
C++において,小数同士の計算は誤差が出てしまう. 誤差込みで値が等しいか調べる.
Definition math_util.h:45
constexpr T Squared(const T num) noexcept
2乗した値を返す関数.
Definition math_util.h:59
Vector3 RotateVector3(const Vector3 &vec, const EulerXYZ &rot)
回転させたベクトルを返す.三角関数の処理が多く重たいので注意.
ロボットの関節の状態を表す構造体.
bool is_in_range
目標座標に脚が届かないならば false になる.
2次元の線分を表す構造体.
bool HasIntersection(const LineSegment2 &other) const
他の線分と交点が存在しているかどうか調べる関数.
float 型と double 型の定数を提供するクラス.
Definition math_const.h:25
クォータニオンを表す構造体.
constexpr Quaternion GetConjugate() const noexcept
クォータニオンの共役を返す. 共役なクォータニオンとは,ベクトル成分の符号を反転させたもの q = w + xi + yj + zk とすると, qの共役は w - xi - yj - zk となる...
グラフ構造のためのノード(頂点).旧名 LNODE
std::array< Vector3, HexapodConst::kLegNum > leg_pos
[4 * 3 * 6 = 72 byte] 脚先の座標.(coxa(脚の付け根)を原点とする)
leg_func::LegStateBit leg_state
[4 byte] 脚状態,重心パターンを bitで表す.旧名 leg_con.
Vector3 center_of_mass_global_coord
[4 * 3 = 12byte] グローバル座標系における重心の位置.旧名 GCOM
Quaternion posture
[4 * 4 = 16byte] 姿勢を表すクォータニオン.
2次元の位置ベクトルを表す構造体.
Vector2 GetNormalized() const
このベクトルを正規化したベクトルを返す.
constexpr float GetSquaredLength() const noexcept
このベクトルの長さの2乗を返す.
constexpr float Cross(const Vector2 &other) const noexcept
自分×引数 の外積の結果を返す.
float GetLength() const
このベクトルの長さを返す.
3次元の位置ベクトルを表す構造体.
float x
ロボットの正面方向に正.
constexpr float GetSquaredLength() const noexcept
ベクトルの長さの2乗を返す.
float z
ロボットの上向きに正.
float GetLength() const noexcept
ベクトルの長さを返す.
constexpr Vector2 ProjectedXY() const noexcept
XY平面に射影したベクトルを返す.
float y
ロボットの左向きに正.