Aoife put her finger on it. We run AGVs in a pharma warehouse and had the same failure until we changed three things.
Mechanical: let the dock do the final alignment. A V-shaped funnel or two angled guide rails that steer the robot into position in the last 15 cm, with spring-loaded contacts that have some travel. IR only has to get it into the funnel. Michael’s wider contacts help, but the funnel is what fixes the crooked case.
Logic: “docked” means charging current flows, not “IR is strongest”. After stopping, wait 2 s and read the charge current. If it’s not there, back off 30 cm, approach again, up to 3 tries. After 3 failures stop trying and report it.
Twin side: place each dock (if it reports anything) on the room asset it sits in, and place the robots on the site, since they move between zones and report their zone in telemetry. Then derive a status key for the robots, either on the Pi or in the root flow: critical after 3 failed docking tries or battery under 15 %, warning while it’s retrying, ok otherwise. Site status takes the worst status of everything placed under it, so a stuck robot turns the hall red on the site view without anyone opening telemetry. Also store a numeric copy (0/1/2), because text keys have no chart history. How the status rolls up: Site status and the status key.

