mirror of
https://github.com/Team4388/RiseOfRidgebotics2020.git
synced 2026-06-09 08:48:01 -06:00
Conventions
No functional change
This commit is contained in:
@@ -127,6 +127,20 @@ public final class Constants {
|
|||||||
public static final double ENCODER_TICKS_PER_REV = 2048;
|
public static final double ENCODER_TICKS_PER_REV = 2048;
|
||||||
public static final double NEO_UNITS_PER_REV = 42;
|
public static final double NEO_UNITS_PER_REV = 42;
|
||||||
public static final double DEGREES_PER_ROT = 360;
|
public static final double DEGREES_PER_ROT = 360;
|
||||||
|
|
||||||
|
public static final int TURRET_RIGHT_SOFT_LIMIT = -2;
|
||||||
|
public static final int TURRET_LEFT_SOFT_LIMIT = -55;
|
||||||
|
public static final double TURRET_SPEED_MULTIPLIER = 0.3;
|
||||||
|
public static final double TURRET_CALIBRATE_SPEED = 0.075;
|
||||||
|
|
||||||
|
public static final int HOOD_UP_SOFT_LIMIT = 33;
|
||||||
|
public static final int HOOD_DOWN_SOFT_LIMIT = 3;
|
||||||
|
public static final double HOOD_CONVERT_SLOPE = 0.47;
|
||||||
|
public static final double HOOD_CONVERT_B = 40.5;
|
||||||
|
public static final double HOOD_CALIBRATE_SPEED = 0.1;
|
||||||
|
|
||||||
|
public static final double DRUM_RAMP_LIMIT = 1000;
|
||||||
|
public static final double DRUM_VELOCITY_BOUND = 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class ClimberConstants {
|
public static final class ClimberConstants {
|
||||||
@@ -142,6 +156,7 @@ public final class Constants {
|
|||||||
public static final double STORAGE_PARTIAL_BALL = 2;
|
public static final double STORAGE_PARTIAL_BALL = 2;
|
||||||
public static final double STORAGE_FULL_BALL = 7;
|
public static final double STORAGE_FULL_BALL = 7;
|
||||||
public static final double STORAGE_SPEED = 0.5;
|
public static final double STORAGE_SPEED = 0.5;
|
||||||
|
public static final double STORAGE_TIMEOUT = 2000;
|
||||||
|
|
||||||
/* Ball Indexes */
|
/* Ball Indexes */
|
||||||
public static final int BEAM_SENSOR_DIO_0 = 0;
|
public static final int BEAM_SENSOR_DIO_0 = 0;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import com.revrobotics.CANSparkMax.SoftLimitDirection;
|
|||||||
|
|
||||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||||
import edu.wpi.first.wpilibj2.command.CommandBase;
|
import edu.wpi.first.wpilibj2.command.CommandBase;
|
||||||
|
import frc4388.robot.Constants.ShooterConstants;
|
||||||
import frc4388.robot.subsystems.Shooter;
|
import frc4388.robot.subsystems.Shooter;
|
||||||
import frc4388.robot.subsystems.ShooterAim;
|
import frc4388.robot.subsystems.ShooterAim;
|
||||||
|
|
||||||
@@ -18,7 +19,9 @@ public class CalibrateShooter extends CommandBase {
|
|||||||
Shooter m_shooter;
|
Shooter m_shooter;
|
||||||
ShooterAim m_shooterAim;
|
ShooterAim m_shooterAim;
|
||||||
/**
|
/**
|
||||||
* Creates a new CalibrateShooter.
|
* Calibrates the turret by moving the hood all the way down and moving the turret all the way right, then reseting the encoders
|
||||||
|
* @param shootSub The Shooter subsystem
|
||||||
|
* @param aimSub The ShooterAim subsystem
|
||||||
*/
|
*/
|
||||||
public CalibrateShooter(Shooter shootSub, ShooterAim aimSub) {
|
public CalibrateShooter(Shooter shootSub, ShooterAim aimSub) {
|
||||||
m_shooter = shootSub;
|
m_shooter = shootSub;
|
||||||
@@ -37,12 +40,12 @@ public class CalibrateShooter extends CommandBase {
|
|||||||
m_shooter.m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kForward, false);
|
m_shooter.m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kForward, false);
|
||||||
m_shooter.m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kReverse, false);
|
m_shooter.m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kReverse, false);
|
||||||
m_shooter.m_angleEncoder.setPosition(0);
|
m_shooter.m_angleEncoder.setPosition(0);
|
||||||
m_shooter.m_angleAdjustMotor.set(-0.1);
|
m_shooter.m_angleAdjustMotor.set(-ShooterConstants.HOOD_CALIBRATE_SPEED);
|
||||||
|
|
||||||
m_shooterAim.m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kForward, false);
|
m_shooterAim.m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kForward, false);
|
||||||
m_shooterAim.m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kReverse, false);
|
m_shooterAim.m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kReverse, false);
|
||||||
m_shooterAim.m_shooterRotateEncoder.setPosition(0);
|
m_shooterAim.m_shooterRotateEncoder.setPosition(0);
|
||||||
m_shooterAim.m_shooterRotateMotor.set(0.075);
|
m_shooterAim.m_shooterRotateMotor.set(ShooterConstants.TURRET_CALIBRATE_SPEED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called once the command ends or is interrupted.
|
// Called once the command ends or is interrupted.
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ public class HoldTarget extends CommandBase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the Limelight to track the target
|
* Uses the Limelight to track the target
|
||||||
|
* @param shooterSubsystem The Shooter subsystem
|
||||||
|
* @param aimSubsystem The ShooterAim subsystem
|
||||||
*/
|
*/
|
||||||
public HoldTarget(Shooter shooterSubsystem, ShooterAim aimSubsystem) {
|
public HoldTarget(Shooter shooterSubsystem, ShooterAim aimSubsystem) {
|
||||||
m_shooterAim = aimSubsystem;
|
m_shooterAim = aimSubsystem;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ package frc4388.robot.commands;
|
|||||||
|
|
||||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||||
import edu.wpi.first.wpilibj2.command.CommandBase;
|
import edu.wpi.first.wpilibj2.command.CommandBase;
|
||||||
|
import frc4388.robot.Constants.ShooterConstants;
|
||||||
import frc4388.robot.subsystems.Shooter;
|
import frc4388.robot.subsystems.Shooter;
|
||||||
|
|
||||||
public class HoodPositionPID extends CommandBase {
|
public class HoodPositionPID extends CommandBase {
|
||||||
@@ -30,7 +31,9 @@ public class HoodPositionPID extends CommandBase {
|
|||||||
// Called every time the scheduler runs while the command is scheduled.
|
// Called every time the scheduler runs while the command is scheduled.
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
firingAngle = (-0.47*m_shooter.addFireAngle())+40.5;
|
double slope = ShooterConstants.HOOD_CONVERT_SLOPE;
|
||||||
|
double b = ShooterConstants.HOOD_CONVERT_B;
|
||||||
|
firingAngle = (-slope*m_shooter.addFireAngle())+b;
|
||||||
SmartDashboard.putNumber("Shoot Angle From Equation", m_shooter.addFireAngle());
|
SmartDashboard.putNumber("Shoot Angle From Equation", m_shooter.addFireAngle());
|
||||||
SmartDashboard.putNumber("Fire Angle", firingAngle);
|
SmartDashboard.putNumber("Fire Angle", firingAngle);
|
||||||
m_shooter.runAngleAdjustPID(firingAngle);
|
m_shooter.runAngleAdjustPID(firingAngle);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import frc4388.robot.subsystems.Storage;
|
|||||||
// https://docs.wpilib.org/en/latest/docs/software/commandbased/convenience-features.html
|
// https://docs.wpilib.org/en/latest/docs/software/commandbased/convenience-features.html
|
||||||
public class ShootPrepGroup extends ParallelCommandGroup {
|
public class ShootPrepGroup extends ParallelCommandGroup {
|
||||||
/**
|
/**
|
||||||
* Preps the Shooter to be fired
|
* Prepares the Shooter to be fired
|
||||||
* @param m_shooter The Shooter subsytem
|
* @param m_shooter The Shooter subsytem
|
||||||
* @param m_shooterAim The ShooterAim subsystem
|
* @param m_shooterAim The ShooterAim subsystem
|
||||||
* @param m_storage The Storage subsytem
|
* @param m_storage The Storage subsytem
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ package frc4388.robot.commands;
|
|||||||
|
|
||||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||||
import edu.wpi.first.wpilibj2.command.CommandBase;
|
import edu.wpi.first.wpilibj2.command.CommandBase;
|
||||||
|
import frc4388.robot.Constants.ShooterConstants;
|
||||||
import frc4388.robot.subsystems.Shooter;
|
import frc4388.robot.subsystems.Shooter;
|
||||||
|
|
||||||
public class ShooterVelocityControlPID extends CommandBase {
|
public class ShooterVelocityControlPID extends CommandBase {
|
||||||
@@ -16,9 +17,8 @@ public class ShooterVelocityControlPID extends CommandBase {
|
|||||||
double m_targetVel;
|
double m_targetVel;
|
||||||
double m_actualVel;
|
double m_actualVel;
|
||||||
/**
|
/**
|
||||||
* Creates a new ShooterVelocityControlPID.
|
* Runs the drum at a velocity
|
||||||
* @param subsystem The Shooter subsytem
|
* @param subsystem The Shooter subsytem
|
||||||
* @param targetVel The target velocity
|
|
||||||
*/
|
*/
|
||||||
public ShooterVelocityControlPID(Shooter subsystem) {
|
public ShooterVelocityControlPID(Shooter subsystem) {
|
||||||
m_shooter = subsystem;
|
m_shooter = subsystem;
|
||||||
@@ -48,9 +48,9 @@ public class ShooterVelocityControlPID extends CommandBase {
|
|||||||
// Returns true when the command should end.
|
// Returns true when the command should end.
|
||||||
@Override
|
@Override
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
//Tells wether the target velocity has been reached
|
//Tells whether the target velocity has been reached
|
||||||
double upperBound = m_targetVel + 300;
|
double upperBound = m_targetVel + ShooterConstants.DRUM_VELOCITY_BOUND;
|
||||||
double lowerBound = m_targetVel - 300;
|
double lowerBound = m_targetVel - ShooterConstants.DRUM_VELOCITY_BOUND;
|
||||||
if (m_actualVel < upperBound && m_actualVel > lowerBound){
|
if (m_actualVel < upperBound && m_actualVel > lowerBound){
|
||||||
SmartDashboard.putBoolean("ShooterVelocityPID Finished", true);
|
SmartDashboard.putBoolean("ShooterVelocityPID Finished", true);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ public class StorageIntake extends CommandBase {
|
|||||||
public Storage m_storage;
|
public Storage m_storage;
|
||||||
public boolean intook;
|
public boolean intook;
|
||||||
/**
|
/**
|
||||||
* Creates a new storageIntake.
|
* Runs the Storage in for intaking
|
||||||
|
* @param inSub The Intake subsystem
|
||||||
|
* @param storeSub The Storage subsytem
|
||||||
*/
|
*/
|
||||||
public StorageIntake(Intake inSub, Storage storeSub) {
|
public StorageIntake(Intake inSub, Storage storeSub) {
|
||||||
m_intake = inSub;
|
m_intake = inSub;
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import frc4388.robot.subsystems.Storage;
|
|||||||
public class StorageOutake extends CommandBase {
|
public class StorageOutake extends CommandBase {
|
||||||
Storage m_storage;
|
Storage m_storage;
|
||||||
/**
|
/**
|
||||||
* Creates a new storageOutake.
|
* Runs the Storage out for outaking
|
||||||
|
* @param storeSub The Storage subsystem
|
||||||
*/
|
*/
|
||||||
public StorageOutake(Storage storeSub) {
|
public StorageOutake(Storage storeSub) {
|
||||||
m_storage = storeSub;
|
m_storage = storeSub;
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ public class StoragePositionPID extends CommandBase {
|
|||||||
public Storage m_storage;
|
public Storage m_storage;
|
||||||
double startPos;
|
double startPos;
|
||||||
/**
|
/**
|
||||||
* Creates a new StoragePositionPID.
|
* Moves the storage a number of rotations
|
||||||
|
* @param subsystem The Storage subsystem
|
||||||
*/
|
*/
|
||||||
public StoragePositionPID(Storage subsystem) {
|
public StoragePositionPID(Storage subsystem) {
|
||||||
m_storage = subsystem;
|
m_storage = subsystem;
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ import frc4388.robot.subsystems.Storage;
|
|||||||
|
|
||||||
public class StoragePrepAim extends CommandBase {
|
public class StoragePrepAim extends CommandBase {
|
||||||
Storage m_storage;
|
Storage m_storage;
|
||||||
|
double startTime;
|
||||||
/**
|
/**
|
||||||
* Creates a new storagePrepAim.
|
* Prepares the Storage for aiming
|
||||||
|
* @param storeSub The Storage subsystem
|
||||||
*/
|
*/
|
||||||
public StoragePrepAim(Storage storeSub) {
|
public StoragePrepAim(Storage storeSub) {
|
||||||
m_storage = storeSub;
|
m_storage = storeSub;
|
||||||
@@ -25,6 +27,7 @@ public class StoragePrepAim extends CommandBase {
|
|||||||
// Called when the command is initially scheduled.
|
// Called when the command is initially scheduled.
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
|
startTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called every time the scheduler runs while the command is scheduled.
|
// Called every time the scheduler runs while the command is scheduled.
|
||||||
@@ -46,7 +49,7 @@ public class StoragePrepAim extends CommandBase {
|
|||||||
// Returns true when the command should end.
|
// Returns true when the command should end.
|
||||||
@Override
|
@Override
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
if (!m_storage.getBeam(1)){
|
if (!m_storage.getBeam(1) || startTime + StorageConstants.STORAGE_TIMEOUT <= System.currentTimeMillis()){
|
||||||
SmartDashboard.putBoolean("StoragePrepAim Finished", true);
|
SmartDashboard.putBoolean("StoragePrepAim Finished", true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ public class StoragePrepIntake extends CommandBase {
|
|||||||
public double startTime;
|
public double startTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new StoragePrepIntake.
|
* Prepares the Storage for intaking
|
||||||
|
* @param inSub The Intake subsystem
|
||||||
|
* @param storeSub the Storage subsystem
|
||||||
*/
|
*/
|
||||||
public StoragePrepIntake(Intake inSub, Storage storeSub) {
|
public StoragePrepIntake(Intake inSub, Storage storeSub) {
|
||||||
m_intake = inSub;
|
m_intake = inSub;
|
||||||
@@ -52,7 +54,7 @@ public class StoragePrepIntake extends CommandBase {
|
|||||||
// Returns true when the command should end.
|
// Returns true when the command should end.
|
||||||
@Override
|
@Override
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
if (!m_storage.getBeam(0) || startTime + 2000 <= System.currentTimeMillis()){
|
if (!m_storage.getBeam(0) || startTime + StorageConstants.STORAGE_TIMEOUT <= System.currentTimeMillis()){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ public class StorageRun extends CommandBase {
|
|||||||
// Called every time the scheduler runs while the command is scheduled.
|
// Called every time the scheduler runs while the command is scheduled.
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
System.err.println("oiudhgisbjkljasbhfkofhdnsekdfjbsjfvsdkcfbsdjhfgvsdkjfbsd");
|
|
||||||
m_storage.runStorage(StorageConstants.STORAGE_SPEED);
|
m_storage.runStorage(StorageConstants.STORAGE_SPEED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ public class TrackTarget extends CommandBase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the Limelight to track the target
|
* Uses the Limelight to track the target
|
||||||
|
* @param shooterSubsystem The Shooter subsystem
|
||||||
|
* @param aimSubsystem The ShooterAim subsystem
|
||||||
*/
|
*/
|
||||||
public TrackTarget(Shooter shooterSubsystem, ShooterAim aimSubsystem) {
|
public TrackTarget(Shooter shooterSubsystem, ShooterAim aimSubsystem) {
|
||||||
m_shooterAim = aimSubsystem;
|
m_shooterAim = aimSubsystem;
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ public class TrimShooter extends CommandBase {
|
|||||||
|
|
||||||
public Shooter m_shooter;
|
public Shooter m_shooter;
|
||||||
/**
|
/**
|
||||||
* Creates a new TrimShooter.
|
* Trims the shooter based on the D-Pad inputs
|
||||||
|
* @param shootSub The Shooter subsytems
|
||||||
*/
|
*/
|
||||||
public TrimShooter(Shooter shootSub) {
|
public TrimShooter(Shooter shootSub) {
|
||||||
m_shooter = shootSub;
|
m_shooter = shootSub;
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class Shooter extends SubsystemBase {
|
|||||||
public Trims shooterTrims;
|
public Trims shooterTrims;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a new Shooter subsystem.
|
* Creates a new Shooter subsystem, with the drum shooter and the angle adjsuter.
|
||||||
*/
|
*/
|
||||||
public Shooter() {
|
public Shooter() {
|
||||||
//Testing purposes reseting gyros
|
//Testing purposes reseting gyros
|
||||||
@@ -100,8 +100,8 @@ public class Shooter extends SubsystemBase {
|
|||||||
|
|
||||||
m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kForward, true);
|
m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kForward, true);
|
||||||
m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kReverse, true);
|
m_angleAdjustMotor.enableSoftLimit(SoftLimitDirection.kReverse, true);
|
||||||
m_angleAdjustMotor.setSoftLimit(SoftLimitDirection.kForward, 33);
|
m_angleAdjustMotor.setSoftLimit(SoftLimitDirection.kForward, ShooterConstants.HOOD_UP_SOFT_LIMIT);
|
||||||
m_angleAdjustMotor.setSoftLimit(SoftLimitDirection.kReverse, 3);
|
m_angleAdjustMotor.setSoftLimit(SoftLimitDirection.kReverse, ShooterConstants.HOOD_DOWN_SOFT_LIMIT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ public class Shooter extends SubsystemBase {
|
|||||||
*/
|
*/
|
||||||
public void runDrumShooterVelocityPID(double targetVel, double actualVel) {
|
public void runDrumShooterVelocityPID(double targetVel, double actualVel) {
|
||||||
SmartDashboard.putNumber("shoot", actualVel);
|
SmartDashboard.putNumber("shoot", actualVel);
|
||||||
if (actualVel < targetVel - 1000){
|
if (actualVel < targetVel - ShooterConstants.DRUM_RAMP_LIMIT){
|
||||||
m_shooterFalcon.set(TalonFXControlMode.PercentOutput, 1);//Ramp up
|
m_shooterFalcon.set(TalonFXControlMode.PercentOutput, 1);//Ramp up
|
||||||
}
|
}
|
||||||
else{ //PID Based on targetVel
|
else{ //PID Based on targetVel
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class ShooterAim extends SubsystemBase {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new ShooterAim.
|
* Creates a subsytem for the turret aiming
|
||||||
*/
|
*/
|
||||||
public ShooterAim() {
|
public ShooterAim() {
|
||||||
//resetGyroShooterRotate();
|
//resetGyroShooterRotate();
|
||||||
@@ -47,12 +47,12 @@ public class ShooterAim extends SubsystemBase {
|
|||||||
|
|
||||||
m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kForward, false);
|
m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kForward, false);
|
||||||
m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kReverse, true);
|
m_shooterRotateMotor.enableSoftLimit(SoftLimitDirection.kReverse, true);
|
||||||
m_shooterRotateMotor.setSoftLimit(SoftLimitDirection.kForward, -2);
|
m_shooterRotateMotor.setSoftLimit(SoftLimitDirection.kForward, ShooterConstants.TURRET_RIGHT_SOFT_LIMIT);
|
||||||
m_shooterRotateMotor.setSoftLimit(SoftLimitDirection.kReverse, -56);
|
m_shooterRotateMotor.setSoftLimit(SoftLimitDirection.kReverse, ShooterConstants.TURRET_LEFT_SOFT_LIMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void runShooterWithInput(double input) {
|
public void runShooterWithInput(double input) {
|
||||||
m_shooterRotateMotor.set(input/3);
|
m_shooterRotateMotor.set(input*ShooterConstants.TURRET_SPEED_MULTIPLIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -102,15 +102,4 @@ public class Storage extends SubsystemBase {
|
|||||||
public void setStoragePID(double position){
|
public void setStoragePID(double position){
|
||||||
m_storagePIDController.setReference(position , ControlType.kPosition);
|
m_storagePIDController.setReference(position , ControlType.kPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
If pressing aim
|
|
||||||
run unti; hitting top beam
|
|
||||||
else
|
|
||||||
Run until hitting bottom beam
|
|
||||||
dont run intake if balls not at bottom
|
|
||||||
|
|
||||||
2 beamms total
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user