@@ -54,6 +54,11 @@ def generate_launch_description():
5454 demo_pkg_dir , "config" , "panda_manifest.yaml"
5555 )
5656
57+ # Factory world file path
58+ factory_world = os .path .join (
59+ demo_pkg_dir , "worlds" , "factory.sdf"
60+ )
61+
5762 headless = LaunchConfiguration ("headless" , default = "False" )
5863
5964 # ── Robot description (URDF with ros2_control + Gazebo hardware) ─
@@ -99,6 +104,7 @@ def generate_launch_description():
99104 world_joint = (
100105 ' <link name="world"/>\n '
101106 ' <joint name="world_to_panda" type="fixed">\n '
107+ ' <origin xyz="0 0 0.75" rpy="0 0 0"/>\n '
102108 ' <parent link="world"/>\n '
103109 ' <child link="panda_link0"/>\n '
104110 ' </joint>\n '
@@ -107,6 +113,122 @@ def generate_launch_description():
107113 "</robot>" , world_joint + "</robot>"
108114 )
109115
116+ # ── Inject Gazebo visual materials for robot links ───────────────
117+ # Gives the Panda arm a realistic industrial appearance in Gazebo
118+ # with white body links, dark joints, and orange accents (Franka
119+ # Emika brand colors).
120+ gazebo_materials = (
121+ # Base and main body links — white with subtle metallic sheen
122+ ' <gazebo reference="panda_link0">\n '
123+ " <visual>\n "
124+ " <material>\n "
125+ " <ambient>0.85 0.85 0.85 1</ambient>\n "
126+ " <diffuse>0.92 0.92 0.92 1</diffuse>\n "
127+ " <specular>0.6 0.6 0.6 1</specular>\n "
128+ " </material>\n "
129+ " </visual>\n "
130+ " </gazebo>\n "
131+ ' <gazebo reference="panda_link1">\n '
132+ " <visual>\n "
133+ " <material>\n "
134+ " <ambient>0.85 0.85 0.85 1</ambient>\n "
135+ " <diffuse>0.92 0.92 0.92 1</diffuse>\n "
136+ " <specular>0.6 0.6 0.6 1</specular>\n "
137+ " </material>\n "
138+ " </visual>\n "
139+ " </gazebo>\n "
140+ # Joints — dark anthracite grey
141+ ' <gazebo reference="panda_link2">\n '
142+ " <visual>\n "
143+ " <material>\n "
144+ " <ambient>0.25 0.25 0.28 1</ambient>\n "
145+ " <diffuse>0.35 0.35 0.38 1</diffuse>\n "
146+ " <specular>0.4 0.4 0.4 1</specular>\n "
147+ " </material>\n "
148+ " </visual>\n "
149+ " </gazebo>\n "
150+ ' <gazebo reference="panda_link3">\n '
151+ " <visual>\n "
152+ " <material>\n "
153+ " <ambient>0.85 0.85 0.85 1</ambient>\n "
154+ " <diffuse>0.92 0.92 0.92 1</diffuse>\n "
155+ " <specular>0.6 0.6 0.6 1</specular>\n "
156+ " </material>\n "
157+ " </visual>\n "
158+ " </gazebo>\n "
159+ ' <gazebo reference="panda_link4">\n '
160+ " <visual>\n "
161+ " <material>\n "
162+ " <ambient>0.25 0.25 0.28 1</ambient>\n "
163+ " <diffuse>0.35 0.35 0.38 1</diffuse>\n "
164+ " <specular>0.4 0.4 0.4 1</specular>\n "
165+ " </material>\n "
166+ " </visual>\n "
167+ " </gazebo>\n "
168+ # Upper arm — white
169+ ' <gazebo reference="panda_link5">\n '
170+ " <visual>\n "
171+ " <material>\n "
172+ " <ambient>0.85 0.85 0.85 1</ambient>\n "
173+ " <diffuse>0.92 0.92 0.92 1</diffuse>\n "
174+ " <specular>0.6 0.6 0.6 1</specular>\n "
175+ " </material>\n "
176+ " </visual>\n "
177+ " </gazebo>\n "
178+ # Wrist joint — dark
179+ ' <gazebo reference="panda_link6">\n '
180+ " <visual>\n "
181+ " <material>\n "
182+ " <ambient>0.25 0.25 0.28 1</ambient>\n "
183+ " <diffuse>0.35 0.35 0.38 1</diffuse>\n "
184+ " <specular>0.4 0.4 0.4 1</specular>\n "
185+ " </material>\n "
186+ " </visual>\n "
187+ " </gazebo>\n "
188+ # End-effector flange — white
189+ ' <gazebo reference="panda_link7">\n '
190+ " <visual>\n "
191+ " <material>\n "
192+ " <ambient>0.85 0.85 0.85 1</ambient>\n "
193+ " <diffuse>0.92 0.92 0.92 1</diffuse>\n "
194+ " <specular>0.6 0.6 0.6 1</specular>\n "
195+ " </material>\n "
196+ " </visual>\n "
197+ " </gazebo>\n "
198+ # Hand / gripper — dark grey with slight blue tint
199+ ' <gazebo reference="panda_hand">\n '
200+ " <visual>\n "
201+ " <material>\n "
202+ " <ambient>0.2 0.22 0.28 1</ambient>\n "
203+ " <diffuse>0.3 0.32 0.38 1</diffuse>\n "
204+ " <specular>0.45 0.45 0.5 1</specular>\n "
205+ " </material>\n "
206+ " </visual>\n "
207+ " </gazebo>\n "
208+ # Finger tips — dark rubber-like
209+ ' <gazebo reference="panda_leftfinger">\n '
210+ " <visual>\n "
211+ " <material>\n "
212+ " <ambient>0.15 0.15 0.15 1</ambient>\n "
213+ " <diffuse>0.22 0.22 0.22 1</diffuse>\n "
214+ " <specular>0.1 0.1 0.1 1</specular>\n "
215+ " </material>\n "
216+ " </visual>\n "
217+ " </gazebo>\n "
218+ ' <gazebo reference="panda_rightfinger">\n '
219+ " <visual>\n "
220+ " <material>\n "
221+ " <ambient>0.15 0.15 0.15 1</ambient>\n "
222+ " <diffuse>0.22 0.22 0.22 1</diffuse>\n "
223+ " <specular>0.1 0.1 0.1 1</specular>\n "
224+ " </material>\n "
225+ " </visual>\n "
226+ " </gazebo>\n "
227+ )
228+ robot_description_raw = robot_description_raw .replace (
229+ "</robot>" , gazebo_materials + "</robot>"
230+ )
231+
110232 robot_description = {"robot_description" : robot_description_raw }
111233
112234 # ── SRDF ─────────────────────────────────────────────────────────
@@ -185,6 +307,11 @@ def generate_launch_description():
185307 value = "offscreen" ,
186308 condition = IfCondition (headless ),
187309 ),
310+ # ── Add world directory to Gazebo resource path ────────
311+ SetEnvironmentVariable (
312+ name = "GZ_SIM_RESOURCE_PATH" ,
313+ value = os .path .join (demo_pkg_dir , "worlds" ),
314+ ),
188315 # ── Gazebo Harmonic (GUI) ────────────────────────────────
189316 IncludeLaunchDescription (
190317 PythonLaunchDescriptionSource (
@@ -198,7 +325,9 @@ def generate_launch_description():
198325 )
199326 ]
200327 ),
201- launch_arguments = {"gz_args" : "-r empty.sdf" }.items (),
328+ launch_arguments = {
329+ "gz_args" : f"-r { factory_world } "
330+ }.items (),
202331 condition = UnlessCondition (headless ),
203332 ),
204333 # ── Gazebo Harmonic (headless — server only) ─────────────
@@ -214,7 +343,9 @@ def generate_launch_description():
214343 )
215344 ]
216345 ),
217- launch_arguments = {"gz_args" : "-r -s empty.sdf" }.items (),
346+ launch_arguments = {
347+ "gz_args" : f"-r -s { factory_world } "
348+ }.items (),
218349 condition = IfCondition (headless ),
219350 ),
220351 # ── Clock bridge (Gazebo → ROS 2) ────────────────────────
0 commit comments