-
Notifications
You must be signed in to change notification settings - Fork 5
Add turret/auto targeting/SOTM #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
08a615e
Add some targeting for the potential 'superstructure'
tricktrap 8127ec1
Publish calculated aim direction
tricktrap 9b2e380
Add aiming command
tricktrap dab94b4
One last stab before mechanism debugging
tricktrap 4f62ec4
Add override while working from mac
tricktrap 84bfce0
Finally
tricktrap 05582e5
Factor out aiming into its own command
tricktrap 51e21bd
Add basic framework for range tables for shooter
tricktrap ef0edcf
Start correcting 3d axis oopsies
tricktrap cee56d1
Finally work out most of the rest of the coordinate issues
tricktrap 2688df9
Improve simulated shooting with half-updated simulation of fuel
tricktrap 6705efa
Merge in RI3D branch as of successful shooter test
tricktrap 8a1e110
Merge branch 'ri3d' of github.com:CranberryAlarm/CA26_RobotCode into …
tricktrap 95151e1
Merge in RI3D panic code from Tuesday lol
tricktrap 2b11aa8
Switch hood to passive-only implementation for now
tricktrap 0f70cbe
Fix indentation and line length
tricktrap 0074041
Shorten fake time of flight lookup table to make situation with aimpo…
tricktrap 18719f7
Re-use negated correctiveVector correctly for 3d visualization
tricktrap e23f9f5
Switch back to hard-coded simulated launch velocity for now
tricktrap cbb2ce6
Re-use hood's angle since the subsystem can be used again
tricktrap 0ecdd29
Speed control for shooting works
dracco1993 9800945
Slightly better tuning
dracco1993 0109e6b
Merge branch 'ri3d' of github.com:CranberryAlarm/CA26_RobotCode into …
tricktrap e23c8fc
Clean up ShooterSubsystem
tricktrap 80f4533
Turret is workably tuned
dracco1993 574704c
Merge in latest turret control code from Ri3D
tricktrap e5a74c3
WIP
dracco1993 6d8d5e4
Not better, but different
dracco1993 465737a
It's working, but aimed wrong
dracco1993 eaff02a
Invert the turret motor
dracco1993 26881df
Translation is now working, rotation is a no
dracco1993 2d97a7f
WIP
dracco1993 51ac183
AS export
dracco1993 00f4cb5
Add 3D models for better debugging
dracco1993 f5c5dd8
It's working! (maybe) 🤞
dracco1993 d949da4
Set correct p-value
dracco1993 f514bb0
Support for aimed turret in 3d field
dracco1993 7fea7cf
Cleanup, started work on auto shooting
dracco1993 625b4e2
SOTM works, and is _mostly_ tuned 🤞
dracco1993 0629f9c
Hacked 2026 maplesim into things
dracco1993 90131d0
Fuel firing sim works
dracco1993 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| { | ||
| "name": "2026 CA26", | ||
| "rotations": [ | ||
| { | ||
| "axis": "x", | ||
| "degrees": 90.0 | ||
| }, | ||
| { | ||
| "axis": "y", | ||
| "degrees": 0.0 | ||
| }, | ||
| { | ||
| "axis": "z", | ||
| "degrees": 90.0 | ||
| } | ||
| ], | ||
| "position": [0.0, 0.0, 0.0], | ||
| "cameras": [], | ||
| "components": [ | ||
| { | ||
| "zeroedRotations": [ | ||
| { | ||
| "axis": "x", | ||
| "degrees": 90.0 | ||
| }, | ||
| { | ||
| "axis": "y", | ||
| "degrees": 0.0 | ||
| }, | ||
| { | ||
| "axis": "z", | ||
| "degrees": 90.0 | ||
| } | ||
| ], | ||
| "zeroedPosition": [0.205, 0.0, -0.375] | ||
| } | ||
| ] | ||
| } |
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
169 changes: 169 additions & 0 deletions
169
src/main/java/frc/robot/commands/ShootOnTheMoveCommand.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| package frc.robot.commands; | ||
|
|
||
| import java.util.Map; | ||
| import java.util.function.Supplier; | ||
|
|
||
| import org.littletonrobotics.junction.Logger; | ||
|
|
||
| import edu.wpi.first.math.geometry.Pose3d; | ||
| import edu.wpi.first.math.geometry.Rotation3d; | ||
| import edu.wpi.first.math.geometry.Translation2d; | ||
| import edu.wpi.first.math.geometry.Translation3d; | ||
| import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap; | ||
| import static edu.wpi.first.units.Units.Degrees; | ||
| import static edu.wpi.first.units.Units.Meters; | ||
| import static edu.wpi.first.units.Units.RPM; | ||
| import edu.wpi.first.units.measure.Angle; | ||
| import edu.wpi.first.units.measure.AngularVelocity; | ||
| import edu.wpi.first.units.measure.Distance; | ||
| import edu.wpi.first.wpilibj2.command.Command; | ||
| import frc.robot.subsystems.Superstructure; | ||
| import frc.robot.subsystems.SwerveSubsystem; | ||
|
|
||
| public class ShootOnTheMoveCommand extends Command { | ||
| private final SwerveSubsystem drivetrain; | ||
| private final Superstructure superstructure; | ||
|
|
||
| private Supplier<Translation3d> aimPointSupplier; // The point to aim at | ||
| private AngularVelocity latestShootSpeed; | ||
| private Angle latestHoodAngle; | ||
| private Angle latestTurretAngle; | ||
|
|
||
| public ShootOnTheMoveCommand(SwerveSubsystem drivetrain, Superstructure superstructure, | ||
| Supplier<Translation3d> aimPointSupplier) { | ||
| this.drivetrain = drivetrain; | ||
| this.superstructure = superstructure; | ||
| this.aimPointSupplier = aimPointSupplier; | ||
|
|
||
| // We use the drivetrain to determine linear velocity, but don't require it for | ||
| // control. We | ||
| // will be using the superstructure to control the shooting mechanism so it's a | ||
| // requirement. | ||
| // addRequirements(superstructure); | ||
|
|
||
| // TODO: figure out if the above is actually required. Right now, when you start | ||
| // some other command, the auto aim can't start back up again | ||
| } | ||
|
|
||
| @Override | ||
| public void initialize() { | ||
| super.initialize(); | ||
|
|
||
| latestHoodAngle = superstructure.getHoodAngle(); | ||
| latestTurretAngle = superstructure.getTurretAngle(); | ||
| latestShootSpeed = superstructure.getShooterSpeed(); | ||
|
|
||
| // TODO: when this current command ends, we should probably cancel the dynamic | ||
| // aim command | ||
| superstructure.aimDynamicCommand( | ||
| () -> { | ||
| return this.latestShootSpeed; | ||
| }, | ||
| () -> { | ||
| return this.latestTurretAngle; | ||
| }, | ||
| () -> { | ||
| return this.latestHoodAngle; | ||
| }).schedule(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isFinished() { | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public void execute() { | ||
| // Calculate trajectory to aimPoint | ||
| var target = aimPointSupplier.get(); | ||
|
|
||
| var shooterLocation = drivetrain.getPose3d().getTranslation() | ||
| .plus(superstructure.getShooterPose().getTranslation()); | ||
|
|
||
| // Ignore this parameter for now, the range tables will account for it :/ | ||
| // var deltaH = target.getMeasureZ().minus(shooterLocation.getMeasureZ()); | ||
| var shooterOnGround = new Translation2d(shooterLocation.getX(), shooterLocation.getY()); | ||
| var targetOnGround = new Translation2d(target.getX(), target.getY()); | ||
|
|
||
| var distanceToTarget = Meters.of(shooterOnGround.getDistance(targetOnGround)); | ||
|
|
||
| // Get time of flight. We could try to do this analytically but for now it's | ||
| // easier and more realistic | ||
| // to use a simple linear approximation based on empirical data. | ||
| double timeOfFlight = getFlightTime(distanceToTarget); | ||
|
|
||
| // Calculate corrective vector based on our current velocity multiplied by time | ||
| // of flight. | ||
| // If we're stationary, this should be zero. If we're backing up, this will be | ||
| // "ahead" of the target, etc. | ||
| var updatedPosition = drivetrain.getFieldVelocity().times(timeOfFlight); | ||
| var correctiveVector = new Translation2d(updatedPosition.vxMetersPerSecond, updatedPosition.vyMetersPerSecond) | ||
| .unaryMinus(); | ||
| var correctiveVector3d = new Translation3d(correctiveVector.getX(), correctiveVector.getY(), 0); | ||
|
|
||
| Logger.recordOutput("FieldSimulation/AimTargetCorrected", | ||
| new Pose3d(target.plus(correctiveVector3d), Rotation3d.kZero)); | ||
|
|
||
| var correctedTarget = targetOnGround.plus(correctiveVector); | ||
|
|
||
| var vectorToTarget = drivetrain.getPose().getTranslation().minus(correctedTarget); | ||
|
|
||
| var correctedDistance = Meters.of(vectorToTarget.getNorm()); | ||
| var calculatedHeading = vectorToTarget.getAngle() | ||
| .rotateBy(drivetrain.getHeading().unaryMinus()) | ||
| .getMeasure(); | ||
|
|
||
| Logger.recordOutput("ShootOnTheMove/RobotHeading", drivetrain.getHeading()); | ||
| Logger.recordOutput("ShootOnTheMove/CalculatedHeading", calculatedHeading); | ||
| Logger.recordOutput("ShootOnTheMove/distanceToTarget", distanceToTarget); | ||
|
|
||
| latestTurretAngle = calculatedHeading; | ||
| latestShootSpeed = calculateRequiredShooterSpeed(correctedDistance); | ||
|
|
||
| // TODO: add this back if/when we have a real hood, for now, just set it to the | ||
| // current angle | ||
| // latestHoodAngle = calculateRequiredHoodAngle(correctedDistance); | ||
| latestHoodAngle = superstructure.getHoodAngle(); | ||
|
|
||
| superstructure.setShooterSetpoints( | ||
| latestShootSpeed, | ||
| latestTurretAngle, | ||
| latestHoodAngle); | ||
|
|
||
| // System.out.println("Shooting at distance: " + correctedDistance + " requires | ||
| // speed: " + latestShootSpeed | ||
| // + ", hood angle: " + latestHoodAngle + ", turret angle: " + | ||
| // latestTurretAngle); | ||
| } | ||
|
|
||
| private double getFlightTime(Distance distanceToTarget) { | ||
| // Simple linear approximation based on empirical data. | ||
| return TIME_OF_FLIGHT_BY_DISTANCE.get(distanceToTarget.in(Meters)); | ||
| } | ||
|
|
||
| private AngularVelocity calculateRequiredShooterSpeed(Distance distanceToTarget) { | ||
| return RPM.of(SHOOTING_SPEED_BY_DISTANCE.get(distanceToTarget.in(Meters))); | ||
| } | ||
|
|
||
| private Angle calculateRequiredHoodAngle(Distance distanceToTarget) { | ||
| return Degrees.of(HOOD_ANGLE_BY_DISTANCE.get(distanceToTarget.in(Meters))); | ||
| } | ||
|
|
||
| // meters, seconds | ||
| private static final InterpolatingDoubleTreeMap TIME_OF_FLIGHT_BY_DISTANCE = InterpolatingDoubleTreeMap.ofEntries( | ||
| Map.entry(1.0, 1.0), | ||
| Map.entry(4.86, 1.5)); | ||
|
|
||
| // meters, RPS | ||
| private static final InterpolatingDoubleTreeMap SHOOTING_SPEED_BY_DISTANCE = InterpolatingDoubleTreeMap.ofEntries( | ||
| Map.entry(2.0, 2700.0), | ||
| Map.entry(3.0, 3000.0), | ||
| Map.entry(4.0, 3300.0), | ||
| Map.entry(4.86, 3750.0)); | ||
|
|
||
| // meters, degrees | ||
| private static final InterpolatingDoubleTreeMap HOOD_ANGLE_BY_DISTANCE = InterpolatingDoubleTreeMap.ofEntries( | ||
| Map.entry(1.0, 15.0), | ||
| Map.entry(2.0, 30.0), | ||
| Map.entry(3.0, 45.0)); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition
|| truemakes this always evaluate to true, meaning joystick connection warnings will be silenced even on real robots. This appears to be debug code that should be removed.