Tools¶
Reporting & Verification¶
The reporting & verification suite's HTML report generators and the static two-run compare page.
report¶
HTML diagnostic report generation for calibration results.
Renders the same statistics as
BaseCalibration.print_quality_report() (convergence, per-DOF
residuals, parameter uncertainty, correlation, validation) as a
self-contained, shareable HTML page instead of terminal text — with a
visual encoding of which parameters are well identified and which are
not, and an auto-generated "insights" list flagging things worth a
second look.
generate_calibration_report(calibrator, output_path=None, title=None)
¶
Render a self-contained HTML diagnostic report for a calibration run.
Reuses the metrics already computed by
BaseCalibration.print_quality_report() — no new computation is
performed here, only presentation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibrator
|
A |
required | |
output_path
|
Optional[str]
|
If given, the HTML is also written to this path. |
None
|
title
|
Optional[str]
|
Optional report title. Defaults to the robot's class name. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
The rendered HTML document as a string. |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If |
Source code in src/figaroh/tools/report.py
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 | |
identification_report¶
HTML diagnostic report generation for dynamic identification results.
Renders the same statistics as
BaseIdentification.print_quality_report() (condition number, torque
residuals, base-parameter uncertainty, held-out validation, optional
physical-consistency / reconstruction status) as a self-contained,
shareable HTML page — the identification analogue of
tools/report.py's calibration report.
Identification and calibration produce structurally different
diagnostics (a one-shot linear QR solve vs. an iterative nonlinear fit
with outlier removal), so this is a separate adapter rather than a
forced re-use of generate_calibration_report — see
docs/decisions/roadmap-mujoco-sysid-inspired-features.md (Feature
1b) for the comparison that motivated this split. Only the
domain-independent HTML/CSS layer is shared, via
tools/_report_common.py.
generate_identification_report(identifier, output_path=None, title=None)
¶
Render a self-contained HTML diagnostic report for an identification run.
Reuses the metrics already computed by
BaseIdentification.print_quality_report() — no new computation
is performed here, only presentation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
identifier
|
A |
required | |
output_path
|
Optional[str]
|
If given, the HTML is also written to this path. |
None
|
title
|
Optional[str]
|
Optional report title. Defaults to the robot's class name. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
The rendered HTML document as a string. |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If |
Source code in src/figaroh/tools/identification_report.py
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | |
compare_report¶
Static, offline, two-run comparison page (Feature 6, Phase C).
Unlike tools/report.py / tools/identification_report.py, this
module does not render a specific run's data at generation time. It
emits a self-contained HTML shell that a user opens directly in a
browser and then loads two *_verification.json files into (drag-and-
drop or a file picker) — the two exports produced by
BaseCalibration.export_verification_report() /
BaseIdentification.export_verification_report() (Step 2, extended in
Step 3 with the series/compat fields this page reads). Everything
happens client-side in JavaScript: no backend, no network request, no
change to either base class (see the roadmap's Step 5 "Files (modified):
none required").
Per D3 (roadmap), a compatibility check (same domain, same DOF/joint
names, same decimate setting for identification, comparable sample
counts) runs before anything is rendered; on mismatch the page blocks
the comparison with a clear message and offers an explicit "compare
anyway" override rather than silently overlaying incompatible runs.
generate_compare_page(output_path=None, title=None)
¶
Render the static, self-contained two-run comparison page.
Unlike the calibration/identification report generators, this takes
no run object — it emits a template that loads two
export_verification_report() JSON files client-side (drag-and-
drop or a file picker) and, after a mandatory compatibility check
(D3), renders a per-metric diff table and an overlaid before/after
series chart. No network request, no backend: the returned document
is fully self-contained and can be opened directly from disk.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
output_path
|
Optional[str]
|
If given, the HTML is also written to this path. |
None
|
title
|
Optional[str]
|
Optional page title. Defaults to a generic comparison title. |
None
|
Returns:
| Type | Description |
|---|---|
str
|
The rendered HTML document as a string. |
Source code in src/figaroh/tools/compare_report.py
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | |
stages¶
StageResult records: which step (data, fit, validation, physical, export)
ran, failed, fell back or did not run (#55).
Which step produced a result, and whether it ran, failed or fell back.
See docs/decisions/data-result-contract.md (#55). Identification and
calibration record one :class:StageResult per step they run on
obj.stages; results dictionaries carry them under "stages" and the
run archive writes them to stages.json. A stage that did not run has no
record, or an explicit not_run when that is worth stating.
record_stage(obj, stage, status, reason='', metrics=None, artifacts=None)
¶
Record stage on obj.stages, replacing an earlier record of it.
metrics maps a name to (value, unit) or to a bare value (unit
"").
Source code in src/figaroh/tools/stages.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | |
drop_stage(obj, stage)
¶
Remove the record of stage from obj.stages (a no-op if none).
Source code in src/figaroh/tools/stages.py
85 86 87 | |
stages_as_dicts(obj)
¶
obj.stages as plain dicts (for results dictionaries and JSON).
Source code in src/figaroh/tools/stages.py
90 91 92 | |
with_schema(obj, verdict)
¶
A verdict dict with schema_version and the run's stage records.
The records go under stage_records: the verdict's own stages is
the per-stage status map and must not be replaced (#63).
Source code in src/figaroh/tools/stages.py
95 96 97 98 99 100 101 102 103 104 105 | |
apply_to_verdict(verdict, obj, selected_stage='fit')
¶
Separate per-stage verdicts from the run's records (#63).
verdict.stages keeps its scoped entries (numerical_execution,
prediction, solver) and gains data, fit,
validation, physical and export from the records: pass,
fail, fallback (validation on training data: not held-out
evidence) or not_run; a stage with no record keeps
not_evaluated. data_provenance mirrors data.
Source code in src/figaroh/tools/stages.py
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | |
stages_line(obj)
¶
One-line terminal summary, e.g. data ok · fit ok · validation
fallback (training data, not held-out).
Source code in src/figaroh/tools/stages.py
143 144 145 146 147 148 149 150 151 152 153 154 | |
_report_common¶
Shared HTML/CSS primitives and the VerificationVerdict/ThresholdCheck
dataclasses used by both report generators.
Shared HTML/CSS primitives for the calibration and identification
diagnostic reports (tools/report.py and
tools/identification_report.py).
Calibration and identification produce structurally different diagnostics (iterative nonlinear fit with outlier removal vs. one-shot linear QR solve), so each gets its own report module — but both render as a self-contained HTML page with the same look, the same escaping rules, and the same confidence-tier vocabulary. This module holds only that shared, domain-independent layer.
ThresholdCheck(name, value, threshold, comparison, passed, status='pass', required=True, reason='')
dataclass
¶
One metric checked against one threshold.
VerificationVerdict(passed, checks, metrics, insights=list(), metadata=dict(), series=dict(), compat=dict(), status='not_evaluated', scope='thresholds', stages=dict(), policy=dict(), stage_records=list(), selected_stage='fit', splits=dict())
dataclass
¶
Machine-checkable pass/fail against a set of quality thresholds.
Produced by :func:evaluate_thresholds; insights/metadata/
series/compat are filled in by the caller
(BaseCalibration.verify() / BaseIdentification.verify())
after construction, since those are domain-specific / provenance
data rather than threshold arithmetic. metadata holds the full
nested provenance record from
:func:figaroh.tools.provenance.collect_run_provenance (run id,
asset identity, nominal model, config, software, data, timestamps).
evaluate_thresholds(metrics, thresholds)
¶
Evaluate explicit limits; missing required evidence cannot pass.
Specs accept required=False for advisory checks. Missing metrics are
recorded as not evaluated; computed nonfinite values fail. Empty policies
have no acceptance evidence and return not evaluated, with passed=False.
Source code in src/figaroh/tools/_report_common.py
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | |
scoped_verification(metrics, thresholds, scope, arrays, independent, prediction_keys, solver_success=None, facts=None)
¶
Build a scoped verdict without claiming unrequested model stages.
Execution verifies finite, nonempty numerical outputs. Prediction also requires independent measurements and explicit error limits for every requested output. Neither scope certifies physical feasibility or export.
facts maps a name to None (not evaluated), a bool, or a
(bool, reason) tuple whose reason is the message of a failing fact.
Source code in src/figaroh/tools/_report_common.py
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 | |
verification_json_data(data)
¶
Keep invalid evidence readable in strict JSON; status retains failure.
Source code in src/figaroh/tools/_report_common.py
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | |
build_provenance_metadata(config_file_path, robot_name)
¶
Git commit, config file hash, timestamp, robot name — for a
:class:VerificationVerdict's metadata field.
Source code in src/figaroh/tools/_report_common.py
779 780 781 782 783 784 785 786 787 788 789 | |
provenance¶
Run provenance metadata — git commit, config hash, timestamps, robot/asset identity — attached to every calibration/identification run.
Run provenance capture — the single source of truth for "what produced this fit": the nominal reference model, the exact config used, software versions, input data files, and (if configured) the physical asset identity. Consumed identically by the terminal report, the HTML report, the JSON verification verdict, and the run archive, so the four can never disagree about what produced a given result.
Reuses :func:figaroh.tools._report_common._git_commit_hash and
:func:figaroh.tools._report_common._config_file_sha256 rather than
duplicating hashing logic.
collect_splits(obj)
¶
Which data trained and which validated this run (#63).
From the data-contract objects when the run used them
(trajectory / observations and their validation counterparts:
files with sha256, session, adapter); "legacy input" otherwise,
whose files are listed under provenance data. validation_source
comes from the run's validation stage: held_out, or
training_fallback when no held-out data was available.
Source code in src/figaroh/tools/provenance.py
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | |
collect_run_provenance(obj, task)
¶
Build the full provenance record for one V&V run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
Any
|
A |
required |
task
|
str
|
|
required |
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
A JSON-serializable nested dict (see module docstring for the |
Dict[str, Any]
|
four consumers). Never raises: every sub-lookup is best-effort. |
Source code in src/figaroh/tools/provenance.py
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | |
run_archive¶
Writes each run to a timestamped results/runs/<robot>/<task>/<timestamp>/
directory (config snapshot, provenance JSON, report) instead of overwriting
a single results/ path.
Longitudinal run archive — a fleet's V&V history.
export_html_report()/export_verification_report() write to fixed
filenames that get overwritten by the next run, so a robot calibrated
monthly only ever has its most recent report on disk. :func:archive_run
instead writes each run to its own immutable, timestamped directory under
results/runs/{asset_id}/{task}/{timestamp}_{git_short}/ and appends a
one-line summary to results/runs/index.jsonl — a zero-dependency,
git-diffable, jq-able index of every run ever performed, per asset.
Call after :meth:~figaroh.identification.base_identification.BaseIdentification.solve
(and, typically, after export_html_report()/export_verification_report()
so their output gets copied in alongside the raw provenance/parameters).
compute_run_dir(obj, root='results/runs')
¶
Compute this run's dedicated directory path from provenance.
Deterministic for a given obj._run_provenance — safe to call more
than once (e.g. once for the HTML report's output_path, again for the
verdict's) and get back the identical path, since the timestamp is
read from the already-fixed provenance record, never re-derived from
wall clock.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
Any
|
A |
required |
root
|
str
|
Archive root directory (created if missing). |
'results/runs'
|
Returns:
| Name | Type | Description |
|---|---|---|
Path |
Path
|
The directory for this run, created if missing. |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If called before :meth: |
Source code in src/figaroh/tools/run_archive.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
archive_run(obj, run_dir)
¶
Finalize archiving into an already-computed run_dir.
Writes provenance.json / config.snapshot.yaml / parameters.csv, and appends the index.jsonl entry (reading run_dir/verdict.json for pass/metrics if the caller already wrote one there).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
obj
|
Any
|
A |
required |
run_dir
|
Path
|
The directory for this run (typically obtained via
:func: |
required |
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The path to this run's archive directory (echoed back for convenience). |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If called before :meth: |
Source code in src/figaroh/tools/run_archive.py
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | |
Linear Solver¶
Multivariate linear solver for robot parameter identification.
This module provides advanced linear regression solvers optimized for overdetermined systems (thin, tall matrices) with support for: - Multiple regularization methods (Ridge, Lasso, Elastic Net, Tikhonov) - Linear equality and inequality constraints - Robust regression methods - Physical parameter bounds - Iterative refinement for improved accuracy
LinearSolver(method='lstsq', regularization=None, alpha=0.0, l1_ratio=0.5, weights=None, constraints=None, bounds=None, max_iter=1000, tol=1e-06, verbose=False)
¶
Advanced linear solver for overdetermined systems: Ax = b
Optimized for robot identification where A is typically: - Dense (not sparse) - Large (many samples) - Thin (more rows than columns, overdetermined)
Attributes:
| Name | Type | Description |
|---|---|---|
method |
str
|
Solving method to use |
regularization |
str
|
Type of regularization |
alpha |
float
|
Regularization strength |
constraints |
dict
|
Linear constraints on solution |
bounds |
tuple
|
Box constraints on variables |
solver_info |
dict
|
Information about the solution |
Initialize linear solver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
str
|
Solving method (see METHODS) |
'lstsq'
|
regularization
|
str
|
'l1', 'l2', 'elastic_net', or None |
None
|
alpha
|
float
|
Regularization strength (>=0) |
0.0
|
l1_ratio
|
float
|
Elastic net mixing (0=Ridge, 1=Lasso) |
0.5
|
weights
|
ndarray
|
Sample weights for weighted least squares |
None
|
constraints
|
dict
|
Linear constraints: - 'A_eq': Equality constraint matrix (A_eq @ x = b_eq) - 'b_eq': Equality constraint vector - 'A_ineq': Inequality constraint matrix (A_ineq @ x <= b_ineq) - 'b_ineq': Inequality constraint vector |
None
|
bounds
|
tuple
|
Box constraints (lower, upper) for each variable |
None
|
max_iter
|
int
|
Maximum iterations for iterative methods |
1000
|
tol
|
float
|
Convergence tolerance |
1e-06
|
verbose
|
bool
|
Print solver information |
False
|
Source code in src/figaroh/tools/solver.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
solve(A, b)
¶
Solve the linear system Ax = b.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
A
|
ndarray
|
Design matrix (n_samples, n_features) |
required |
b
|
ndarray
|
Target vector (n_samples,) |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ndarray |
Solution vector x (n_features,) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If inputs are incompatible |
LinAlgError
|
If solution fails |
Source code in src/figaroh/tools/solver.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | |
solve_linear_system(A, b, method='lstsq', **kwargs)
¶
Convenience function to solve linear system Ax = b.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
A
|
ndarray
|
Design matrix (n_samples, n_features) |
required |
b
|
ndarray
|
Target vector (n_samples,) |
required |
method
|
str
|
Solving method |
'lstsq'
|
**kwargs
|
Additional arguments for LinearSolver |
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(solution x, solver_info dict) |
Example
A = np.random.randn(1000, 50) # 1000 samples, 50 features b = np.random.randn(1000) x, info = solve_linear_system(A, b, method='ridge', alpha=0.1)
Source code in src/figaroh/tools/solver.py
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 | |
The linear solver provides comprehensive solving methods for robot parameter identification:
- Basic methods: lstsq, QR decomposition, SVD
- Regularized methods: Ridge (L2), Lasso (L1), Elastic Net, Tikhonov
- Advanced methods: Constrained optimization, robust regression, weighted least squares
- Constraint support: Box constraints, linear equality/inequality constraints
- Quality metrics: RMSE, R², condition number, residual analysis
Robot Management¶
Robot(robot_urdf, package_dirs, isFext=False, freeflyer_ori=None, freeflyer_limits=None)
¶
Bases: RobotWrapper
Enhanced Robot class with advanced free-flyer support and visualization utilities.
This class extends RobotWrapper with: - Sophisticated free-flyer configuration and limits - Integrated visualization support - Convenient API for common robot operations - Enhanced error handling and validation
Initialize enhanced robot model from URDF.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
robot_urdf
|
str
|
Path to URDF file |
required |
package_dirs
|
str
|
Package directories for mesh files |
required |
isFext
|
bool
|
Whether to add floating base joint |
False
|
freeflyer_ori
|
Optional[ndarray]
|
Optional 3x3 rotation matrix for floating base orientation |
None
|
freeflyer_limits
|
Optional[Tuple[float, float]]
|
Optional custom limits for free-flyer (default: (-1, 1)) |
None
|
Source code in src/figaroh/tools/robot.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | |
num_joints
property
¶
Number of actuated joints (excluding universe and free-flyer).
actuated_joint_names
property
¶
Names of actuated joints only.
freeflyer_limits
property
¶
Current free-flyer position limits.
backend
property
¶
Lazily-created DynamicsBackend wrapping this robot's model.
Returns a PinocchioBackend that shares the same pin.Model and pin.Data as this Robot instance — no URDF re-loading, no model duplication. Used by RegressorBuilder and other tools to route dynamics computation through the backend abstraction.
Returns:
| Type | Description |
|---|---|
|
PinocchioBackend instance |
update_freeflyer_limits(limits)
¶
Update free-flyer limits dynamically.
Source code in src/figaroh/tools/robot.py
100 101 102 103 104 105 106 | |
display_q0(visualizer_type=None, q=None)
¶
Enhanced visualization with configuration options.
Source code in src/figaroh/tools/robot.py
108 109 110 111 112 113 114 115 116 117 118 119 120 121 | |
get_configuration_bounds()
¶
Get configuration space bounds with proper handling of quaternions.
Source code in src/figaroh/tools/robot.py
177 178 179 180 181 182 183 184 185 186 187 188 189 | |
validate_configuration(q)
¶
Validate if configuration is within bounds and constraints.
Source code in src/figaroh/tools/robot.py
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | |
__repr__()
¶
Enhanced string representation.
Source code in src/figaroh/tools/robot.py
210 211 212 213 214 215 216 217 | |
create_robot(robot_urdf, package_dirs=None, loader='figaroh', enhanced_features=True, **kwargs)
¶
Factory function to create robots with optional enhanced features.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
robot_urdf
|
str
|
Robot identifier or URDF path |
required |
package_dirs
|
Optional[str]
|
Package directories |
None
|
loader
|
str
|
Loader type from load_robot.py |
'figaroh'
|
enhanced_features
|
bool
|
If True, returns Robot class with enhanced features |
True
|
**kwargs
|
Additional arguments for loaders |
{}
|
Returns:
| Type | Description |
|---|---|
Union[Robot, RobotWrapper]
|
Robot instance (if enhanced_features=True) or RobotWrapper |
Source code in src/figaroh/tools/robot.py
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | |
load_robot(robot_urdf, package_dirs=None, isFext=False, load_by_urdf=True, robot_pkg=None, loader='figaroh', **kwargs)
¶
Load robot model from various sources with multiple loader options.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
robot_urdf
|
str
|
Path to URDF file or robot name for robot_description |
required |
package_dirs
|
Optional[str]
|
Package directories for mesh files |
None
|
isFext
|
bool
|
Whether to add floating base joint |
False
|
load_by_urdf
|
bool
|
Whether to load from URDF file (vs ROS param server) |
True
|
robot_pkg
|
Optional[str]
|
Name of robot package for path resolution |
None
|
loader
|
str
|
Loader type - "figaroh", "robot_description", "yourdfpy" |
'figaroh'
|
**kwargs
|
Additional arguments passed to the specific loader |
{}
|
Returns:
| Type | Description |
|---|---|
Union[Robot, RobotWrapper, Any]
|
Robot object based on loader type: |
Union[Robot, RobotWrapper, Any]
|
|
Union[Robot, RobotWrapper, Any]
|
|
Union[Robot, RobotWrapper, Any]
|
|
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If URDF file not found |
ImportError
|
If required packages not available |
ValueError
|
If the specified loader is not supported |
For loading by URDF, robot_urdf and package_dirs can be different.
1/ If package_dirs is not provided directly, robot_pkg is used to look up the package directory. 2/ If no mesh files, package_dirs and robot_pkg are not used. 3/ If load_by_urdf is False, the robot is loaded from the ROS parameter server. 4/ For robot_description loader, robot_urdf should be the robot name. 5/ For yourdfpy loader, returns URDF object suitable for viser visualization.
Source code in src/figaroh/tools/load_robot.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | |
get_available_loaders()
¶
Get information about available robot loaders.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
dict
|
Information about each loader and its availability |
Source code in src/figaroh/tools/load_robot.py
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | |
list_available_robots(loader='robot_description')
¶
List available robot descriptions for a given loader.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
loader
|
str
|
Loader type to check for available robots |
'robot_description'
|
Returns:
| Name | Type | Description |
|---|---|---|
list |
list
|
Available robot names |
Source code in src/figaroh/tools/load_robot.py
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 | |
Regressor Builder¶
Regressor matrix computation utilities for robot dynamic identification.
RegressorConfig(has_friction=False, has_actuator_inertia=False, has_joint_offset=False, is_joint_torques=True, is_external_wrench=False, force_torque=None, additional_columns=0)
dataclass
¶
Configuration for regressor computation.
extra_blocks()
¶
Enabled per-joint extra parameter blocks, in column order.
The order matches add_standard_additional_parameters:
viscous friction, static friction, actuator inertia, joint offset.
Source code in src/figaroh/tools/regressor.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 | |
RegressorBuilder(robot, config=None)
¶
Enhanced regressor builder with better organization.
Source code in src/figaroh/tools/regressor.py
52 53 54 55 56 57 58 59 60 61 62 63 64 | |
build_basic_regressor(q, v, a, identif_config=None)
¶
Build basic regressor matrix.
Source code in src/figaroh/tools/regressor.py
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | |
build_regressor_basic(robot, q, v, a, identif_config, tau=None)
¶
Legacy function for backward compatibility.
Source code in src/figaroh/tools/regressor.py
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | |
eliminate_non_dynaffect(W, params_std, tol_e=1e-06)
¶
Eliminate columns with small L2 norm.
Source code in src/figaroh/tools/regressor.py
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | |
get_index_eliminate(W, params_std, tol_e=1e-06)
¶
Get indices of columns to eliminate based on tolerance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
Joint torque regressor matrix |
required | |
params_std
|
Standard parameters dictionary |
required | |
tol_e
|
Tolerance value |
1e-06
|
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
|
Source code in src/figaroh/tools/regressor.py
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | |
build_regressor_reduced(W, idx_e)
¶
Build reduced regressor matrix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
Input regressor matrix |
required | |
idx_e
|
Indices of columns to eliminate |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ndarray |
Reduced regressor matrix |
Source code in src/figaroh/tools/regressor.py
322 323 324 325 326 327 328 329 330 331 332 333 | |
build_total_regressor_current(W_b_u, W_b_l, W_l, I_u, I_l, param_standard_l, identif_config)
¶
Build regressor for total least squares with current measurements.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W_b_u
|
Base regressor for unloaded case |
required | |
W_b_l
|
Base regressor for loaded case |
required | |
W_l
|
Full regressor for loaded case |
required | |
I_u
|
Joint currents in unloaded case |
required | |
I_l
|
Joint currents in loaded case |
required | |
param_standard_l
|
Standard parameters in loaded case |
required | |
identif_config
|
Dictionary of settings |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
|
Source code in src/figaroh/tools/regressor.py
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 | |
build_total_regressor_wrench(W_b_u, W_b_l, W_l, tau_u, tau_l, param_standard_l, identif_config)
¶
Build regressor for total least squares with external wrench measurements.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W_b_u
|
Base regressor for unloaded case |
required | |
W_b_l
|
Base regressor for loaded case |
required | |
W_l
|
Full regressor for loaded case |
required | |
tau_u
|
External wrench in unloaded case |
required | |
tau_l
|
External wrench in loaded case |
required | |
param_standard_l
|
Standard parameters in loaded case |
required | |
identif_config
|
Dictionary of settings. Must provide
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
|
Source code in src/figaroh/tools/regressor.py
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 | |
Robot Visualization¶
Enhanced robot visualization utilities with better performance.
VisualizationConfig(com_color=None, axes_color=None, force_color=None, bbox_color=None, scale_factor=1.0)
dataclass
¶
Configuration for robot visualization.
RobotVisualizer(model, data, viz, config=None)
¶
Enhanced robot visualizer with better organization.
Source code in src/figaroh/tools/robotvisualization.py
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | |
update_kinematics(q)
¶
Update robot kinematics efficiently.
Source code in src/figaroh/tools/robotvisualization.py
78 79 80 81 82 83 | |
display_com(q, frame_indices)
¶
Display center of mass positions with better naming.
Source code in src/figaroh/tools/robotvisualization.py
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | |
display_axes(q, axis_length=0.15, axis_radius=0.01)
¶
Display coordinate axes for joints.
Source code in src/figaroh/tools/robotvisualization.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | |
display_force(force, placement, scale=0.001, name='force_vector')
¶
Display force vector with better scaling.
Source code in src/figaroh/tools/robotvisualization.py
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
display_bounding_boxes(q, com_min, com_max, frame_indices)
¶
Display COM bounding boxes for optimization visualization.
Source code in src/figaroh/tools/robotvisualization.py
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | |
display_joints(q)
¶
Display joint frames efficiently.
Source code in src/figaroh/tools/robotvisualization.py
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | |
place(viz, name, M)
¶
Legacy placement function.
Source code in src/figaroh/tools/robotvisualization.py
251 252 253 254 | |
display_COM(model, data, viz, q, IDX)
¶
Legacy COM display function.
Source code in src/figaroh/tools/robotvisualization.py
257 258 259 260 261 262 263 | |
display_axes(model, data, viz, q)
¶
Legacy axes display function.
Source code in src/figaroh/tools/robotvisualization.py
266 267 268 269 270 | |
rotation_matrix_from_vectors(vec1, vec2)
¶
Legacy rotation function.
Source code in src/figaroh/tools/robotvisualization.py
273 274 275 276 277 | |
display_force(viz, phi, M_se3)
¶
Legacy force display function.
Source code in src/figaroh/tools/robotvisualization.py
280 281 282 283 284 | |
display_bounding_boxes(viz, model, data, q, COM_min, COM_max, IDX)
¶
Legacy bounding box display function.
Source code in src/figaroh/tools/robotvisualization.py
287 288 289 290 291 292 293 294 295 296 297 298 299 | |
display_joints(viz, model, data, q)
¶
Legacy joint display function.
Source code in src/figaroh/tools/robotvisualization.py
302 303 304 305 306 | |
Robot Collisions¶
Enhanced collision detection and visualization utilities.
CollisionManager(robot, geom_model=None, geom_data=None, viz=None)
¶
Enhanced collision detection with better performance and safety.
Source code in src/figaroh/tools/robotcollisions.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | |
setup_collision_pairs(srdf_model_path=None)
¶
Setup collision pairs with optional SRDF filtering.
Source code in src/figaroh/tools/robotcollisions.py
78 79 80 81 82 83 84 85 86 87 88 | |
check_collisions(q, update_geometry=True)
¶
Check for collisions at given configuration.
Source code in src/figaroh/tools/robotcollisions.py
90 91 92 93 94 95 96 97 98 99 100 101 102 | |
get_collision_details()
¶
Get detailed collision information.
Source code in src/figaroh/tools/robotcollisions.py
104 105 106 107 108 109 110 111 112 113 | |
get_collision_distances(collision_details=None)
¶
Get minimum distances for collision pairs.
Source code in src/figaroh/tools/robotcollisions.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
get_all_distances()
¶
Get distances for all collision pairs.
Source code in src/figaroh/tools/robotcollisions.py
135 136 137 138 139 140 141 142 143 144 145 | |
print_collision_pairs()
¶
Print all collision pair information.
Source code in src/figaroh/tools/robotcollisions.py
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | |
visualize_collisions(collision_details=None)
¶
Visualize collision contacts with enhanced display.
Source code in src/figaroh/tools/robotcollisions.py
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | |
CollisionWrapper(robot, geom_model=None, geom_data=None, viz=None)
¶
Bases: CollisionManager
Legacy wrapper.
.. deprecated:: 1.0
Use :class:CollisionManager. Removal in 2.0.
Source code in src/figaroh/tools/robotcollisions.py
234 235 236 237 238 239 240 241 242 243 244 245 246 247 | |
add_collisions()
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
249 250 251 252 | |
remove_collisions(srdf_model_path)
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
254 255 256 257 | |
computeCollisions(q, geom_data=None)
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
259 260 261 262 263 | |
getCollisionList()
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
265 266 267 | |
getCollisionDistances(collisions=None)
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
269 270 271 | |
getDistances()
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
273 274 275 | |
getAllpairs()
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
277 278 279 | |
check_collision(q)
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
281 282 283 | |
displayCollisions(collisions=None)
¶
Legacy method.
Source code in src/figaroh/tools/robotcollisions.py
285 286 287 | |
add_non_adjacent_pairs(model, geom_model)
¶
Add a collision pair for every two geometries on non-adjacent bodies.
Geometries on the same joint, or on a joint and its parent (adjacent
bodies, usually in contact by design), are not paired. Fixed bodies
belong to the joint they are merged into (universe for the world).
Returns the number of pairs added.
Source code in src/figaroh/tools/robotcollisions.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | |
QR Decomposition¶
QR decomposition utilities for robot parameter identification.
This module provides QR-based helpers to:
- identify a set of base parameters (a full-rank subset) from a rank-deficient regressor
- express those base parameters as linear combinations of the original/full parameters
In particular, both QR workflows compute a matrix $M$ such that:
$$ \phi_{base} = M\,\theta_{full} $$
where columns of $M$ correspond to the remaining parameter vector ordered as
params_r.
Note
In FIGAROH, params_r typically refers to the list of
standard parameter
names remaining after column elimination (e.g., after removing all-zero
regressor columns). It is not necessarily the complete set of standard
parameters (which is often available as a dictionary like params_std).
Use :meth:QRDecomposer.expand_mapping_matrix_to_full if you need an "M"
defined over a full, canonical parameter ordering.
The resulting row ordering matches the returned base-parameter expressions.
QRResult(rank, base_indices, pivot_order, W_b, beta, M, base_param_expressions, phi_b, phi_b_nom, method, diag_R, cond_R1)
dataclass
¶
Structured output of a QR base-parameter decomposition.
All numerical fields are stored at full float64 precision. Rounding for display is done only at the expression-building stage.
Attributes:
| Name | Type | Description |
|---|---|---|
rank |
int
|
Identified numerical rank of the regressor. |
base_indices |
List[int]
|
Column indices into |
pivot_order |
Optional[List[int]]
|
Full pivot permutation used by the pivoting path
(from :func: |
W_b |
ndarray
|
Base regressor matrix, shape |
beta |
ndarray
|
Dependency coefficient matrix, shape |
M |
ndarray
|
Base mapping matrix satisfying |
base_param_expressions |
List[str]
|
Human-readable expression strings, length
|
phi_b |
Optional[ndarray]
|
Identified base-parameter values, shape |
phi_b_nom |
Optional[ndarray]
|
Nominal base-parameter values from |
method |
str
|
|
diag_R |
ndarray
|
Absolute diagonal of |
cond_R1 |
float
|
Condition number of the |
QRDecomposer(tolerance=TOL_QR, beta_tolerance=TOL_BETA, relative_tolerance=None, deterministic=True)
¶
Enhanced QR decomposition handler for robot parameter identification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
deterministic
|
bool
|
Choose base columns with
:func: |
True
|
Source code in src/figaroh/tools/qrdecomposition.py
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | |
get_M()
¶
Return the last computed base mapping matrix M (or None).
Source code in src/figaroh/tools/qrdecomposition.py
211 212 213 | |
get_M_labels()
¶
Return (base_param_expr, params_r) labels for the last stored M.
Source code in src/figaroh/tools/qrdecomposition.py
215 216 217 | |
get_base_indices()
¶
Return the base-column indices (into params_r) from the last
double_decomposition() call, or None if not yet run.
These indices select the columns of a reduced regressor (built
with the same params_r ordering) that reproduce base-parameter
predictions: tau ≈ W_reduced[:, base_indices] @ phi_base. Since
the base/dependent column split reflects the robot's kinematic
structure rather than a specific trajectory, this selection is
valid for any regressor built with the same params_r ordering
— e.g. to evaluate an identified model on held-out validation data.
Source code in src/figaroh/tools/qrdecomposition.py
219 220 221 222 223 224 225 226 227 228 229 230 231 | |
get_diagnostics()
¶
Return stability diagnostics from the last decomposition.
Keys
rank: identified rank.
diag_R: absolute diagonal of R at the factorisation point.
cond_R1: condition number of the R[:rank, :rank] block.
method: "pivoting" or "double".
Source code in src/figaroh/tools/qrdecomposition.py
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | |
decompose(W_e, params_r, tau=None, params_std=None, method='double')
¶
Unified entry point that returns a structured :class:QRResult.
This is the preferred API for new code. It delegates to either
:meth:decompose_with_pivoting (method="pivoting") or
:meth:double_decomposition (method="double"), but always
returns a :class:QRResult regardless of path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W_e
|
ndarray
|
Full regressor matrix, shape |
required |
params_r
|
List[str]
|
Remaining parameter names (columns of |
required |
tau
|
Optional[ndarray]
|
Torque/effort vector, shape |
None
|
params_std
|
Optional[Dict[str, float]]
|
Optional prior parameter dict used to compute
|
None
|
method
|
str
|
|
'double'
|
Returns:
| Type | Description |
|---|---|
QRResult
|
A fully-populated :class: |
Source code in src/figaroh/tools/qrdecomposition.py
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | |
decompose_with_pivoting(tau, W_e, params_r)
¶
Perform QR decomposition with column pivoting.
This identifies an effective rank, computes base parameters, and
returns a base regressor W_b along with a dict mapping
base-parameter expressions to values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tau
|
ndarray
|
Torque/effort vector, shape (m,). |
required |
W_e
|
ndarray
|
Full regressor matrix, shape (m, n). |
required |
params_r
|
List[str]
|
Remaining parameter names (columns of W_e), length n. |
required |
Returns:
| Type | Description |
|---|---|
Tuple[ndarray, Dict[str, float]]
|
(W_b, base_parameters) where: - W_b has shape (m, r) with r = rank(W_e) - base_parameters maps expression strings (length r) to values. |
Source code in src/figaroh/tools/qrdecomposition.py
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 | |
double_decomposition(tau, W_e, params_r, params_std=None)
¶
Perform the "double QR" workflow for base-parameter identification.
This follows a two-stage procedure
1) Identify an independent/base subset via QR on W_e.
2) Regroup columns and run a second QR to compute linear
dependencies.
The output base parameters are returned as expression strings built from the original parameter names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tau
|
ndarray
|
Torque/effort vector, shape (m,). |
required |
W_e
|
ndarray
|
Full regressor matrix, shape (m, n). |
required |
params_r
|
List[str]
|
Remaining parameter names (columns of W_e), length n. |
required |
params_std
|
Optional[Dict[str, float]]
|
Optional mapping from full parameter name -> value. If provided, also returns the standard-parameter values of the base expressions. Returns: If params_std is None: (W_b, base_parameters, params_base_expr, phi_b) else: (W_b, base_parameters, params_base_expr, phi_b, phi_b_nom) |
None
|
Where
|
|
required |
Source code in src/figaroh/tools/qrdecomposition.py
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | |
compute_nominal_base_parameters(base_params, regroup_params, beta, params_std)
¶
Compute numerical values of base parameters from priors.
This computes the numerical value of each base expression using:
phi_std[i] = params_std[base_param]
+ sum_j beta[i, j] * params_std[dep_param]
Source code in src/figaroh/tools/qrdecomposition.py
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 | |
get_base_mapping_matrix_pivoting(W_e, params_r)
¶
Return the base-parameter mapping matrix M for pivoting-QR.
The matrix M satisfies phi_base = M @ theta_r where
theta_r is ordered as params_r (the remaining parameters).
Row order matches the returned base-parameter expression strings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W_e
|
ndarray
|
Full regressor matrix, shape (m, n). |
required |
params_r
|
List[str]
|
Remaining parameter names (columns of W_e), length n. |
required |
Returns:
| Type | Description |
|---|---|
Tuple[ndarray, List[str]]
|
(M, base_params_expr) - M has shape (r, n) where r is the identified rank - base_params_expr is a list[str] of length r |
Source code in src/figaroh/tools/qrdecomposition.py
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 | |
get_base_mapping_matrix_double(W_e, params_r)
¶
Return the base-parameter mapping matrix M for the double-QR workflow.
The returned M satisfies phi_base = M @ theta_r with columns
ordered as params_r (the remaining parameters).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W_e
|
ndarray
|
Full regressor matrix, shape (m, n). |
required |
params_r
|
List[str]
|
Remaining parameter names (columns of W_e), length n. |
required |
Returns:
| Type | Description |
|---|---|
Tuple[ndarray, List[str], List[int], List[int]]
|
(M, base_params_expr, base_indices, regroup_indices) - M has shape (r, n) - base_params_expr is a list[str] of length r - base_indices and regroup_indices index into params_r |
Source code in src/figaroh/tools/qrdecomposition.py
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 | |
get_base_mapping_matrix(W_e, params_r, method='double')
¶
Convenience wrapper to retrieve the base mapping matrix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W_e
|
ndarray
|
Full regressor matrix, shape (m, n). |
required |
params_r
|
List[str]
|
Remaining parameter names (columns of W_e), length n. |
required |
method
|
str
|
"double" (default) or "pivoting". |
'double'
|
Returns:
| Type | Description |
|---|---|
Tuple[ndarray, List[str]]
|
(M, base_params_expr) |
Raises:
| Type | Description |
|---|---|
ValueError
|
if method is not recognized. |
Source code in src/figaroh/tools/qrdecomposition.py
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 | |
expand_mapping_matrix_to_full(M, params_r, full_param_names)
staticmethod
¶
Expand an M defined on params_r into a full parameter ordering.
This is useful when the QR routines operate on a reduced set of parameters (after removing all-zero columns), but you want a mapping matrix defined over the complete standard-parameter list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
M
|
ndarray
|
Base mapping matrix for remaining parameters, shape (r, n_r). |
required |
params_r
|
List[str]
|
Remaining parameter names (columns of |
required |
full_param_names
|
List[str]
|
Full/canonical parameter ordering to expand into. |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
M_full of shape (r, n_full) where columns not present in |
ndarray
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
if M has incompatible shape or if a name in params_r is missing from full_param_names. |
Source code in src/figaroh/tools/qrdecomposition.py
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 | |
deterministic_column_pivots(W, names=None, *, tol=TOL_QR, relative_tol=None, tie_rtol=TIE_RTOL)
¶
Pick independent regressor columns the same way on every machine.
LAPACK's pivoted QR (scipy.linalg.qr(pivoting=True)) takes the column
of largest residual norm at each step. Columns whose norms tie to rounding
error (common in rigid-body regressors) are then ordered by BLAS noise,
so the selected set, and with it phi_base, depends on the platform.
This greedy selection (Gram-Schmidt on the R factor, with
re-orthogonalisation) takes the largest-residual column too, but treats
all columns within tie_rtol of the largest as tied and picks the one
with the smallest name (falling back to the smallest index when names
is None). The outcome then depends on the column names, not on their
order in W or on rounding noise below tie_rtol.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
W
|
ndarray
|
Regressor, shape |
required |
names
|
Optional[List[str]]
|
Column names, length n. Ties are broken by name. |
None
|
tol
|
float
|
Absolute rank threshold on the residual norm. |
TOL_QR
|
relative_tol
|
Optional[float]
|
If set, threshold is |
None
|
tie_rtol
|
float
|
Relative width of the tie band. |
TIE_RTOL
|
Returns:
| Type | Description |
|---|---|
ndarray
|
|
int
|
entries are the selected columns in selection order, followed by the |
Tuple[ndarray, int]
|
remaining columns in ascending name (index) order. |
Source code in src/figaroh/tools/qrdecomposition.py
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | |
QR_pivoting(tau, W_e, params_r, tol_qr=TOL_QR)
¶
Legacy QR pivoting function.
.. deprecated:: 1.0
Use :meth:QRDecomposer.decompose_with_pivoting. Removal in 2.0.
Source code in src/figaroh/tools/qrdecomposition.py
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 | |
double_QR(tau, W_e, params_r, params_std=None, tol_qr=TOL_QR)
¶
Legacy double QR function.
.. deprecated:: 1.0
Use :meth:QRDecomposer.double_decomposition. Removal in 2.0.
Source code in src/figaroh/tools/qrdecomposition.py
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 | |
get_baseParams(W_e, params_r, params_std=None, tol_qr=TOL_QR)
¶
Legacy function for getting base parameters.
Source code in src/figaroh/tools/qrdecomposition.py
928 929 930 931 932 933 934 935 936 937 938 939 | |
get_baseIndex(W_e, params_r, tol_qr=TOL_QR)
¶
Legacy function for getting base indices.
Source code in src/figaroh/tools/qrdecomposition.py
942 943 944 945 946 947 948 949 950 | |
build_baseRegressor(W_e, idx_base)
¶
Legacy function for building base regressor.
Source code in src/figaroh/tools/qrdecomposition.py
953 954 955 | |
cond_num(W_b, norm_type=None)
¶
Calculate condition number with various norms.
Source code in src/figaroh/tools/qrdecomposition.py
958 959 960 961 962 963 964 965 | |
redistribute_min_norm(M, phi_base)
¶
Minimum-norm redistribution of base-parameter values onto the full
standard-parameter set, via the Moore-Penrose pseudoinverse of M.
Given $\phi_{base} = M\,\theta_r$, returns
$\hat\theta_r = M^+\,\phi_{base}$: the minimum-L2-norm $\theta_r$
consistent with the identified $\phi_{base}$, i.e. each redundant
group's fitted value is spread across its members instead of being
concentrated on one arbitrary representative (the effective default
when only the base subset is reported and everything else is left at
its nominal value). Round-trips exactly:
M @ redistribute_min_norm(M, phi_base) == phi_base (up to floating
point), so predictions built from the redistributed vector are
unchanged from those built from the base-only fit.
This does not add information: non-identifiable directions stay non-identifiable. It only picks a less arbitrary point among the (infinite) equally-valid ways to split an identified combination back onto its individually non-identifiable members.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
M
|
ndarray
|
Base-mapping matrix, shape |
required |
phi_base
|
ndarray
|
Fitted base-parameter values, shape |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
|
Source code in src/figaroh/tools/qrdecomposition.py
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 | |
propagate_covariance_min_norm(M, C_base)
¶
Propagate base-parameter covariance through the minimum-norm map.
Returns $C_{full} = M^+\,C_{base}\,(M^+)^T$ — the covariance of the
minimum-norm estimator (:func:redistribute_min_norm), conditional
on having committed to that redistribution choice. It is not the
true uncertainty of each individual standard parameter: along
directions M cannot see, the data provides literally zero
information, and this propagation reports a finite number reflecting
the estimator's own sensitivity to noise in phi_base, not an
unconditional physical uncertainty. Callers surfacing this to users
must label it as such.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
M
|
ndarray
|
Base-mapping matrix, shape |
required |
C_base
|
ndarray
|
Covariance of the fitted base parameters, shape
|
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
|
Source code in src/figaroh/tools/qrdecomposition.py
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 | |
Robot IPOPT¶
General IPOPT-based optimization framework for robotics applications.
This module provides a comprehensive, flexible framework for setting up and solving nonlinear optimization problems using IPOPT (Interior Point OPTimizer), with specialized support for robotics applications including trajectory optimization, parameter identification, and general robot optimization problems.
Key Features
- Unified IPOPT interface with robotics-specific configurations
- Automatic differentiation support for gradients and Jacobians
- Built-in problem validation and result analysis
- Specialized classes for trajectory optimization problems
- Factory functions for rapid problem setup
- Comprehensive logging and iteration tracking
Main Classes
- IPOPTConfig: Configuration management for IPOPT solver settings
- BaseOptimizationProblem: Abstract base class for optimization problems
- RobotIPOPTSolver: High-level solver interface with result analysis
- TrajectoryOptimizationProblem: Specialized class for trajectory problems
Usage Examples
Basic trajectory optimization:
from figaroh.tools.robotipopt import IPOPTConfig, RobotIPOPTSolver
# Create custom problem class
class MyProblem(BaseOptimizationProblem):
def objective(self, x):
return np.sum(x**2) # Minimize sum of squares
def constraints(self, x):
return np.array([x[0] + x[1] - 1.0]) # x[0] + x[1] = 1
# ... implement other required methods
# Solve the problem
problem = MyProblem()
config = IPOPTConfig.for_trajectory_optimization()
solver = RobotIPOPTSolver(problem, config)
success, results = solver.solve()
Using the factory function:
from figaroh.tools.robotipopt import create_trajectory_solver
def my_objective(x):
return np.sum(x**2)
def my_constraints(x):
return np.array([x[0] + x[1] - 1.0])
def get_bounds():
var_bounds = ([-10, -10], [10, 10])
cons_bounds = ([0], [0])
return var_bounds, cons_bounds
def initial_guess():
return [0.5, 0.5]
solver = create_trajectory_solver(
my_objective, my_constraints, get_bounds, initial_guess
)
success, results = solver.solve()
Complete robotics example:
import numpy as np
from figaroh.tools.robotipopt import (
BaseOptimizationProblem, RobotIPOPTSolver, IPOPTConfig
)
class RobotTrajectoryProblem(BaseOptimizationProblem):
def __init__(self, robot, waypoints, active_joints):
super().__init__("RobotTrajectory")
self.robot = robot
self.waypoints = waypoints
self.active_joints = active_joints
self.n_joints = len(active_joints)
self.n_waypoints = len(waypoints)
self.n_vars = self.n_joints * self.n_waypoints
def get_variable_bounds(self):
# Joint limits for all waypoints
lb = [-np.pi] * self.n_vars
ub = [np.pi] * self.n_vars
return lb, ub
def get_constraint_bounds(self):
# Boundary conditions (start/end positions)
n_constraints = 2 * self.n_joints
return [0] * n_constraints, [0] * n_constraints
def get_initial_guess(self):
# Linear interpolation between start and end
return np.linspace(
self.waypoints[0], self.waypoints[-1],
self.n_waypoints * self.n_joints
)
def objective(self, x):
# Minimize trajectory smoothness (squared accelerations)
q = x.reshape(self.n_waypoints, self.n_joints)
acc = np.diff(q, n=2, axis=0) # Second differences
return np.sum(acc**2)
def constraints(self, x):
# Enforce boundary conditions
q = x.reshape(self.n_waypoints, self.n_joints)
constraints = np.concatenate([
q[0] - self.waypoints[0], # Start position
q[-1] - self.waypoints[-1] # End position
])
return constraints
# Usage
problem = RobotTrajectoryProblem(robot, waypoints, active_joints)
config = IPOPTConfig.for_trajectory_optimization()
solver = RobotIPOPTSolver(problem, config)
if solver.validate_problem_setup():
success, results = solver.solve()
if success:
optimal_trajectory = results['x_opt'].reshape(
problem.n_waypoints, problem.n_joints
)
print("Optimization successful!")
print(f"Final objective: {results['obj_val']:.6f}")
print(solver.get_solution_summary())
Dependencies
- cyipopt: Python interface to IPOPT solver
- numpy: Numerical computations
- numdifftools: Automatic differentiation (fallback)
References
- IPOPT documentation: https://coin-or.github.io/Ipopt/
- cyipopt: https://github.com/mechmotum/cyipopt
IPOPTConfig(tolerance=1e-06, acceptable_tolerance=0.0001, max_iterations=3000, max_cpu_time=1000000.0, print_level=5, output_file=None, hessian_approximation='limited-memory', warm_start=True, check_derivatives=True, linear_solver='mumps', custom_options=dict())
dataclass
¶
Configuration parameters for IPOPT solver.
This class provides a convenient way to set IPOPT solver options with sensible defaults for robotics applications. It includes predefined configurations for common robotics optimization scenarios.
The configuration is designed to work well with: - Trajectory optimization problems (smooth, continuous trajectories) - Parameter identification (high-precision parameter estimation) - General robotics optimization (balanced performance/accuracy)
Attributes:
| Name | Type | Description |
|---|---|---|
tolerance |
float
|
Primary convergence tolerance for optimization. Default: 1e-6. Smaller values increase precision but runtime. |
acceptable_tolerance |
float
|
Fallback tolerance if primary fails. Default: 1e-4. Used when primary tolerance cannot be achieved. |
max_iterations |
int
|
Maximum number of optimization iterations. Default: 3000. Increase for complex problems. |
max_cpu_time |
float
|
Maximum CPU time in seconds. Default: 1e6. Prevents infinite loops in difficult problems. |
print_level |
int
|
IPOPT output verbosity (0-12). Default: 5. Higher values provide more detailed output. |
output_file |
Optional[str]
|
File to save IPOPT output. Default: None. Useful for debugging and analysis. |
hessian_approximation |
str
|
Hessian computation method. Default: "limited-memory". Options: "exact", "limited-memory". |
warm_start |
bool
|
Use previous solution as starting point. Default: True. Speeds up subsequent optimizations. |
check_derivatives |
bool
|
Enable derivative checking. Default: True. Helps detect implementation errors. |
linear_solver |
str
|
Linear algebra solver backend. Default: "mumps". Options: "mumps", "ma27", "ma57", "ma77". |
custom_options |
Dict[str, Any]
|
Additional IPOPT options. Default: {}. For advanced users to set specialized options. |
Examples:
Basic usage:
# Use default configuration
config = IPOPTConfig()
# Customize specific parameters
config = IPOPTConfig(
tolerance=1e-8,
max_iterations=5000,
print_level=3
)
Predefined configurations:
# For trajectory optimization (speed-focused)
config = IPOPTConfig.for_trajectory_optimization()
# For parameter identification (precision-focused)
config = IPOPTConfig.for_parameter_identification()
Custom IPOPT options:
config = IPOPTConfig(
custom_options={
"mu_strategy": "adaptive",
"nlp_scaling_method": "gradient-based"
}
)
Note
All string options in custom_options should be provided as strings. They will be automatically encoded to bytes for IPOPT compatibility.
to_ipopt_options()
¶
Convert configuration to IPOPT option dictionary.
Transforms the configuration parameters into the format expected by IPOPT, including proper encoding of string options to bytes.
Returns:
| Type | Description |
|---|---|
Dict[str, Any]
|
Dict[str, Any]: Dictionary of IPOPT options ready for use with cyipopt.Problem.add_option() |
Note
All string values are automatically encoded to bytes as required by the IPOPT C interface via cyipopt.
Source code in src/figaroh/tools/robotipopt.py
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | |
for_trajectory_optimization()
classmethod
¶
Create configuration optimized for trajectory optimization problems.
This configuration prioritizes convergence speed over extreme precision, making it suitable for real-time or interactive trajectory planning. Uses adaptive barrier parameter strategy for better convergence.
Returns:
| Name | Type | Description |
|---|---|---|
IPOPTConfig |
IPOPTConfig
|
Optimized configuration for trajectory problems. |
Source code in src/figaroh/tools/robotipopt.py
331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 | |
for_parameter_identification()
classmethod
¶
Create configuration optimized for parameter identification problems.
This configuration prioritizes high precision over speed, making it suitable for accurate parameter estimation in robotics applications. Uses exact Hessian computation and monotone barrier strategy for numerical stability.
Returns:
| Name | Type | Description |
|---|---|---|
IPOPTConfig |
IPOPTConfig
|
Optimized configuration for parameter identification. |
Source code in src/figaroh/tools/robotipopt.py
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | |
BaseOptimizationProblem(name='OptimizationProblem')
¶
Bases: ABC
Abstract base class for IPOPT optimization problems.
This class defines the interface that all IPOPT problems must implement. Subclasses should implement the objective function, constraints, and their derivatives (or use automatic differentiation).
The class provides default implementations for gradient and Jacobian computation using automatic differentiation via numdifftools. For better performance, subclasses can override these methods with analytical derivatives.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable name for the optimization problem. |
logger |
Logger
|
Logger instance for this problem. |
iteration_data |
Dict
|
Storage for tracking optimization iterations. |
callback_data |
Dict
|
Storage for passing data between methods. |
Required Methods (must be implemented by subclasses): - get_variable_bounds(): Return variable bounds as (lower, upper) - get_constraint_bounds(): Return constraint bounds as (lower, upper) - get_initial_guess(): Return initial guess for optimization variables - objective(x): Evaluate objective function at point x - constraints(x): Evaluate constraint functions at point x
Optional Methods (have default implementations): - gradient(x): Compute objective gradient (uses auto-diff by default) - jacobian(x): Compute constraint Jacobian (uses auto-diff by default) - hessian(x, lagrange, obj_factor): Compute Hessian (IPOPT approx by default) - intermediate(...): Callback for iteration tracking
Examples:
Basic implementation:
class QuadraticProblem(BaseOptimizationProblem):
def get_variable_bounds(self):
return ([-10, -10], [10, 10])
def get_constraint_bounds(self):
return ([0], [0]) # Equality constraint
def get_initial_guess(self):
return [1.0, 1.0]
def objective(self, x):
return x[0]**2 + x[1]**2 # Minimize sum of squares
def constraints(self, x):
return np.array([x[0] + x[1] - 1.0]) # x[0] + x[1] = 1
With custom derivatives:
class CustomProblem(BaseOptimizationProblem):
# ... implement required methods ...
def gradient(self, x):
# Custom analytical gradient
return np.array([2*x[0], 2*x[1]])
def jacobian(self, x):
# Custom analytical Jacobian
return np.array([[1.0, 1.0]])
Initialize the optimization problem.
Source code in src/figaroh/tools/robotipopt.py
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | |
get_variable_bounds()
abstractmethod
¶
Get bounds for optimization variables.
Returns:
| Type | Description |
|---|---|
Tuple[List[float], List[float]]
|
Tuple of (lower_bounds, upper_bounds) |
Source code in src/figaroh/tools/robotipopt.py
466 467 468 469 470 471 472 473 474 | |
get_constraint_bounds()
abstractmethod
¶
Get bounds for constraints.
Returns:
| Type | Description |
|---|---|
Tuple[List[float], List[float]]
|
Tuple of (constraint_lower_bounds, constraint_upper_bounds) |
Source code in src/figaroh/tools/robotipopt.py
476 477 478 479 480 481 482 483 484 | |
get_initial_guess()
abstractmethod
¶
Get initial guess for optimization variables.
Returns:
| Type | Description |
|---|---|
List[float]
|
Initial guess as list of floats |
Source code in src/figaroh/tools/robotipopt.py
486 487 488 489 490 491 492 493 494 | |
objective(x)
abstractmethod
¶
Evaluate objective function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
Optimization variables |
required |
Returns:
| Type | Description |
|---|---|
float
|
Objective function value |
Source code in src/figaroh/tools/robotipopt.py
496 497 498 499 500 501 502 503 504 505 506 507 | |
constraints(x)
abstractmethod
¶
Evaluate constraint functions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
Optimization variables |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Constraint function values |
Source code in src/figaroh/tools/robotipopt.py
509 510 511 512 513 514 515 516 517 518 519 520 | |
gradient(x)
¶
Compute gradient of objective function.
Default implementation uses automatic differentiation. Override for custom implementations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
Optimization variables |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Gradient vector |
Source code in src/figaroh/tools/robotipopt.py
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 | |
jacobian(x)
¶
Compute Jacobian of constraint functions.
Default implementation uses automatic differentiation. Override for custom implementations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
Optimization variables |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Jacobian matrix |
Source code in src/figaroh/tools/robotipopt.py
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 | |
hessian(x, lagrange, obj_factor)
¶
Compute Hessian of Lagrangian.
Default implementation returns False to use IPOPT's approximation. Override for custom implementations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
ndarray
|
Optimization variables |
required |
lagrange
|
ndarray
|
Lagrange multipliers |
required |
obj_factor
|
float
|
Objective scaling factor |
required |
Returns:
| Type | Description |
|---|---|
Union[bool, ndarray]
|
Hessian matrix or False to use approximation |
Source code in src/figaroh/tools/robotipopt.py
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 | |
intermediate(alg_mod, iter_count, obj_value, inf_pr, inf_du, mu, d_norm, regularization_size, alpha_du, alpha_pr, ls_trials)
¶
Intermediate callback for iteration tracking.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alg_mod
|
int
|
Algorithm mode |
required |
iter_count
|
int
|
Iteration count |
required |
obj_value
|
float
|
Current objective value |
required |
inf_pr
|
float
|
Primal infeasibility |
required |
inf_du
|
float
|
Dual infeasibility |
required |
mu
|
float
|
Barrier parameter |
required |
d_norm
|
float
|
Step size |
required |
regularization_size
|
float
|
Regularization parameter |
required |
alpha_du
|
float
|
Dual step size |
required |
alpha_pr
|
float
|
Primal step size |
required |
ls_trials
|
int
|
Line search trials |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True to continue optimization, False to stop |
Source code in src/figaroh/tools/robotipopt.py
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | |
RobotIPOPTSolver(problem, config=None)
¶
General IPOPT solver for robotics optimization problems.
This class provides a high-level interface for solving optimization problems using IPOPT, with built-in support for result analysis, error handling, and problem validation specifically designed for robotics applications.
Features
- Automatic problem setup and configuration
- Built-in problem validation before solving
- Comprehensive result analysis and logging
- Solution history tracking for multiple solves
- Robotics-specific error handling and diagnostics
- Support for iterative solving and warm starts
Attributes:
| Name | Type | Description |
|---|---|---|
problem |
BaseOptimizationProblem
|
The optimization problem to solve. |
config |
IPOPTConfig
|
IPOPT solver configuration. |
logger |
Logger
|
Logger for solver operations. |
last_solution |
ndarray
|
Most recent optimization solution. |
last_info |
Dict
|
Most recent IPOPT solver information. |
solve_history |
List[Dict]
|
History of all solve attempts. |
Examples:
Basic usage:
# Create problem and solver
problem = MyOptimizationProblem()
solver = RobotIPOPTSolver(problem)
# Solve the problem
success, results = solver.solve()
if success:
print(f"Optimal solution: {results['x_opt']}")
print(f"Objective value: {results['obj_val']}")
With custom configuration:
# Create custom configuration
config = IPOPTConfig(
tolerance=1e-8,
max_iterations=5000,
print_level=3
)
# Create solver with custom config
solver = RobotIPOPTSolver(problem, config)
# Validate problem before solving
if solver.validate_problem_setup():
success, results = solver.solve()
Multiple solves with warm start:
solver = RobotIPOPTSolver(problem)
# First solve
success1, results1 = solver.solve()
# Modify problem parameters...
problem.update_parameters(new_params)
# Second solve (uses warm start automatically)
success2, results2 = solver.solve()
# Access solve history
print(f"Solved {len(solver.solve_history)} problems")
Initialize the IPOPT solver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
problem
|
BaseOptimizationProblem
|
Optimization problem to solve |
required |
config
|
Optional[IPOPTConfig]
|
IPOPT configuration (default: trajectory optimization config) |
None
|
Source code in src/figaroh/tools/robotipopt.py
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 | |
solve()
¶
Solve the optimization problem.
Performs the complete optimization process including problem setup, IPOPT configuration, solving, and result analysis. The method handles all IPOPT interactions and provides comprehensive error handling and logging.
Returns:
| Type | Description |
|---|---|
Tuple[bool, Dict[str, Any]]
|
Tuple[bool, Dict[str, Any]]: A tuple containing: - success (bool): True if optimization succeeded, False otherwise - results (Dict[str, Any]): Dictionary containing: * 'x_opt': Optimal solution vector * 'obj_val': Final objective function value * 'status': IPOPT exit status code * 'status_msg': Human-readable status message * 'solve_time': Total optimization time in seconds * 'iterations': Number of iterations performed * 'iteration_data': Detailed iteration history * 'callback_data': Custom data from problem callbacks * 'ipopt_info': Complete IPOPT solver information * 'success': Copy of success flag for convenience |
Raises:
| Type | Description |
|---|---|
Exception
|
If critical errors occur during problem setup or solving. Non-critical errors are caught and returned in results. |
Note
IPOPT status codes for success: 0 (solved) and 1 (solved to
acceptable level). All other codes, including -1 (maximum number
of iterations exceeded), indicate failure or early termination;
the last iterate is still returned in x_opt.
Source code in src/figaroh/tools/robotipopt.py
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 | |
get_solution_summary()
¶
Get a summary of the last solution.
Source code in src/figaroh/tools/robotipopt.py
846 847 848 849 850 851 852 853 854 855 856 857 858 859 | |
validate_problem_setup()
¶
Validate that the optimization problem is properly set up.
Returns:
| Type | Description |
|---|---|
bool
|
True if problem appears valid, False otherwise |
Source code in src/figaroh/tools/robotipopt.py
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | |
TrajectoryOptimizationProblem(name='TrajectoryOptimization')
¶
Bases: BaseOptimizationProblem
Specialized optimization problem for trajectory optimization.
This class provides a framework for trajectory optimization problems with common patterns like waypoint parameterization and constraint handling.
Initialize trajectory optimization problem.
Source code in src/figaroh/tools/robotipopt.py
918 919 920 921 922 923 924 925 926 927 928 | |
set_objective_function(obj_func)
¶
Set custom objective function.
Source code in src/figaroh/tools/robotipopt.py
930 931 932 | |
set_constraint_function(cons_func)
¶
Set custom constraint function.
Source code in src/figaroh/tools/robotipopt.py
934 935 936 | |
objective(x)
¶
Evaluate objective function.
Source code in src/figaroh/tools/robotipopt.py
938 939 940 941 942 943 944 945 | |
constraints(x)
¶
Evaluate constraint functions.
Source code in src/figaroh/tools/robotipopt.py
947 948 949 950 951 952 953 954 | |
create_trajectory_solver(objective_func, constraint_func, get_bounds_func, initial_guess_func, name='CustomTrajectory')
¶
Factory function to create a trajectory optimization solver.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
objective_func
|
Callable[[ndarray], float]
|
Function to evaluate objective |
required |
constraint_func
|
Callable[[ndarray], ndarray]
|
Function to evaluate constraints |
required |
get_bounds_func
|
Callable[[], Tuple[Tuple[List, List], Tuple[List, List]]]
|
Function that returns ((var_lb, var_ub), (cons_lb, cons_ub)) |
required |
initial_guess_func
|
Callable[[], List[float]]
|
Function that returns initial guess |
required |
name
|
str
|
Problem name |
'CustomTrajectory'
|
Returns:
| Type | Description |
|---|---|
RobotIPOPTSolver
|
Configured IPOPT solver |
Source code in src/figaroh/tools/robotipopt.py
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 | |
Random Data Generation¶
generate_waypoints(N, robot, mlow, mhigh)
¶
Generate random values for joint positions, velocities, accelerations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
N
|
Number of samples |
required | |
robot
|
Robot model object |
required | |
mlow
|
Lower bound for random values |
required | |
mhigh
|
Upper bound for random values |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(q, v, a) joint position, velocity, acceleration arrays |
Source code in src/figaroh/tools/randomdata.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |
generate_waypoints_fext(N, robot, mlow, mhigh)
¶
Generate random values for joints with external forces.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
N
|
Number of samples |
required | |
robot
|
Robot model object |
required | |
mlow
|
Lower bound for random values |
required | |
mhigh
|
Upper bound for random values |
required |
Returns:
| Name | Type | Description |
|---|---|---|
tuple |
(q, v, a) joint position, velocity, acceleration arrays |
Source code in src/figaroh/tools/randomdata.py
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | |
get_torque_rand(N, robot, q, v, a, identif_config)
¶
Calculate random torque values including various dynamic effects.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
N
|
Number of samples |
required | |
robot
|
Robot model object |
required | |
q
|
Joint positions array |
required | |
v
|
Joint velocities array |
required | |
a
|
Joint accelerations array |
required | |
identif_config
|
Dictionary of dynamic parameters |
required |
Returns:
| Name | Type | Description |
|---|---|---|
array |
Joint torques array |
Source code in src/figaroh/tools/randomdata.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
URDF Export¶
Applies calibrated joint parameters back onto a URDF file.
URDF exporter for identified/calibrated robot parameters.
Reads a nominal URDF and produces a modified URDF by applying parameter
overlays. Parameter names encode the semantics: d_px_joint2 is additive
(geometric offset), m_link1 is absolute (mass override).
This is used after identification or calibration to materialize results into a tangible URDF file for downstream use (simulation, visualization, model-based control).
Two parameter categories
Joint-level parameters (auto-applied to the URDF): These directly modify the URDF's joint origins, link inertias, and dynamics attributes. They come from figaroh's identification or calibration solvers and can be applied automatically:
- Joint placement (in the joint frame): ``d_px_{joint}``,
``d_py_{joint}``, ``d_pz_{joint}``, ``d_phix_{joint}``,
``d_phiy_{joint}``, ``d_phiz_{joint}``; a joint's six values are
composed as ``origin * SE3(exp3(d_phi), d_p)``
- Joint offset / calibration (additive): ``offsetPX_{joint}``,
``offsetPY_{joint}``, ``offsetPZ_{joint}``, ``offsetRX_{joint}``,
``offsetRY_{joint}``, ``offsetRZ_{joint}``
- Mass (absolute): ``m_{link}``
- Standard inertial parameters (absolute, all ten per link):
``m_``, ``mx_``, ``my_``, ``mz_``, ``Ixx_``, ``Ixy_``, ``Iyy_``,
``Ixz_``, ``Iyz_``, ``Izz_`` + ``{link}``; see
:func:`_apply_standard_inertial` for the conventions
- Viscous/static friction (absolute): ``fv_{joint}``, ``fs_{joint}``
- Armature (absolute): ``Ia_{joint}``
- Joint elasticity (additive): ``k_PX_{joint}``, ..., ``k_RZ_{joint}``,
stored as a custom ``<dynamics elasticity>`` attribute that URDF
parsers ignore: it does not change the reloaded kinematics
Inertial targets (``m_`` ... ``Izz_``) name a link, or a moving joint
as identification does (``get_standard_parameters`` keys by Pinocchio
joint); a joint resolves to its child link.
Refused (``ValueError``, nothing written): legacy ``off_{joint}``; names
targeting a joint or link the URDF does not have; a joint carrying both
``offset*`` and ``d_*``; a partial inertial set (first moments or tensor
entries without all ten parameters); a joint target whose child link has
massive links attached by fixed joints (Pinocchio merges them into the
joint's body, so the estimate does not belong to one URDF link); a set
with ``m <= 0``; and, unless ``allow_infeasible=True``, a set that is not
physically consistent.
Metrology frame parameters (user-defined, not auto-applied):
These define the transformation between the robot (URDF) and the
external measurement system (mocap, camera, chessboard, etc.).
They depend on the calibration setup, not on the URDF itself.
export_urdf() will not auto-apply them; instead it logs a
reminder and returns them as metadata for the user to configure::
base_px, base_py, base_pz, base_phix, base_phiy, base_phiz
Transform from the **metrology frame** (e.g. mocap world,
Vicon origin) to the robot's ``base_link``.
Default: identity (no offset from origin).
pEEx_{frame}, pEEy_{frame}, pEEz_{frame}
phiEEx_{frame}, phiEEy_{frame}, phiEEz_{frame}
Transform from the last robot joint (e.g. ``arm_7_joint``,
``head_2_link``) to the **measurement frame** mounted on the
end-effector. What this frame is depends on calibration type:
- **Mocap calibration**: optical marker cluster frame
(markers attached to the end-effector).
- **Eye-hand calibration**: camera optical frame
(e.g. ``xtion_rgb_optical_frame``) or chessboard frame
(pattern on the gripper).
Default: identity (measurement frame coincides with the joint).
Typical usage::
from figaroh.tools.urdf_exporter import export_urdf, frame_settings_doc
# Joint-level params (auto-applied to URDF)
params = {
"d_px_joint2": 0.05,
"m_link1": 2.5,
"fv_joint1": 0.2,
}
modified_path = export_urdf("robot.urdf", params, verbose=True)
# Metrology frames (user-defined — see frame_settings_doc())
defaults = frame_settings_doc()
# → prints descriptions + default values for base and EE frame params
is_kinematic_correction(name)
¶
Whether name is a joint correction that changes the reloaded
kinematics: a full_params placement (d_*) or a joint offset
(offset*). Frame, elastic and dynamic parameters are not.
Source code in src/figaroh/tools/urdf_exporter.py
299 300 301 302 303 304 | |
frame_settings_doc(*, calibration_type=None, verbose=True)
¶
Return default metrology-frame parameter values with explanations.
These parameters define the transformation between the robot and the external measurement system. They are not intrinsic to the URDF and must be configured by the user for each calibration setup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibration_type
|
Optional[str]
|
Optional hint for context-specific defaults.
|
None
|
verbose
|
bool
|
If True (default), prints descriptions to stderr. |
True
|
Returns:
| Type | Description |
|---|---|
dict
|
dict with default values for all base-frame and EE-frame params:: { "base_px": 0.0, ... "pEEx_arm_7_link": 0.0, ... } |
Source code in src/figaroh/tools/urdf_exporter.py
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | |
export_urdf(nominal_urdf_path, params, *, output_path=None, verbose=False, allow_infeasible=False, merged_bodies='refuse', psd_eig_tol=-1e-10)
¶
Apply identified/calibrated joint-level parameters to a nominal URDF.
This function auto-applies parameters that modify the URDF directly
(joint placements, mass, inertias, friction, etc. — see module docstring).
It does not apply metrology frame parameters (base_*, pEE*,
phiEE*); those depend on the calibration setup and must be
configured by the user — see :func:frame_settings_doc.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nominal_urdf_path
|
Union[str, Path]
|
Path to the nominal (reference) URDF file. |
required |
params
|
dict
|
Dictionary of |
required |
output_path
|
Optional[Union[str, Path]]
|
Path for the modified URDF. If |
None
|
verbose
|
bool
|
If True, log which params were applied. |
False
|
allow_infeasible
|
bool
|
Write a complete inertial set whose pseudo-inertia is not positive semidefinite, with a warning, instead of raising. |
False
|
merged_bodies
|
str
|
What to do when an inertial set names a joint whose
Pinocchio body also holds massive links attached by fixed joints.
|
'refuse'
|
psd_eig_tol
|
float
|
Smallest pseudo-inertia eigenvalue still accepted as feasible. Pass the tolerance the estimate was accepted with, so an estimate accepted upstream is not refused here. |
-1e-10
|
Returns:
| Type | Description |
|---|---|
str
|
Absolute path to the modified URDF file (joint params applied). Use |
str
|
func: |
str
|
separately. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If nominal_urdf_path does not exist. |
ValueError
|
If a parameter name is unknown, names a joint or link
the URDF does not have, belongs to a category the exporter does
not write (legacy |
Source code in src/figaroh/tools/urdf_exporter.py
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 | |
Geometric Calibration Export¶
Produces the PAL Robotics robot_state_publisher.geometric_calibration
runtime-correction YAML (e.g. /etc/calibration/master_calibration.yaml)
from a solved calibrator's redistributed parameters — a different deploy
target from URDF Export above (a small runtime overlay applied on top of
the original URDF, not a modified URDF file).
PAL Robotics robot_state_publisher geometric-calibration deploy file.
Produces the runtime joint-correction YAML PAL robots (TIAGo, TIAGo Pro,
TALOS, ...) read at /etc/calibration/master_calibration.yaml
(robot_state_publisher: geometric_calibration: {<joint>_<axis>: value}),
directly from a solved BaseCalibration.
This is a different deploy target from
:mod:figaroh.tools.urdf_exporter: that module bakes corrections into a
modified URDF file; this one produces a small runtime correction
overlay PAL's robot_state_publisher applies on top of the original,
unmodified URDF at startup. Both read the same d_px_{joint}-style
(full_params) and offsetRZ_{joint}-style (joint_offset)
parameter names — this module reuses
:func:figaroh.tools.urdf_exporter._parse_param_name rather than
re-deriving that parsing. The keys are additive deltas on the URDF
<origin> xyz and rpy as written; pass nominal_urdf so they are
exact (figaroh-plus#123).
The values come from
:meth:~figaroh.calibration.base_calibration.BaseCalibration.redistribute_parameters:
for the structural method, the weighted minimum-norm lift of the fitted
base parameters onto every joint (figaroh-plus#111), so a joint whose
correction was represented by another parameter in the fit still gets its
share; for the other estimation methods, the fitted joint parameters. Use
:meth:~figaroh.calibration.base_calibration.BaseCalibration.joint_corrections
to write the same values into a URDF.
build_geometric_calibration(calibrator, *, min_sigma=None, nominal_urdf=None, allow_failed_fit=False)
¶
Build a PAL robot_state_publisher.geometric_calibration dict
from a solved BaseCalibration instance's redistributed parameters.
Per-joint kinematic corrections are included: full_params
placements (d_px_{joint} etc.) and joint_offset offsets
(offsetRZ_{joint} etc., figaroh-plus#123), both converted to
additive deltas on the joint's URDF origin. Marker/tip, base-frame and
elasticity parameters are not kinematic joint corrections in
:func:~figaroh.tools.urdf_exporter._parse_param_name's registry and
are dropped by the category check. The base frame needs no exclusion:
the lift holds the base-frame rows at 0, so every lifted value is a joint
correction.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibrator
|
A solved |
required | |
min_sigma
|
Optional[float]
|
If given, only include parameters with
|
None
|
nominal_urdf
|
Optional[str]
|
The URDF the robot runs, to which the deltas are
added. Its |
None
|
allow_failed_fit
|
bool
|
export although the |
False
|
Returns:
| Type | Description |
|---|---|
Dict[str, Dict[str, Dict[str, float]]]
|
|
Raises:
| Type | Description |
|---|---|
CalibrationError
|
The |
Source code in src/figaroh/tools/geometric_calibration_export.py
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | |
export_geometric_calibration_yaml(calibrator, output_path, *, min_sigma=None, header_comment=None, nominal_urdf=None, allow_failed_fit=False)
¶
:func:build_geometric_calibration + write as YAML, PAL deploy-ready.
PAL's master_calibration.yaml layout (robot_state_publisher:
geometric_calibration: with <joint>_<axis> keys), so the output
drops in at /etc/calibration/master_calibration.yaml on a PAL robot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibrator
|
A solved |
required | |
output_path
|
str
|
Destination YAML file path. |
required |
min_sigma
|
Optional[float]
|
See :func: |
None
|
nominal_urdf
|
Optional[str]
|
See :func: |
None
|
header_comment
|
Optional[str]
|
Optional single-line comment written above the YAML document (e.g. source data file, sample count, RMSE), for provenance. |
None
|
allow_failed_fit
|
bool
|
See :func: |
False
|
Returns:
| Type | Description |
|---|---|
str
|
|
Source code in src/figaroh/tools/geometric_calibration_export.py
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 | |
Export Validation¶
FK consistency checks and interactive viser visualization for a calibration-exported URDF.
URDF model comparison and validation utilities.
Provides tools to compare two URDF models (nominal vs. modified after parameter application) through forward-kinematics analysis and viser-based visualization.
Typical usage::
from figaroh.tools.export_validation import URDFComparison
comp = URDFComparison("robot.urdf", "robot_modified.urdf")
print(comp.fk_consistency_check())
# → FkConsistencyResult(rmse_position=0.051, rmse_orientation=0.098, ...)
# Interactive viser visualization:
comp.show_trajectory_animation()
comp.show_static_grid()
PoseDelta(translation, rotation, twist, q)
dataclass
¶
FK pose difference between two models at a single configuration.
The delta is expressed as M_nominal⁻¹ · M_modified, i.e. the
SE3 transform from the nominal end-effector frame to the modified one.
position_error()
¶
Euclidean distance in meters.
Source code in src/figaroh/tools/export_validation.py
62 63 64 | |
orientation_error()
¶
Angle-axis magnitude in radians.
Source code in src/figaroh/tools/export_validation.py
66 67 68 | |
FkConsistencyResult(rmse_position, rmse_orientation, max_position, max_orientation, per_sample)
dataclass
¶
Aggregated FK consistency check — compares nominal vs. exported URDF FK.
PoseError(q, position_error_mm, orientation_error_deg, pose_delta, label='')
dataclass
¶
FK error at a single static configuration with user label.
URDFComparison(nominal_urdf, modified_urdf)
¶
Compare two URDF models via FK analysis and viser visualization.
Loads both URDFs into Pinocchio for FK computation and into yourdfpy (when needed) for viser rendering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
nominal_urdf
|
Union[str, Path]
|
Path to the original/reference URDF. |
required |
modified_urdf
|
Union[str, Path]
|
Path to the URDF after parameter application. |
required |
Source code in src/figaroh/tools/export_validation.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | |
fk_consistency_check(n_samples=100, seed=42)
¶
Check the exported URDF reproduces the calibrated FK numerically.
This is a file-integrity check — it verifies the exported URDF file is self-consistent with the calibration results. It does NOT test against ground-truth measurements (use calibration validation for that).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_samples
|
int
|
Number of random configurations to sample. |
100
|
seed
|
int
|
Random seed for reproducibility. |
42
|
Returns:
| Type | Description |
|---|---|
FkConsistencyResult
|
FkConsistencyResult with aggregated FK consistency metrics. |
Source code in src/figaroh/tools/export_validation.py
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
static_poses(poses=None)
¶
Compute FK errors at specific joint configurations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
poses
|
Optional[List[Union[List[float], ndarray]]]
|
List of joint configuration vectors. If None, a default set of 20 meaningful poses is used (covering home, limits, mixed-angle combinations). |
None
|
Returns:
| Type | Description |
|---|---|
List[PoseError]
|
List of PoseError, one per configuration. |
Source code in src/figaroh/tools/export_validation.py
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | |
show_overlay(server=None, port=8080, orig_color=(51, 102, 229), mod_color=(229, 51, 51), duration=5.0)
¶
Display both models overlaid in viser.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
server
|
Existing viser server, or None to create one. |
None
|
|
port
|
int
|
Port for new server (ignored if server is given). |
8080
|
orig_color
|
Tuple[int, int, int]
|
RGB color for the original model (0-255). |
(51, 102, 229)
|
mod_color
|
Tuple[int, int, int]
|
RGB color for the modified model (0-255). |
(229, 51, 51)
|
duration
|
float
|
Seconds to keep the display open. |
5.0
|
Source code in src/figaroh/tools/export_validation.py
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | |
show_trajectory_animation(n_configs=50, seed=42, server=None, port=8080, duration=10.0)
¶
Animate through random joint configs, tracing end-effector paths.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_configs
|
int
|
Number of random configurations to animate. |
50
|
seed
|
int
|
Random seed. |
42
|
server
|
Existing viser server, or None to create one. |
None
|
|
port
|
int
|
Port for new server. |
8080
|
duration
|
float
|
Seconds to keep the display open after animation. |
10.0
|
Source code in src/figaroh/tools/export_validation.py
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 | |
show_static_grid(poses=None, server=None, port=8080, duration=15.0, spacing=2.0)
¶
Display a grid of static configurations with error labels.
Each cell shows both models at the same configuration, with the position (mm) and orientation (deg) error overlaid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
poses
|
Optional[List[Union[List[float], ndarray]]]
|
Joint configurations. If None, uses 24 default poses. |
None
|
server
|
Existing viser server, or None to create one. |
None
|
|
port
|
int
|
Port for new server. |
8080
|
duration
|
float
|
Seconds to keep the display open. |
15.0
|
spacing
|
float
|
Distance between grid cells in meters. |
2.0
|
Source code in src/figaroh/tools/export_validation.py
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | |
show_interactive_validation(n_trajectory=50, seed=42, port=8080)
¶
Interactive combined visualization with trajectory, static comparison, error plots, replay, and opacity controls.
Opens a single viser server containing:
- Trajectory animation — 50 random configurations with path traces for both nominal and modified models. Replay button allows re-running.
- Static pose comparison — overlays both models at the same configuration with opacity slider for the modified model.
- Error plots — uplot charts for trajectory and static pose errors (position in mm, orientation in degrees).
- Pose selector — slider to cycle through static configurations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_trajectory
|
int
|
Number of random configurations to animate. |
50
|
seed
|
int
|
Random seed for reproducibility. |
42
|
port
|
int
|
Port for the viser server. |
8080
|
Source code in src/figaroh/tools/export_validation.py
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | |