GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
dxlib_gui_node_displayer.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 <format>
11
12#include <magic_enum.hpp>
13
14#include <Dxlib.h>
15
16#include "math_util.h"
17#include "math_rot_converter.h"
18#include "string_util.h"
19#include "font_loader.h"
20#include "leg_state.h"
21#include "phantomx_mk2_const.h"
22
23
24namespace designlab
25{
26
28 const int pos_x,
29 const int pos_y,
30 const std::shared_ptr<const IHexapodCoordinateConverter>& converter_ptr,
31 const std::shared_ptr<const IHexapodJointCalculator>& calculator_ptr,
32 const std::shared_ptr<const IHexapodPostureValidator>& checker_ptr) :
33 AbstractDxlibGui{ 470, 680 },
34 converter_ptr_(converter_ptr),
35 calculator_ptr_(calculator_ptr),
36 checker_ptr_(checker_ptr),
37 display_type_(DisplayMode::kDefualt),
38 window_x_(pos_x),
39 window_y_(pos_y)
40{
41 // ボタンを作成する.
42 const int button_size_x = 90;
43 const int button_size_y = 30;
44
45 button_.push_back(
46 std::make_unique<SimpleButton>(
47 "基本情報",
48 10 + button_size_x / 2,
49 gui_top_pos_y_ + height_ - button_size_y / 2 - 10,
50 button_size_x,
51 button_size_y));
52
53 button_.back()->SetActivateFunction(
54 [this]() {display_type_ = DisplayMode::kDefualt; });
55
56 button_.push_back(
57 std::make_unique<SimpleButton>(
58 "joint",
59 (10 + button_size_x / 2) + (10 + button_size_x),
60 gui_top_pos_y_ + height_ - button_size_y / 2 - 10,
61 button_size_x,
62 button_size_y));
63
64 button_.back()->SetActivateFunction(
65 [this]() {display_type_ = DisplayMode::kJointState; });
66
67 button_.push_back(
68 std::make_unique<SimpleButton>(
69 "脚先座標",
70 (10 + button_size_x / 2) + (10 + button_size_x) * 2,
71 gui_top_pos_y_ + height_ - button_size_y / 2 - 10,
72 button_size_x,
73 button_size_y));
74
75 button_.back()->SetActivateFunction(
76 [this]() {display_type_ = DisplayMode::kGlobalPos; });
77
78 const int close_button_size = 28;
79 const int close_button_x = gui_left_pos_x_ + width_ - close_button_size / 2 - 2;
80 const int close_button_y = gui_top_pos_y_ + close_button_size / 2 + 2;
81
82 button_.push_back(std::make_unique<SimpleButton>(
83 "×", close_button_x, close_button_y,
84 close_button_size, close_button_size));
85
86 button_.back()->SetActivateFunction([this]() { SetVisible(false); });
87}
88
90{
91 // ノードをセットする.
92 display_node_ = node;
93
94 if (!calculator_ptr_)
95 {
96 return;
97 }
98
99 // 関節の角度をセットする.
100 joint_state_ = calculator_ptr_->CalculateAllJointState(display_node_);
101}
102
104{
105 // ボタンの更新を行う.
106 for (auto& button : button_)
107 {
108 button->Update();
109 }
110
111 if (!IsInWindow())
112 {
113 SetVisible(false);
114 }
115}
116
118{
119 // 枠.
120 DrawBackground("NodeDisplay");
121
122 // テキスト.
123 if (display_type_ == DisplayMode::kDefualt)
124 {
125 DrawNodeInfo();
126 }
127 else if (display_type_ == DisplayMode::kJointState)
128 {
129 DrawJointInfo();
130 }
131 else if (display_type_ == DisplayMode::kGlobalPos)
132 {
133 DrawGlobalPosInfo();
134 }
135
136 // ボタンを描画する.
137 for (auto& button : button_)
138 {
139 button->Draw();
140 }
141}
142
143void DxlibGuiNodeDisplayer::DrawNodeInfo() const
144{
146
147 const unsigned int text_color = GetColor(10, 10, 10);
148 const unsigned int text_color_dark = GetColor(80, 80, 80);
149
150 const int text_pos_x = gui_left_pos_x_ + 10;
151 const int text_pos_y_min = gui_top_pos_y_ + kTitleBarHeight + 10;
152 const int text_interval_y = 20;
153
154 const std::array<std::string, HexapodConst::kLegNum> leg_name = {
155 "右前", "右中", "右後", "左後", "左中", "左前" };
156
157 int text_line = 0;
158
159 DrawFormatStringToHandle(
160 text_pos_x, text_pos_y_min + text_interval_y * (text_line++),
161 text_color, font_handle_, "階層");
162 DrawFormatStringToHandle(
163 text_pos_x, text_pos_y_min + text_interval_y * (text_line++),
164 text_color, font_handle_,
165 " bit : %s", display_node_.leg_state.to_string().c_str());
166
167 const auto com_pos_name =
168 EnumToStringRemoveTopK(
170 const auto com_pos_num = leg_func::GetDiscreteComPos(display_node_.leg_state);
171
172 DrawFormatStringToHandle(
173 text_pos_x, text_pos_y_min + text_interval_y * (text_line++),
174 text_color, font_handle_,
175 " 重心 : %s(%d)", com_pos_name.c_str(), com_pos_num);
176
177 std::string str_leg_pos_right = "";
178 std::string str_leg_pos_left = "";
179 std::string str_ground = "";
180
181 for (int i = 0; i < HexapodConst::kLegNum; i++)
182 {
183 if (leg_func::IsGrounded(display_node_.leg_state, i))
184 {
185 str_ground += "接地,";
186 }
187 else
188 {
189 str_ground += "遊脚,";
190 }
191
192 const enums::DiscreteLegPos pos =
193 leg_func::GetDiscreteLegPos(display_node_.leg_state, i);
194
195 if (i < HexapodConst::kLegNum / 2)
196 {
197 str_leg_pos_right += std::format(
198 "{}-{}({}), ",
199 leg_name[i],
201 static_cast<int>(pos));
202 }
203 else
204 {
205 str_leg_pos_left += std::format(
206 "{}-{}({}), ",
207 leg_name[i],
209 static_cast<int>(pos));
210 }
211 }
212 DrawFormatStringToHandle(
213 text_pos_x,
214 text_pos_y_min + text_interval_y * (text_line++),
215 text_color, font_handle_,
216 " 脚位置 : ", str_leg_pos_right.c_str());
217
218 DrawFormatStringToHandle(
219 text_pos_x,
220 text_pos_y_min + text_interval_y * (text_line++),
221 text_color, font_handle_,
222 " %s", str_leg_pos_right.c_str());
223
224 DrawFormatStringToHandle(
225 text_pos_x, text_pos_y_min + text_interval_y * (text_line++),
226 text_color, font_handle_,
227 " %s", str_leg_pos_left.c_str());
228
229 DrawFormatStringToHandle(
230 text_pos_x, text_pos_y_min + text_interval_y * (text_line++),
231 text_color, font_handle_,
232 " 脚の状態:%s", str_ground.c_str());
233
234 // 重心を表示する
235 ++text_line;
236 DrawFormatStringToHandle(
237 text_pos_x,
238 text_pos_y_min + text_interval_y * (text_line++),
239 text_color, font_handle_,
240 "重心位置");
241
242 DrawFormatStringToHandle(
243 text_pos_x,
244 text_pos_y_min + text_interval_y * (text_line++),
245 text_color, font_handle_,
246 " %s", display_node_.center_of_mass_global_coord.ToString().c_str());
247
248 // 回転を表示する
249 DrawFormatStringToHandle(
250 text_pos_x,
251 text_pos_y_min + text_interval_y * (text_line++),
252 text_color, font_handle_,
253 "回転 (w:%5.3f,x:%5.3f,y:%5.3f,z:%5.3f)",
254 display_node_.posture.w,
255 display_node_.posture.v.x,
256 display_node_.posture.v.y,
257 display_node_.posture.v.z);
258
259 // オイラー角にして表示する.
260 const EulerXYZ euler = ToEulerXYZ(display_node_.posture);
261
262 DrawFormatStringToHandle(
263 text_pos_x,
264 text_pos_y_min + text_interval_y * (text_line++),
265 text_color, font_handle_,
266 " オイラー角(x:%5.3f[deg],y:%5.3f[deg],z:%5.3f[deg])",
267 math_util::ConvertRadToDeg(euler.x_angle),
268 math_util::ConvertRadToDeg(euler.y_angle),
269 math_util::ConvertRadToDeg(euler.z_angle));
270
271 // 脚の位置を表示する.
272 ++text_line;
273 DrawFormatStringToHandle(
274 text_pos_x,
275 text_pos_y_min + text_interval_y * (text_line++),
276 text_color, font_handle_,
277 "脚位置");
278
279 for (int i = 0; i < HexapodConst::kLegNum; i++)
280 {
281 DrawFormatStringToHandle(
282 text_pos_x,
283 text_pos_y_min + text_interval_y * (text_line++),
284 text_color, font_handle_,
285 "%s %s",
286 leg_name[i].c_str(),
287 display_node_.leg_pos[i].ToString().c_str());
288 }
289
290 // 脚の基準座標を表示する.
291 for (int i = 0; i < HexapodConst::kLegNum; i++)
292 {
293 if (display_node_.leg_pos[i] == display_node_.leg_reference_pos[i])
294 {
295 DrawFormatStringToHandle(
296 text_pos_x,
297 text_pos_y_min + text_interval_y * (text_line++),
298 text_color_dark, font_handle_,
299 " %s脚の基準座標は現在の脚位置と同じです.", leg_name[i].c_str());
300 }
301 else
302 {
303 DrawFormatStringToHandle(
304 text_pos_x,
305 text_pos_y_min + text_interval_y * (text_line++),
306 text_color_dark, font_handle_,
307 " %s脚の基準座標(x:%5.3f,y:%5.3f,z:%5.3f)",
308 leg_name[i].c_str(),
309 display_node_.leg_reference_pos[i].x,
310 display_node_.leg_reference_pos[i].y,
311 display_node_.leg_reference_pos[i].z);
312 }
313 }
314
315 // 深さと次の動作を表示する.
316 ++text_line;
317
318 DrawFormatStringToHandle(
319 text_pos_x,
320 text_pos_y_min + text_interval_y * (text_line++),
321 text_color, font_handle_,
322 "深さ:%d, 次の動作 : %s",
323 display_node_.depth,
324 EnumToStringRemoveTopK(display_node_.next_move).c_str());
325
326 DrawFormatStringToHandle(
327 text_pos_x,
328 text_pos_y_min + text_interval_y * (text_line++),
329 text_color, font_handle_,
330 "指定がなければ単位は長さが[mm],角度が[rad]");
331}
332
333void DxlibGuiNodeDisplayer::DrawJointInfo() const
334{
337
338 const unsigned int text_color = GetColor(10, 10, 10);
339 const unsigned int error_text_color = GetColor(128, 10, 10);
340 const int text_pos_x = gui_left_pos_x_ + 10;
341 const int text_pos_y_min = gui_top_pos_y_ + kTitleBarHeight + 10;
342 const int text_interval_y = 20;
343
344 if (!calculator_ptr_)
345 {
346 DrawFormatStringToHandle(
347 text_pos_x,
348 text_pos_y_min + text_interval_y * 0,
349 text_color,
351 "計算クラスが nullptr です");
352 return;
353 }
354 if (!checker_ptr_)
355 {
356 DrawFormatStringToHandle(
357 text_pos_x,
358 text_pos_y_min + text_interval_y * 0,
359 text_color,
361 "チェッカークラスが nullptr です");
362 return;
363 }
364
365 for (int i = 0; i < HexapodConst::kLegNum; i++)
366 {
367 if (joint_state_[i].joint_angle.size() != 3)
368 {
369 DrawFormatStringToHandle(
370 text_pos_x,
371 text_pos_y_min + text_interval_y * 0,
372 text_color,
374 "間接の計算ができていない,またはされていません.");
375
376 return;
377 }
378 if (joint_state_[i].joint_pos_leg_coordinate.size() != 4)
379 {
380 DrawFormatStringToHandle(
381 text_pos_x,
382 text_pos_y_min + text_interval_y * 0,
383 text_color,
385 "間接の計算ができていない,またはされていません.");
386
387 return;
388 }
389 }
390
391 int text_line = 0;
392
393
394 for (int i = 0; i < HexapodConst::kLegNum; i++)
395 {
396 const float coxa_angle_deg =
397 ConvertRadToDeg(joint_state_[i].joint_angle[0]);
398 const float femur_angle_deg =
399 ConvertRadToDeg(joint_state_[i].joint_angle[1]);
400 const float tibia_angle_deg =
401 ConvertRadToDeg(joint_state_[i].joint_angle[2]);
402
403 DrawFormatStringToHandle(
404 text_pos_x,
405 text_pos_y_min + text_interval_y * (text_line++),
406 text_color,
408 "[%d] c %s[deg],f %s[deg],t %s[deg]",
409 i,
410 FloatingPointNumToString(coxa_angle_deg).c_str(),
411 FloatingPointNumToString(femur_angle_deg).c_str(),
412 FloatingPointNumToString(tibia_angle_deg).c_str());
413
414 const auto coxa_to_femur = joint_state_[i].joint_pos_leg_coordinate[0] -
415 joint_state_[i].joint_pos_leg_coordinate[1];
416 const auto femur_to_tibia = joint_state_[i].joint_pos_leg_coordinate[1] -
417 joint_state_[i].joint_pos_leg_coordinate[2];
418 const auto tibia_to_end = joint_state_[i].joint_pos_leg_coordinate[2] -
419 joint_state_[i].joint_pos_leg_coordinate[3];
420
421 DrawFormatStringToHandle(
422 text_pos_x,
423 text_pos_y_min + text_interval_y * (text_line++),
424 text_color,
426 " c %3.3f[mm],f %3.3f[mm],t %3.3f[mm]",
427 coxa_to_femur.GetLength(),
428 femur_to_tibia.GetLength(),
429 tibia_to_end.GetLength());
430
431
432 if (checker_ptr_->IsLegInRange(
433 i, joint_state_[i].joint_pos_leg_coordinate[3]))
434 {
435 DrawFormatStringToHandle(
436 text_pos_x,
437 text_pos_y_min + text_interval_y * (text_line++),
438 text_color,
440 " 近似値された可動域内にあります.");
441 }
442 else
443 {
444 DrawFormatStringToHandle(
445 text_pos_x,
446 text_pos_y_min + text_interval_y * (text_line++),
447 error_text_color,
449 " 近似値された可動域外です.");
450 }
451
452
453 std::string str = "";
454
455 const float coxa_min_angle =
458 const float coxa_max_angle =
461
462 if (joint_state_[i].joint_angle[0] < coxa_min_angle)
463 {
464 str += "coxa_min ";
465 }
466
467 if (joint_state_[i].joint_angle[0] > coxa_max_angle)
468 {
469 str += "coxa_max ";
470 }
471
472 if (joint_state_[i].joint_angle[1] < PhantomXMkIIConst::kFemurAngleMin)
473 {
474 str += "femur_min ";
475 }
476
477 if (joint_state_[i].joint_angle[1] > PhantomXMkIIConst::kFemurAngleMax)
478 {
479 str += "femur_max ";
480 }
481
482 if (joint_state_[i].joint_angle[2] < PhantomXMkIIConst::kTibiaAngleMin)
483 {
484 str += "tibia_min ";
485 }
486
487 if (joint_state_[i].joint_angle[2] > PhantomXMkIIConst::kTibiaAngleMax)
488 {
489 str += "tibia_max ";
490 }
491
492 if (!joint_state_[i].is_in_range)
493 {
494 str += "脚先が届いていません ";
495 }
496
497 if (!str.empty())
498 {
499 const size_t max_str_size = 30;
500 if (str.size() > max_str_size) { str = str.substr(0, max_str_size); }
501
502 DrawFormatStringToHandle(
503 text_pos_x,
504 text_pos_y_min + text_interval_y * (text_line++),
505 error_text_color,
507 " 実際の可動域の外です. %s", str.c_str());
508 }
509 else
510 {
511 DrawFormatStringToHandle(
512 text_pos_x,
513 text_pos_y_min + text_interval_y * (text_line++),
514 text_color,
516 " 実際の可動域の内です.");
517 }
518 }
519}
520
521void DxlibGuiNodeDisplayer::DrawGlobalPosInfo() const
522{
523 const unsigned int text_color = GetColor(10, 10, 10);
524 const int text_pos_x = gui_left_pos_x_ + 10;
525 const int text_pos_y_min = gui_top_pos_y_ + kTitleBarHeight + 10;
526 const int text_interval_y = 20;
527 const std::array<std::string, HexapodConst::kLegNum> leg_name = {
528 "右前", "右中", "右後", "左後", "左中", "左前" };
529
530 int text_line = 0;
531
532 DrawFormatStringToHandle(text_pos_x,
533 text_pos_y_min + text_interval_y * (text_line++),
534 text_color,
536 "脚先座標(ローカル座標)");
537
538 for (int i = 0; i < HexapodConst::kLegNum; i++)
539 {
540 DrawFormatStringToHandle(
541 text_pos_x,
542 text_pos_y_min + text_interval_y * (text_line++),
543 text_color,
545 "%s %s",
546 leg_name[i].c_str(),
547 display_node_.leg_pos[i].ToString().c_str());
548 }
549
550
551 ++text_line;
552 DrawFormatStringToHandle(text_pos_x,
553 text_pos_y_min + text_interval_y * (text_line++),
554 text_color,
556 "脚先座標(ロボット座標)");
557
558 for (int i = 0; i < HexapodConst::kLegNum; i++)
559 {
560 const std::string str =
561 converter_ptr_->ConvertLegToRobotCoordinate(
562 display_node_.leg_pos[i], i).ToString();
563
564 DrawFormatStringToHandle(
565 text_pos_x,
566 text_pos_y_min + text_interval_y * (text_line++),
567 text_color,
569 "%s %s", leg_name[i].c_str(), str.c_str());
570 }
571
572 ++text_line;
573 DrawFormatStringToHandle(text_pos_x,
574 text_pos_y_min + text_interval_y * (text_line++),
575 text_color,
577 "脚先座標(グローバル座標)");
578
579 DrawFormatStringToHandle(
580 text_pos_x,
581 text_pos_y_min + text_interval_y * (text_line++),
582 text_color,
584 "重心 %s",
585 display_node_.center_of_mass_global_coord.ToString().c_str());
586
587 ++text_line;
588
589 for (int i = 0; i < HexapodConst::kLegNum; i++)
590 {
591 DrawFormatStringToHandle(
592 text_pos_x,
593 text_pos_y_min + text_interval_y * (text_line++),
594 text_color,
596 "%s %s",
597 leg_name[i].c_str(),
598 converter_ptr_->ConvertLegToGlobalCoordinate(
599 display_node_.leg_pos[i],
600 i,
601 display_node_.center_of_mass_global_coord,
602 display_node_.posture,
603 true).ToString().c_str());
604 }
605
606 ++text_line;
607
608 // 脚先の付け根からの距離を表示する.
609 for (int i = 0; i < HexapodConst::kLegNum; i++)
610 {
611 DrawFormatStringToHandle(
612 text_pos_x + width_ / 2 * (i % 2),
613 text_pos_y_min + text_interval_y * text_line,
614 text_color,
616 "%s %f",
617 leg_name[i].c_str(),
618 display_node_.leg_pos[i].ProjectedXY().GetLength());
619
620 if (i % 2 == 1) { ++text_line; }
621 }
622}
623
624bool DxlibGuiNodeDisplayer::IsInWindow() const
625{
626 return gui_left_pos_x_ < window_x_ && gui_top_pos_y_ < window_y_ &&
628}
629
630} // namespace designlab
Dxlibを使ったGUIの抽象クラス.
void DrawBackground(const std::string &str) const
int gui_left_pos_x_
GUIの左端の位置.
static constexpr int kTitleBarHeight
タイトルバーの高さ.
const int width_
GUIの横幅.
int gui_top_pos_y_
GUIの上端の位置.
void SetVisible(bool visible) override
GUIの表示を行うかどうかを設定する.
int font_handle_
フォントハンドル.
std::vector< std::unique_ptr< SimpleButton > > button_
ボタンのリスト.
const int height_
GUIの縦幅.
void SetNode(const RobotStateNode &node) override
ノードをセットする.
void Draw() const override
GUIの描画.
DxlibGuiNodeDisplayer(int window_x, int window_y, const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr, const std::shared_ptr< const IHexapodJointCalculator > &calculator_ptr, const std::shared_ptr< const IHexapodPostureValidator > &checker_ptr)
void Update() override
GUIの更新,毎フレーム実行すること.
static constexpr int kLegNum
static constexpr float kTibiaAngleMax
static constexpr float kFemurAngleMin
第2関節の可動範囲の最大値[rad].詳しくは referenceフォルダ参照.
static constexpr float kFemurAngleMax
第2関節の可動範囲の最小値[rad].詳しくは referenceフォルダ参照.
static constexpr float kCoxaAngleMin
第1関節の可動範囲の最大値[rad].詳しくは referenceフォルダ参照.
static constexpr float kTibiaAngleMin
第2関節の可動範囲の最大値[rad].詳しくは referenceフォルダ参照.
static constexpr std::array< float, kPhantomXLegNum > kCoxaDefaultAngle
第1関節の初期角度[rad]
static constexpr float kCoxaAngleMax
第2関節の可動範囲の最小値[rad].詳しくは referenceフォルダ参照.
DiscreteLegPos
離散化された脚位置を表す列挙体. 先行研究では 1~7の int型の数値で表現されているが, 可読性を上げるために列挙体にした. 離散化された脚位置は 3bit (0 ~ 7)の範囲で表現される...
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)
現在の脚状態から重心パターンを取得する.
enums::DiscreteLegPos GetDiscreteLegPos(const LegStateBit &leg_state, const int leg_index)
脚状態を取得する.
std::string FloatingPointNumToString(const T num, const int digit=kDigit, const int width=kWidth)
小数を文字列に変換する関数. C++ では C のフォーマットのように %3.3f とかで小数を文字列に変換できないため自作する.
Definition math_util.h:161
constexpr T ConvertRadToDeg(const T rad) noexcept
角度を [rad]から [deg] に変換する関数.
Definition math_util.h:117
std::string EnumToStringRemoveTopK(const T &enum_value)
enumを文字列に変換する関数. Google C++ coding style だと enumの要素は 先頭にkをつけてキャメルケースで書くことが推奨されている. 例えば,
Definition string_util.h:54
EulerXYZ ToEulerXYZ(const RotationMatrix3x3 &rot)
回転角行列からXYZオイラー角への変換.
Vector3 v
ベクトル成分.
float w
スカラー成分.
グラフ構造のためのノード(頂点).旧名 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] 姿勢を表すクォータニオン.
std::array< Vector3, HexapodConst::kLegNum > leg_reference_pos
int depth
[4 byte] 自身の深さ.一番上の親が深さ0となる.
float x
ロボットの正面方向に正.
float z
ロボットの上向きに正.
std::string ToString() const
このベクトルを文字列にして返す. (x, y, z) の形式,小数点以下3桁まで.
float y
ロボットの左向きに正.