What this is: A redesign of how we paint meaning onto the drone’s indoor map — moving from one flat list of labels to three independent “semantic zone” layers. Why it’s here: It’s the moment our map stopped being a single-choice paint-by-numbers and became something closer to how a human actually reads a room — danger, things-worth-mapping, and mission goals all at the same time.
Date: 2026-06-16 Ticket: 37-semantic-zones-3layer-contract
Glossary
- Semantic zones — coloring the map by meaning rather than just “wall vs. free space.” Think of it like a highlighter pass over a floor plan: this corner is dangerous, that doorway is interesting, this spot is the mission target. The drone uses these colors to decide where to fly and what to look at.
- 3-layer (three layers) — instead of giving each map tile exactly one label, we keep three separate “transparent sheets” stacked on top of the same map. One sheet is about flying safely, one is about what’s worth photographing, one is about the mission. A single tile can carry a mark on all three sheets at once.
- Data contract — the agreed-upon shape of the data: what each layer contains, who fills it in, and where it lives. It’s the handshake between the simulator, the editor, and the learning agent so nobody guesses about the format. Like a shared spreadsheet template everyone fills in the same columns.
- obs (observation) — what the model “sees” as input on every step, the way your eyes deliver a snapshot each instant.
- one-hot — a way to encode “which category is this?” using all zeros and a single one. Like a row of light switches where exactly one is flipped on.
- overlay — a swappable layer laid on top of the map; here it’s the mission/task layer.
- occupancy — the occupancy map: where there’s a wall, where it’s free, and where it’s still unknown.
- anti-vacuum-cleaner — a rule that says a tile counts as “explored” when a sensor ray actually saw it, not because the drone physically drove over every square. It stops the agent from behaving like a robot vacuum that has to bump into everything.
1. What I wanted
For a while our map had ONE list of 13 labels, and every tile got exactly one of them. That sounds tidy until you hit the obvious case: a doorway that is also narrow. Is that tile “narrow” or is it “doorway”? You had to pick — and whichever you picked, the other meaning quietly vanished.
Aleks suggested I stop forcing that choice. Instead of one list, split meaning into three independent layers, so a tile can be marked on more than one at the same time. I wanted to make that real: define the layers, give them a clean data shape, and decide how each one gets stored.
2. What I tried
I settled the design into three layers, each answering a different question:
- Navigator — “how do I fly here, and how dangerous is it?” Near a wall (risky), narrow gap, corner, open space, a column to avoid, or just a normal safe path.
- Cartographer — “what’s worth putting on the map?” A door (leads to a new room), the frontier between known and unknown, the shadow behind an obstacle, or a tile we’ve already captured.
- Tasks / flags — “the mission.” Target point, start, landing spot, mandatory scan, no-go zone. This layer is often empty and changes from job to job.
The payoff is exactly the doorway problem solved: a tile that is both a door and narrow now gets TWO marks at once — “narrow” on the Navigator layer and “door” on the Cartographer layer. Nothing gets lost.
To make this usable I did three things:
- Wrote a config file holding ALL the zones and their colors (
semantic_zones.yaml). The map editor reads it so you can actually see the coloring. I picked color families on purpose: Navigator gets warm tones (red = danger fading to green = open), Cartographer gets cool tones (blue / cyan), and Tasks get bright, loud flag colors. - Proposed a display scheme: data is always stored as three layers, but you can show it EITHER as three separate toggleable layers (on/off each) OR as a single tile sliced into three colored stripes (Aleks’s gradient idea). That’s purely a viewing mode — the underlying data never changes.
- Answered the storage question (below), because “three layers” immediately raises “okay, but where does each one live?”
3. What happened
The clean part of the answer was sorting out what is fixed versus what is swappable:
| Thing | Who produces it | How it’s stored |
|---|---|---|
| Map geometry (walls) | Simulation (worlds_a1/) |
One per map |
| Navigator layer | Computed from geometry | Not stored separately — derived on the fly |
| Cartographer layer | Lives during flight (what’s been scouted) | Written into the flight log so a run can be replayed |
| Task layer | The mission designer | Stored as separate files, SEVERAL per map |
So one map can have many task layouts. Geometry is the “hard” part — one wall map, done by the simulator. The Navigator layer falls out of that geometry automatically, so there’s no reason to store it twice. The Cartographer layer is alive only while flying — it records what’s actually been scouted — and we tuck it into the flight log so a run can be replayed exactly.
The task layer is the one we keep as standalone files, and crucially we keep many per map. One map → many mission layouts. Switching the job is just picking a different file in the GUI. That matched what Aleks asked for word-for-word: “one map — different placements of flight-task zones.”
There’s also a quiet correctness win baked into the Cartographer layer. The “explored” mark (MAPPED) follows the anti-vacuum-cleaner rule: a tile is explored when a sensor ray genuinely saw it, not because the drone bothered to physically fly over every square. That keeps the agent honest about coverage instead of rewarding a needless lawnmower pattern.
4. Sources
rl-lab/docs/dev-log/37-semantic-zones-3layer-contract_HUMANED.mdsemantic_zones.yaml— the zone + color config the map editor reads.worlds_a1/— simulation-side map geometry.
5. What’s next
The design is settled; the wiring is the follow-on work. The Navigator and Cartographer layers need to flow into the agent’s observation in a clean encoded form (one-hot per layer), and the editor’s two display modes — three toggleable layers vs. the three-stripe tile — both need to read from the same semantic_zones.yaml so the colors stay in sync. Once the task layer’s multi-file picker is in the GUI, swapping missions on a fixed map should be a one-click thing.