or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

batch-operations.mdbatch-rotations.mdcamera.mdcoordinates.mdeditor.mdindex.mdplot-utils.mdrotations.mdtrajectories.mdtransform-manager.mdtransformations.mduncertainty.mdurdf.mdvisualization.md

urdf.mddocs/

0

# URDF

1

2

Loading and managing robot kinematic chains from URDF (Unified Robot Description Format) files with joint control, collision detection, and 3D visualization capabilities.

3

4

## Capabilities

5

6

### UrdfTransformManager Class

7

8

Extended TransformManager with URDF loading and joint management capabilities.

9

10

```python { .api }

11

class UrdfTransformManager(TransformManager):

12

def __init__(self, strict_check=True, check=True):

13

"""Initialize URDF-capable transformation manager."""

14

15

def load_urdf(self, urdf_xml, mesh_path=None, package_dir=None):

16

"""

17

Load robot description from URDF file.

18

19

Parameters:

20

- urdf_xml: str - URDF XML content or file path

21

- mesh_path: str, optional - Path to mesh files

22

- package_dir: str, optional - ROS package directory

23

"""

24

25

def add_joint(self, joint_name, from_frame, to_frame, child2parent, axis, limits=(float("-inf"), float("inf")), joint_type="revolute"):

26

"""

27

Add joint to robot model.

28

29

Parameters:

30

- joint_name: str - Joint identifier

31

- from_frame: str - Parent frame name

32

- to_frame: str - Child frame name

33

- child2parent: array, shape (4, 4) - Joint transformation

34

- axis: array, shape (3,) - Joint rotation axis

35

- limits: tuple - Joint angle limits (min, max)

36

- joint_type: str - Joint type ("revolute", "prismatic", "fixed")

37

"""

38

39

def set_joint(self, joint_name, value):

40

"""

41

Set joint position.

42

43

Parameters:

44

- joint_name: str - Joint identifier

45

- value: float - Joint angle in radians (or position for prismatic)

46

"""

47

48

def get_joint_limits(self, joint_name):

49

"""

50

Get joint limits.

51

52

Parameters:

53

- joint_name: str - Joint identifier

54

55

Returns:

56

- limits: tuple - (min_limit, max_limit)

57

"""

58

59

def plot_visuals(self, frame, ax=None, ax_s=1, wireframe=False, convex_hull_of_mesh=True, alpha=0.3):

60

"""Plot visual geometries of robot in specified frame."""

61

62

def plot_collision_objects(self, frame, ax=None, ax_s=1, wireframe=True, convex_hull_of_mesh=True, alpha=1.0):

63

"""Plot collision geometries of robot in specified frame."""

64

```

65

66

### Geometry Classes

67

68

Classes representing different geometric shapes in URDF files.

69

70

```python { .api }

71

class Box(Geometry):

72

def __init__(self, frame, mesh_path, package_dir, color):

73

"""Box geometry primitive."""

74

75

# Attributes:

76

# size: np.ndarray, shape (3,) - Box dimensions [width, height, depth]

77

78

class Sphere(Geometry):

79

def __init__(self, frame, mesh_path, package_dir, color):

80

"""Sphere geometry primitive."""

81

82

# Attributes:

83

# radius: float - Sphere radius

84

85

class Cylinder(Geometry):

86

def __init__(self, frame, mesh_path, package_dir, color):

87

"""Cylinder geometry primitive."""

88

89

# Attributes:

90

# radius: float - Cylinder radius

91

# length: float - Cylinder height

92

93

class Mesh(Geometry):

94

def __init__(self, frame, mesh_path, package_dir, color):

95

"""Mesh geometry from file."""

96

97

# Attributes:

98

# filename: str - Path to mesh file

99

# scale: np.ndarray, shape (3,) - Scaling factors [x, y, z]

100

```

101

102

### URDF Parsing Functions

103

104

Utility functions for parsing URDF XML content.

105

106

```python { .api }

107

def parse_urdf(urdf_xml, mesh_path=None, package_dir=None, strict_check=True):

108

"""

109

Parse URDF XML into structured data.

110

111

Parameters:

112

- urdf_xml: str - URDF XML content

113

- mesh_path: str, optional - Path to mesh files

114

- package_dir: str, optional - ROS package directory

115

- strict_check: bool - Enable strict validation

116

117

Returns:

118

- robot_name: str - Robot name from URDF

119

- links: list of Link - Parsed link objects

120

- joints: list of Joint - Parsed joint objects

121

"""

122

123

def initialize_urdf_transform_manager(tm, robot_name, links, joints):

124

"""

125

Initialize TransformManager from parsed URDF data.

126

127

Parameters:

128

- tm: UrdfTransformManager - Transform manager instance

129

- robot_name: str - Robot name

130

- links: list of Link - Link objects

131

- joints: list of Joint - Joint objects

132

"""

133

```

134

135

### Exception Class

136

137

```python { .api }

138

class UrdfException(Exception):

139

"""Exception raised during URDF parsing or processing."""

140

```

141

142

## Usage Examples

143

144

### Loading Simple Robot

145

146

```python

147

from pytransform3d.urdf import UrdfTransformManager

148

149

# Create URDF manager

150

utm = UrdfTransformManager()

151

152

# Load robot from URDF file

153

with open("robot.urdf", "r") as f:

154

urdf_content = f.read()

155

156

utm.load_urdf(urdf_content, mesh_path="./meshes/")

157

158

# Print available frames

159

print("Robot frames:", utm.nodes)

160

161

# Set joint positions

162

utm.set_joint("shoulder_joint", 0.5) # 0.5 radians

163

utm.set_joint("elbow_joint", -1.2) # -1.2 radians

164

165

# Get end effector pose

166

base_to_end = utm.get_transform("base_link", "end_effector")

167

print(f"End effector position: {base_to_end[:3, 3]}")

168

```

169

170

### Joint Control and Limits

171

172

```python

173

from pytransform3d.urdf import UrdfTransformManager

174

import numpy as np

175

176

utm = UrdfTransformManager()

177

utm.load_urdf(urdf_content)

178

179

# Get joint limits

180

shoulder_limits = utm.get_joint_limits("shoulder_joint")

181

print(f"Shoulder joint limits: {shoulder_limits}")

182

183

# Set joint within limits

184

joint_angle = np.clip(1.5, shoulder_limits[0], shoulder_limits[1])

185

utm.set_joint("shoulder_joint", joint_angle)

186

187

# Animate joint motion

188

angles = np.linspace(shoulder_limits[0], shoulder_limits[1], 50)

189

end_positions = []

190

191

for angle in angles:

192

utm.set_joint("shoulder_joint", angle)

193

T = utm.get_transform("base_link", "end_effector")

194

end_positions.append(T[:3, 3])

195

196

end_positions = np.array(end_positions)

197

print(f"End effector trajectory: {end_positions.shape}")

198

```

199

200

### Robot Visualization

201

202

```python

203

import matplotlib.pyplot as plt

204

from pytransform3d.urdf import UrdfTransformManager

205

from pytransform3d.plot_utils import make_3d_axis

206

207

# Load robot

208

utm = UrdfTransformManager()

209

utm.load_urdf(urdf_content, mesh_path="./meshes/")

210

211

# Set robot configuration

212

utm.set_joint("base_joint", 0.0)

213

utm.set_joint("shoulder_joint", 0.5)

214

utm.set_joint("elbow_joint", -1.0)

215

utm.set_joint("wrist_joint", 0.3)

216

217

# Plot robot

218

ax = make_3d_axis(ax_s=2)

219

220

# Plot coordinate frames

221

utm.plot_frames_in("base_link", ax=ax, s=0.1)

222

223

# Plot visual geometries

224

utm.plot_visuals("base_link", ax=ax, alpha=0.7)

225

226

# Plot collision objects (wireframe)

227

utm.plot_collision_objects("base_link", ax=ax, wireframe=True, alpha=0.3)

228

229

ax.set_xlabel('X')

230

ax.set_ylabel('Y')

231

ax.set_zlabel('Z')

232

plt.show()

233

```

234

235

### Multiple Robot Configurations

236

237

```python

238

import numpy as np

239

import matplotlib.pyplot as plt

240

from pytransform3d.urdf import UrdfTransformManager

241

242

utm = UrdfTransformManager()

243

utm.load_urdf(urdf_content)

244

245

# Define multiple configurations

246

configurations = [

247

{"shoulder_joint": 0.0, "elbow_joint": 0.0},

248

{"shoulder_joint": 0.5, "elbow_joint": -1.0},

249

{"shoulder_joint": 1.0, "elbow_joint": -1.5},

250

{"shoulder_joint": -0.5, "elbow_joint": 0.8},

251

]

252

253

# Plot workspace

254

fig = plt.figure(figsize=(12, 8))

255

ax = fig.add_subplot(111, projection='3d')

256

257

colors = ['red', 'green', 'blue', 'orange']

258

259

for i, config in enumerate(configurations):

260

# Set configuration

261

for joint_name, angle in config.items():

262

utm.set_joint(joint_name, angle)

263

264

# Get end effector position

265

T = utm.get_transform("base_link", "end_effector")

266

pos = T[:3, 3]

267

268

# Plot end effector

269

ax.scatter(*pos, c=colors[i], s=100, label=f'Config {i+1}')

270

271

# Plot robot frames (smaller)

272

utm.plot_frames_in("base_link", ax=ax, s=0.05)

273

274

ax.set_xlabel('X')

275

ax.set_ylabel('Y')

276

ax.set_zlabel('Z')

277

ax.legend()

278

plt.show()

279

```

280

281

### Robot Workspace Analysis

282

283

```python

284

import numpy as np

285

from pytransform3d.urdf import UrdfTransformManager

286

287

utm = UrdfTransformManager()

288

utm.load_urdf(urdf_content)

289

290

# Sample joint space

291

n_samples = 1000

292

joint_names = ["shoulder_joint", "elbow_joint", "wrist_joint"]

293

294

# Get joint limits

295

limits = {}

296

for joint_name in joint_names:

297

limits[joint_name] = utm.get_joint_limits(joint_name)

298

299

# Generate random configurations

300

workspace_points = []

301

for _ in range(n_samples):

302

config = {}

303

for joint_name in joint_names:

304

low, high = limits[joint_name]

305

if np.isfinite(low) and np.isfinite(high):

306

angle = np.random.uniform(low, high)

307

else:

308

angle = np.random.uniform(-np.pi, np.pi)

309

config[joint_name] = angle

310

utm.set_joint(joint_name, angle)

311

312

# Get end effector position

313

T = utm.get_transform("base_link", "end_effector")

314

workspace_points.append(T[:3, 3])

315

316

workspace_points = np.array(workspace_points)

317

318

# Analyze workspace

319

print(f"Workspace bounds:")

320

print(f" X: {workspace_points[:, 0].min():.3f} to {workspace_points[:, 0].max():.3f}")

321

print(f" Y: {workspace_points[:, 1].min():.3f} to {workspace_points[:, 1].max():.3f}")

322

print(f" Z: {workspace_points[:, 2].min():.3f} to {workspace_points[:, 2].max():.3f}")

323

324

# Plot workspace

325

fig = plt.figure()

326

ax = fig.add_subplot(111, projection='3d')

327

ax.scatter(workspace_points[:, 0], workspace_points[:, 1], workspace_points[:, 2],

328

alpha=0.1, s=1)

329

ax.set_xlabel('X')

330

ax.set_ylabel('Y')

331

ax.set_zlabel('Z')

332

plt.show()

333

```