target_finder — EETargetFinder (mesh sampling, candidate scoring, FOV coverage marking)
Purpose
Samples surface targets on the inspection mesh, scores candidate camera poses, and marks
per-triangle FOV coverage via Open3D raycasting. The scorer is ANCHOR-only (inert in POSE,
the adopted default), but the coverage marker runs in every mode — so this file is the source
ofinspection.area_coverage_frac, not the target-selection lever.
Role in the system
- Standalone helper (not part of the guidance inheritance chain). Owned by ee_guidance (
EEGuidance),
the leaf of the deep guidance chain com_guidance → base_guidance → ee_guidance. - Called by ee_guidance:
choose_goal(ANCHOR-mode selection) and the coverage marker. - Also called by breve_controller:
compute_triangle_camera_visibilitymarks the FOV from the
actual camera pose everyEE_COVERAGE_MARK_STRIDEth step. - Geometry is shared from
utils/mesh.Mesh(one load, one scene); the finder keeps its own
KDTreeFlannquery trees over that data. - Records and enums (
CameraPose,SurfaceTarget,Selection,ScoringMode) come from guidance_classes.
Inputs / Outputs
- In: config (
camera_guidance.targeting.*), the robot, aMesh; per-call an anchorp_cor aCameraPose. - Out:
Selection(chosen target + pose + score breakdown), visible-target index lists, and the
area-weightedinspection_coverage_dataPackage (unique triangles, 1× / 2× covered-area fractions). - Side effect: mutates coverage memory
seen_triangles(set) andtriangle_stats(per-triangle counts).
Key methods
choose_goal— top-level scorer entry: candidate poses around the anchor → bestSelection—GNC/guidance/target_finder.py:546candidate_camera_poses— rank hemisphere poses by visible-target count —:126query_candidate_targets_from_position— position-only visibility (depth + incidence + line-of-sight) —:159compute_triangle_camera_visibility— pinhole-frustum raycast; the actual coverage marker —:201score_target— per-(target, pose) score across all terms —:360combined_score— fold terms into one scalar per the activeScoringMode—:463inspection_coverage_data— area-weighted coverage summary (the reported metric) —:266build_surface_targets— seed RNG, sample targets, tag nearest triangle —:95
Footguns
PRODUCT mode makes the weights INERT
ScoringMode.PRODUCTmultiplies the raw score terms with no per-term weights — the
scoring.weightsconfig keys do nothing in that mode. The active default isEXPONENTIAL(TASK_7),
which is weight-aware (equals PRODUCT when all weights are 1.0). (GNC/INSIGHTS.md[footgun])
Reproducibility rides on the Open3D global RNG seed
Open3D’s surface sampler takes no seed argument.
build_surface_targetsseeds the global RNG
(o3d.utility.random.seed(int(scoring.sampling.seed))) so surface sampling → target selection →
TARGETING is reproducible. Anything that re-seeds or reorders that global RNG breaks byte-identity.
(GNC/INSIGHTS.md[config])
Query trees must stay
KDTreeFlannfor bit-identityThe finder keeps its own
KDTreeFlannquery trees over the sharedMeshdata so query semantics
stay bit-identical with the pinned baselines. AcKDTreeswap is a deferred perf change, not a
free substitution. (GNC/INSIGHTS.md[perf])
Scorer is ANCHOR-only; coverage is trajectory-driven
In POSE mode (the adopted default) the pose is scheduled and the scorer is inert — yet coverage
still accrues becausecompute_triangle_camera_visibilitymarks the FOV in every mode. Don’t tune
scoring weights / reselect cadence to move coverage; that lever is the orbit trajectory. (GNC/INSIGHTS.md[guidance])
No stable score leaf for no-target / fallback steps
score_targetflags (# MAJOR ISSUE) that it does not expose a stable score leaf for
no-target / fallback steps — the score breakdown collapses to theNO_SCORE()NaN sentinel.
Pseudocode (ANCHOR-mode goal selection)
choose_goal(p_c):
candidates = candidate_camera_poses(p_c) # hemisphere around the anchor, ranked by visible count
for pose in candidates:
for target in query_candidate_targets_from_position(pose.p_e): # depth + incidence + LOS gate
s = score_target(target, pose, p_c) # view·novelty·area·stability·motion·anchor·manip
best = s if s.total_score > best.total_score else best
return best # Selection (target + pose + score terms)
# every step (POSE or ANCHOR), strided in the controller:
compute_triangle_camera_visibility(actual_pose) # raycast frustum → seen_triangles, triangle_stats
inspection_coverage_data() # area-weighted 1× / 2× coverage fractions
Equations & references
Key equations mirrored from current_sota — the math source of truth; see there for derivations.
Area coverage (surface-area fraction seen) — §7, eq (7.1):
ANCHOR weighted-product score (inert in POSE; novelty ) — §7, eq (7.2):
References:
- Coverage / pointing metrics (§7): current_sota > 7 — implemented at
GNC/guidance/target_finder.py:201
onward; the pointing versine1 − cos θitself lives in the measurement layer, not here.
Related
ee_guidance · guidance_classes · breve_controller · guidance_rollout · terminology · target_finding_coverage