Phase VMilestoneDay 13: A whole house, and a second arm that found ten bugs
Four Venlo rows, eight metres end to end, and a trolley that rides the heating pipes instead of the floor. Dutch glasshouse heating pipe is 51 mm OD on 550 mm centres, and it is already there in every house worth selling into, already straight, already load-bearing, already used by the crop trolleys the growers push around by hand.
Putting the base on that rail makes it a 1-DOF robot. There is one number describing where it is, it comes off a wheel encoder, and it does not drift because the rail does not let it. There is no localisation stack. There is no map. It physically cannot wander into a crop row, in the sense that a bollard cannot wander into traffic. An AMR here would be solving SLAM in a repetitive, self-similar, visually hostile corridor in order to reproduce a constraint the building is giving away for free.
Why the row pitch is what forces two arms
A Venlo row pitch is 1.60 m. The trolley runs down the middle, so it sits 800 mm from each crop wall. Every clearance number from Phase II and Phase III — the 40 mm planner defence, the 15 mm guard, the approach envelopes, the staging planes — was measured at 600 mm. All of that would have needed re-measuring.
It did not, because 800 − 600 = 200, and an arm mounted 200 mm off the deck centreline toward its own crop wall sees exactly the geometry it was characterised at. Every earlier number survives unchanged. And the 200 mm on the other side of the centreline is not wasted space — it is where the second arm goes. The second arm is not an upgrade. It is what the building’s own dimensions hand you once you stop fighting them.

A shift with nothing handed to it
The run: the robot is told the house exists and which aisle it is in. It is not told where a single tomato is. It scouts, builds its own fruit list, drives, picks, crates.
| Quantity | Result |
|---|---|
| Fruit in the house | 48 |
| Ripe on its row | 5 |
| Crated | 4 |
| Refused (real 30 mm neighbour) | 1 |
| Never detected | 2 |
| Scouting | 20 s |
| Driving | 33 s |
| Picking | 76 s |
The one refusal is the good kind. There was a genuine neighbour at 30 mm, inside the 40 mm the planner defends, and no route cleared it, so the planner declined rather than gambling. That is the behaviour Phase II was built for, arriving unprompted in a scene nobody hand-authored.
Ten bugs the second arm found
Fitting a second arm and then parallelising it turned up ten defects that had been shipping. This list is the most useful thing on the page, because every one of them was invisible in a working single-arm system.
- The two arms were parked 83 mm inside each other, forearm through forearm. This is visible in every render since the arm was added. Nothing was looking.
- Nothing checked arm against arm. The obstacle set was built from crop and structure, so the clash above was in nobody’s obstacle set — not a missed collision, an unasked question.
- Arm B’s grasps were being scored against arm A’s gripper. B reported failure on picks that had demonstrably worked.
- The planner previewed routes with 13 free DOF that the executor then flew with 6. Every preview was of a robot that does not exist.
- Two arms were one rigid assembly moved by two different transports. It surfaced twice — once as a teleport, once as a pole leaving its camera behind — and was one defect.
- Preferred posture lived in the null space.
- So did permitted joint speed. Both were invisible with one arm: the tool arrives at the same pose either way, and the crop only cares where the tool is. It took a second arm — whose elbow is the thing you collide with — to make the null space observable at all. That is the general lesson. A redundant manipulator has degrees of freedom that no single-arm test can see, because nothing in a single-arm world is downstream of them.
- A numpy mask was 39% of the entire simulation. It was never profiled, because a plausible story about camera cadences had been written down as a comment, and the comment was believed.
Two more are in my notes and not yet written up. They will land here rather than be quietly dropped to make the count work.
Number eight is the one to take personally. A comment is not evidence. It cost 39% of wall-clock for weeks because it read like an explanation.
The concurrency result is a limit, not a win
Both arms’ PARK postures fold the elbow across the aisle. Both elbows therefore want the shared middle of the deck, and the arms interlock there. I narrowed that interlock four times. Every narrowing found another contact at 12–15 mm.
The important part of that: the hazard is the arm that is waiting, not the one moving. A parked arm is not out of the way. It is a static obstacle sitting in the exact volume the other arm needs, and it got there by being told to relax.
So what shipped is an interlock over the whole mission: 6/7 crated, 0 guard aborts, 0% manipulation overlap. Manipulation is serialised. Everything else — mapping, planning, both deck heads scanning, travel — runs concurrent. Calling this a two-arm speedup would be a lie; the second arm currently buys reach and redundancy, not throughput.



