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

transform-manager.mddocs/

0

# Transform Manager

1

2

Graph-based system for managing complex transformation chains with automatic path finding between coordinate frames. Supports static and time-varying transformations with efficient computation and visualization capabilities.

3

4

## Capabilities

5

6

### TransformManager Class

7

8

Core class for managing static transformation graphs between coordinate frames.

9

10

```python { .api }

11

class TransformManager:

12

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

13

"""

14

Initialize transformation manager.

15

16

Parameters:

17

- strict_check: bool - Enable strict validation

18

- check: bool - Enable transformation checks

19

"""

20

21

def add_transform(self, from_frame, to_frame, A2B):

22

"""

23

Add transformation between frames.

24

25

Parameters:

26

- from_frame: str - Source frame name

27

- to_frame: str - Target frame name

28

- A2B: array, shape (4, 4) - Transformation matrix

29

"""

30

31

def get_transform(self, from_frame, to_frame):

32

"""

33

Get transformation between any two frames.

34

35

Parameters:

36

- from_frame: str - Source frame name

37

- to_frame: str - Target frame name

38

39

Returns:

40

- A2B: array, shape (4, 4) - Transformation matrix

41

"""

42

43

def plot_frames_in(self, frame, ax=None, s=1.0, ax_s=1, **kwargs):

44

"""

45

Plot all frames in specified reference frame.

46

47

Parameters:

48

- frame: str - Reference frame name

49

- ax: Axes3D, optional - Matplotlib 3D axis

50

- s: float - Scaling factor for frame visualization

51

- ax_s: float - Axis scaling factor

52

"""

53

54

def plot_connections_in_frame(self, frame, ax=None, s=1.0, ax_s=1, **kwargs):

55

"""Plot frame connections as lines."""

56

57

def check_consistency(self):

58

"""Check consistency of all transformations in graph."""

59

60

def whitelist_frames(self, frames):

61

"""Restrict graph to specified frames."""

62

63

def remove_frame(self, frame):

64

"""Remove frame and its connections from graph."""

65

66

def connected_components(self):

67

"""Find connected components in transformation graph."""

68

69

@property

70

def nodes(self):

71

"""Get all frame names in the graph."""

72

73

@property

74

def transforms(self):

75

"""Get all transformations as dictionary."""

76

```

77

78

### TemporalTransformManager Class

79

80

Extended manager for time-varying transformations with temporal interpolation.

81

82

```python { .api }

83

class TemporalTransformManager(TransformManager):

84

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

85

"""Initialize temporal transformation manager."""

86

87

def add_transform(self, from_frame, to_frame, transform, static=True):

88

"""

89

Add time-varying transformation.

90

91

Parameters:

92

- from_frame: str - Source frame name

93

- to_frame: str - Target frame name

94

- transform: TimeVaryingTransform or array - Transform object or static matrix

95

- static: bool - Whether transform is static

96

"""

97

98

def get_transform(self, from_frame, to_frame, time=None):

99

"""

100

Get transformation at specific time.

101

102

Parameters:

103

- from_frame: str - Source frame name

104

- to_frame: str - Target frame name

105

- time: float, optional - Time for interpolation

106

107

Returns:

108

- A2B: array, shape (4, 4) - Transformation at specified time

109

"""

110

```

111

112

### Time-Varying Transform Classes

113

114

Base classes for defining time-dependent transformations.

115

116

```python { .api }

117

class TimeVaryingTransform:

118

"""Abstract base class for time-varying transformations."""

119

120

def as_matrix(self, time):

121

"""

122

Get transformation matrix at specific time.

123

124

Parameters:

125

- time: float - Time value

126

127

Returns:

128

- A2B: array, shape (4, 4) - Transformation matrix

129

"""

130

131

class StaticTransform(TimeVaryingTransform):

132

def __init__(self, A2B):

133

"""

134

Static transformation that doesn't change over time.

135

136

Parameters:

137

- A2B: array, shape (4, 4) - Static transformation matrix

138

"""

139

140

class NumpyTimeseriesTransform(TimeVaryingTransform):

141

def __init__(self, times, transforms, interpolation_method="slerp"):

142

"""

143

Time-varying transformation from numpy array timeseries.

144

145

Parameters:

146

- times: array, shape (n,) - Time stamps

147

- transforms: array, shape (n, 4, 4) - Transformation matrices

148

- interpolation_method: str - Interpolation method ("slerp" or "linear")

149

"""

150

```

151

152

### TransformGraphBase Class

153

154

Base class providing core graph functionality for transformation management.

155

156

```python { .api }

157

class TransformGraphBase:

158

"""Base class for transformation graphs with path finding algorithms."""

159

160

def shortest_path(self, from_frame, to_frame):

161

"""Find shortest path between frames in graph."""

162

163

def has_frame(self, frame):

164

"""Check if frame exists in graph."""

165

166

def get_frames(self):

167

"""Get all frame names."""

168

```

169

170

## Usage Examples

171

172

### Basic Transform Management

173

174

```python

175

import numpy as np

176

import pytransform3d.transformations as pt

177

from pytransform3d.transform_manager import TransformManager

178

179

# Create transform manager

180

tm = TransformManager()

181

182

# Add transformations between frames

183

base_to_link1 = pt.transform_from(p=[1, 0, 0])

184

tm.add_transform("base", "link1", base_to_link1)

185

186

link1_to_link2 = pt.transform_from(p=[0, 1, 0])

187

tm.add_transform("link1", "link2", link1_to_link2)

188

189

link2_to_end = pt.transform_from(p=[0, 0, 1])

190

tm.add_transform("link2", "end_effector", link2_to_end)

191

192

# Get transformation between any two frames

193

base_to_end = tm.get_transform("base", "end_effector")

194

print(f"Base to end effector:\n{base_to_end}")

195

196

# Get transformation in reverse direction

197

end_to_base = tm.get_transform("end_effector", "base")

198

print(f"End effector to base:\n{end_to_base}")

199

```

200

201

### Kinematic Chain Visualization

202

203

```python

204

import matplotlib.pyplot as plt

205

from pytransform3d.transform_manager import TransformManager

206

from pytransform3d.plot_utils import make_3d_axis

207

208

# Create kinematic chain

209

tm = TransformManager()

210

211

# Add joints in a simple arm

212

tm.add_transform("base", "shoulder", pt.transform_from(p=[0, 0, 0.1]))

213

tm.add_transform("shoulder", "elbow", pt.transform_from(p=[0.3, 0, 0]))

214

tm.add_transform("elbow", "wrist", pt.transform_from(p=[0.25, 0, 0]))

215

tm.add_transform("wrist", "hand", pt.transform_from(p=[0.1, 0, 0]))

216

217

# Plot all frames

218

ax = make_3d_axis(ax_s=1)

219

tm.plot_frames_in("base", ax=ax, s=0.1)

220

tm.plot_connections_in_frame("base", ax=ax)

221

plt.show()

222

```

223

224

### Time-Varying Transformations

225

226

```python

227

import numpy as np

228

from pytransform3d.transform_manager import TemporalTransformManager, NumpyTimeseriesTransform

229

import pytransform3d.transformations as pt

230

231

# Create temporal transform manager

232

ttm = TemporalTransformManager()

233

234

# Define time-varying transformation (rotating joint)

235

times = np.linspace(0, 2*np.pi, 100)

236

transforms = []

237

for t in times:

238

R = pr.matrix_from_euler([0, 0, t], "xyz", extrinsic=True)

239

T = pt.transform_from(R=R, p=[0, 0, 0])

240

transforms.append(T)

241

242

transforms = np.array(transforms)

243

rotating_joint = NumpyTimeseriesTransform(times, transforms)

244

245

# Add static and time-varying transforms

246

ttm.add_transform("base", "rotating_link", rotating_joint, static=False)

247

ttm.add_transform("rotating_link", "end", pt.transform_from(p=[1, 0, 0]), static=True)

248

249

# Get transformation at specific times

250

T_at_0 = ttm.get_transform("base", "end", time=0)

251

T_at_pi = ttm.get_transform("base", "end", time=np.pi)

252

253

print(f"Transform at t=0:\n{T_at_0[:3, 3]}") # translation part

254

print(f"Transform at t=π:\n{T_at_pi[:3, 3]}") # translation part

255

```

256

257

### Complex Robot Structure

258

259

```python

260

from pytransform3d.transform_manager import TransformManager

261

import pytransform3d.transformations as pt

262

import pytransform3d.rotations as pr

263

264

# Create complex robot structure

265

tm = TransformManager()

266

267

# Base platform

268

tm.add_transform("world", "base_platform", pt.transform_from(p=[0, 0, 0.05]))

269

270

# Left arm

271

R_left = pr.matrix_from_euler([0, 0, np.pi/4], "xyz", extrinsic=True)

272

tm.add_transform("base_platform", "left_shoulder", pt.transform_from(R=R_left, p=[-0.2, 0.3, 0.4]))

273

tm.add_transform("left_shoulder", "left_elbow", pt.transform_from(p=[0.3, 0, 0]))

274

tm.add_transform("left_elbow", "left_hand", pt.transform_from(p=[0.25, 0, 0]))

275

276

# Right arm

277

R_right = pr.matrix_from_euler([0, 0, -np.pi/4], "xyz", extrinsic=True)

278

tm.add_transform("base_platform", "right_shoulder", pt.transform_from(R=R_right, p=[0.2, 0.3, 0.4]))

279

tm.add_transform("right_shoulder", "right_elbow", pt.transform_from(p=[0.3, 0, 0]))

280

tm.add_transform("right_elbow", "right_hand", pt.transform_from(p=[0.25, 0, 0]))

281

282

# Head

283

tm.add_transform("base_platform", "neck", pt.transform_from(p=[0, 0, 0.6]))

284

tm.add_transform("neck", "head", pt.transform_from(p=[0, 0, 0.1]))

285

286

# Eyes

287

tm.add_transform("head", "left_eye", pt.transform_from(p=[-0.03, 0.05, 0.02]))

288

tm.add_transform("head", "right_eye", pt.transform_from(p=[0.03, 0.05, 0.02]))

289

290

# Get transformation between hands

291

left_to_right = tm.get_transform("left_hand", "right_hand")

292

print(f"Left hand to right hand distance: {np.linalg.norm(left_to_right[:3, 3]):.3f}m")

293

294

# Check graph properties

295

print(f"Total frames: {len(tm.nodes)}")

296

print(f"Frames: {list(tm.nodes)}")

297

```

298

299

### Graph Analysis

300

301

```python

302

from pytransform3d.transform_manager import TransformManager

303

304

# Create disconnected graph

305

tm = TransformManager()

306

307

# First component

308

tm.add_transform("A", "B", np.eye(4))

309

tm.add_transform("B", "C", np.eye(4))

310

311

# Second component (disconnected)

312

tm.add_transform("X", "Y", np.eye(4))

313

tm.add_transform("Y", "Z", np.eye(4))

314

315

# Find connected components

316

components = tm.connected_components()

317

print(f"Connected components: {components}")

318

319

# Check consistency

320

try:

321

tm.check_consistency()

322

print("Graph is consistent")

323

except Exception as e:

324

print(f"Graph inconsistency: {e}")

325

326

# Try to get transform between disconnected components

327

try:

328

T = tm.get_transform("A", "X") # Will fail - no path

329

except KeyError:

330

print("No path between disconnected components")

331

```