Skip to content

fix(photon-lib): do not crash constrained solvepnp when heading-free with empty buffer#2529

Open
JosephTLockwood wants to merge 2 commits into
PhotonVision:mainfrom
JosephTLockwood:fix/constrained-solvepnp-headingfree-crash
Open

fix(photon-lib): do not crash constrained solvepnp when heading-free with empty buffer#2529
JosephTLockwood wants to merge 2 commits into
PhotonVision:mainfrom
JosephTLockwood:fix/constrained-solvepnp-headingfree-crash

Conversation

@JosephTLockwood

Copy link
Copy Markdown
Contributor

Description

Constrained solvePnP unconditionally unwrapped the heading-buffer sample (Optional.get() in Java, std::optional::value() in C++), so running heading-free with an empty heading buffer crashed (NoSuchElementException / bad_optional_access).

Both implementations now early-return only when a heading is actually required, and pass a safe placeholder otherwise — the solver's heading-free cost function never reads the provided heading. A regression test (PhotonPoseEstimatorTest) exercises the heading-free + empty-buffer path.

Meta

Merge checklist:

  • Pull Request title is a short, imperative summary of proposed changes
  • The description documents the what and why
  • If this PR addresses a bug, a regression test for it is added

…with empty buffer

estimateConstrainedSolvepnpPose only checked for a heading sample when
headingFree was false, but then unconditionally sampled the heading
buffer again and unwrapped it when building the solver call. A user
running CONSTRAINED_SOLVEPNP with headingFree=true who never called
addHeadingData therefore got a NoSuchElementException (Java) or
std::bad_optional_access (C++) instead of a pose estimate, even though
the heading-free solver never reads that heading: the generated casadi
cost functions for the heading-free problems never dereference the
gyro_theta argument (no arg[6] access in any
constrained_solvepnp_*_tags_free.c), only the heading-fixed variants do.

Sample the buffer once per invocation, keep returning empty when the
heading is fixed and no sample exists, and fall back to a zero
Rotation2d placeholder in heading-free mode. This also removes the
redundant double/triple buffer sampling per estimate.

Add a Java regression test that runs the heading-free strategy with no
heading data and asserts it does not throw.
@JosephTLockwood JosephTLockwood requested a review from a team as a code owner July 6, 2026 00:20
@github-actions github-actions Bot added the photonlib Things related to the PhotonVision library label Jul 6, 2026
if (!headingFree && headingSampleOpt.isEmpty()) {
return Optional.empty();
}
// The solver's heading-free cost function never reads the provided heading, so any

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment feels unhelpful and specific to this bug

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped it on both Java and C++.

Address review feedback on PhotonVision#2529: remove the comment describing why an
empty heading buffer is safe in heading-free mode. It described this
specific fix rather than documenting the code; the guard above and the
.orElse/.value_or placeholder are self-explanatory. Removed on both Java
and C++.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

photonlib Things related to the PhotonVision library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants