package com.team254.frc2015.subsystems; import com.team254.frc2015.Constants; import com.team254.frc2015.ElevatorSafety; import com.team254.frc2015.subsystems.controllers.BangBangFinishLineController; import com.team254.frc2015.subsystems.controllers.ElevatorSqueezeController; import com.team254.frc2015.subsystems.controllers.TrajectoryFollowingPositionController; import com.team254.lib.trajectory.TrajectoryFollower; import com.team254.lib.util.*; import edu.wpi.first.wpilibj.ChezyInterruptHandlerFunction; import edu.wpi.first.wpilibj.DigitalInput; import edu.wpi.first.wpilibj.Encoder; import edu.wpi.first.wpilibj.Solenoid; public class ElevatorCarriage extends Subsystem implements Loopable { public CheesySpeedController m_motor; public Solenoid m_brake; public Encoder m_encoder; public DigitalInput m_home; protected Controller m_controller = null; protected boolean m_initialized = true; protected double m_zero_offset = 0; private boolean m_fast_hit_top = false; private boolean m_interrupts_on = false; protected ChezyInterruptHandlerFunction<ElevatorCarriage> isr = new ChezyInterruptHandlerFunction<ElevatorCarriage>() { @Override public void interruptFired(int interruptAssertedMask, ElevatorCarriage param) { if (!m_initialized) { m_zero_offset = getRelativeHeight(); m_initialized = true; disableInterrupts(); System.out.println("Interrupt hit! " + m_zero_offset); } } @Override public ElevatorCarriage overridableParamater() { return ElevatorCarriage.this; } }; private void enableInterrupts() { if (!m_interrupts_on) { m_home.requestInterrupts(isr); m_home.setUpSourceEdge(false, true); // Pulled high be default, need falling edge m_interrupts_on = true; m_home.enableInterrupts(); } else { System.err.println("You done goofed. Don't request interrupts twice!"); } } public void disableInterrupts() { m_home.disableInterrupts(); m_interrupts_on = false; } public void findHome() { m_initialized = false; enableInterrupts(); } protected Limits m_limits = new Limits(); boolean m_brake_on_target = false; public class Limits { protected double m_min_position; protected double m_max_position; protected double m_rezero_position; protected double m_home_position; } public ElevatorCarriage(String name, CheesySpeedController motor, Solenoid brake, Encoder encoder, DigitalInput home, boolean needs_init) { super(name); m_motor = motor; m_brake = brake; m_encoder = encoder; m_home = home; m_initialized = !needs_init; reloadConstants(); } public Controller getCurrentController() { return m_controller; } public double getEncoderVelocity() { return m_encoder.getRate() * 2.0 * Constants.kElevatorPulleyRadiusInches * Math.PI / Constants.kElevatorEncoderCountsPerRev; } protected double getRelativeHeight() { return m_encoder.get() * 2.0 * Constants.kElevatorPulleyRadiusInches * Math.PI / Constants.kElevatorEncoderCountsPerRev; } public double getHeight() { if (m_initialized) { return m_limits.m_rezero_position + (getRelativeHeight() - m_zero_offset); } else { return getRelativeHeight() + m_limits.m_home_position; } } public double getVelocity() { return m_encoder.getRate() * 2.0 * Constants.kElevatorPulleyRadiusInches * Math.PI / Constants.kElevatorEncoderCountsPerRev; } public TrajectoryFollower.TrajectorySetpoint getSetpoint() { TrajectoryFollower.TrajectorySetpoint setpoint; // Rather than reading encoder velocity, we report the last commanded // velocity from a velocity profile. This ensures that the input is // smooth when changing setpoints. if (m_controller instanceof TrajectoryFollowingPositionController) { setpoint = ((TrajectoryFollowingPositionController) m_controller) .getSetpoint(); } else { setpoint = new TrajectoryFollower.TrajectorySetpoint(); setpoint.pos = getHeight(); } return setpoint; } public double getGoalHeight() { if (m_controller instanceof TrajectoryFollowingPositionController) { return ((TrajectoryFollowingPositionController) m_controller) .getGoal(); } else if (m_controller instanceof BangBangFinishLineController) { return ((BangBangFinishLineController) m_controller).getGoal(); } else { return -1; } } public double getCommand() { return m_motor.get(); } protected void setSpeedUnsafe(double speed) { m_motor.set(speed); } @Override public void reloadConstants() { m_controller = null; } protected void setSpeedOpenLoopSafe(double desired_speed) { if (desired_speed > 1E-3 || desired_speed < -1E-3) { setBrake(false); } setSpeedUnsafe(desired_speed); } protected void setSpeedSafe(double desired_speed) { double height = getHeight(); if (desired_speed > 1E-3 || desired_speed < -1E-3) { setBrake(false); } if (height >= m_limits.m_max_position) { desired_speed = Math.min(0, desired_speed); } else if (height <= m_limits.m_min_position) { desired_speed = Math.max(0, desired_speed); } setSpeedUnsafe(desired_speed); } protected void setBrake(boolean on) { m_brake.set(on); // brake is normally applied if (on) { setSpeedUnsafe(0); } } public boolean getBrake() { return m_brake.get(); } public synchronized void setPositionSetpointUnsafe(double setpoint, boolean brake_on_target) { m_brake_on_target = brake_on_target; TrajectoryFollower.TrajectorySetpoint prior_setpoint = getSetpoint(); if (!(m_controller instanceof TrajectoryFollowingPositionController)) { TrajectoryFollower.TrajectoryConfig config = new TrajectoryFollower.TrajectoryConfig(); config.dt = Constants.kControlLoopsDt; config.max_acc = Constants.kElevatorMaxAccelInchesPerSec2; config.max_vel = Constants.kElevatorMaxSpeedInchesPerSec; m_controller = new TrajectoryFollowingPositionController( Constants.kElevatorCarriagePositionKp, Constants.kElevatorCarriagePositionKi, Constants.kElevatorCarriagePositionKd, Constants.kElevatorCarriagePositionKv, Constants.kElevatorCarriagePositionKa, Constants.kElevatorOnTargetError, config); } ((TrajectoryFollowingPositionController) m_controller).setGoal( prior_setpoint, setpoint); } public synchronized void setPositionSetpoint(double setpoint, boolean brake_on_target) { setPositionSetpointUnsafe(setpoint, brake_on_target); } public synchronized void setFastPositionSetpoint(double setpoint) { if (!(m_controller instanceof BangBangFinishLineController)) { m_controller = new BangBangFinishLineController(0.5); } m_controller.reset(); m_fast_hit_top = false; ((BangBangFinishLineController) m_controller).setGoal(setpoint); } public boolean isInitialized() { return m_initialized; } public synchronized void setOpenLoop(double speed, boolean brake) { m_controller = null; setBrake(brake); setSpeedOpenLoopSafe(speed); } public synchronized void squeeze() { if (!(m_controller instanceof ElevatorSqueezeController)) { m_controller = new ElevatorSqueezeController(); } } public boolean fastHitTop() { return m_fast_hit_top; } private void setSpeedIfValid(double speed) { if (m_controller instanceof TrajectoryFollowingPositionController) { TrajectoryFollowingPositionController position_controller = (TrajectoryFollowingPositionController) m_controller; if (!ElevatorSafety .isMoveLegal(this, position_controller.getSetpoint())) { // If this move is illegal, stop immediately. TrajectoryFollower.TrajectorySetpoint setpoint = new TrajectoryFollower.TrajectorySetpoint(); setpoint.pos = getHeight(); position_controller.setGoal(setpoint, getHeight()); setSpeedSafe(0.0); } else { setSpeedSafe(speed); } } else if (m_controller instanceof BangBangFinishLineController) { BangBangFinishLineController bangbang = (BangBangFinishLineController) m_controller; if (!ElevatorSafety.isMoveLegal(this, bangbang.getGoal())) { // Stop immediately. setSpeedSafe(0.0); setBrake(true); m_fast_hit_top = true; System.out.println("Hit top!!!!"); m_controller = null; } else { setSpeedSafe(speed); } } } @Override public synchronized void update() { if (m_controller instanceof TrajectoryFollowingPositionController) { TrajectoryFollowingPositionController position_controller = (TrajectoryFollowingPositionController) m_controller; if (position_controller.isOnTarget()) { // No need to brake at bottom of travel. setBrake(m_brake_on_target && getHeight() > 1.0); position_controller.update(getHeight(), getVelocity()); if (!m_brake_on_target) { setSpeedIfValid(position_controller.get()); } else { setOpenLoop(0, true); m_controller = null; } } else { position_controller.update(getHeight(), getVelocity()); setSpeedIfValid(position_controller.get()); } } else if (m_controller instanceof BangBangFinishLineController) { double power = ((BangBangFinishLineController) m_controller).update(getHeight()); if (power != 0.0) { setBrake(false); setSpeedIfValid(power); } else { setBrake(true); } } else if (m_controller instanceof ElevatorSqueezeController) { double power = ((ElevatorSqueezeController) m_controller) .update(); setBrake(false); setSpeedSafe(power); } else { // Do nothing } // Failsafe if (getBrake()) { setSpeedUnsafe(0); } } @Override public void getState(StateHolder states) { states.put("height", getHeight()); states.put("velocity", getEncoderVelocity()); states.put("setpoint", getSetpoint().pos); states.put("home_dio", getHomeSensorHovered()); states.put("current", m_motor.getSignedCurrent()); states.put("pwm", m_motor.get()); states.put("intialized", m_initialized); } public boolean getHomeSensorHovered() { return !m_home.get(); } public boolean isOnTarget() { return m_initialized && (m_controller != null ? m_controller.isOnTarget() : true); } }