Skip to content

Commit d27cad3

Browse files
authored
Add robot name modification feature to change_urdf_root command (#570)
When changing the root link of a URDF that was generated from xacro modules, the robot name now automatically changes to reflect the new root configuration. This prevents naming conflicts when using modularize-urdf to convert the modified URDF back to xacro format. Previously, when converting a root-changed URDF to xacro using modularize-urdf, the generated macro would have the same name as the original, causing conflicts when trying to use both the original and root-changed versions in the same xacro file. Changes: - Auto-generate new robot name as "{original}_root_{new_root_link}" by default - Add --robot-name option for custom robot names - Add --keep-robot-name option to preserve the original name - Update URDFXMLRootLinkChanger to support robot name modification
1 parent dde639a commit d27cad3

File tree

2 files changed

+87
-5
lines changed

2 files changed

+87
-5
lines changed

skrobot/apps/change_urdf_root.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ def main():
2828
2929
# Change root link with verbose output
3030
change_urdf_root robot.urdf new_root output.urdf --verbose
31+
32+
# Change root link with custom robot name
33+
change_urdf_root robot.urdf new_root output.urdf --robot-name my_robot
34+
35+
# Keep original robot name
36+
change_urdf_root robot.urdf new_root output.urdf --keep-robot-name
3137
""")
3238

3339
parser.add_argument(
@@ -62,6 +68,16 @@ def main():
6268
action='store_true',
6369
help='Overwrite output file if it exists')
6470

71+
parser.add_argument(
72+
'--robot-name',
73+
type=str,
74+
help='Custom robot name for the output URDF')
75+
76+
parser.add_argument(
77+
'--keep-robot-name',
78+
action='store_true',
79+
help='Keep the original robot name (do not auto-generate new name)')
80+
6581
args = parser.parse_args()
6682

6783
# Check if input file exists
@@ -80,8 +96,10 @@ def main():
8096
# If --list is specified, show all links and exit
8197
if args.list:
8298
current_root = changer.get_current_root_link()
99+
robot_name = changer.get_robot_name()
83100
links = changer.list_links()
84101

102+
print("Robot name: {}".format(robot_name))
85103
print("Current root link: {}".format(current_root))
86104
print("Total links: {}".format(len(links)))
87105
print("\nAll links:")
@@ -122,7 +140,21 @@ def main():
122140

123141
# Show current state
124142
current_root = changer.get_current_root_link()
143+
current_robot_name = changer.get_robot_name()
144+
145+
# Determine robot name for output
146+
if args.keep_robot_name:
147+
output_robot_name = current_robot_name
148+
elif args.robot_name:
149+
output_robot_name = args.robot_name
150+
else:
151+
# Default: auto-generate based on new root link
152+
output_robot_name = "{}_root_{}".format(
153+
current_robot_name, args.new_root_link)
154+
125155
if args.verbose:
156+
print("Current robot name: {}".format(current_robot_name))
157+
print("New robot name: {}".format(output_robot_name))
126158
print("Current root link: {}".format(current_root))
127159
print("New root link: {}".format(args.new_root_link))
128160
print("Output file: {}".format(args.output_urdf))
@@ -137,18 +169,31 @@ def main():
137169
if args.verbose:
138170
print("Changing root link...")
139171

140-
changer.change_root_link(args.new_root_link, args.output_urdf)
172+
# Pass robot name (either custom or None for auto-generation)
173+
if args.keep_robot_name:
174+
changer.change_root_link(args.new_root_link, args.output_urdf,
175+
robot_name=current_robot_name)
176+
elif args.robot_name:
177+
changer.change_root_link(args.new_root_link, args.output_urdf,
178+
robot_name=args.robot_name)
179+
else:
180+
# Let the changer auto-generate the name
181+
changer.change_root_link(args.new_root_link, args.output_urdf)
141182

142183
# Verify the result
143184
if args.verbose:
144185
print("Verifying result...")
145186

146187
result_changer = URDFXMLRootLinkChanger(args.output_urdf)
147188
actual_root = result_changer.get_current_root_link()
189+
actual_robot_name = result_changer.get_robot_name()
148190

149191
if actual_root == args.new_root_link:
150192
print("Successfully changed root link from '{}' "
151193
"to '{}'".format(current_root, args.new_root_link))
194+
if current_robot_name != actual_robot_name:
195+
print("Robot name changed from '{}' to '{}'".format(
196+
current_robot_name, actual_robot_name))
152197
print("Modified URDF saved to: {}".format(args.output_urdf))
153198
else:
154199
print("Failed to change root link. Expected "

skrobot/urdf/xml_root_link_changer.py

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def list_links(self):
124124
"""
125125
return list(self.links.keys())
126126

127-
def change_root_link(self, new_root_link, output_path):
127+
def change_root_link(self, new_root_link, output_path, robot_name=None):
128128
"""Change the root link and save the modified URDF.
129129
130130
Parameters
@@ -133,6 +133,9 @@ def change_root_link(self, new_root_link, output_path):
133133
Name of the new root link
134134
output_path : str
135135
Path where the modified URDF will be saved
136+
robot_name : str, optional
137+
New robot name. If None, generates a default name based on
138+
the original robot name and new root link.
136139
137140
Raises
138141
------
@@ -144,8 +147,13 @@ def change_root_link(self, new_root_link, output_path):
144147
"Link '{}' not found in URDF".format(new_root_link))
145148

146149
current_root = self.get_current_root_link()
150+
151+
# Set robot name if needed
152+
if robot_name is not None or new_root_link != current_root:
153+
self._set_robot_name(robot_name, new_root_link)
154+
147155
if new_root_link == current_root:
148-
# No change needed, just copy the file
156+
# No change needed to kinematic tree, just save with new name
149157
self._save_urdf(output_path)
150158
return
151159

@@ -476,6 +484,33 @@ def _save_urdf(self, output_path):
476484
# Format the output for better readability
477485
self._format_xml_file(output_path)
478486

487+
def get_robot_name(self):
488+
"""Get the current robot name.
489+
490+
Returns
491+
-------
492+
str
493+
Current robot name, or 'robot' if not set
494+
"""
495+
return self.root.get('name', 'robot')
496+
497+
def _set_robot_name(self, robot_name, new_root_link):
498+
"""Set the robot name.
499+
500+
Parameters
501+
----------
502+
robot_name : str or None
503+
New robot name. If None, generates default name.
504+
new_root_link : str
505+
Name of the new root link (used for default naming)
506+
"""
507+
if robot_name is None:
508+
# Generate default name: original_name_root_new_root_link
509+
original_name = self.get_robot_name()
510+
robot_name = "{}_root_{}".format(original_name, new_root_link)
511+
512+
self.root.set('name', robot_name)
513+
479514
def _format_xml_file(self, file_path):
480515
"""Format XML file for better readability.
481516
@@ -504,7 +539,7 @@ def _format_xml_file(self, file_path):
504539
pass
505540

506541

507-
def change_urdf_root_link(urdf_path, new_root_link, output_path):
542+
def change_urdf_root_link(urdf_path, new_root_link, output_path, robot_name=None):
508543
"""Change the root link of a URDF file.
509544
510545
Parameters
@@ -515,6 +550,8 @@ def change_urdf_root_link(urdf_path, new_root_link, output_path):
515550
Name of the new root link
516551
output_path : str
517552
Path where the modified URDF will be saved
553+
robot_name : str, optional
554+
New robot name. If None, generates a default name.
518555
"""
519556
changer = URDFXMLRootLinkChanger(urdf_path)
520-
changer.change_root_link(new_root_link, output_path)
557+
changer.change_root_link(new_root_link, output_path, robot_name=robot_name)

0 commit comments

Comments
 (0)