001/**
002 * Copyright 2024 The Space Cookies : Girl Scout Troop #62868 and FRC Team #1868
003 * Open Source Software; you may modify and/or share it under the terms of
004 * the 3-Clause BSD License found in the root directory of this project.
005 */
006
007package tagalong.commands.aim;
008
009import edu.wpi.first.math.geometry.Pose2d;
010import edu.wpi.first.math.geometry.Translation2d;
011import java.util.function.DoubleSupplier;
012import java.util.function.Supplier;
013import tagalong.commands.base.PivotToDynamicCmd;
014import tagalong.math.AlgebraicUtils;
015import tagalong.subsystems.TagalongSubsystemBase;
016import tagalong.subsystems.micro.augments.PivotAugment;
017
018/**
019 * Command that continuously points at a target in 2d space while compensating for the current
020 * rotation of the robot. Since this is strictly rotational targeting give robot position as (X, Y)
021 * pose
022 */
023public class PivotAimAtYawCompCmd<T extends TagalongSubsystemBase & PivotAugment>
024    extends PivotToDynamicCmd<T> {
025  @SuppressWarnings("unused")
026  /**
027   * Target to aim at
028   */
029  private final Translation2d _target;
030  @SuppressWarnings("unused")
031  /**
032   * Robot location supplier (x, y, theta)
033   */
034  private final Supplier<Pose2d> _locationSupplier;
035
036  /**
037   * Transform position into an optimal path angle to target, compensates for the current robot yaw
038   * while respecting the system's positional limits
039   *
040   * @param location Current robot location supplier
041   * @param pivotPosition Pivot position supplier
042   * @param target Target to aim at's location
043   * @param pivotMinRot pivots minimum position in rotations
044   * @param pivotMaxRot pivots maximum position in rotations
045   * @return Optimal path target angle for the pivot
046   */
047  protected static DoubleSupplier positionTransform(
048      Supplier<Pose2d> location,
049      DoubleSupplier pivotPosition,
050      final Translation2d target,
051      double pivotMinRot,
052      double pivotMaxRot
053  ) {
054    return () -> {
055      Pose2d curPos = location.get();
056      // Robot to target
057      double toTargetRot =
058          Math.atan((target.getX() - curPos.getX()) / (target.getY() - curPos.getY()));
059      // Delta between front of robot and that target, aka the target angle for the system
060      double delta = (toTargetRot - curPos.getRotation().getRotations()) % 1.0;
061      delta += delta < 0 ? 1.0 : 0;
062
063      // Take the shortest path to that position
064      double scopedAngle = AlgebraicUtils.placeInScopeRot(pivotPosition.getAsDouble(), delta);
065      if (scopedAngle > pivotMaxRot) {
066        scopedAngle -= 1.0;
067      }
068      if (scopedAngle < pivotMinRot) {
069        scopedAngle += 1.0;
070      }
071
072      return AlgebraicUtils.clamp(scopedAngle, pivotMinRot, pivotMaxRot);
073    };
074  }
075
076  /**
077   * Minimal constructor with default parameters
078   *
079   * @param id                Integer ID of the pivot microsystem inside the
080   *                          Tagalong Subsystem
081   * @param pivot            Tagalong Subsystem containing a pivot microsystem
082   * @param positionSupplier  Supplies the current robot position position
083   * @param target            Unmoving 2-dimensional target location
084   */
085  public PivotAimAtYawCompCmd(
086      int id, T pivot, Supplier<Pose2d> positionSupplier, Translation2d target
087  ) {
088    this(id, pivot, positionSupplier, target, true);
089  }
090
091  /**
092   * Minimal constructor with default parameters
093   *
094   * @param pivot            Tagalong Subsystem containing a pivot microsystem
095   * @param positionSupplier  Supplies the current robot position position
096   * @param target            Unmoving 2-dimensional target location
097   */
098  public PivotAimAtYawCompCmd(T pivot, Supplier<Pose2d> positionSupplier, Translation2d target) {
099    this(pivot, positionSupplier, target, true);
100  }
101
102  /**
103   * Constructor that creates the command with the below parameters.
104   *
105   * @param id                Integer ID of the pivot microsystem inside the
106   *                          Tagalong Subsystem
107   * @param pivot            Tagalong Subsystem containing a pivot microsystem
108   * @param positionSupplier  Supplies the current robot position position
109   * @param target            Unmoving 2-dimensional target location
110   * @param holdPositionAfter If the pivot should hold position when the command completes
111   * @param maxVelocityRPS    The maximum velocity of the pivot, in rotations per second, during
112   *     this command
113   */
114  public PivotAimAtYawCompCmd(
115      int id,
116      T pivot,
117      Supplier<Pose2d> positionSupplier,
118      Translation2d target,
119      boolean holdPositionAfter,
120      double maxVelocityRPS
121  ) {
122    super(
123        id,
124        pivot,
125        positionTransform(
126            positionSupplier,
127            pivot.getPivot(id)::getPivotPosition,
128            target,
129            pivot.getPivot(id)._minPositionRot,
130            pivot.getPivot(id)._maxPositionRot
131        ),
132        holdPositionAfter,
133        maxVelocityRPS
134    );
135    _target = target;
136    _locationSupplier = positionSupplier;
137  }
138
139  /**
140   * Constructor that creates the command with the below parameters.
141   *
142   * @param pivot            Tagalong Subsystem containing a pivot microsystem
143   * @param positionSupplier  Supplies the current robot position position
144   * @param target            Unmoving 2-dimensional target location
145   * @param holdPositionAfter If the pivot should hold position when the command completes
146   * @param maxVelocityRPS    The maximum velocity of the pivot, in rotations per second, during
147   *     this command
148   */
149  public PivotAimAtYawCompCmd(
150      T pivot,
151      Supplier<Pose2d> positionSupplier,
152      Translation2d target,
153      boolean holdPositionAfter,
154      double maxVelocityRPS
155  ) {
156    super(
157        pivot,
158        positionTransform(
159            positionSupplier,
160            pivot.getPivot()::getPivotPosition,
161            target,
162            pivot.getPivot()._minPositionRot,
163            pivot.getPivot()._maxPositionRot
164        ),
165        holdPositionAfter,
166        maxVelocityRPS
167    );
168    _target = target;
169    _locationSupplier = positionSupplier;
170  }
171
172  /**
173   * Constructor that creates the command with the below parameters.
174   *
175   * @param id                Integer ID of the pivot microsystem inside the
176   *                          Tagalong Subsystem
177   * @param pivot            Tagalong Subsystem containing a pivot microsystem
178   * @param positionSupplier  Supplies the current robot position position
179   * @param target            Unmoving 2-dimensional target location
180   * @param holdPositionAfter If the pivot should hold position when the command completes
181   */
182  public PivotAimAtYawCompCmd(
183      int id,
184      T pivot,
185      Supplier<Pose2d> positionSupplier,
186      Translation2d target,
187      boolean holdPositionAfter
188  ) {
189    this(
190        id, pivot, positionSupplier, target, holdPositionAfter, pivot.getPivot(id)._maxVelocityRPS
191    );
192  }
193
194  /**
195   * Constructor that creates the command with the below parameters.
196   *
197   * @param pivot            Tagalong Subsystem containing a pivot microsystem
198   * @param positionSupplier  Supplies the current robot position position
199   * @param target            Unmoving 2-dimensional target location
200   * @param holdPositionAfter If the pivot should hold position when the command completes
201   */
202  public PivotAimAtYawCompCmd(
203      T pivot, Supplier<Pose2d> positionSupplier, Translation2d target, boolean holdPositionAfter
204  ) {
205    this(pivot, positionSupplier, target, holdPositionAfter, pivot.getPivot()._maxVelocityRPS);
206  }
207}