feat(nav2): load custom editor layouts in gazebo
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
@@ -76,6 +77,59 @@ def create_flat_house_world(gazebo_dir):
|
|||||||
return flat_world_path
|
return flat_world_path
|
||||||
|
|
||||||
|
|
||||||
|
def create_custom_layout_world():
|
||||||
|
"""Build a Gazebo world from the editor's persisted 2D layout."""
|
||||||
|
layout_path = os.environ.get('WORLD_LAYOUT_PATH', '/modules/world-layout.json')
|
||||||
|
try:
|
||||||
|
with open(layout_path, 'r', encoding='utf-8') as source:
|
||||||
|
objects = json.load(source).get('objects', [])
|
||||||
|
except (OSError, ValueError, AttributeError):
|
||||||
|
objects = []
|
||||||
|
|
||||||
|
models = []
|
||||||
|
for index, item in enumerate(objects):
|
||||||
|
if not isinstance(item, dict):
|
||||||
|
continue
|
||||||
|
position = item.get('position') or [0, 0, 0]
|
||||||
|
rotation = item.get('rotation') or [0, 0, 0]
|
||||||
|
size = item.get('size') or [1, 1, 1]
|
||||||
|
try:
|
||||||
|
x, y, z = (float(position[0]), float(position[1]), float(position[2]))
|
||||||
|
yaw = float(rotation[2])
|
||||||
|
sx, sy, sz = (max(0.05, float(size[0])), max(0.05, float(size[1])), max(0.05, float(size[2])))
|
||||||
|
except (IndexError, TypeError, ValueError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
name = f"custom_{item.get('type', 'box')}_{index}"
|
||||||
|
if item.get('type') == 'pillar':
|
||||||
|
geometry = f'<cylinder><radius>{sx / 2.0}</radius><length>{sz}</length></cylinder>'
|
||||||
|
else:
|
||||||
|
geometry = f'<box><size>{sx} {sy} {sz}</size></box>'
|
||||||
|
models.append(
|
||||||
|
f'''<model name="{name}">
|
||||||
|
<static>true</static>
|
||||||
|
<pose>{x} {y} {z} 0 0 {yaw}</pose>
|
||||||
|
<link name="link">
|
||||||
|
<collision name="collision"><geometry>{geometry}</geometry></collision>
|
||||||
|
<visual name="visual"><geometry>{geometry}</geometry><material><ambient>0.34 0.58 0.82 1</ambient><diffuse>0.34 0.58 0.82 1</diffuse></material></visual>
|
||||||
|
</link>
|
||||||
|
</model>'''
|
||||||
|
)
|
||||||
|
|
||||||
|
world_path = os.path.join(tempfile.gettempdir(), 'nav2_custom_layout.world')
|
||||||
|
with open(world_path, 'w', encoding='utf-8') as destination:
|
||||||
|
destination.write('''<?xml version="1.0"?>
|
||||||
|
<sdf version="1.6">
|
||||||
|
<world name="nav2_custom_layout">
|
||||||
|
<include><uri>model://sun</uri></include>
|
||||||
|
<include><uri>model://ground_plane</uri></include>
|
||||||
|
<physics type="ode"><real_time_update_rate>1000</real_time_update_rate></physics>
|
||||||
|
''')
|
||||||
|
destination.write('\n'.join(models))
|
||||||
|
destination.write('\n </world>\n</sdf>\n')
|
||||||
|
return world_path
|
||||||
|
|
||||||
|
|
||||||
def launch_gazebo(context):
|
def launch_gazebo(context):
|
||||||
gazebo_dir = get_package_share_directory('turtlebot3_gazebo')
|
gazebo_dir = get_package_share_directory('turtlebot3_gazebo')
|
||||||
simulator_dir = get_package_share_directory('nav2_turtlebot_simulator')
|
simulator_dir = get_package_share_directory('nav2_turtlebot_simulator')
|
||||||
@@ -86,7 +140,9 @@ def launch_gazebo(context):
|
|||||||
if render_mode not in {'flat', 'full'}:
|
if render_mode not in {'flat', 'full'}:
|
||||||
raise RuntimeError('render_mode must be either flat or full')
|
raise RuntimeError('render_mode must be either flat or full')
|
||||||
|
|
||||||
if world == 'turtlebot3_house.world' and render_mode == 'flat':
|
if world == 'empty_world.world' and os.path.isfile(os.environ.get('WORLD_LAYOUT_PATH', '/modules/world-layout.json')):
|
||||||
|
world_path = create_custom_layout_world()
|
||||||
|
elif world == 'turtlebot3_house.world' and render_mode == 'flat':
|
||||||
world_path = create_flat_house_world(gazebo_dir)
|
world_path = create_flat_house_world(gazebo_dir)
|
||||||
else:
|
else:
|
||||||
world_path = os.path.join(
|
world_path = os.path.join(
|
||||||
|
|||||||
Reference in New Issue
Block a user