Skip to content

Fix OTF aiming at field walls with velocity clamping#554

Open
phurley67 wants to merge 1 commit into
mainfrom
fix/wall-aware-velocity-clamping
Open

Fix OTF aiming at field walls with velocity clamping#554
phurley67 wants to merge 1 commit into
mainfrom
fix/wall-aware-velocity-clamping

Conversation

@phurley67

Copy link
Copy Markdown
Contributor

Summary

  • Adds getWallCorrectedChassisSpeeds() to Swerve that zeros the velocity component pointing off-field when the robot is within ~8 inches of a wall boundary
  • getFuturePoseFromTime() and Cannon's hub angular velocity now use corrected speeds
  • getCurrentRobotChassisSpeeds() is unchanged — PathPlanner and other consumers are unaffected

Problem

When strafing against a field wall, wheel odometry reports velocity into the wall (wheels spin but robot doesn't move). The OTF solver uses this phantom velocity to predict future pose, causing it to lead shots incorrectly.

Approach

Wall-aware clamping is preferred over pose differentiation because it:

  • Adds zero noise (keeps 250Hz wheel odometry for normal driving)
  • Has no latency (unlike vision-differentiated velocity)
  • Only modifies the specific velocity component that's wrong
  • Preserves parallel-to-wall velocity (which is correct and needed for OTF)

Test plan

  • Verify static aiming is unaffected (robot not near walls)
  • Test OTF while strafing along a wall — shots should no longer over-lead
  • Test OTF while strafing into a corner — both X and Y clamping active
  • Verify turret feedforward is smooth near walls (no jitter)

Closes #553

🤖 Generated with Claude Code

When strafing against a wall, wheel odometry reports velocity into the
wall even though the robot isn't moving that direction. This causes the
OTF solver to lead shots based on phantom motion. Fix by zeroing the
velocity component pointing off-field when the robot pose is within
bumper-width of a wall boundary.

Closes #553

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 7, 2026 23:51

Copilot AI left a comment

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.

Pull request overview

This PR addresses incorrect on-the-fly (OTF) shot leading when the drivetrain is pressed against a field wall by clamping “phantom” off-field velocity components near field boundaries, and then using those corrected speeds in OTF future-pose and hub angular velocity calculations.

Changes:

  • Added Swerve.getWallCorrectedChassisSpeeds() to zero field-relative velocity components that point out of bounds when near a wall.
  • Updated Swerve.getFuturePoseFromTime() to use wall-corrected chassis speeds for OTF pose prediction.
  • Updated Cannon.getHubAngularVelocity(...) to use wall-corrected chassis speeds; added FieldConstants.FIELD_LENGTH/FIELD_WIDTH.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/main/java/frc/robot/subsystems/Swerve.java Introduces wall-aware chassis-speed clamping and uses it for OTF future pose prediction.
src/main/java/frc/robot/subsystems/Cannon.java Switches hub angular velocity computation to use wall-corrected drivetrain speeds.
src/main/java/frc/robot/constants/FieldConstants.java Adds explicit field X/Y extents for wall boundary checks.

Comment on lines +433 to +437
// When the robot is pressed against a field wall, wheels spin but the robot
// doesn't actually move into the wall. This zeros the velocity component
// pointing off-field so the OTF solver doesn't lead shots based on phantom motion.
private static final double WALL_MARGIN = 0.20; // meters (~8 in, bumper width + tolerance)

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

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

WALL_MARGIN is compared against the robot pose translation, which is typically the robot’s center of rotation. With DriveConstants.RobotWidth = 30 in (half-width ~0.38 m), a margin of 0.20 m likely won’t trigger until the robot center is unrealistically close to/through the wall, so the clamping may never activate when actually pressed against a wall. Consider basing the margin on half the robot’s footprint (e.g., RobotWidth/2 plus tolerance) or explicit bumper-to-center X/Y extents.

Copilot uses AI. Check for mistakes.
Comment on lines 414 to 418
double robotTargetAngle = getTargetAngle(pose).in(Radians);

Translation2d fieldRelativeVelocity = new Translation2d(drivetrain.getCurrentRobotChassisSpeeds().vxMetersPerSecond, drivetrain.getCurrentRobotChassisSpeeds().vyMetersPerSecond).rotateBy(drivetrain.getPose().getRotation());
Translation2d fieldRelativeVelocity = new Translation2d(drivetrain.getWallCorrectedChassisSpeeds().vxMetersPerSecond, drivetrain.getWallCorrectedChassisSpeeds().vyMetersPerSecond).rotateBy(drivetrain.getPose().getRotation());

double hubRotation = (-fieldRelativeVelocity.getX() * Math.sin(robotTargetAngle) + fieldRelativeVelocity.getY() * Math.cos(robotTargetAngle)) / getTargetDistance().in(Meters);

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

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

getHubAngularVelocity(Pose2d pose) mixes the passed-in pose (used for getTargetAngle(pose)) with the current distance (getTargetDistance()), which can be inconsistent—especially when this is called with a future-predicted pose during OTF. Use getTargetDistance(pose) so the geometry matches the provided pose. Also, getWallCorrectedChassisSpeeds() is called twice in the same expression; store it in a local variable to avoid potential intra-cycle inconsistencies and extra work.

Copilot uses AI. Check for mistakes.
Comment on lines 50 to +53
public static final double FIELD_MIDDLE_Y = 4.034663;

public static final double FIELD_LENGTH = 16.540988; // meters (X extent)
public static final double FIELD_WIDTH = 8.069326; // meters (Y extent)

Copilot AI Apr 7, 2026

Copy link

Choose a reason for hiding this comment

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

FIELD_LENGTH/FIELD_WIDTH introduce a second source of truth for the same dimensions already hard-coded elsewhere in this file (e.g., FIELD). To avoid future drift, consider defining the field dimensions in one place (have FIELD and other rectangles reference these constants, or derive these constants from FIELD).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wall-aware velocity clamping for OTF aiming

2 participants