/* * Strongback * Copyright 2015, Strongback and individual contributors by the @authors tag. * See the COPYRIGHT.txt in the distribution for a full listing of individual * contributors. * * Licensed under the MIT License; you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://opensource.org/licenses/MIT * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.strongback.hardware; import java.util.Collections; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.strongback.Executable; import org.strongback.annotation.ThreadSafe; import org.strongback.control.Controller; import org.strongback.control.PIDController; import org.strongback.control.TalonController; import edu.wpi.first.wpilibj.CANTalon; import edu.wpi.first.wpilibj.CANTalon.TalonControlMode; /** * A hardware-based Talon SRX PID controller. */ @ThreadSafe class HardwareTalonController extends HardwareTalonSRX implements TalonController { private static final Executable NO_OP = (clock) -> { }; private static final class Gains implements TalonController.Gains { private final double p; private final double i; private final double d; private final double feedForward; private final double iZone; private final double closedLoopRampRate; protected Gains(double p, double i, double d, double feedForward, double iZone, double closeLoopRampRate) { this.p = p; this.i = i; this.d = d; this.feedForward = feedForward; this.iZone = iZone; this.closedLoopRampRate = closeLoopRampRate; }; @Override public double getP() { return p; } @Override public double getI() { return i; } @Override public double getD() { return d; } @Override public double getFeedForward() { return feedForward; } @Override public double getIzone() { return iZone; } @Override public double getCloseLoopRampRate() { return closedLoopRampRate; } } private double tolerance; private volatile int currentProfile = 0; private final Set<Integer> profiles = Collections.newSetFromMap(new ConcurrentHashMap<>()); HardwareTalonController(CANTalon talon, double pulsesPerDegree, double analogTurnsOverVoltageRange) { super(talon, pulsesPerDegree, analogTurnsOverVoltageRange); profiles.add(currentProfile); } @Override public Controller disable() { talon.disable(); return this; } @Override public Controller enable() { talon.enableControl(); return this; } @Override public boolean isEnabled() { return talon.isControlEnabled(); } @Override public double getValue() { return talon.get(); } @Override public double getTarget() { double targetPosition = talon.getSetpoint(); return this.selectedInput.angleInDegreesFromRawPosition(targetPosition); } @Override public TalonController withTarget(double angleInDegrees) { talon.set(this.selectedInput.rawPositionForAngleInDegrees(angleInDegrees)); return this; } @Override public double getTolerance() { return this.tolerance; } @Override public TalonController withTolerance(double tolerance) { this.tolerance = tolerance; return this; } @Override public boolean computeOutput() { // The Talon SRX is always computing output, so we don't have to do anything except // return whether we're within tolerance ... return isWithinTolerance(); } @Override public Controller reset() { talon.ClearIaccum(); return this; } @Override public Executable executable() { return NO_OP; } @Override public boolean hasExecutable() { return false; } @Override public ControlMode getControlMode() { return ControlMode.valueOf(talon.getControlMode().value); } @Override public TalonController setControlMode(ControlMode mode) { talon.changeControlMode(TalonControlMode.valueOf(mode.value())); return this; } @Override public TalonController setFeedbackDevice(FeedbackDevice device) { super.setFeedbackDevice(device); return this; } @Override public TalonController setStatusFrameRate(StatusFrameRate frameRate, int periodMillis) { talon.setStatusFrameRateMs(edu.wpi.first.wpilibj.CANTalon.StatusFrameRate.valueOf(frameRate.value()), periodMillis); return this; } @Override public TalonController reverseOutput(boolean flip) { talon.reverseOutput(flip); return this; } @Override public TalonController reverseSensor(boolean flip) { super.reverseSensor(flip); return this; } @Override public TalonController setForwardSoftLimit(int forwardLimitDegrees) { super.setForwardSoftLimit(forwardLimitDegrees); return this; } @Override public HardwareTalonController enableForwardSoftLimit(boolean enable) { super.enableForwardSoftLimit(enable); return this; } @Override public HardwareTalonController setReverseSoftLimit(int reverseLimitDegrees) { super.setReverseSoftLimit(reverseLimitDegrees); return this; } @Override public HardwareTalonController enableReverseSoftLimit(boolean enable) { super.enableReverseSoftLimit(enable); return this; } @Override public HardwareTalonController enableLimitSwitch(boolean forward, boolean reverse) { super.enableLimitSwitch(forward, reverse); return this; } @Override public HardwareTalonController enableBrakeMode(boolean brake) { super.enableBrakeMode(brake); return this; } @Override public HardwareTalonController setForwardLimitSwitchNormallyOpen(boolean normallyOpen) { super.setForwardLimitSwitchNormallyOpen(normallyOpen); return this; } @Override public HardwareTalonController setReverseLimitSwitchNormallyOpen(boolean normallyOpen) { super.setReverseLimitSwitchNormallyOpen(normallyOpen); return this; } @Override public HardwareTalonController withGains(double p, double i, double d) { talon.setPID(p, i, d); return this; } @Override public HardwareTalonController withGains(double p, double i, double d, double feedForward) { talon.setPID(p, i, d); talon.setF(feedForward); return this; } @Override public HardwareTalonController withGains(double p, double i, double d, double feedForward, int izone, double closeLoopRampRate) { talon.setPID(p, i, d); talon.setF(feedForward); talon.setIZone(izone); talon.setCloseLoopRampRate(closeLoopRampRate); return this; } @Override public HardwareTalonController withProfile(int profile, double p, double i, double d) { return withProfile(profile,p,i,d,0.0,0,0.0); } @Override public HardwareTalonController withProfile(int profile, double p, double i, double d, double feedForward) { return withProfile(profile,p,i,d,feedForward,0,0.0); } @Override public HardwareTalonController withProfile(int profile, double p, double i, double d, double feedForward, int izone, double closeLoopRampRate) { talon.setPID(p, i, d, feedForward, izone, closeLoopRampRate, profile); return this; } @Override public PIDController useProfile(int profile) { talon.setProfile(profile); this.currentProfile = profile; this.profiles.add(profile); return this; } @Override public int getCurrentProfile() { return currentProfile; } @Override public Set<Integer> getProfiles() { return Collections.unmodifiableSet(profiles); } @Override public TalonController.Gains getGainsForCurrentProfile() { return new Gains(talon.getP(),talon.getI(), talon.getD(), talon.getF(), talon.getIZone(), talon.getCloseLoopRampRate()); } @Override public TalonController setVoltageRampRate(double rampRate) { super.setVoltageRampRate(rampRate); return this; } @Override public TalonController clearStickyFaults() { super.clearStickyFaults(); return this; } @Override public TalonController setSafetyEnabled(boolean enabled) { super.setSafetyEnabled(enabled); return this; } @Override public TalonController setExpiration(double timeout) { super.setExpiration(timeout); return this; } }