Status In development

Sheet 01 of 04/Finding people

Personal systems projectDrawing 15.2 of 25Part 2 of 3

Finding people

Four ways to find a person through a wall, where the gun is pointing in the dark, and a map that refuses to freeze a person into a wall.

Specification / as recorded

Status
In development, 2026
Role
Solo
Written
About 129,000 lines of hand-written C++17 across 15 subsystems
Desktop tests
105 run, 105 pass, on a laptop with no sensor attached
Not run on hardware
Zero lines. Every performance figure below is a budget
Owned
The helmet display. Everything else is still unbought
Target
Jetson Orin Nano 8GB worn on the body, Raspberry Pi 5 on the robot

Sheet 02 of 04/Through walls

Four ways to find a person through a wall

The feature that makes this worth building is that the helmet draws people you cannot see. There are four independent ways of finding them, deliberately, because each one fails differently.

  • Ultra-wideband two way ranging. Nodes on both shoulders and the chest range against every other node in the mesh. This is the accurate one, good to something like 10 to 30 cm, and it is the tier the rest of the system leans on for its own position. It only finds people who are carrying a tag.
  • Distributed acoustic time-difference-of-arrival. Small microphone arrays on the rig and on the dog cross correlate to get a bearing on a sound. This is the best tier for finding an untagged person, and the only one nobody can switch off, because it does not require the other side to cooperate or emit anything. It is also the fussiest: the microphone positions have to be known to millimetres, since 5 mm of geometry error is about 1.9 degrees of bearing error.
  • 24 GHz Doppler radar. Cheap modules, around twelve dollars each, which is cheap enough to buy several and experiment. Good at motion, weak at identity.
  • Passive radio sniffing. Detects devices rather than people.

The reason for four tiers rather than one good one is that a single source is a single failure mode, and the interesting cases are where they disagree. Every rig and every dog broadcasts what it found, and each rig fuses them all into one world model with per contact provenance and confidence, so the display can tell you not just that something is there but how it was found and how much that is worth.

That confidence has to travel with the estimate rather than being invented at draw time. The rule the HUD enforces is that a weak inference must never render with the same visual weight as a corroborated one, and that rule is only enforceable if uncertainty arrives attached to the value. So an uncertainty structure rides on almost every estimate in the system. A contact that has not been observed recently fades and is eventually dropped rather than sitting there looking confident.

There is a smaller rule in the same spirit that I like more than it probably deserves: hue never carries meaning alone. Every contact class gets a shape as well as a colour, so friendly is cyan and a solid chevron, unknown is amber and an open bracket, hostile is red and a diamond, and the robot gets its own. Two reasons, and the second one is the one I would not have thought of first: roughly 8% of men have a colour vision deficiency, and a red overlay on a thermal image in a smoke filled room desaturates anyway.

Identification comes from the ultra-wideband tag, and it is deliberately conservative in one direction: an untagged person is unknown, never implicitly hostile. And a track marked friendly is never eligible as an aim target, a rule enforced in the targeting logic rather than only in the renderer, so that a rendering bug cannot put a hostile outline on a teammate. There is a unit test whose only job is that rule.

The whole thing rests on consent. This is a game among friends who all agree to wear a tag, and the passive radio tier should be pointed at people who know the system exists rather than at bystanders who do not.

A dark circular minimap render showing a rotated floor plan in blue grey and cream, with a small green triangle marking the viewer's position and heading
PlatePL-01
TitleMinimap
ViewDetail
Drawn by the mapping code against a simulated arena. Pale lines are geometry it has confirmed, blue grey is floor it has seen, flat dark is where it has never looked.

Sheet 03 of 04/Gun tracking

Where the gun is pointing, in the dark

Four 940 nm infrared LEDs sit on the gun's rail in an asymmetric planar pattern. A global shutter camera on the helmet wears a 940 nm bandpass filter, which makes its image almost entirely black except for those four dots. Blob detection finds them, a correspondence step decides which dot is which, and a perspective-n-point solve recovers the gun's pose. An inertial measurement unit on the gun running at 400 Hz is fused in to fill the gaps when the constellation is occluded, which happens constantly, because in real use a gun spends a lot of its time behind a forearm.

The result is a drift free absolute pose in total darkness, which is the property that makes it worth all that machinery rather than just integrating the gun's own gyro.

The reason 940 nm rather than 850 nm is a competitive one. 850 nm glows visibly red, and anyone with an infrared sensitive camera sees a beacon on your head. In a game where the other side builds their own sensors, that is precisely the wrong outcome. The one deliberate exception written into that rule is eye tracking, whose LEDs would be 850 nm because they sit inside a sealed helmet where nothing escapes and 850 nm buys materially better sensor efficiency. Right now it governs nothing, because the eye cameras were cut from the build and there is no 850 nm emitter on the rig at all. The rule stays as written, for the day they go back in.

It is drawn as a cone, never as a dot. The total error stack is around one to two degrees, which at 20 m is a circle 35 to 70 cm across. Drawing that as a crisp pixel would be the display lying about what it knows, and rendering a weak inference as a confident marker is how somebody ends up shooting at the wrong doorway. So the reticle is an uncertainty cone that grows with range and with how long the filter has been coasting on the inertial sensor since it last saw the LEDs.

The calibration document is blunt about how this fails. If the aim is offset by a fixed angle at all ranges, that is a zeroing error and re-zeroing fixes it. If the offset varies with range, it is a mount translation error rather than a rotation error, and re-zeroing will not fix it no matter how many times you try. If the solve intermittently converges to a mirrored pose and the aim vector snaps between two solutions as the gun rotates, that is the classic planar target ambiguity and the fix is upstream, in the measured LED geometry.

Sheet 04 of 04/Mapping

The map will not freeze a person into a wall

The rig builds an occupancy grid of the arena from stereo depth as it walks around, at 5 cm cells, and merges it with the grids its teammates are building. These two renders are that code running against a simulated arena, and they are the closest thing this project has to a result.

A dark circular minimap render showing a rotated floor plan in blue grey and cream, with a small green triangle marking the viewer's position and heading
PlatePL-02
TitleMinimap
ViewDetail
Drawn by the mapping code against a simulated arena. Pale lines are geometry it has confirmed, blue grey is floor it has seen, flat dark is where it has never looked.

The interesting rule is that people are explicitly not walls. A person standing still in front of a depth sensor looks exactly like geometry, and a naive occupancy grid will happily burn them into the map as a permanent obstacle. Then they walk away and the map has a wall in the middle of a corridor that nobody can see, which is worse than having no map, because the wearer trusts it.

An occupancy grid render on a near black background, with white walls, dark blue grey floor regions and a thick magenta shape running across the middle
PlatePL-03
TitleSame grid without the fog
ViewDetail
Magenta is everything the map has decided is moving, which it refuses to freeze into a wall no matter how solid it looks right now.

The other rule is about when to stop writing. The mapping pose normally comes from the ultra-wideband mesh, which is accurate to 10 to 30 cm, comfortably inside a 5 cm cell budget. If the mesh drops out, satellite positioning is available outdoors and is accurate to two to five metres, which is wrong by forty to a hundred cells. A map drawn from that pose puts walls tens of cells away from where they are, and the map still looks correct, so the wearer trusts it and walks into a wall the map does not show.

So satellite positioning is the one rung on the degradation ladder that adds a sensor instead of removing one, and it is the one that is easiest to get wrong, because the failure looks like success. The code stops writing the map entirely, keeps the last one, and marks it stale. That is enforced in three places rather than one, and the third is a test that compares the whole occupancy grid byte for byte across an outage. It is the only check that fails if a later change quietly makes satellite fixes an anchor again.