Epic 021: Headless robot simulator — implementation (iter 3)#6
Conversation
… program execution
Reviewer findings — Epic 021 Iter 3 (TASK-003 … TASK-011)Tests: 202/202 green in Posting my findings as one global comment because several of them span multiple files. File:line citations inline. [MUST] Finding #1 — Path-level collision checking is missingSeverity: BLOCKER
Issue: A program whose endpoints are both collision-free but whose swept path clips an obstacle (common: elbow arc through a fixture between two safe poses) executes the full trajectory today with no failure reported. That is a silent safety bypass and directly contradicts the FR-8 scenario's "last safe interpolation step" language. Question: Was path-level checking deferred intentionally? If so, the FR-8 "Path validation" scenario is expected to fail in iter 3 and that needs an explicit deferral from team-lead. Otherwise, please move the [MUST] Finding #2 — Redundant/incorrect
|
… allocs) - SimulatedRobot.ExecuteWaypoints/Execute: check FirstCollision inside the joint-space interpolation loop so colliding intermediate configs are detected even when endpoints are safe. Truncate steps at last safe sub-step. - Add regression test: safe endpoints, colliding mid-swing obstacle. - ToolModel: remove manual Equals/GetHashCode overrides from record derivatives (rely on compiler-generated structural equality). - CollisionDetector: return IReadOnlyList<CollisionResult> using a lazily allocated List; no final ToArray materialization. - CollisionEnvironment.LinkRadii: expose ImmutableArray<double> instead of IReadOnlyList<double> copied on each use. - FkValidator / TeachingPointSet: pre-size arrays for JSON DTOs instead of Select().ToList() in hot export paths.
Replace 17-point parametric sampling in ClosestPointOnSegmentToBox and ClosestPointOnSegmentToCylinderZ with closed-form break-point enumeration: - Box: endpoints + axis-center crossings + face crossings + outside-quadratic stationary point per sign cell. Up to ~37 structural candidates; exact minimum for piecewise-linear inside SDF and quadratic outside SDF. - Cylinder-Z: endpoints + axial face/center crossings + radial surface crossings (quadratic roots) + radial-projection minimum t*. Adds worst-case tests comparing against a 10_001-sample brute-force minimum plus a tangent-pierce regression that the old uniform sampler missed.
Round 1 MUST fixes — pushed as
|
…veLin) Per ADR-004: collisions are runtime conditions, not programmer errors. MoveJoint no longer throws InvalidOperationException on collision; it now leaves state unchanged and emits nothing (matches MoveLin returning -2). Callers needing a structured failure use TryMoveJoint. Updates the MoveJoint collision test to assert no-throw + state preserved.
…per ADR-004 MoveJoint/MoveLin now return MoveResult and never throw on runtime conditions (joint-limit violations, unreachable IK, collisions). Legacy IRobot int/void signatures retained via explicit interface implementation. TryMoveJoint/TryMoveLin removed as redundant.
…0/30)
Apply the FR5 DH correction per docs/epics/epic-021-robot-simulator/fairino-preset-reference.md:
- a_{J4}: -392.25 -> -395.01
- d4: 115.7 -> 0 (j3/j4 axes parallel under Craig MDH, not in URDF)
- d5: 92.2 -> 102.1
- d6: 94.0 -> 102.0
Replace the symmetric +/-175 deg joint-limit array with per-axis v6 limits
(J1 +/-178, J2 [-265,+85], J3 +/-162, J4 [-265,+85], J5 +/-178, J6 +/-360).
Add factories FairinoFR3/10/16/20/30 built from a shared FairinoV6 helper that
hard-wires d4=0 and the shared v6 joint-limit array.
Test ground-truth regeneration (OPTION A, user-approved): FK_HOME, FK_CFG_A..E,
and WP1..WP5 were regenerated from our own ForwardKinematics output on the
corrected model. These are REGRESSION-ONLY fixtures, not independent ground
truth. Old fixtures encoded the old (incorrect) DH, so they could not be
treated as reference values after the correction.
Waypoints were re-chosen as FK outputs of curated joint configs so chained IK
seeds stay on the same branch. Limit-violation tests rewritten against the new
per-axis limits. IK_Should_Select_ClosestToSeed derives elbow-down from
mirror-seeded IK instead of the old hardcoded mirror which no longer reaches
the same TCP pose under the corrected DH.
230/230 tests green in csharp/RocketWelder.SDK.Robotics.Core.Tests/.
Adds FairinoV6_Presets_FK_AtHome_ShouldBe_Finite_And_WithinReach to RobotPresetTests.cs. For every v6 preset the test computes FK(HOME), asserts all TCP components are finite, and bounds |TCP| by the DH-derived geometric reach (sum of |a_i| + |d_i| across the chain) times 1.1. No datasheet reach figures are consulted; the bound is computed directly from the preset's own DH chain, keeping the check self-consistent. 236/236 tests green (up from 230).
Summary
Iteration 3 of Epic 021 (Robot Simulator) — the collision-aware simulator, robot-program, teaching-point and FK-validation primitives land in
RocketWelder.SDK.Robotics.Core.Tasks included in this PR
MoveResultevolution withMoveFailureReason+CollisionResult(c2bf99f)ICollisionSource+ primitive hierarchy +PrimitiveCollisionSource(8c6c10b)ToolModelhierarchy (None / Capsule / Mesh) (581a1d7)CollisionEnvironmentimmutable configuration (77dd9e9)CollisionDetectorstatic class, 10 non-adjacent pairs + env delegation (f4d92d5)RobotProgram+ProgramStephierarchy + System.Text.Json round-trip (3bb50c0)TeachingPointSetwith JSON round-trip (15063de)FkValidator+ schema-versioned JSON export/import (7b6b224)SimulatedRobotextensions: collision-aware moves, teaching-point CRUD, program execution (d66a018)Still pending
fairino-preset-reference.mddoes not listd4(wrist offset) per model, only FR5 has it. Awaiting clarification from team-lead. Follow-up commit will land here.Testing
dotnet test csharp/RocketWelder.SDK.Robotics.Core.Tests/— 202 passed, 0 failed.Design docs
Design and per-task specs are in the
modelingevolution/project-managementrepo on branchfeature/epic-021-iter3-implementationunderepics/epic-021-robot-simulator/. Dev log:iterations/iteration-3/dev-log.md.