Skip to content

Conversation

MichaelLesirge
Copy link
Contributor

@MichaelLesirge MichaelLesirge commented Jul 3, 2025

This PR adds two new utility methods to Java/C++ MathUtil for 2D joystick processing

  • Translation2d applyDeadband2d(Translation2d value, double deadband, double maxDistance)
  • Translation2d copySignPow2d(Translation2d value, double exponent, double maxDistance)
  • And overloads for max distance (default of 1)

These functions are useful for teams using joysticks with circular input profiles, which is a common practice. Currently, MathUtil.deadband and MathUtil.copySignPow only support 1D inputs, so teams often end up writing custom logic that combines hypot, atan2, and Transform2d.

For example this:

  private static Translation2d getLinearVelocityFromJoysticks(double x, double y) {
    // Apply deadband
    double linearMagnitude = MathUtil.applyDeadband(Math.hypot(x, y), DEADBAND);
    Rotation2d linearDirection = new Rotation2d(Math.atan2(y, x));

    // Square magnitude for more precise control
    linearMagnitude = linearMagnitude * linearMagnitude;

    // Return new linear velocity
    return new Pose2d(new Translation2d(), linearDirection)
        .transformBy(new Transform2d(linearMagnitude, 0.0, new Rotation2d()))
        .getTranslation();
  }

Could be done like this:

  private static Translation2d getLinearVelocityFromJoysticks(double x, double y) {
    Translation2d linearVelocity = new Translation2d(x, y);

    // Apply deadband
    linearVelocity = MathUtil.applyDeadband(linearVelocity, DEADBAND);

    // Square magnitude for more precise control
    linearVelocity = MathUtil.copySignPow(linearVelocity, 2);

    return linearVelocity;
  }

I believe this is correct for WPILib because this is a pretty generic function which a lot of teams already do, but adding it here would increase visibility and allow newer teams to find this more easily and implement it, improving their performance.

@github-actions github-actions bot added the component: wpimath Math library label Jul 3, 2025
@MichaelLesirge MichaelLesirge reopened this Jul 7, 2025
@MichaelLesirge MichaelLesirge marked this pull request as ready for review July 7, 2025 18:28
@MichaelLesirge MichaelLesirge requested a review from a team as a code owner July 7, 2025 18:28
@MichaelLesirge
Copy link
Contributor Author

MichaelLesirge commented Jul 7, 2025

I feel like applyDeadband and copySignPow (both 1d and 2d) could be moved to their own file, like suggested by @calcmogul in #6903. Probably for 2027

Something like this may belong in a separate utility class like edu.wpi.first.wpilibj.DriverUtil, though idk what else we'd put in there.

But would want feedback to confirm. I was thinking JoystickMathUtil, or the suggested DriverUtil.

@MichaelLesirge MichaelLesirge changed the title Add 2D variants of MathUtil.applyDeadband and MathUtil.copySignPow2d for circular joystick inputs [wpimath] Add 2D variants of MathUtil.applyDeadband and MathUtil.copySignPow2d for circular joystick inputs Jul 10, 2025
@MichaelLesirge
Copy link
Contributor Author

I'd rather not provide two nearly identical ways of doing the same thing.

Finally got back to this. I went with using Vectors, and made it work for 2d, 3d, etc, while on it. I could only figure out how to implement the function for vectors of doubles cause I am a bit of a template noob and trying to use units with vectors was giving difficult errors.

@KangarooKoala
Copy link
Contributor

Looks like Eigen assumes that the sqrt of the scalar type can be converted to the scalar type:

EIGEN_DEVICE_FUNC static EIGEN_ALWAYS_INLINE Scalar run(const Scalar& x) {

However, this isn't true for units, so I'm not sure what we should do.

Also, the name CopySignPow doesn't really make sense for vectors, since vectors don't have signs. Maybe CopyDirectionPow or MagnitudePow? Ideally the name we pick can also be used for the scalar version. (Fortunately the original CopySignPow was added in #8013 after the last stable release, so we should have more leeway to change the name without going through a whole deprecation cycle)

@MichaelLesirge
Copy link
Contributor Author

Also, the name CopySignPow doesn't really make sense for vectors, since vectors don't have signs. Maybe CopyDirectionPow or MagnitudePow? Ideally the name we pick can also be used for the scalar version. (Fortunately the original CopySignPow was added in #8013 after the last stable release, so we should have more leeway to change the name without going through a whole deprecation cycle)

Could I do that in this pull request?

@KangarooKoala
Copy link
Contributor

Also, the name CopySignPow doesn't really make sense for vectors, since vectors don't have signs. Maybe CopyDirectionPow or MagnitudePow? Ideally the name we pick can also be used for the scalar version. (Fortunately the original CopySignPow was added in #8013 after the last stable release, so we should have more leeway to change the name without going through a whole deprecation cycle)

Could I do that in this pull request?

You could probably use a different name for the new methods, but it might be nicer if changing the original version was a separate PR. I'm not really sure though- @calcmogul What do you think?

@calcmogul
Copy link
Member

the original CopySignPow was added in #8013 after the last stable release, so we should have more leeway to change the name without going through a whole deprecation cycle

Yea, if a feature hasn't been in a release yet, we can rename it to whatever we want with no warning.

it might be nicer if changing the original version was a separate PR

Yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants