GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
graphic_main_display_model.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 <numbers>
11
13#include "camera_dragger.h"
14#include "math_util.h"
15#include "dxlib_camera.h"
16#include "dxlib_gui_camera.h"
19#include "dxlib_util.h"
21#include "keyboard.h"
22#include "map_creator_factory.h"
23#include "map_renderer.h"
24#include "node_initializer.h"
26#include "toml_file_importer.h"
27#include "phantomx_mk2_const.h"
28#include "world_grid_renderer.h"
29
30
31namespace designlab
32{
33
35 const std::shared_ptr<const IHexapodCoordinateConverter>& converter_ptr,
36 const std::shared_ptr<const IHexapodJointCalculator>& calculator_ptr,
37 const std::shared_ptr<const IHexapodPostureValidator>& checker_ptr,
38 const std::shared_ptr<const ApplicationSettingRecord>& setting_ptr) :
39 mouse_ptr_(std::make_shared<Mouse>()),
40 calculator_ptr_(calculator_ptr),
41 converter_ptr_(converter_ptr)
42{
43 NodeInitializer node_initializer{ Vector3{0.f, 0.f, 30.f}, EulerXYZ(), HexapodMove::kNone };
44 robot_ = node_initializer.InitNode();
45
46 TomlFileImporter<SimulationSettingRecord> simulation_setting_importer;
47 const SimulationSettingRecord simulation_setting_record = simulation_setting_importer.ImportOrUseDefault("./simulation_condition/simulation_setting.toml");
48 auto map_creator = MapCreatorFactory::Create(simulation_setting_record);
49
50 map_state_ = map_creator->InitMap();
51 divided_map_state_.Init(map_state_, {});
52
53 const auto camera = std::make_shared<DxlibCamera>();
54 const auto camera_gui = std::make_shared<DxlibGuiCamera>(setting_ptr->window_size_x, setting_ptr->window_size_y, camera);
55 camera_gui->SetPos(10, 10, kDxlibGuiAnchorLeftTop, true);
56
57 const auto camera_dragger = std::make_shared<CameraDragger>(camera);
58
59 const auto camera_parameter_gui = std::make_shared<DxlibGuiCameraParameterDisplayer>(setting_ptr->window_size_x, setting_ptr->window_size_y, camera);
60 camera_parameter_gui->SetPos(10, 10, kDxlibGuiAnchorLeftTop, true);
61 camera_parameter_gui->SetVisible(false);
62
63 const auto node_display_gui = std::make_shared<DxlibGuiNodeDisplayer>(setting_ptr->window_size_x, setting_ptr->window_size_y, converter_ptr, calculator_ptr, checker_ptr);
64 node_display_gui->SetPos(setting_ptr->window_size_x - 10, 10, kDxlibGuiAnchorRightTop, true);
65
66 const auto [hexapod_renderer, hexapod_node_setter] =
67 HexapodRendererBuilder::Build(converter_ptr_, calculator_ptr_, setting_ptr->gui_display_quality);
68
69 const auto map_renderer = std::make_shared<MapRenderer>();
70 map_renderer->SetMapState(map_state_);
71 map_renderer->SetNode(robot_);
72
73 const auto world_grid_renderer = std::make_shared<WorldGridRenderer>();
74
75 const auto approximated_motion_range_render =
76 std::make_shared<ApproximatedMotionRangeRender>(checker_ptr, converter_ptr);
77
78 gui_updater_.Register(camera_parameter_gui, 1);
79 gui_updater_.Register(camera_dragger, 0);
80 gui_updater_.Register(node_display_gui, 1);
81 gui_updater_.Register(camera_gui, 1);
82
83 gui_updater_.OpenTerminal();
84
85 node_setter_group_.Register(approximated_motion_range_render);
86 node_setter_group_.Register(camera_gui);
87 node_setter_group_.Register(node_display_gui);
88 node_setter_group_.Register(hexapod_node_setter);
89 node_setter_group_.Register(map_renderer);
90
91 // render_group_.Register(approximated_motion_range_render);
92 render_group_.Register(hexapod_renderer);
93 render_group_.Register(map_renderer);
94 render_group_.Register(world_grid_renderer);
95}
96
97
99{
100 assert(mouse_ptr_ != nullptr);
101
102 mouse_ptr_->Update();
103
104 if (keyboard_.GetPressingCount(KEY_INPUT_LSHIFT) > 0 ||
105 keyboard_.GetPressingCount(KEY_INPUT_RSHIFT) > 0)
106 {
107 MoveBody();
108 }
109 else
110 {
111 MoveLeg();
112 }
113
114 gui_updater_.Activate(mouse_ptr_);
115
116 node_setter_group_.SetNode(robot_);
117
118 keyboard_.Update();
119
120 return true;
121}
122
124{
125 render_group_.Draw();
126
127 gui_updater_.Draw();
128}
129
130
131void GraphicMainDisplayModel::MoveBody()
132{
133 const float kComSpeed = 1.1f;
134
135 if (keyboard_.GetPressingCount(KEY_INPUT_Q) > 0)
136 {
137 Vector3 com =
139 RotateVector3(Vector3::GetUpVec() * kComSpeed, robot_.posture);
140
141 robot_.ChangeGlobalCenterOfMass(com, false);
142 }
143 else if (keyboard_.GetPressingCount(KEY_INPUT_E) > 0)
144 {
145 Vector3 com =
147 RotateVector3(Vector3::GetUpVec() * -kComSpeed, robot_.posture);
148
149 robot_.ChangeGlobalCenterOfMass(com, false);
150 }
151 else if (keyboard_.GetPressingCount(KEY_INPUT_A) > 0)
152 {
153 Vector3 com =
155 RotateVector3(Vector3::GetLeftVec() * kComSpeed, robot_.posture);
156
157 robot_.ChangeGlobalCenterOfMass(com, false);
158 }
159 else if (keyboard_.GetPressingCount(KEY_INPUT_D) > 0)
160 {
161 Vector3 com =
163 RotateVector3(Vector3::GetLeftVec() * -kComSpeed, robot_.posture);
164
165 robot_.ChangeGlobalCenterOfMass(com, false);
166 }
167 else if (keyboard_.GetPressingCount(KEY_INPUT_W) > 0)
168 {
169 Vector3 com =
171 RotateVector3(Vector3::GetFrontVec() * kComSpeed, robot_.posture);
172
173 robot_.ChangeGlobalCenterOfMass(com, false);
174 }
175 else if (keyboard_.GetPressingCount(KEY_INPUT_S) > 0)
176 {
177 Vector3 com =
179 RotateVector3(Vector3::GetFrontVec() * -kComSpeed, robot_.posture);
180
181 robot_.ChangeGlobalCenterOfMass(com, false);
182 }
183 else if (keyboard_.GetPressingCount(KEY_INPUT_R) > 0)
184 {
185 float angle_speed = kComSpeed / 360.0f * 2.f * std::numbers::pi_v<float>;
186
187 if (keyboard_.GetPressingCount(KEY_INPUT_I) > 0)
188 {
189 angle_speed *= -1.f;
190 }
191
192 Quaternion rot = Quaternion::MakeByAngleAxis(angle_speed,
193 Vector3::GetFrontVec()) * robot_.posture;
194
195 robot_.ChangePosture(converter_ptr_, rot);
196 }
197 else if (keyboard_.GetPressingCount(KEY_INPUT_P) > 0)
198 {
199 float angle_speed = kComSpeed / 360.0f * 2.f * std::numbers::pi_v<float>;
200
201 if (keyboard_.GetPressingCount(KEY_INPUT_I) > 0)
202 {
203 angle_speed *= -1.f;
204 }
205
206 Quaternion rot = Quaternion::MakeByAngleAxis(angle_speed, Vector3::GetLeftVec()) *
207 robot_.posture;
208
209 robot_.ChangePosture(converter_ptr_, rot);
210 }
211 else if (keyboard_.GetPressingCount(KEY_INPUT_Y) > 0)
212 {
213 float angle_speed = kComSpeed / 360.0f * 2.f * std::numbers::pi_v<float>;
214
215 if (keyboard_.GetPressingCount(KEY_INPUT_I) > 0)
216 {
217 angle_speed *= -1.f;
218 }
219
220 Quaternion rot = Quaternion::MakeByAngleAxis(angle_speed, Vector3::GetUpVec()) * robot_.posture;
221
222 robot_.ChangePosture(converter_ptr_, rot);
223 }
224}
225
226void GraphicMainDisplayModel::MoveLeg()
227{
228 const float kSpeed = 1;
229 const float kAngleSpeed = 0.01f;
230
231 for (int i = 0; i < HexapodConst::kLegNum; i++)
232 {
233 if (keyboard_.GetPressingCount(KEY_INPUT_1 + i) > 0)
234 {
235 if (keyboard_.GetPressingCount(KEY_INPUT_Q) > 0)
236 {
237 robot_.leg_pos[i].z += kSpeed;
238 }
239 else if (keyboard_.GetPressingCount(KEY_INPUT_E) > 0)
240 {
241 robot_.leg_pos[i].z -= kSpeed;
242 }
243 else if (keyboard_.GetPressingCount(KEY_INPUT_A) > 0)
244 {
245 robot_.leg_pos[i].y += kSpeed;
246 }
247 else if (keyboard_.GetPressingCount(KEY_INPUT_D) > 0)
248 {
249 robot_.leg_pos[i].y -= kSpeed;
250 }
251 else if (keyboard_.GetPressingCount(KEY_INPUT_W) > 0)
252 {
253 robot_.leg_pos[i].x += kSpeed;
254 }
255 else if (keyboard_.GetPressingCount(KEY_INPUT_S) > 0)
256 {
257 robot_.leg_pos[i].x -= kSpeed;
258 }
259 else if (keyboard_.GetPressingCount(KEY_INPUT_M) == 1)
260 {
261 Vector3 global =
262 converter_ptr_->ConvertLegToGlobalCoordinate(
263 robot_.leg_reference_pos[i],
264 i,
266 robot_.posture,
267 true);
268
269 int map_x = divided_map_state_.GetDividedMapIndexX(global.x);
270 int map_y = divided_map_state_.GetDividedMapIndexY(global.y);
271
272 if (keyboard_.GetPressingCount(KEY_INPUT_UP) > 0)
273 {
274 map_x++;
275 }
276 else if (keyboard_.GetPressingCount(KEY_INPUT_DOWN) > 0)
277 {
278 map_x--;
279 }
280 if (keyboard_.GetPressingCount(KEY_INPUT_LEFT) > 0)
281 {
282 map_y++;
283 }
284 else if (keyboard_.GetPressingCount(KEY_INPUT_RIGHT) > 0)
285 {
286 map_y--;
287 }
288
289 Vector3 map_pos = divided_map_state_.GetPointPos(
290 map_x, map_y,
291 divided_map_tile_index_ % divided_map_state_.GetPointNum(map_x, map_y));
292
293 ++divided_map_tile_index_;
294
295 robot_.leg_pos[i] = converter_ptr_->ConvertGlobalToLegCoordinate(
296 map_pos, i, robot_.center_of_mass_global_coord, robot_.posture, true);
297 }
298
299 if (keyboard_.GetPressingCount(KEY_INPUT_C) > 0 ||
300 keyboard_.GetPressingCount(KEY_INPUT_F) > 0 ||
301 keyboard_.GetPressingCount(KEY_INPUT_T) > 0)
302 {
303 std::array<HexapodJointState, HexapodConst::kLegNum> res =
304 calculator_ptr_->CalculateAllJointState(robot_);
305
306 float coxa = res[i].joint_angle[0];
307 float femur = res[i].joint_angle[1];
308 float tibia = res[i].joint_angle[2];
309
310 if (keyboard_.GetPressingCount(KEY_INPUT_C) > 0)
311 {
312 const float speed =
313 keyboard_.GetPressingCount(KEY_INPUT_I) > 0 ?
314 kAngleSpeed : kAngleSpeed * -1.f;
315
316 coxa += speed;
317
320
323 }
324 else if (keyboard_.GetPressingCount(KEY_INPUT_F) > 0)
325 {
326 const float speed = keyboard_.GetPressingCount(KEY_INPUT_I) > 0 ?
327 kAngleSpeed : kAngleSpeed * -1.f;
328
329 femur += speed;
330
331 femur = (femur + tibia - std::numbers::pi_v<float>) > 0 ? femur - speed : femur;
334 }
335 else if (keyboard_.GetPressingCount(KEY_INPUT_T) > 0)
336 {
337 float speed = keyboard_.GetPressingCount(KEY_INPUT_I) > 0 ? kAngleSpeed : kAngleSpeed * -1.f;
338 tibia += speed;
339 tibia = (femur + tibia - std::numbers::pi_v<float>) > 0 ? tibia - speed : tibia;
342 }
343
344 Vector3 leg_pos;
345
346 leg_pos += Vector3{
349 0 };
350
351 leg_pos += Vector3{
352 PhantomXMkIIConst::kFemurLength * cos(coxa) * cos(femur),
353 PhantomXMkIIConst::kFemurLength * sin(coxa) * cos(femur),
355 };
356
357 leg_pos += Vector3{
358 PhantomXMkIIConst::kTibiaLength * cos(coxa) * cos(femur + tibia),
359 PhantomXMkIIConst::kTibiaLength * sin(coxa) * cos(femur + tibia),
360 PhantomXMkIIConst::kTibiaLength * sin(femur + tibia)
361 };
362
363 robot_.leg_pos[i] = leg_pos;
364 }
365 }
366 }
367}
368
369} // 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)を返す.
void Init(const MapState &map_state, const Vector3 global_robot_com)
マップのデータを初期化する. ロボットの重心座標を中心にマップのデータを格子状に分割し, その中に存在する脚設置可能点を集める.
constexpr int GetDividedMapIndexY(const float pos_y) const noexcept
指定した座標を DividedMap のインデックスに変換する. 範囲外の値を指定した場合でも,値を丸めずに返す. そのため,IsInMap で範囲内に存在するかどうかを確認する必要がある.
int GetPointNum(int x_index, int y_index) const
格子状に切り分けられたマップから,脚設置可能点の数を取得する. 範囲外の値を指定した場合は,0を返す.
void Register(const std::shared_ptr< IDxlib3dRenderer > &renderer)
3D描画を行うクラスを登録する.
void Draw() const
登録されているクラスの draw 関数を呼ぶ. また,Zソートを行う.
void Register(const std::shared_ptr< T > &gui_ptr, int priority)
UpdateとDrawを行うGUIを登録する. IDxlibClickableまたは,IDxlibDraggable, IDxlibWheelHandlerを継承している場合は,それらも同時に登録す...
void OpenTerminal()
Terminalを開く. 他のGUIをRegisterした後に呼び出すこと. 2回目以降の呼び出しは無視される. また,Terminalは最も優先度が高い.
void Draw() const
登録済みのGUIのDraw関数を実行する.
void Activate(const std::shared_ptr< const Mouse > &mouse_ptr)
GUIのUpdate関数を実行し,クリック,ドラッグなどの判定を行う. 優先度の高いものから順に各種判定を行う.
void Register(const std::shared_ptr< IDxlibNodeSetter > &setter)
ノードの設定を行うクラスを登録する.
void SetNode(const RobotStateNode &node)
登録済みの全てのクラスに対してノードの設定を行う.
void Draw() const override
描画を行う. ここでは描画系の処理のみを行い内部のデータを 更新しないため const を付けている.
bool Update() override
描画画面の更新を行う.純粋仮想関数のため, 継承先では必ず override する必要がある.
GraphicMainDisplayModel(const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr, const std::shared_ptr< const IHexapodJointCalculator > &calculator_ptr, const std::shared_ptr< const IHexapodPostureValidator > &checker_ptr, const std::shared_ptr< const ApplicationSettingRecord > &setting_ptr)
static constexpr int kLegNum
static std::tuple< std::shared_ptr< IDxlib3dRenderer >, std::shared_ptr< IDxlibNodeSetter > > Build(const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr, const std::shared_ptr< const IHexapodJointCalculator > &calculator_ptr, DisplayQuality display_quality)
HexapodRendererクラスのインスタンスを作成する. static関数なので,HexapodRendererBuilder::Build()と呼び出す.
void Update()
キー入力を更新する. これを毎フレーム実行しないと,キー入力を取得できない.
Definition keyboard.cpp:25
int GetPressingCount(const int key_code) const
keyCodeのキーが押されているフレーム数を取得する.
Definition keyboard.cpp:58
static std::unique_ptr< IMapCreator > Create(const SimulationSettingRecord &record)
マップを生成するクラスを生成する.
Dxlibでマウス入力を取得するクラス.
Definition mouse.h:21
ノードの初期化を行うクラス. シミュレーション時にノードの初期値を設定するために使用する.
static constexpr float kFemurLength
第2関節部の長さ[mm].
static constexpr float kTibiaAngleMax
static constexpr float kFemurAngleMin
第2関節の可動範囲の最大値[rad].詳しくは referenceフォルダ参照.
static constexpr float kFemurAngleMax
第2関節の可動範囲の最小値[rad].詳しくは referenceフォルダ参照.
static constexpr float kCoxaLength
第1関節部の長さ[mm].
static constexpr float kCoxaAngleMin
第1関節の可動範囲の最大値[rad].詳しくは referenceフォルダ参照.
static constexpr float kTibiaAngleMin
第2関節の可動範囲の最大値[rad].詳しくは referenceフォルダ参照.
static constexpr float kTibiaLength
第3関節部の長さ[mm].
static constexpr std::array< float, kPhantomXLegNum > kCoxaDefaultAngle
第1関節の初期角度[rad]
static constexpr float kCoxaAngleMax
第2関節の可動範囲の最小値[rad].詳しくは referenceフォルダ参照.
tomlファイルを読み込んで構造体に変換するテンプレートクラス.
T ImportOrUseDefault(const std::string &file_path) const
指定したファイルパスのファイルを読み込み,構造体に変換する. 読込に失敗した場合は,デフォルトの構造体を返す. また,読込に失敗した場合には, デフォルトの構造体をファイルに出力するかどうかをユーザに問...
Vector3 RotateVector3(const Vector3 &vec, const EulerXYZ &rot)
回転させたベクトルを返す.三角関数の処理が多く重たいので注意.
constexpr unsigned int kDxlibGuiAnchorRightTop
@ kNone
何も動作をしない.
constexpr unsigned int kDxlibGuiAnchorLeftTop
Definition com_type.h:24
XYZオイラー角を用いた回転を表す構造体.
Definition math_euler.h:33
static Quaternion MakeByAngleAxis(float rad_angle, const Vector3 &axis)
回転軸と回転角からクォータニオンを作成する. q = cos(θ/2) * w + sin(θ/2) * { v.x + v.y + v.z } となる. ノルムは必ず1になる.
std::array< Vector3, HexapodConst::kLegNum > leg_pos
[4 * 3 * 6 = 72 byte] 脚先の座標.(coxa(脚の付け根)を原点とする)
void ChangeGlobalCenterOfMass(const designlab::Vector3 &new_com, bool do_change_leg_base_pos)
重心位置を変更する関数.
void ChangePosture(const std::shared_ptr< const IHexapodCoordinateConverter > &converter_ptr, const designlab::Quaternion &new_posture)
クォータニオンを変更し,胴体を回転させる関数.
Vector3 center_of_mass_global_coord
[4 * 3 = 12byte] グローバル座標系における重心の位置.旧名 GCOM
Quaternion posture
[4 * 4 = 16byte] 姿勢を表すクォータニオン.
std::array< Vector3, HexapodConst::kLegNum > leg_reference_pos
3次元の位置ベクトルを表す構造体.
static constexpr Vector3 GetUpVec() noexcept
上に進む単位ベクトルを返す. 静的な関数なので,Vector3::GetUpVec() と呼び出せる.
static constexpr Vector3 GetFrontVec() noexcept
正面に進む単位ベクトルを返す. 静的な関数なので,Vector3::GetFrontVec() と呼び出せる.
static constexpr Vector3 GetLeftVec() noexcept
左に進む単位ベクトルを返す. 静的な関数なので,Vector3::GetLeftVec() と呼び出せる.