Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ skr visualize-mesh mesh_file.stl

# Convert wheel collision models
skr convert-wheel-collision robot.urdf --output converted.urdf

# Generate robot class from URDF geometry
skr generate-robot-class robot.urdf --output MyRobot.py
```

### Legacy Commands (still supported)
Expand Down
24 changes: 24 additions & 0 deletions docs/source/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,29 @@ Convert wheel collision models in URDF files.

skr convert-wheel-collision robot.urdf --output converted.urdf

generate-robot-class
~~~~~~~~~~~~~~~~~~~~

Generate Python robot class from URDF geometry. This tool automatically detects
kinematic chains (arms, legs, head, torso) and generates a Python class with
appropriate properties and end-effector coordinates.

No LLM or API keys required - uses only URDF structure and geometry.

.. code-block:: bash

# Generate robot class and print to stdout
skr generate-robot-class robot.urdf

# Save to file
skr generate-robot-class robot.urdf --output MyRobot.py

# Specify custom class name
skr generate-robot-class robot.urdf --class-name MyCustomRobot --output MyRobot.py

# Show detected groups without generating code
skr generate-robot-class robot.urdf --show-groups

Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation examples show basic usage but don't mention the PatternConfig customization feature or the package:// URL support, which are key features of this implementation. Consider adding examples showing these advanced features.

Suggested change
# Use a custom PatternConfig to control naming and grouping
skr generate-robot-class robot.urdf --pattern-config my_patterns.yml --output MyRobotCustom.py
# Load URDF from a ROS-style package:// URL
skr generate-robot-class package://my_robot_description/urdf/robot.urdf --output MyRobotFromPackage.py

Copilot uses AI. Check for mistakes.
Backward Compatibility
----------------------

Expand All @@ -124,6 +147,7 @@ For backward compatibility, all original individual commands are still available
urdf-hash robot.urdf
visualize-mesh mesh_file.stl
convert-wheel-collision robot.urdf --output converted.urdf
generate-robot-class robot.urdf --output MyRobot.py

Getting Help
------------
Expand Down
1 change: 1 addition & 0 deletions skrobot/apps/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def get_available_apps():
'urdf_hash': ('Calculate URDF hash', None),
'convert_wheel_collision': ('Convert wheel collision model', None),
'extract_sub_urdf': ('Extract sub-URDF from a root link', None),
'generate_robot_class': ('Generate robot class from URDF geometry', None),
}

for filename in os.listdir(apps_dir):
Expand Down
80 changes: 80 additions & 0 deletions skrobot/apps/generate_robot_class.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/env python

"""Generate robot class from URDF geometry.
This tool generates Python robot class code with kinematic chain properties
(arm, right_arm, left_arm, etc.) from any URDF robot model.
No LLM or API keys required - uses only URDF structure and geometry.
"""

import argparse


def main():
parser = argparse.ArgumentParser(
description='Generate robot class from URDF geometry')
parser.add_argument(
'input_urdfpath',
type=str,
help='Input URDF path')
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI help text 'Input URDF path' on line 20 could be more descriptive. Consider changing it to 'Path to input URDF file (supports package:// URLs)' to inform users about the package:// URL support that was added in this PR.

Suggested change
help='Input URDF path')
help='Path to input URDF file (supports package:// URLs)')

Copilot uses AI. Check for mistakes.
parser.add_argument(
'--output', '-o',
type=str,
default=None,
help='Output path for generated Python file')
parser.add_argument(
'--class-name', '-c',
type=str,
default=None,
help='Class name for the generated class (default: auto-generated)')
parser.add_argument(
'--show-groups',
action='store_true',
help='Show detected groups without generating code')
args = parser.parse_args()

from skrobot.models.urdf import RobotModelFromURDF
from skrobot.urdf.robot_class_generator import generate_groups_from_geometry
from skrobot.urdf.robot_class_generator import generate_robot_class_from_geometry

robot = RobotModelFromURDF(urdf_file=args.input_urdfpath)

print(f"Robot: {robot.name}")
print(f"Links: {len(robot.link_list)}")
print(f"Joints: {len(robot.joint_list)}")
print()

if args.show_groups:
groups, end_effectors, end_coords_info, robot_name = \
generate_groups_from_geometry(robot)
print("Detected groups:")
for group_name, group_data in groups.items():
links = group_data.get('links', [])
tip = group_data.get('tip_link', 'N/A')
print(f" {group_name}: {len(links)} links, tip={tip}")
print()
print("End coordinates:")
for group_name, ec_info in end_coords_info.items():
parent = ec_info.get('parent_link', 'N/A')
pos = ec_info.get('pos', [0, 0, 0])
print(f" {group_name}: parent={parent}, pos={pos}")
return

code = generate_robot_class_from_geometry(
robot,
output_path=args.output,
class_name=args.class_name,
urdf_path=args.input_urdfpath,
)
Comment on lines +41 to +69
Copy link

Copilot AI Jan 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI application doesn't include any error handling for cases where the URDF file cannot be loaded or when robot class generation fails. Consider wrapping the robot loading (line 41) and code generation (lines 64-69) in try-except blocks to provide user-friendly error messages instead of raw Python tracebacks.

Copilot uses AI. Check for mistakes.

if args.output:
print(f"Generated class saved to: {args.output}")
else:
print("Generated code:")
print("-" * 60)
print(code)


if __name__ == '__main__':
main()
4 changes: 4 additions & 0 deletions skrobot/urdf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from skrobot.urdf.modularize_urdf import find_root_link
from skrobot.urdf.modularize_urdf import transform_urdf_to_macro
from skrobot.urdf.primitives_converter import convert_meshes_to_primitives
from skrobot.urdf.robot_class_generator import generate_groups_from_geometry
from skrobot.urdf.robot_class_generator import generate_robot_class_from_geometry
from skrobot.urdf.scale_urdf import scale_urdf
from skrobot.urdf.transform_urdf import transform_urdf_with_world_link
from skrobot.urdf.wheel_collision_converter import convert_wheel_collisions_to_cylinders
Expand All @@ -23,4 +25,6 @@
'get_mesh_dimensions',
'extract_sub_urdf',
'scale_urdf',
'generate_groups_from_geometry',
'generate_robot_class_from_geometry',
]
Loading