GaitGeneration by Graph Search
読み取り中…
検索中…
一致する文字列を見つけられません
map_creator_for_simulation.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 <algorithm>
11#include <random>
12
13#include "cassert_define.h"
14#include "math_util.h"
15
16namespace designlab {
17
19 const SimulationMapParameter& param)
20 : parameter_(param) {
21 // map_min_x が map_max_x より小さいことを確認する.
22 assert(parameter_.map_min_x < parameter_.map_max_x);
23
24 // map_min_y が map_max_y より小さいことを確認する.
25 assert(parameter_.map_min_y < parameter_.map_max_y);
26}
27
29 std::vector<Vector3> map_data;
30
31 switch (parameter_.mode) {
33 CreateFlatMap(&map_data);
34 break;
35 }
37 CreateVerticalStripeMap(&map_data);
38 break;
39 }
41 CreateHorizontalStripeMap(&map_data);
42 break;
43 }
45 CreateDiagonalStripeMap(&map_data);
46 break;
47 }
49 CreateMeshMap(&map_data);
50 break;
51 }
53 CreateLatticePointMap(&map_data);
54 break;
55 }
57 CreateCircleMap(&map_data);
58 break;
59 }
61 CreateDonutMap(&map_data);
62 break;
63 }
64 default: {
65 // 異常な値が入力されたら,平面のマップを生成する.
66 CreateFlatMap(&map_data);
67 break;
68 }
69 }
70
71 // オプション指定に基づき,Z座標を変更する.
72
73 if (parameter_.option &
74 static_cast<unsigned int>(SimulationMapOption::kPerforated)) {
75 // 穴あき地形にする.
76 ChangeMapToPerforated(&map_data);
77 }
78
79 if (parameter_.option &
80 static_cast<unsigned int>(SimulationMapOption::kStep)) {
81 // 階段状にする.
82 ChangeMapToStep(&map_data);
83 }
84
85 if (parameter_.option &
86 static_cast<unsigned int>(SimulationMapOption::kSlope)) {
87 // 坂道にする.
88 ChangeMapToSlope(&map_data);
89 }
90
91 if (parameter_.option &
92 static_cast<unsigned int>(SimulationMapOption::kTilt)) {
93 // 坂道にする.
94 ChangeMapToTilt(&map_data);
95 }
96
97 if (parameter_.option &
98 static_cast<unsigned int>(SimulationMapOption::kRough)) {
99 // デコボコにする.
100 ChangeMapToRough(&map_data);
101 }
102
103 if (parameter_.option &
104 static_cast<unsigned int>(SimulationMapOption::kRadiation)) {
105 // 放射状に穴をあける.
106 ChangeMapToRadial(&map_data);
107 }
108
109 return MapState(map_data);
110}
111
113 [[maybe_unused]] MapState* current_map) const {
114 // マップを更新する必要がないので,何もしない.
115}
116
117void MapCreatorForSimulation::CreateFlatMap(std::vector<Vector3>* map) const {
118 assert(map != nullptr); // map が nullptr でないことを確認する.
119 assert(map->empty()); // map が空であることを確認する.
120
121 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
122 const float x_max = (parameter_.map_max_x - parameter_.map_min_x) /
124 const float y_max = (parameter_.map_max_y - parameter_.map_min_y) /
126
127 for (int x = 0; x < x_max; x++) {
128 for (int y = 0; y < y_max; y++) {
129 // ロボットの正面方向.
130 const float x_pos =
131 parameter_.map_min_x + x * MapState::kMapPointDistance;
132
133 // ロボットの側面方向.
134 const float y_pos =
135 parameter_.map_min_y + y * MapState::kMapPointDistance;
136
137 map->push_back(
138 {x_pos, y_pos, parameter_.base_z}); // 脚設置可能点を追加する.
139 }
140 }
141}
142
143void MapCreatorForSimulation::CreateVerticalStripeMap(
144 std::vector<Vector3>* map) const {
145 assert(map != nullptr); // map が nullptr でないことを確認する.
146 assert(map->empty()); // map が空であることを確認する.
147
148 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
149 const float x_max = (parameter_.map_max_x - parameter_.map_min_x) /
151 const float y_max = (parameter_.map_max_y - parameter_.map_min_y) /
153
154 for (int x = 0; x < x_max; x++) {
155 for (int y = 0; y < y_max; y++) {
156 // 縦じまをつくるために,一定間隔ごとに追加する.最初の待機場所の座標ならば無条件に追加する.
157 const float x_rough =
158 (parameter_.map_start_rough_x - parameter_.map_min_x) /
160
161 if (y % (parameter_.stripe_interval * 2) < parameter_.stripe_interval ||
162 x < x_rough) {
163 // ロボットの正面方向.
164 const float x_pos =
165 parameter_.map_min_x + x * MapState::kMapPointDistance;
166
167 // ロボットの側面方向.
168 const float y_pos =
169 parameter_.map_min_y + y * MapState::kMapPointDistance;
170
171 map->push_back(
172 {x_pos, y_pos, parameter_.base_z}); // 脚設置可能点を追加する.
173 }
174 }
175 }
176}
177
178void MapCreatorForSimulation::CreateHorizontalStripeMap(
179 std::vector<Vector3>* map) const {
180 assert(map != nullptr); // map が nullptr でないことを確認する.
181 assert(map->empty()); // map が空であることを確認する.
182
183 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
184 const float x_max = (parameter_.map_max_x - parameter_.map_min_x) /
186 const float y_max = (parameter_.map_max_y - parameter_.map_min_y) /
188
189 for (int x = 0; x < x_max; x++) {
190 for (int y = 0; y < y_max; y++) {
191 // 縦じまをつくるために,一定間隔ごとに追加する.最初の待機場所の座標ならば無条件に追加する.
192 const float x_rough =
193 (parameter_.map_start_rough_x - parameter_.map_min_x) /
195
196 if (x % (parameter_.stripe_interval * 2) < parameter_.stripe_interval ||
197 x < x_rough) {
198 // ロボットの正面方向.
199 const float x_pos =
200 parameter_.map_min_x + x * MapState::kMapPointDistance;
201
202 // ロボットの側面方向.
203 const float y_pos =
204 parameter_.map_min_y + y * MapState::kMapPointDistance;
205
206 map->push_back(
207 {x_pos, y_pos, parameter_.base_z}); // 脚設置可能点を追加する.
208 }
209 }
210 }
211}
212
213void MapCreatorForSimulation::CreateDiagonalStripeMap(
214 std::vector<Vector3>* map) const {
215 assert(map != nullptr); // map が nullptr でないことを確認する.
216 assert(map->empty()); // map が空であることを確認する.
217
218 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
219 const float x_max = (parameter_.map_max_x - parameter_.map_min_x) /
221 const float y_max = (parameter_.map_max_y - parameter_.map_min_y) /
223
224 for (int x = 0; x < x_max; x++) {
225 for (int y = 0; y < y_max; y++) {
226 // 斜めじまをつくるために,一定間隔ごとに追加する.最初の待機場所の座標ならば無条件に追加する.
227 const bool x_in_stripe =
228 x % (parameter_.stripe_interval * 2) < parameter_.stripe_interval;
229
230 const bool y_in_stripe =
231 y % (parameter_.stripe_interval * 2) < parameter_.stripe_interval;
232
233 const bool do_create_map = x_in_stripe == y_in_stripe;
234
235 const float x_rough =
236 (parameter_.map_start_rough_x - parameter_.map_min_x) /
238
239 if (do_create_map || x < x_rough) {
240 // ロボットの正面方向.
241 const float x_pos =
242 parameter_.map_min_x + x * MapState::kMapPointDistance;
243
244 // ロボットの側面方向.
245 const float y_pos =
246 parameter_.map_min_y + y * MapState::kMapPointDistance;
247
248 map->push_back(
249 {x_pos, y_pos, parameter_.base_z}); // 脚設置可能点を追加する.
250 }
251 }
252 }
253}
254
255void MapCreatorForSimulation::CreateMeshMap(std::vector<Vector3>* map) const {
256 assert(map != nullptr); // map が nullptr でないことを確認する.
257 assert(map->empty()); // map が空であることを確認する.
258
259 // マップの xとyの存在範囲全体に脚設置可能点を敷き詰める.
260 const float x_max = (parameter_.map_max_x - parameter_.map_min_x) /
262 const float y_max = (parameter_.map_max_y - parameter_.map_min_y) /
264
265 for (int x = 0; x < x_max; x++) {
266 for (int y = 0; y < y_max; y++) {
267 // 網目模様をつくるために,一定間隔ごとに追加する.
268 // 最初の待機場所の座標ならば無条件に追加する.
269 bool do_create_map;
270
271 if ((x % (parameter_.stripe_interval * 2) < parameter_.stripe_interval)) {
272 if ((y % (parameter_.stripe_interval * 2) <
273 parameter_.stripe_interval)) {
274 do_create_map = true;
275 } else {
276 do_create_map = false;
277 }
278 } else {
279 do_create_map = true;
280 }
281
282 const float x_rough =
283 (parameter_.map_start_rough_x - parameter_.map_min_x) /
285
286 if (do_create_map || x < x_rough) {
287 // ロボットの正面方向.
288 const float x_pos =
289 parameter_.map_min_x + x * MapState::kMapPointDistance;
290
291 // ロボットの側面方向.
292 const float y_pos =
293 parameter_.map_min_y + y * MapState::kMapPointDistance;
294
295 map->push_back(
296 {x_pos, y_pos, parameter_.base_z}); // 脚設置可能点を追加する.
297 }
298 }
299 }
300}
301
302void MapCreatorForSimulation::CreateLatticePointMap(
303 std::vector<Vector3>* map) const {
304 assert(map != nullptr); // map が nullptr でないことを確認する.
305 assert(map->empty()); // map が空であることを確認する.
306
307 // マップの x と y の存在範囲全体に脚設置可能点を敷き詰める.
308
309 const float x_max = (parameter_.map_max_x - parameter_.map_min_x) /
311 const float y_max = (parameter_.map_max_y - parameter_.map_min_y) /
313
314 for (int x = 0; x < x_max; x++) {
315 for (int y = 0; y < y_max; y++) {
316 // 網目模様をつくるために,一定間隔ごとに追加する.
317 // 最初の待機場所の座標ならば無条件に追加する.
318 bool do_create_map = false;
319
320 if ((x % (parameter_.stripe_interval * 2) < parameter_.stripe_interval)) {
321 if ((y % (parameter_.stripe_interval * 2) >=
322 parameter_.stripe_interval)) {
323 do_create_map = false;
324 } else {
325 do_create_map = true;
326 }
327 } else {
328 do_create_map = false;
329 }
330
331 const float x_rough =
332 (parameter_.map_start_rough_x - parameter_.map_min_x) /
334
335 if (do_create_map || x < x_rough) {
336 // ロボットの正面方向.
337 const float x_pos =
338 parameter_.map_min_x + x * MapState::kMapPointDistance;
339
340 // ロボットの側面方向.
341 const float y_pos =
342 parameter_.map_min_y + y * MapState::kMapPointDistance;
343
344 // 脚設置可能点を追加する.
345 map->push_back({x_pos, y_pos, parameter_.base_z});
346 }
347 }
348 }
349}
350
351void MapCreatorForSimulation::CreateCircleMap(std::vector<Vector3>* map) const {
352 assert(map != nullptr); // map が nullptr でないことを確認する.
353
354 // 円が存在する範囲に脚設置可能点を敷き詰める.
355 // その後,円の外側の脚設置可能点を削除する.
356
357 const float x_min = parameter_.circle_center.x - parameter_.circle_radius;
358 const float x_max = parameter_.circle_center.x + parameter_.circle_radius;
359 const float y_min = parameter_.circle_center.y - parameter_.circle_radius;
360 const float y_max = parameter_.circle_center.y + parameter_.circle_radius;
361
362 for (int x = 0; x < (x_max - x_min) / MapState::kMapPointDistance; ++x) {
363 for (int y = 0; y < (y_max - y_min) / MapState::kMapPointDistance; ++y) {
364 // ロボットの正面方向.
365 const float x_pos = x_min + x * MapState::kMapPointDistance;
366
367 // ロボットの側面方向.
368 const float y_pos = y_min + y * MapState::kMapPointDistance;
369
370 // 脚設置可能点を追加する.
371 const float distance =
372 Vector2(x_pos, y_pos)
373 .GetDistanceFrom(parameter_.circle_center.ProjectedXY());
374
375 if (distance <= parameter_.circle_radius) {
376 map->push_back({x_pos, y_pos, parameter_.base_z});
377 }
378 }
379 }
380}
381
382void MapCreatorForSimulation::CreateDonutMap(std::vector<Vector3>* map) const {
383 assert(map != nullptr); // map が nullptr でないことを確認する.
384
385 // ドーナツが存在する範囲に脚設置可能点を敷き詰める.
386 // その後,ドーナツの外側の脚設置可能点を削除する.
387
388 const float x_min = parameter_.circle_center.x - parameter_.circle_radius;
389 const float x_max = parameter_.circle_center.x + parameter_.circle_radius;
390 const float y_min = parameter_.circle_center.y - parameter_.circle_radius;
391 const float y_max = parameter_.circle_center.y + parameter_.circle_radius;
392
393 for (int x = 0; x < (x_max - x_min) / MapState::kMapPointDistance; ++x) {
394 for (int y = 0; y < (y_max - y_min) / MapState::kMapPointDistance; ++y) {
395 // ロボットの正面方向.
396 const float x_pos = x_min + x * MapState::kMapPointDistance;
397
398 // ロボットの側面方向.
399 const float y_pos = y_min + y * MapState::kMapPointDistance;
400
401 // 脚設置可能点を追加する.
402 const float distance =
403 Vector2(x_pos, y_pos)
404 .GetDistanceFrom(parameter_.circle_center.ProjectedXY());
405
406 if (parameter_.donut_radius <= distance &&
407 distance <= parameter_.circle_radius) {
408 map->push_back({x_pos, y_pos, parameter_.base_z});
409 }
410 }
411 }
412}
413
414void MapCreatorForSimulation::ChangeMapToPerforated(
415 std::vector<Vector3>* map) const {
416 assert(map != nullptr); // map が nullptr でないことを確認する.
417
418 // 厳密にホール率に合わせるために,まずはマップを stripe_interval
419 // に合わせて区切って, 全部で何マスあるか調べる.
420 const int cell_num_x =
421 static_cast<int>((parameter_.map_max_x - parameter_.map_start_rough_x) /
423 parameter_.stripe_interval;
424
425 const int cell_num_y =
426 static_cast<int>((parameter_.map_max_y - parameter_.map_min_y) /
428 parameter_.stripe_interval;
429
430 const int cell_sum = cell_num_x * cell_num_y;
431
432 // マスの数だけ要素を持つ vector を用意する.値は全て false で初期化する.
433 std::vector<bool> do_perforated(cell_sum, false);
434
435 // ホール率に合わせて,値を true に変更する.
436 const int hole_num = cell_sum * parameter_.hole_rate / 100;
437
438 for (int i = 0; i < hole_num; i++) {
439 do_perforated.at(i) = true;
440 }
441
442 // ランダムなホールにするために要素の順番をシャッフルする.
443 std::shuffle(std::begin(do_perforated), std::end(do_perforated),
444 std::default_random_engine());
445
446 // マップに穴をあける.
447 for (auto itr = (*map).begin(); itr != (*map).end();) {
448 // 待機場所の外に対してのみ作業をする.
449 if ((*itr).x < parameter_.map_start_rough_x) {
450 itr++;
451 continue;
452 }
453
454 // マスで区切るとどこに位置するかを調べる.
455 const int cell_pos_x =
456 static_cast<int>(((*itr).x - parameter_.map_start_rough_x) /
458 parameter_.stripe_interval;
459
460 const int cell_pos_y = static_cast<int>(((*itr).y - parameter_.map_min_y) /
462 parameter_.stripe_interval;
463
464 const int cell_index = cell_pos_x * cell_num_y + cell_pos_y;
465
466 // cell_pos の値がおかしくないかチェックする.
467 if (0 <= cell_index && cell_index < do_perforated.size()) {
468 // 穴あけをする場所ならば.
469 if (do_perforated[cell_index]) {
470 // 脚設置可能点を消してイテレータを更新する.
471 itr = (*map).erase(itr);
472 } else {
473 // 消さないならば次へ移動する.
474 itr++;
475 }
476 } else {
477 // 消さずに次へ移動する.
478 itr++;
479 }
480 }
481}
482
483void MapCreatorForSimulation::ChangeMapToStep(std::vector<Vector3>* map) const {
484 assert(map != nullptr); // map が nullptr でないことを確認する.
485
486 for (auto& i : *map) {
487 // 待機場所の外に対してのみ作業をする.
488 if (i.x > parameter_.map_start_rough_x) {
489 // 階段の何段目かを計算する.待機場所のすぐ上が1段目なので1を足している.
490 const int step_count =
491 1 + static_cast<int>((i.x - parameter_.map_start_rough_x) /
492 parameter_.step_length);
493
494 // 階段状にZ座標を変更する.
495 i.z += parameter_.step_height * step_count;
496 }
497 }
498}
499
500void MapCreatorForSimulation::ChangeMapToSlope(
501 std::vector<Vector3>* map) const {
502 assert(map != nullptr); // map が nullptr でないことを確認する.
503
504 for (auto& i : *map) {
505 // 待機場所の外に対してのみ作業をする.
506 if (i.x > parameter_.map_start_rough_x) {
507 // 階段状にZ座標を変更する.
508 i.z += (i.x - parameter_.map_start_rough_x) *
510 }
511 }
512}
513
514void MapCreatorForSimulation::ChangeMapToTilt(std::vector<Vector3>* map) const {
515 assert(map != nullptr); // map が nullptr でないことを確認する.
516
517 for (auto& i : *map) {
518 // 待機場所の外に対してのみ作業をする
519 if (i.x > parameter_.map_start_rough_x) {
520 // 階段状にZ座標を変更する.
521 i.z += i.y * tan(math_util::ConvertDegToRad(parameter_.tilt_angle));
522 }
523 }
524}
525
526void MapCreatorForSimulation::ChangeMapToRough(
527 std::vector<Vector3>* map) const {
528 assert(map != nullptr); // map が nullptr でないことを確認する.
529
530 // まずはマップを STRIPE_INTERVAL
531 // にあわせて区切って,全部で何マスあるか調べる.
532 const int cell_num_x =
533 static_cast<int>((parameter_.map_start_rough_x - parameter_.map_min_x) /
535 parameter_.stripe_interval;
536
537 const int cell_num_y =
538 static_cast<int>((parameter_.map_max_y - parameter_.map_min_y) /
540 parameter_.stripe_interval;
541
542 const int cell_sum = cell_num_x * cell_num_y;
543
544 // マスの数だけ要素を持つ vector を用意する.
545 std::vector<float> change_z_length;
546
547 for (int i = 0; i < cell_sum; i++) {
548 // ランダムなZ座標を入れる.
549 change_z_length.push_back(math_util::GenerateRandomNumber(
550 parameter_.rough_min_height, parameter_.rough_max_height));
551 }
552
553 for (auto& i : *map) {
554 if (i.x <= parameter_.map_start_rough_x) {
555 continue;
556 }
557
558 // マスで区切るとどこに位置するかを調べる.
559 const int cell_pos_x =
560 static_cast<int>((i.x - parameter_.map_start_rough_x) /
562 parameter_.stripe_interval;
563
564 const int cell_pos_y = static_cast<int>((i.y - parameter_.map_min_y) /
566 parameter_.stripe_interval;
567
568 const int cell_index = cell_pos_x * cell_num_y + cell_pos_y;
569
570 // cell_index の値がおかしくないかチェックする.
571 if (0 <= cell_index && cell_index < change_z_length.size()) {
572 i.z += change_z_length[cell_index];
573 }
574 }
575}
576
577void MapCreatorForSimulation::ChangeMapToRadial(
578 std::vector<Vector3>* map) const {
579 assert(map != nullptr); // map が nullptr でないことを確認する.
580
581 const float divided_angle =
582 std::numbers::pi_v<float> / parameter_.radial_division;
583
584 for (auto itr = (*map).begin(); itr != (*map).end();) {
585 // 放射状の穴あけの中心からの角度を計算する.
586 const float angle =
587 atan2((*itr).y - parameter_.radial_center.y,
588 (*itr).x - parameter_.radial_center.x) +
589 std::numbers::pi_v<float> +
591
592 if (static_cast<int>(angle / divided_angle) % 2 == 1) {
593 const int i = static_cast<int>(
594 angle / divided_angle); // 何番目の角度かを計算する.
595 const float angle_dif =
596 angle - i * divided_angle; // 何番目の角度からの差を計算する.
597
598 // 角度の差がホール率より小さい場合は消す.
599 if (angle_dif < divided_angle * parameter_.radial_hole_rate / 100) {
600 // 脚設置可能点を消してイテレータを更新する.
601 itr = (*map).erase(itr);
602 } else {
603 // 消さないならば次へ移動する.
604 itr++;
605 }
606 } else {
607 // 消さないならば次へ移動する.
608 itr++;
609 }
610 }
611}
612
613} // namespace designlab
MapState InitMap() const override
マップの初期化を行う.
MapCreatorForSimulation(const SimulationMapParameter &param)
コンストラクタで作成するマップ情報を与える.
void UpdateMap(MapState *current_map) const override
マップの更新を行う.
マップを表すクラス.
Definition map_state.h:29
static constexpr float kMapPointDistance
z軸から(上から)みたとき,格子点状に分けられた脚接地可能点の間隔 [mm].
Definition map_state.h:79
T GenerateRandomNumber(T min, T max)
指定した範囲内の乱数を生成する.
Definition math_util.h:97
constexpr T ConvertDegToRad(const T deg) noexcept
角度を [deg] から [rad] に変換する関数.
Definition math_util.h:119
@ kTilt
縦軸を中心軸として回転させた地形に変化させる.
@ kRough
凸凹の地形に変化させる.
@ kRadiation
放射状の地形に変化させる.
@ kPerforated
穴の空いたマップに変化させる.
@ kStep
階段状の地形に変化させる.
@ kSlope
スロープ状の地形に変化させる.
@ kHorizontalStripe
横じまの面を生成する.
@ kVerticalStripe
縦じまの面を生成する.
@ kLatticePoint
格子点の面を生成する.網目状の逆.
@ kFlat
普通の平らな面を生成する.
@ kMesh
格子状の面を生成する.網目状の地形ともいっていい.
@ kDiagonalStripe
斜めじまの面を生成する.
@ kCircle
円形の面を生成する.
@ kDonut
ドーナツ状の面を生成する.
マップ生成時のモードとオプションを指定する構造体.
int radial_hole_rate
放射状の地形のホール率[%].
int radial_division
放射状の地形の分割数.
float map_max_y
マップのY座標の最大値.
int stripe_interval
各種模様や穴を作成する際,これで指定したマス分の1辺を持つ正方形状にあなをあける.
float map_min_x
マップのX座標の最小値.
float map_start_rough_x
不整地が始まるX座標.
float circle_radius
円 / ドーナツの半径.
float radial_angle_offset
放射状の地形の角度オフセット[deg].
float map_min_y
マップのY座標の最小値.
float donut_radius
ドーナツの内側の半径.
unsigned int option
マップ生成のオプションを指定するbit.
Vector2 radial_center
放射状の地形の中心座標.
float step_height
段差高さ[mm].負の値にすると下りの階段になる.
float rough_min_height
デコボコな地形の最小高さ[mm]
float map_max_x
マップのX座標の最大値.
float slope_angle
斜面の傾斜角[deg]
float rough_max_height
デコボコな地形の最大高さ[mm]
float tilt_angle
地形を傾ける角度[deg]
float base_z
マップの基準となるZ座標.
Vector3 circle_center
円 / ドーナツの中心座標.
int hole_rate
不整地上の足場を除外する割合。ホール率[%]
float x
ロボットの正面方向に正.
constexpr Vector2 ProjectedXY() const noexcept
XY平面に射影したベクトルを返す.
float y
ロボットの左向きに正.