URDF Processor API Reference

This page documents ManipulaPy.urdf_processor, the module for URDF (Unified Robot Description Format) processing and conversion to ManipulaPy objects.

Tip

For conceptual explanations, see URDF Processor User Guide.

Quick Navigation

URDFToSerialManipulator Class

class ManipulaPy.urdf_processor.URDFToSerialManipulator(urdf_name, use_pybullet_limits=False, backend='builtin', load_meshes=False, validate=False)[source]

Bases: object

A class to convert URDF files to SerialManipulator objects and simulate them using PyBullet.

Supports multiple URDF parser backends:
  • β€œbuiltin”: Native ManipulaPy parser (NumPy 2.0 compatible, default)

  • β€œurchin”: Legacy urchin parser (requires urchin, not NumPy 2.0 compatible)

  • β€œpybullet”: PyBullet-based parser (requires pybullet)

Features:
  • Direct conversion to SerialManipulator and ManipulatorDynamics

  • Forward kinematics (single and batch)

  • URDF validation

  • Optional PyBullet joint limit extraction

  • Visualization and animation

Example

>>> processor = URDFToSerialManipulator("robot.urdf")
>>> manipulator = processor.serial_manipulator
>>> T_ee = manipulator.forward_kinematics([0, 0, 0, 0, 0, 0])
>>> # Batch FK for trajectory
>>> configs = np.random.uniform(-np.pi, np.pi, (100, 6))
>>> transforms = processor.batch_forward_kinematics(configs)

Converts URDF files to SerialManipulator and ManipulatorDynamics objects with PyBullet integration.

Constructor

Parameters:
  • urdf_name (str | Path) –

  • use_pybullet_limits (bool) –

  • backend (str) –

  • load_meshes (bool) –

  • validate (bool) –

__init__(urdf_name, use_pybullet_limits=False, backend='builtin', load_meshes=False, validate=False)[source]

Initializes the object with the given urdf_name.

Parameters:
  • urdf_name (str | Path) – Path to the URDF file.

  • use_pybullet_limits (bool) – Whether to override URDF limits with PyBullet’s. Default False (use URDF limits directly).

  • backend (str) – Parser backend - β€œbuiltin” (default), β€œurchin”, or β€œpybullet”

  • load_meshes (bool) – Whether to load mesh geometry. Default False.

  • validate (bool) – Whether to validate URDF structure. Default False.

Parameters:

  • urdf_name (str) – Path to the URDF file

  • use_pybullet_limits (bool) – Override URDF joint limits with PyBullet values (default: True)

Process:

  1. Load URDF using urchin library

  2. Extract kinematic and dynamic parameters

  3. Optionally retrieve joint limits from PyBullet

  4. Create SerialManipulator and ManipulatorDynamics objects

Attributes Created:

  • urdf_name (str) – Path to URDF file

  • robot (urchin.URDF) – Loaded URDF object

  • robot_data (dict) – Extracted robot parameters

  • serial_manipulator (SerialManipulator) – Kinematics object

  • dynamics (ManipulatorDynamics) – Dynamics object

URDF Processing

load_urdf(urdf_name)[source]

Load the URDF file and extract the necessary info for the robot model.

DEPRECATED: Use _extract_robot_data() instead. This method is kept for backward compatibility but now delegates to the native parser.

Parameters:

urdf_name (str) – Path to URDF file (ignored, uses self.robot)

Returns:

Robot kinematic/dynamic parameters

Return type:

dict

Parameters:

  • urdf_name (str) – Path to the URDF file

Returns:

  • robot_data (dict) – Dictionary containing:

    • M (numpy.ndarray) – Home configuration matrix (4Γ—4)

    • Slist (numpy.ndarray) – Space frame screw axes (6Γ—n)

    • Blist (numpy.ndarray) – Body frame screw axes (6Γ—n)

    • Glist (list) – Spatial inertia matrices (6Γ—6 each)

    • actuated_joints_num (int) – Number of actuated joints

Process:

  1. Extract joint positions and rotation axes

  2. Build spatial inertia matrices from link properties

  3. Compute screw axes using Product of Exponentials

  4. Generate body frame screw axes via adjoint transformation

_get_joint_limits_from_pybullet()[source]

Connect to PyBullet (in DIRECT mode, so no GUI), load the URDF, and retrieve per-joint limits for all revolute joints.

Returns:

List of (lower, upper) tuples in the order they appear as revolute in the URDF.

Raises:

RuntimeError – If PyBullet is not available.

Return type:

List[Tuple[float, float]]

Returns:

  • joint_limits (list) – List of (lower, upper) tuples for each revolute joint

Process:

  1. Connect to PyBullet in DIRECT mode (no GUI)

  2. Load URDF into PyBullet simulation

  3. Extract joint limits for all revolute joints

  4. Handle continuous joints with (-Ο€, Ο€) defaults

  5. Disconnect from PyBullet

Note: Only processes revolute joints, ignoring fixed and other joint types.

Object Initialization

initialize_serial_manipulator()[source]

Initializes a SerialManipulator object using the extracted URDF data. Overwrites the example joint limits with PyBullet-based ones if available.

Returns:

  • manipulator (SerialManipulator) – Configured kinematics object

Configuration:

  • Uses extracted URDF parameters (M, S_list, B_list)

  • Applies joint limits from PyBullet or defaults

  • Computes omega_list from screw axes

Return type:

SerialManipulator

initialize_manipulator_dynamics()[source]

Initializes the ManipulatorDynamics object using the extracted URDF data.

Returns:

  • dynamics (ManipulatorDynamics) – Configured dynamics object

Configuration:

  • Inherits from SerialManipulator for kinematics

  • Uses spatial inertia matrices (Glist) from URDF

  • Extracts r_list from space frame screw axes

Visualization

visualize_robot(cfg=None)[source]

Visualizes the URDF model.

Parameters:

cfg – Optional joint configuration (array or dict)

Purpose: Display static robot model using matplotlib visualization from urchin library.

Usage: Interactive 3D visualization with rotation and zoom capabilities.

visualize_trajectory(cfg_trajectory=None, loop_time=3.0, use_collision=False)[source]

Animate robot along a trajectory.

Parameters:
  • cfg_trajectory – Joint trajectories as (N, DOF) array or dict {joint_name: array}

  • loop_time – Animation duration in seconds

  • use_collision – Use collision geometry instead of visual

Parameters:

  • cfg_trajectory (numpy.ndarray or dict, optional) – Joint configurations over time

  • loop_time (float) – Animation duration in seconds (default: 3.0)

  • use_collision (bool) – Enable collision visualization (default: False)

Trajectory Formats:

  • NumPy array: Shape (n_timesteps, n_joints) with joint angles

  • Dictionary: {joint_name: [angles…]} mapping joint names to angle sequences

  • None: Uses default motion from 0 to Ο€/2 for all joints

Features:

  • Smooth animation between waypoints

  • Collision geometry visualization

  • Configurable playback speed

Utilities

print_joint_info()[source]

Returns the joint names instead of printing them to console.

Returns:

Contains β€˜num_joints’ and β€˜joint_names’

Return type:

dict

Returns:

  • joint_info (dict) – Dictionary containing:

    • num_joints (int) – Total number of joints

    • joint_names (list) – Names of all joints in order

Purpose: Inspect joint structure without console output.

Static Utility Methods

static transform_to_xyz(T)[source]

Extracts the XYZ position from a 4x4 transformation matrix. Returns a 3-element NumPy array (x, y, z).

Parameters:

T (ndarray) –

Return type:

ndarray

Given a robot URDF and a link name, returns the link associated with that name. Returns None if not found.

Parameters:
  • robot (URDF) –

  • link_name (str) –

static w_p_to_slist(w, p, robot_dof)[source]

Convert angular velocity (w) and position (p) vectors into screw axes (Slist). Slist has shape (6, robot_dof).

Parameters:
Return type:

ndarray

load_urdf(urdf_name)[source]

Load the URDF file and extract the necessary info for the robot model.

DEPRECATED: Use _extract_robot_data() instead. This method is kept for backward compatibility but now delegates to the native parser.

Parameters:

urdf_name (str) – Path to URDF file (ignored, uses self.robot)

Returns:

Robot kinematic/dynamic parameters

Return type:

dict

initialize_serial_manipulator()[source]

Initializes a SerialManipulator object using the extracted URDF data. Overwrites the example joint limits with PyBullet-based ones if available.

Return type:

SerialManipulator

initialize_manipulator_dynamics()[source]

Initializes the ManipulatorDynamics object using the extracted URDF data.

visualize_robot(cfg=None)[source]

Visualizes the URDF model.

Parameters:

cfg – Optional joint configuration (array or dict)

visualize_trajectory(cfg_trajectory=None, loop_time=3.0, use_collision=False)[source]

Animate robot along a trajectory.

Parameters:
  • cfg_trajectory – Joint trajectories as (N, DOF) array or dict {joint_name: array}

  • loop_time – Animation duration in seconds

  • use_collision – Use collision geometry instead of visual

print_joint_info()[source]

Returns the joint names instead of printing them to console.

Returns:

Contains β€˜num_joints’ and β€˜joint_names’

Return type:

dict

get_serial_manipulator()[source]

Get SerialManipulator directly from native URDF parser.

This is a convenience method that uses the native parser’s to_serial_manipulator() method directly.

Returns:

SerialManipulator instance

Return type:

SerialManipulator

get_manipulator_dynamics()[source]

Get ManipulatorDynamics directly from native URDF parser.

This is a convenience method that uses the native parser’s to_manipulator_dynamics() method directly.

Returns:

ManipulatorDynamics instance

Return type:

ManipulatorDynamics

forward_kinematics(cfg, frame='space')[source]

Compute forward kinematics using SerialManipulator.

Parameters:
  • cfg (ndarray | List[float]) – Joint configuration array

  • frame (str) – Reference frame (β€œspace” or β€œbody”)

Returns:

4x4 transformation matrix of end-effector

Return type:

ndarray

Compute forward kinematics for all links using native URDF parser.

This is faster for getting transforms of all links, not just end-effector.

Parameters:
  • cfg (ndarray | List[float] | Dict[str, float] | None) – Joint configuration (None uses current config)

  • use_names (bool) – Return dict with string keys (always True for compatibility)

Returns:

Dict mapping link names to 4x4 transformation matrices

Return type:

Dict[str, ndarray]

batch_forward_kinematics(cfgs, link_name=None)[source]

Compute forward kinematics for multiple configurations (vectorized).

This is 50x+ faster than calling forward_kinematics in a loop.

Parameters:
  • cfgs (ndarray) – Array of configurations with shape (N, num_dofs)

  • link_name (str | None) – If provided, return only transforms for this link. If None, return transforms for all links.

Returns:

(N, 4, 4) array of transforms If link_name is None: Dict mapping link names to (N, 4, 4) arrays

Return type:

If link_name is provided

Example

>>> configs = np.random.uniform(-np.pi, np.pi, (100, 6))
>>> ee_transforms = processor.batch_forward_kinematics(configs, "ee_link")
>>> all_transforms = processor.batch_forward_kinematics(configs)
get_end_effector_transforms(cfgs)[source]

Get end-effector transforms for multiple configurations.

Convenience method for batch FK of end-effector only.

Parameters:

cfgs (ndarray) – Array of configurations with shape (N, num_dofs)

Returns:

(N, 4, 4) array of end-effector transforms

Return type:

ndarray

jacobian(cfg, frame='space')[source]

Compute the Jacobian matrix at given configuration.

Parameters:
  • cfg (ndarray | List[float]) – Joint configuration array

  • frame (str) – Reference frame (β€œspace” or β€œbody”)

Returns:

6xN Jacobian matrix

Return type:

ndarray

inverse_kinematics(T_desired, initial_guess=None, method='robust', **kwargs)[source]

Compute inverse kinematics to reach desired pose.

Parameters:
  • T_desired (ndarray) – Desired 4x4 transformation matrix

  • initial_guess (ndarray | None) – Starting joint configuration (None = zeros)

  • method (str) – IK method - β€œrobust” (default), β€œsmart”, or β€œiterative”

  • **kwargs – Additional arguments passed to IK solver

Returns:

Tuple of (theta, success, iterations)

Return type:

Tuple[ndarray, bool, int]

property num_dofs: int

Number of actuated degrees of freedom.

property joint_names: List[str]

Names of actuated joints in order.

Names of all links.

property end_effector_name: str

Name of the end-effector link.

property joint_limits_array: ndarray

Joint limits as (N, 2) array.

Returns:

, 0] is lower and [:, 1] is upper

Return type:

Array with shape (num_dofs, 2) where [

get_transform(frame_to, frame_from='world', cfg=None)[source]

Get transform between two frames.

Parameters:
  • frame_to (str) – Target frame (link name)

  • frame_from (str) – Source frame (link name or β€œworld”)

  • cfg (ndarray | None) – Joint configuration (None = current config)

Returns:

4x4 transformation matrix from frame_from to frame_to

Return type:

ndarray

create_modifier()[source]

Create a URDFModifier for calibration and payload simulation.

The modifier creates a deep copy of the URDF, so modifications don’t affect the original robot.

Returns:

URDFModifier instance

Return type:

URDFModifier

Example

>>> modifier = processor.create_modifier()
>>> modifier.offset_joint_zero("joint1", 0.01)
>>> modifier.add_payload("ee_link", mass=1.0, com=[0, 0, 0.1])
>>> calibrated_robot = modifier.urdf
validate()[source]

Validate the URDF structure.

Returns:

Dict with β€˜valid’ (bool) and β€˜issues’ (list) keys

Return type:

Dict

Usage Examples

Basic URDF Loading:

from ManipulaPy.urdf_processor import URDFToSerialManipulator

# Load robot from URDF
processor = URDFToSerialManipulator("robot.urdf")

# Access created objects
robot = processor.serial_manipulator
dynamics = processor.dynamics

print(f"Robot has {len(robot.joint_limits)} joints")

Using Built-in Robot Models:

from ManipulaPy.ManipulaPy_data.xarm import urdf_file as xarm_urdf

# Load xArm robot
processor = URDFToSerialManipulator(xarm_urdf)

# Perform forward kinematics
joint_angles = [0.1, 0.2, 0.3, 0, 0, 0]
T = processor.serial_manipulator.forward_kinematics(joint_angles)

Joint Limits Configuration:

# Use PyBullet joint limits (default)
processor_pb = URDFToSerialManipulator("robot.urdf", use_pybullet_limits=True)

# Use default limits (-Ο€, Ο€)
processor_default = URDFToSerialManipulator("robot.urdf", use_pybullet_limits=False)

# Compare joint limits
print("PyBullet limits:", processor_pb.serial_manipulator.joint_limits)
print("Default limits:", processor_default.serial_manipulator.joint_limits)

Robot Visualization:

# Static robot visualization
processor.visualize_robot()

# Trajectory animation with numpy array
import numpy as np

# Create trajectory: 100 timesteps, smooth motion
n_steps = 100
n_joints = len(processor.serial_manipulator.joint_limits)
trajectory = np.zeros((n_steps, n_joints))

for i in range(n_joints):
    trajectory[:, i] = np.linspace(0, np.pi/3, n_steps)

processor.visualize_trajectory(
    cfg_trajectory=trajectory,
    loop_time=5.0,
    use_collision=True
)

Trajectory Animation with Dictionary:

# Get joint names
joint_info = processor.print_joint_info()
joint_names = joint_info["joint_names"]

# Create trajectory dictionary
trajectory_dict = {}
for joint_name in joint_names:
    if "joint" in joint_name.lower():  # Filter actuated joints
        trajectory_dict[joint_name] = [0, np.pi/4, np.pi/2, np.pi/4, 0]

processor.visualize_trajectory(trajectory_dict, loop_time=4.0)

Extracting Robot Parameters:

# Access raw URDF data
robot_data = processor.robot_data

print(f"Home configuration:\n{robot_data['M']}")
print(f"Number of DOF: {robot_data['actuated_joints_num']}")
print(f"Screw axes shape: {robot_data['Slist'].shape}")

# Access inertia matrices
for i, G in enumerate(robot_data['Glist']):
    print(f"Link {i} inertia:\n{G}")

Integration with Kinematics and Dynamics:

# Complete workflow example
processor = URDFToSerialManipulator("robot.urdf")

# Kinematics
joint_angles = [0.5, -0.3, 0.8, 0.1, -0.2, 0.4]
T = processor.serial_manipulator.forward_kinematics(joint_angles)
J = processor.serial_manipulator.jacobian(joint_angles)

# Dynamics
joint_velocities = [0.1, 0.2, 0.0, 0.0, 0.0, 0.0]
joint_accelerations = [1.0, 0.5, 0.0, 0.0, 0.0, 0.0]

torques = processor.dynamics.inverse_dynamics(
    joint_angles, joint_velocities, joint_accelerations,
    g=[0, 0, -9.81], Ftip=[0, 0, 0, 0, 0, 0]
)

print(f"Required torques: {torques}")

Custom URDF Processing:

# Access raw urchin URDF object
urdf_obj = processor.robot

# Inspect URDF structure
print(f"Robot name: {urdf_obj.name}")
print(f"Links: {[link.name for link in urdf_obj.links]}")
print(f"Joints: {[joint.name for joint in urdf_obj.joints]}")

# Get link-wise forward kinematics
link_transforms = urdf_obj.link_fk()
for link_name, transform in link_transforms.items():
    print(f"{link_name}: {transform[:3, 3]}")  # Position only

Error Handling:

try:
    processor = URDFToSerialManipulator("nonexistent.urdf")
except FileNotFoundError:
    print("URDF file not found")
except Exception as e:
    print(f"URDF processing error: {e}")

# Validate extracted parameters
if processor.robot_data["actuated_joints_num"] == 0:
    print("Warning: No actuated joints found")

if len(processor.dynamics.Glist) != processor.robot_data["actuated_joints_num"]:
    print("Warning: Inertia matrix count mismatch")

Key Features

  • Automatic parameter extraction from URDF files using urchin library

  • PyBullet integration for accurate joint limit retrieval

  • Dual object creation (SerialManipulator + ManipulatorDynamics)

  • Flexible visualization with static and animated display options

  • Robust trajectory handling supporting both array and dictionary formats

  • Complete inertia processing from URDF link properties

  • Screw theory conversion from joint parameters to screw axes

  • Error handling for malformed or missing URDF files

Dependencies

  • urchin – URDF loading and visualization

  • PyBullet – Joint limit extraction and simulation

  • NumPy – Numerical computations and array operations

  • ManipulaPy.kinematics – SerialManipulator class

  • ManipulaPy.dynamics – ManipulatorDynamics class

  • ManipulaPy.utils – Utility functions for transformations

See Also