The layout sheet and the cell report¶
Two more documents a cell hands over, both derived from the scene the way the I/O list and the BOM are: the layout sheet — the cell seen from above, as a proposal drawing or the plant's 2D CAD wants it — and the cell report — one page that gathers the numbers everything else measured, with digests of supplied attachments. For a document set with a recorded common input revision, use batch export and verification.
scene.export_layout("layout.svg", scale=200) # for the review
scene.export_layout("layout.dxf") # for the 2D CAD (mm)
report = scene.cell_report({"cycle": tl}, scenarios=runs,
deliverables=["layout.svg", "layout.dxf", "bom.csv", "io.csv"])
report.save("cell_report.md")
report.save("cell_report.json")
The layout sheet¶
Scene.layout projects the scene onto the floor and
renders it; Scene.export_layout writes it,
picking the format from the extension:
| format | what it is |
|---|---|
svg |
a self-contained drawing (scale pixels per metre, default 100) — opens in a browser, drops into a slide |
dxf |
a minimal R12 file — LINE / POLYLINE / CIRCLE / TEXT on named layers, millimetres (units="m" for metres) — opens in any 2D CAD, no dependency on either side |
json |
the drawn items in world metres, for a front end that wants to draw them itself |
What is on it, layer by layer (the DXF layer names in capitals):
- EQUIPMENT — every visible obstacle as its footprint: the convex hull of a primitive, the bounding rectangle of a mesh.
- GROUND — floor slabs and painted markings, i.e. anything whose top is at
or below
ground_z(2 cm by default): drawn faint, and left out of the extents so a 20 m floor does not shrink the cell to a stamp. - ROBOT / REACH — each robot's base as a mark, and, when the robot came
from the catalog with a
reach_mm, its reach as a dashed circle. - DEVICE — conveyor and sink zones (dashed, with the direction of travel), a linear axis's travel, a vehicle's route with its stations.
- SENSOR — zone boxes and beams.
- FRAME — named frames as crosses, labelled by their last segment.
- LABEL — names on the things worth naming: a part
pinned to an obstacle or a group labels it (
Pedestal (PD-500)); the rest label by their name-derived unit, so a USD subtree reads once asConveyorand twelve fence panels once asfence. A ring-shaped group (a fence, a guard) is labelled above its top edge, a compact one at its centre. - DIM / GRID — the overall width and depth, and a metre grid.
frames=False, labels=False, reach=False, grid=None switch the extras
off; title= names the sheet.
The extent the sheet measures is also a query of its own:
Scene.footprint returns min, max, width,
depth, area and height — the plan-view bounding rectangle of the
equipment, ground excluded — so assert scene.footprint()["area"] <= 20
is a one-liner.
What the sheet is not: a drawing with tolerances, a title-block standard, or a projection of every prim's true outline. It is the plan a proposal needs and a layout engineer can trace over — one kind of drawing, honestly derived.
The cell report¶
Scene.cell_report gathers, in one
CellReport:
| section | from | what |
|---|---|---|
robots |
the scene | name, DOF, base position, catalog identity and reach when known |
cycles |
the timelines you pass | duration, step spans, robot busy time and utilization, the branches taken, and the tightest clearance re-scanned against the scene each timeline was baked from (clearance_dt, None to skip) |
io |
the I/O map | point counts by kind and status, node usage, lint findings |
scenarios |
a ScenarioRuns |
the matrix — which scenario completed at what cycle, which stalled and why |
machines |
the parts, devices, sensors and nodes | every machine tool (machine_tool.* part): its door — an axis the machine drives or a loose leaf — with drive, stroke and end-of-travel lanes, the panel's buttons, and the controller hosting its program |
bom |
the BOM | line count, unidentified count, quantity per category, numeric totals |
footprint |
the layout | the plan-view extent |
deliverables |
the paths you pass | size and SHA-256; origin=external_attachment because these calls do not establish the file's input revision |
Pass the cycles as a {name: timeline} dict, a list, or a single
SequenceTimeline; a ScenarioRuns passed as scenarios= fills the matrix
and, when no timelines are given, supplies the cycles too. The matrix is
the FAT sheet's verdict column: a fault authored as a scenario (a stuck
switch, an open wire, the E-stop in) either lets the cycle through or
stalls it, and the row says which and at what step. Every section is
a plain dict or list — report.cycles[0]["duration"],
report.footprint["area"], report.io["unbound"] — and the report renders
the same data as Markdown (to_markdown() / save("…md")) or JSON
(to_json() / save("…json")), with every optional value present as
null so the JSON keeps one shape whether or not a bake was supplied.
The report reads; it does not judge. The numbers it shows are the ones a regression test asserts on:
report = build_cell().cell_report({"cycle": tl})
assert report.cycle_time("cycle") <= 8.0
assert report.min_clearance() > 0.05
assert report.io["unbound"] == 0
assert report.footprint["area"] <= 20.0
assert report.bom["unidentified"] == 0
Pass this report to bt.review(scene, report=report)
to list missing design inputs, known subtotals and unperformed evaluations
alongside these observations. A completed scenario is an execution result;
its expected-behaviour acceptance still needs the project's test conditions.
The document set as one thing¶
Use bt.export_cell to generate the selected files from an independent
snapshot and fresh timelines. Its sequences scope applies to the bake,
I/O list, topology, interlocks, PLCopen, robot scripts and report I/O summary.
The saved project and generated Python retain the full authored cell;
this includes the physical connection plan. exports=["connections"]
writes the requirements CSV/Markdown/JSON and a per-power-supply capacity CSV.
The main batch report also contains these results. Physical requirements
cover the entire cell regardless of the selected operating programs;
the manifest records which programs were evaluated. Multiple programs
produce separate robot scripts. Unsupported scripts and lowering warnings
are recorded as unresolved issues, together with PLCopen stub blocks and
failed scenario executions.
manifest = bt.export_cell(scene, "deliverables/rev1", name="cell",
sequences=["pick"], scenarios=True)
verified = bt.verify_export(manifest, scene=scene)
assert verified["same_revision"]
review = bt.review(scene, manifest=manifest, stage="design",
required=["deliverables"])
review.save("design_review.md") # keep later review files outside the package
The output directory must be new or empty. Files are generated in a
temporary directory, verified, then moved into place. A failed export leaves
no partial package. Existing files can be included with attachments=[...];
they are copied under attachments/ and stay external_attachment.
<name>_manifest.json records:
| field | recorded evidence |
|---|---|
input / input_sha256 |
serialized authored project, catalog IDs and recorded revisions, resolved local geometry paths with SHA-256 and size |
conditions |
ordered program and scenario sets, simulation scan interval and time limit, planner stride, kinematic mode, clearance sampling, USD rate, layout scale and controller export defaults |
generator |
botrail version, native extension hash, Python implementation hashes and manifest validator version |
run_sha256 |
fingerprint of input hash, conditions and generator |
files |
relative path, format, origin, SHA-256, size; generated files also carry input/run fingerprints |
issues |
missing catalog revisions, omitted scripts, lowering warnings, PLCopen stubs and scenario execution failures |
The report includes provenance and exporter issues. The manifest hashes
both report formats as well as the other files; the report lists the files
generated before it. verify_export detects changed, missing and unlisted
files, inconsistent manifest metadata and paths escaping the package.
scene= also compares the current serialized authored input and observed
asset hashes. For example, replacing a freshly generated DI5 script with an
old DI2 script fails verification, even when the I/O CSV still matches.
ok means the integrity checks succeeded. same_revision additionally
requires generated files only; external attachments never count as verified
generated evidence. These flags do not establish design acceptance: a package
can have matching revisions and still contain stub implementations or failed
scenario executions. Requiring deliverables in bt.review keeps those
issues visible as unresolved work.
Geometry hashes identify the local inputs observed at export; assets are
checked again before publication. The snapshot retains loaded models and
colliders without reconstructing them through the project serializer. A
manifest is not a portable asset archive or a signed provenance certificate,
and verification does not rerun simulation. .botrail portability remains
subject to the existing project format's asset support. Catalog revisions
that were not recorded are reported as unknown, rather than looked up later.
export_cell
¶
export_cell(
scene,
out: str | Path,
*,
name: str = "cell",
exports=None,
sequences=None,
scenarios: bool = False,
dt: float = 0.01,
max_duration: float = 120.0,
plan_resolution: float = 0.05,
clearance_dt: float | None = 0.01,
title: str | None = None,
fps: float = 30.0,
scale: float = 100.0,
attachments=None,
) -> Path
Write a manifest and selected documents from a fresh snapshot and bake.
out must be absent or empty; publish into a new directory for each
revision. exports=None means all formats. Every program-dependent
exporter uses sequences (all by default). Bakes are kinematic.
Existing timelines/scripts cannot be substituted for generated results.
attachments are copied and explicitly remain unverified external inputs.
The returned path is usable with :func:verify_export and bt.review.
Export warnings and omitted programs are recorded as unresolved issues.
verify_export
¶
Check manifest consistency and every file, optionally against a live cell.
ok covers integrity and the optional current serialized input match.
same_revision additionally requires no external attachments. Exporter
warnings remain in issues; neither boolean is engineering acceptance.
Source assets need not be installed when checking a handed-over package.
Unlisted files, missing files and paths outside the package are rejected.