package Systems; import edu.wpi.first.wpilibj.CANTalon; import edu.wpi.first.wpilibj.Joystick; import edu.wpi.first.wpilibj.Utility; public class CatapultAssembly { private static boolean initialized = false; // joystick device ids private static final int LEFT_JOYSTICK_ID = 0; private static final int RIGHT_JOYSTICK_ID = 1; // control objects private static Joystick leftJoy, rightJoy; // catapult reset motor private static final int CATAPULT_MOTOR_ID = 9; private static final double NUM_TICKS_PER_REV = 4096; private static final double VERSAPLANETARY_RATIO = 100; private static final double CHOO_CHOO_GEAR_RATIO = 84.0/18.0; private static final double FIRE_ROTATION_BACKOFF_REV = 0.25; private static final double AUTO_RESET_TIME_US = 1000000; private static final double CATAPULT_ROTATION_MULTIPLIER = 1.005; private static final double CATAPULT_FIRE_INCREMENT = FIRE_ROTATION_BACKOFF_REV*NUM_TICKS_PER_REV*VERSAPLANETARY_RATIO*CHOO_CHOO_GEAR_RATIO; private static final double CATAPULT_READY_POSITION = (NUM_TICKS_PER_REV*VERSAPLANETARY_RATIO*CHOO_CHOO_GEAR_RATIO) - CATAPULT_FIRE_INCREMENT; private static final double CATAPULT_FULL_REVOLUTION = (NUM_TICKS_PER_REV*VERSAPLANETARY_RATIO*CHOO_CHOO_GEAR_RATIO)*CATAPULT_ROTATION_MULTIPLIER; // test values for choo-choo - not for normal operation //private static final double CATAPULT_FIRE_INCREMENT = 4096*50; //private static final double CATAPULT_READY_POSITION = 4096*50; private static final int TRIGGER_CYCLE_WAIT_US = 1000000; private static CANTalon catapultMotor; private static boolean catapultKill; private static boolean pressed; private static boolean catapultFired; private static double initTriggerTime; // static initializer public static void initialize() { if (!initialized) { leftJoy = new Joystick(LEFT_JOYSTICK_ID); rightJoy = new Joystick(RIGHT_JOYSTICK_ID); initialized = true; catapultFired = false; // Assumption! catapult starts in the high-energy (ready to shoot) state pressed = false; catapultKill = false; // disable catapult motor if goes wonky System.out.println("Creating catapult motor object..."); // initialize master catapult motor catapultMotor = new CANTalon(CATAPULT_MOTOR_ID); if (catapultMotor != null) { System.out.println("Initializing catapult motor (position mode)..."); //catapultMotor.clearStickyFaults(); // VERY IMPORTANT - CATAPULT MOTOR CAN ONLY BE RUN IN ONE DIRECTION // set up motor for position control mode (PID) catapultMotor.enableControl(); // enables PID control catapultMotor.changeControlMode(CANTalon.TalonControlMode.Position); catapultMotor.setFeedbackDevice(CANTalon.FeedbackDevice.QuadEncoder); //catapultMotor.clearIAccum(); // clear error in PID control catapultMotor.reverseOutput(true); // NEED TO REVERSE OUTPUT - used for closed loops modes only catapultMotor.reverseSensor(true); // encoder needs to be reversed catapultMotor.setPID(0.1, 0, 0.0); //catapultMotor.set(catapultMotor.getPosition()); // set motor to current position catapultMotor.setPosition(0); // initializes encoder to zero catapultMotor.enableBrakeMode(true); //******* VBUS CONTROL ONLY /* catapultMotor.changeControlMode(CANTalon.TalonControlMode.PercentVbus); catapultMotor.enableBrakeMode(true); catapultMotor.setInverted(true); // NEED TO REVERSE OUTPUT - used for Vbus mode ONLY catapultMotor.reverseSensor(true); catapultMotor.setPosition(0); // initializes encoder to zero */ } else System.out.println("ERROR: Catapult motor not initialized!"); } } public static void autoInit() { pressed = false; initTriggerTime = Utility.getFPGATime(); // reset on mode entry, if not ready to shoot if (!readyToShoot()) reset(); } public static void teleopInit() { pressed = false; initTriggerTime = Utility.getFPGATime(); // reset on mode entry, if not ready to shoot if (!readyToShoot()) reset(); } public static void teleopPeriodic() { double currentTime = Utility.getFPGATime(); // if not enough time has passed, no polling allowed! if ((currentTime - initTriggerTime) < TRIGGER_CYCLE_WAIT_US) return; if ((leftJoy.getRawButton(8) || rightJoy.getRawButton(8)) && !catapultKill) { catapultKill = true; catapultMotor.disable(); } if (!catapultKill) { // check for catapult triggers if (leftJoy.getTrigger() && rightJoy.getTrigger() && !pressed) { pressed = true; System.out.println("trigger pressed!"); // reset trigger init time initTriggerTime = Utility.getFPGATime(); // shoot catapult and reset to ready state if (pressed) { shootAndReset(); } } } // quick vbus test - only use when CANDrive not active /* double speed = 0.0; if (leftJoy.getTrigger() && rightJoy.getTrigger()) { speed = 0.2; } System.out.println("catapult motor speed = " + speed + " enc pos = " + catapultMotor.getPosition()); catapultMotor.set(speed); */ } public static void disabledInit() { } public static void shoot() { // if front arm is low enough and catapult ready to shoot... if (FrontArmAssembly.isArmLowEnoughForCatapult() && readyToShoot()) { // fire catapult catapultMotor.setPosition(0); catapultMotor.set(CATAPULT_FIRE_INCREMENT); System.out.println("Catapult Fired! new pos = " + catapultMotor.getPosition()); // set fired flag catapultFired = true; } pressed = false; } public static void reset() { // if in need of a reset... if (isFired()) { // reset catapult motor catapultMotor.setPosition(0); catapultMotor.set(CATAPULT_READY_POSITION); System.out.println("Catapult Reset! new pos = " + catapultMotor.getPosition()); // TODO: resets are not instantaneous. From the command to the final reset state takes a couple of seconds. // Although this delay may introduce a race condition, we do NOT want to introduce wait/delay states. // reset fired flag catapultFired = false; } pressed = false; } public static void shootAndReset() { // if front arm is low enough and catapult is ready to shoot... if (FrontArmAssembly.isArmLowEnoughForCatapult() && readyToShoot()) { // fire and reset catapult catapultMotor.setPosition(0); catapultMotor.set(CATAPULT_FULL_REVOLUTION); System.out.println("Catapult fired AND reset! new pos = " + catapultMotor.getPosition()); // TODO: motor movements are not instantaneous. From the command to the final reset state takes a couple of seconds. // Although this delay may introduce a race condition, we do NOT want to introduce wait/delay states. // reset fired flag catapultFired = false; } pressed = false; } public static boolean isFired() { return catapultFired; } public static boolean readyToShoot() { return !catapultFired; } }