Table Maps
.ftmap is a real data contract, not just an editor export format.
It sits at the intersection of:
- runtime table geometry (
WorldMap, exposed in Python asTableMap) - simulator scenes
- localization
- code generation
- Web IDE map editing
The important part is that not every consumer speaks the exact same shape today.
Canonical runtime types
The runtime geometry implementation is:
WorldMapMapSegment
Python exposes WorldMap as TableMap.
Source of truth:
Runtime .ftmap format: v1
The current runtime binding validates:
format == "flowchart-table-map"version == 1
The accepted in-memory shape is:
{
"format": "flowchart-table-map",
"version": 1,
"table": { "widthCm": 200, "heightCm": 100 },
"lines": [
{
"kind": "line",
"startX": 50,
"startY": 50,
"endX": 150,
"endY": 50,
"widthCm": 1.5
},
{
"kind": "wall",
"startX": 0,
"startY": 0,
"endX": 0,
"endY": 100,
"widthCm": 0
}
]
}
Field meanings:
table.widthCm,table.heightCm: table bounds in cmlines[]: all authored segmentskind:"line"or"wall"startX/startY/endX/endY: segment endpointswidthCm: line thickness or wall thickness
The bindings default missing kind to "line" when building from Python dicts.
Coordinate convention split
This is the detail people usually miss:
- on-disk
.ftmapcoordinates use top-left origin - in-memory
WorldMapuses bottom-left origin,+Xright,+Yup
The loader flips Y on ingest so runtime math stays in standard bottom-up field coordinates.
That is not an implementation accident; it is explicitly documented in the C++ header and in the bundled scene README.
Runtime map queries
TableMap is not just a bag of segments. The runtime binding exposes geometric queries used by sensors and localization:
is_on_lineis_on_black_lineis_on_walldistance_to_nearest_linedistance_to_nearest_wallsensor_field_positionsensor_is_on_linesensor_is_on_wall
It also exposes:
segments()lines()walls()all_segments
Important nuance:
walls()includes synthesized table-border wallsall_segmentscontains authored segments only
Sensor projection convention
Sensor offsets use robot-local coordinates:
forward_cm: along robot headingstrafe_cm: 90 degrees CCW from heading
That means positive strafe_cm is robot-left in the map module.
This is intentionally preserved bit-for-bit with the earlier Python table_map behavior so localization and sensor code do not drift.
IDE/editor format: v2
The Web IDE frontend already has a richer persistent format:
- same
format: "flowchart-table-map" version: 2layers[]transitions[]- optional
activeLayerId
The v2 shape supports:
- stacked layers
- named layers with optional
zCm - transitions/ramps/portals between layers
This is defined in:
Important compatibility reality
Today:
- runtime
WorldMapbinding accepts v1 - Web IDE accepts v1 and v2, then normalizes to v2 internally
- IDE backend also normalizes maps to v2
So “the IDE can edit it” does not automatically mean “the runtime TableMap.from_ftmap(...) binding accepts the exact same structure.”
That split must be kept in mind when moving maps between:
- editor persistence
- project YAML
- simulator materialization
- runtime table map construction
Codegen behavior
robot.physical.table_map may be either:
- a file path string
- an inline map object
During local codegen:
- if
table_mapis a string, the CLI loads the.ftmapfile withjson.load - replaces the path with the parsed object
- then emits
TableMap.from_ftmap(...)into generated robot code
That means codegen expects the runtime-consumable dict shape by the time the generator runs.
If a path was not resolved to a dict, codegen treats that as an error.
Project config implications
This is the practical contract:
- file-path form is convenient for authored map files
- generated runtime code receives an inline dict
- runtime
TableMap.from_ftmap(...)is the final constructor
So if you are debugging a project map issue, check all three layers:
- the
.ftmapfile on disk - the normalized/embedded
robot.physical.table_map - the runtime binding’s expected format version
Bundled scenes
The scene fixtures in raccoon-lib/scenes/ are currently documented as v1:
empty_table.ftmapsingle_line.ftmapwall_box.ftmap
These are useful reference files because they show the runtime-accepted single-layer schema directly.
What still matters for future cleanup
The ecosystem is in a transitional state:
- runtime map binding is still v1-oriented
- IDE/editor persistence is already v2-oriented
So any future “map format” change must answer a concrete question first:
- is this a runtime compatibility change
- an editor-storage change
- or only an IDE-side normalization change
If those are not kept separate, table-map bugs become very hard to diagnose.