Skip to content

Commit

Permalink
Merge branch 'main' into PrepareToScoreInAmpCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
j0ndough authored Feb 7, 2024
2 parents 43f2882 + 22b0cd6 commit 0e476e5
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 47 deletions.
49 changes: 15 additions & 34 deletions src/main/java/competition/Robot.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,34 @@
import competition.injection.components.DaggerRobotComponent;
import competition.injection.components.DaggerRoboxComponent;
import competition.injection.components.DaggerSimulationComponent;
import competition.simulation.Simulator2024;
import competition.subsystems.drive.DriveSubsystem;
import competition.subsystems.pose.PoseSubsystem;
import edu.wpi.first.hal.AllianceStationID;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Translation2d;
import edu.wpi.first.wpilibj.Preferences;
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
import xbot.common.command.BaseRobot;
import xbot.common.math.FieldPose;
import xbot.common.math.MovingAverage;
import xbot.common.math.MovingAverageForDouble;
import xbot.common.math.MovingAverageForTranslation2d;
import xbot.common.subsystems.pose.BasePoseSubsystem;

import java.util.LinkedList;
import java.util.Queue;

public class Robot extends BaseRobot {

public Robot() {
}

Simulator2024 simulator;

@Override
protected void initializeSystems() {
super.initializeSystems();
getInjectorComponent().subsystemDefaultCommandMap();
getInjectorComponent().swerveDefaultCommandMap();
getInjectorComponent().operatorCommandMap();

simulator = getInjectorComponent().simulator2024();

dataFrameRefreshables.add((DriveSubsystem)getInjectorComponent().driveSubsystem());
dataFrameRefreshables.add(getInjectorComponent().poseSubsystem());
dataFrameRefreshables.add(getInjectorComponent().visionSubsystem());
Expand Down Expand Up @@ -102,37 +100,20 @@ private FieldPose getFieldOrigin() {
new MovingAverageForTranslation2d(15);
MovingAverageForDouble rotationAverageCalculator =
new MovingAverageForDouble(15);
MovingAverageForDouble leftArmPositionCalculator =
new MovingAverageForDouble(15);
MovingAverageForDouble rightArmPositionCalculator =
new MovingAverageForDouble(15);
MovingAverageForDouble shooterVelocityCalculator =
new MovingAverageForDouble(50);

@Override
public void simulationPeriodic() {
super.simulationPeriodic();

double robotTopSpeedInMetersPerSecond = 3.0;
double robotLoopPeriod = 0.02;
double poseAdjustmentFactorForSimulation = robotTopSpeedInMetersPerSecond * robotLoopPeriod;

double robotTopAngularSpeedInDegreesPerSecond = 360;
double headingAdjustmentFactorForSimulation = robotTopAngularSpeedInDegreesPerSecond * robotLoopPeriod;

var pose = (PoseSubsystem)getInjectorComponent().poseSubsystem();
var currentPose = pose.getCurrentPose2d();
DriveSubsystem drive = (DriveSubsystem)getInjectorComponent().driveSubsystem();

// Extremely simple physics simulation. We want to give the robot some very basic translational and rotational
// inertia. We can take the moving average of the last second or so of robot commands and apply that to the
// robot's pose. This is a very simple way to simulate the robot's movement without having to do any real physics.

translationAverageCalculator.add(drive.lastRawCommandedDirection);
var currentAverage = translationAverageCalculator.getAverage();

rotationAverageCalculator.add(drive.lastRawCommandedRotation);
var currentRotationAverage = rotationAverageCalculator.getAverage();

var updatedPose = new Pose2d(
new Translation2d(
currentPose.getTranslation().getX() + currentAverage.getX() * poseAdjustmentFactorForSimulation,
currentPose.getTranslation().getY() + currentAverage.getY() * poseAdjustmentFactorForSimulation),
currentPose.getRotation().plus(Rotation2d.fromDegrees(currentRotationAverage * headingAdjustmentFactorForSimulation)));
pose.setCurrentPoseInMeters(updatedPose);
if (simulator != null) {
simulator.update();
}
}
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package competition.injection.components;

import competition.simulation.Simulator2024;
import competition.subsystems.NeoTrellisGamepadSubsystem;
import competition.subsystems.arm.ArmSubsystem;
import competition.subsystems.arm.commands.ExtendArmCommand;
Expand Down Expand Up @@ -48,4 +49,6 @@ public abstract class BaseRobotComponent extends BaseComponent {
public abstract CollectorSubsystem collectorSubsystem();

public abstract ShooterWheelSubsystem shooterSubsystem();

public abstract Simulator2024 simulator2024();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import competition.electrical_contract.CompetitionContract;
import competition.electrical_contract.ElectricalContract;
import competition.electrical_contract.UnitTestCompetitionContract;
import competition.subsystems.drive.DriveSubsystem;
import competition.subsystems.pose.PoseSubsystem;
import dagger.Binds;
Expand All @@ -17,7 +18,7 @@
public abstract class SimulatedRobotModule {
@Binds
@Singleton
public abstract ElectricalContract getElectricalContract(CompetitionContract impl);
public abstract ElectricalContract getElectricalContract(UnitTestCompetitionContract impl);

@Binds
@Singleton
Expand Down
102 changes: 102 additions & 0 deletions src/main/java/competition/simulation/Simulator2024.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package competition.simulation;

import com.revrobotics.CANSparkBase;
import competition.subsystems.arm.ArmSubsystem;
import competition.subsystems.drive.DriveSubsystem;
import competition.subsystems.pose.PoseSubsystem;
import competition.subsystems.shooter.ShooterWheelSubsystem;
import edu.wpi.first.math.geometry.Pose2d;
import edu.wpi.first.math.geometry.Rotation2d;
import edu.wpi.first.math.geometry.Translation2d;
import xbot.common.controls.actuators.mock_adapters.MockCANSparkMax;
import xbot.common.math.MovingAverageForDouble;
import xbot.common.math.MovingAverageForTranslation2d;

import javax.inject.Inject;

public class Simulator2024 {

MovingAverageForTranslation2d translationAverageCalculator =
new MovingAverageForTranslation2d(15);
MovingAverageForDouble rotationAverageCalculator =
new MovingAverageForDouble(15);
MovingAverageForDouble leftArmPositionCalculator =
new MovingAverageForDouble(15);
MovingAverageForDouble rightArmPositionCalculator =
new MovingAverageForDouble(15);
MovingAverageForDouble shooterVelocityCalculator =
new MovingAverageForDouble(50);

private final PoseSubsystem pose;
private final DriveSubsystem drive;
private final ArmSubsystem arm;
private final ShooterWheelSubsystem shooter;

@Inject
public Simulator2024(PoseSubsystem pose, DriveSubsystem drive,
ArmSubsystem arm, ShooterWheelSubsystem shooter) {
this.pose = pose;
this.drive = drive;
this.arm = arm;
this.shooter = shooter;
}



public void update() {
double robotTopSpeedInMetersPerSecond = 3.0;
double robotLoopPeriod = 0.02;
double poseAdjustmentFactorForSimulation = robotTopSpeedInMetersPerSecond * robotLoopPeriod;

double robotTopAngularSpeedInDegreesPerSecond = 360;
double headingAdjustmentFactorForSimulation = robotTopAngularSpeedInDegreesPerSecond * robotLoopPeriod;


var currentPose = pose.getCurrentPose2d();

// Extremely simple physics simulation. We want to give the robot some very basic translational and rotational
// inertia. We can take the moving average of the last second or so of robot commands and apply that to the
// robot's pose. This is a very simple way to simulate the robot's movement without having to do any real physics.

translationAverageCalculator.add(drive.lastRawCommandedDirection);
var currentAverage = translationAverageCalculator.getAverage();

rotationAverageCalculator.add(drive.lastRawCommandedRotation);
var currentRotationAverage = rotationAverageCalculator.getAverage();

var updatedPose = new Pose2d(
new Translation2d(
currentPose.getTranslation().getX() + currentAverage.getX() * poseAdjustmentFactorForSimulation,
currentPose.getTranslation().getY() + currentAverage.getY() * poseAdjustmentFactorForSimulation),
currentPose.getRotation().plus(Rotation2d.fromDegrees(currentRotationAverage * headingAdjustmentFactorForSimulation)));
pose.setCurrentPoseInMeters(updatedPose);

// Let's also have a very simple physics mock for the arm and the shooter.
// Get the power or setpoint for each arm.
double powerToTicksRatio = 1;
var leftMockMotor = ((MockCANSparkMax)arm.armMotorLeft);
var rightMockMotor = ((MockCANSparkMax)arm.armMotorRight);

leftMockMotor.setPosition(leftMockMotor.getPosition() + (leftMockMotor.get() * powerToTicksRatio));
rightMockMotor.setPosition(rightMockMotor.getPosition() + (rightMockMotor.get() * powerToTicksRatio));

// They might be using PID to control the arm. If so, we can use a moving aveage of their setpoint
// to approximate internal PID.
leftArmPositionCalculator.add(leftMockMotor.getReference());
rightArmPositionCalculator.add(rightMockMotor.getReference());

if (leftMockMotor.getControlType() == CANSparkBase.ControlType.kPosition) {
leftMockMotor.setPosition(leftArmPositionCalculator.getAverage());
}
if (rightMockMotor.getControlType() == CANSparkBase.ControlType.kPosition) {
rightMockMotor.setPosition(rightArmPositionCalculator.getAverage());
}

// The shooter wheel should pretty much always be in velocity mode.
var shooterMockMotor = (MockCANSparkMax)shooter.leader;
shooterVelocityCalculator.add(shooterMockMotor.getReference());
if (shooterMockMotor.getControlType() == CANSparkBase.ControlType.kVelocity) {
shooterMockMotor.setVelocity(shooterVelocityCalculator.getAverage());
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/competition/subsystems/arm/ArmSubsystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ public void periodic() {
armMotorRight.periodic();
}

aKitLog.record("Target Angle" + targetAngle);
aKitLog.record("Target Angle", targetAngle);
aKitLog.record("Arm3dState", new Pose3d(
new Translation3d(0, 0, 0),
new Rotation3d(0, 0, 0)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ public enum IntakeState {
public CollectorSubsystem(PropertyFactory pf, XCANSparkMax.XCANSparkMaxFactory sparkMaxFactory,
ElectricalContract electricalContract, XDigitalInput.XDigitalInputFactory xDigitalInputFactory) {
this.contract = electricalContract;
this.collectorMotor = sparkMaxFactory.createWithoutProperties(contract.getCollectorMotor(), getPrefix(), "CollectorMotor");
if (contract.isCollectorReady()) {
this.collectorMotor = sparkMaxFactory.createWithoutProperties(contract.getCollectorMotor(), getPrefix(), "CollectorMotor");
} else {
this.collectorMotor = null;
}

this.inControlNoteSensor = xDigitalInputFactory.create(contract.getInControlNoteSensorDio());
this.readyToFireNoteSensor = xDigitalInputFactory.create(contract.getReadyToFireNoteSensorDio());

Expand All @@ -58,38 +63,55 @@ public void intake(){
if (getGamePieceInControl()) {
power *= intakePowerInControlMultiplier.get();
}
collectorMotor.set(power);
setPower(power);
intakeState = IntakeState.INTAKING;
}
public void eject(){
collectorMotor.set(ejectPower.get());
setPower(ejectPower.get());
intakeState = IntakeState.EJECTING;
}
public void stop(){
collectorMotor.set(0);
setPower(0);
intakeState = IntakeState.STOPPED;
}
public void fire(){
collectorMotor.set(firePower.get());
setPower(firePower.get());
intakeState = IntakeState.FIRING;
}

public void setPower(double power) {
if (contract.isCollectorReady()) {
collectorMotor.set(power);
}
}

public boolean getGamePieceInControl() {
return inControlNoteSensor.get();
if (contract.isCollectorReady()) {
return inControlNoteSensor.get();
}
return false;
}

public boolean getGamePieceReady() {
return readyToFireNoteSensor.get();
if (contract.isCollectorReady()) {
return readyToFireNoteSensor.get();
}
return false;
}

@Override
public void periodic() {
aKitLog.record("HasGamePiece", getGamePieceReady());
if (contract.isCollectorReady()) {
aKitLog.record("HasGamePiece", getGamePieceReady());
}
}

@Override
public void refreshDataFrame() {
collectorMotor.refreshDataFrame();
inControlNoteSensor.refreshDataFrame();
readyToFireNoteSensor.refreshDataFrame();
if (contract.isCollectorReady()) {
collectorMotor.refreshDataFrame();
inControlNoteSensor.refreshDataFrame();
readyToFireNoteSensor.refreshDataFrame();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package competition.subsystems.shooter.commands;

import competition.subsystems.arm.ArmSubsystem;
import competition.subsystems.collector.CollectorSubsystem;
import competition.subsystems.shooter.ShooterWheelSubsystem;
import xbot.common.command.BaseCommand;

import javax.inject.Inject;

public class FireWhenReadyCommand extends BaseCommand {
final ShooterWheelSubsystem wheel;
final ArmSubsystem arm;
final CollectorSubsystem collector;

@Inject
public FireWhenReadyCommand(ShooterWheelSubsystem wheel, ArmSubsystem arm, CollectorSubsystem collector) {
this.wheel = wheel;
this.arm = arm;
this.collector = collector;
}

@Override
public void initialize() {
log.info("Initializing...");
}

@Override
public void execute() {
/* WE CANNOT CHECK IF CURRENT VALUE OF WHEEL AND TARGET VALUE ARE EXACTLY THE SAME, THAT IS WHY WE
HAVE THE TOLERANCE PROPERTIES IN THE FIRST PLACE
RUNS 50 TIMES A SECOND
*/
if (wheel.isMaintainerAtGoal() && arm.isMaintainerAtGoal()) {
collector.fire();
}
}
}

0 comments on commit 0e476e5

Please sign in to comment.