Skip to content

Commit

Permalink
added back fault logging from old swervebase (+doglog fault logging)
Browse files Browse the repository at this point in the history
  • Loading branch information
PGgit08 committed Nov 17, 2024
1 parent ad68058 commit b490171
Show file tree
Hide file tree
Showing 7 changed files with 424 additions and 1 deletion.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ A base project for future robots that has CTRE generated swerve drive code and P
# Features
- Swerve drive code using CTRE's swerve code generator.
- Device logging with SignalLogger and data logging with Epilogue and DogLog.
- Device Fault Logging as telemetry for at-home testing. The faults are also logged with DogLog for post-match review.

# Todo
- Add the working stuff from other SwerveBase (fault logger, photon vision code).
- Add WPILib testing?
- Add WPILib unit testing?
- Add proper licenses

## 2025 Beta Known Issues
- To run sim, do `./gradlew simulateJava` instead of using the WPILib extension.
104 changes: 104 additions & 0 deletions src/main/java/frc/lib/CTREUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

package frc.lib;

import com.ctre.phoenix6.StatusCode;
import com.ctre.phoenix6.hardware.CANcoder;
import com.ctre.phoenix6.hardware.Pigeon2;
import com.ctre.phoenix6.hardware.TalonFX;
import frc.lib.FaultsTable.FaultType;
import java.util.function.Supplier;

/** Utility class for CTRE devices. */
public class CTREUtil {
/**
* Attempts to perform an action on a generic CTRE device. If the action returns a status code
* that is not OK, the action is re-attempted up to 5 times. If it fails after 5 attempts the
* status code is displayed in the fault logger.
*
* @param action The action to perform (returns a StatusCode).
* @param deviceName The name of the device for the fault logger.
* @return True if the attempt failed, False otherwise.
*/
public static boolean attempt(Supplier<StatusCode> action, String deviceName) {
StatusCode statusCode = StatusCode.OK;

for (int i = 0; i < 5; i++) {
// performs the action
statusCode = action.get();

if (statusCode.isOK()) {
break;
}
}

// successful attempt
if (statusCode.isOK()) {
FaultLogger.report(deviceName + ": Config Apply Successful.", FaultType.INFO);
return false;
}

// failed attempt
else {
FaultLogger.report(
deviceName + ": Config Apply Failed: " + statusCode.getDescription(), FaultType.ERROR);
return true;
}
}

/**
* Attempts to perform an action on a TalonFX. If the action returns a status code that is not OK,
* the action is re-attempted up to 5 times. If it fails after 5 attempts the status code is
* displayed in the fault logger.
*
* @param action The action to perform (returns a StatusCode).
* @param talonFX The TalonFX for the fault logger.
* @return True if the attempt failed, False otherwise.
*/
public static boolean attempt(Supplier<StatusCode> action, TalonFX talonFX) {
return attempt(action, getName(talonFX));
}

/**
* Attempts to perform an action on a CANCoder. If the action returns a status code that is not
* OK, the action is re-attempted up to 5 times. If it fails after 5 attempts the status code is
* displayed in the fault logger.
*
* @param action The action to perform (returns a StatusCode).
* @param cancoder The CANCoder for the fault logger.
* @return True if the attempt failed, False otherwise.
*/
public static boolean attempt(Supplier<StatusCode> action, CANcoder cancoder) {
return attempt(action, getName(cancoder));
}

/**
* Attempts to perform an action on a Pigeon2. If the action returns a status code that is not OK,
* the action is re-attempted up to 5 times. If it fails after 5 attempts the status code is
* displayed in the fault logger.
*
* @param action The action to perform (returns a StatusCode).
* @param pigeon The Pigeon for the fault logger.
* @return True if the attempt failed, False otherwise.
*/
public static boolean attempt(Supplier<StatusCode> action, Pigeon2 pigeon) {
return attempt(action, getName(pigeon));
}

/** Returns the name to use when displaying info about a TalonFX. */
public static String getName(TalonFX talonFX) {
return "TalonFX (" + talonFX.getDeviceID() + ")";
}

/** Returns the name to use when displaying info about a CANcoder. */
public static String getName(CANcoder cancoder) {
return "CANcoder (" + cancoder.getDeviceID() + ")";
}

/** Retunrs the name to use when displaying info about a Pigeon. */
public static String getName(Pigeon2 pigeon) {
return "Pigeon (" + pigeon.getDeviceID() + ")";
}
}
241 changes: 241 additions & 0 deletions src/main/java/frc/lib/FaultLogger.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

package frc.lib;

import com.ctre.phoenix6.hardware.CANcoder;
import com.ctre.phoenix6.hardware.Pigeon2;
import com.ctre.phoenix6.hardware.TalonFX;
import dev.doglog.DogLog;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.DriverStation;
import frc.lib.FaultsTable.Fault;
import frc.lib.FaultsTable.FaultType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

// (from team 1155 but slightly modified)

/**
* FaultLogger allows for faults and errors to be logged and displayed.
*
* <pre>
* FaultLogger.register(talonfx); // registers a TalonFX, periodically checking for hardware faults.
* </pre>
*/
public final class FaultLogger {
@FunctionalInterface
public static interface FaultReporter {
void report();
}

// DATA
private static final List<FaultReporter> faultReporters = new ArrayList<>();
private static final Set<Fault> newFaults = new HashSet<>();
private static final Set<Fault> activeFaults = new HashSet<>();
private static final Set<Fault> totalFaults = new HashSet<>();

// NETWORK TABLES
private static final NetworkTable base = NetworkTableInstance.getDefault().getTable("Faults");
private static final FaultsTable activeAlerts = new FaultsTable(base, "Active Faults");
private static final FaultsTable totalAlerts = new FaultsTable(base, "Total Faults");

/** Polls registered fallibles. This method should be called periodically. */
public static void update() {
activeFaults.clear();

faultReporters.forEach(f -> f.report());
activeFaults.addAll(newFaults);
newFaults.clear();

// log to doglog as well
activeFaults.forEach(f -> DogLog.logFault(f.description()));

totalFaults.addAll(activeFaults);

// don't log to NT if there is a match going on (just use doglog)
if (!DriverStation.isFMSAttached()) {
activeAlerts.set(activeFaults);
totalAlerts.set(totalFaults);
}
}

/** Clears total faults. */
public static void clear() {
totalFaults.clear();
activeFaults.clear();
newFaults.clear();
}

/** Clears fault suppliers. */
public static void unregisterAll() {
faultReporters.clear();
}

/**
* Returns the set of all current faults.
*
* @return The set of all current faults.
*/
public static Set<Fault> activeFaults() {
return activeFaults;
}

/**
* Returns the set of all total faults.
*
* @return The set of all total faults.
*/
public static Set<Fault> totalFaults() {
return totalFaults;
}

/**
* Reports a fault.
*
* @param fault The fault to report.
*/
public static void report(Fault fault) {
newFaults.add(fault);

switch (fault.type()) {
case ERROR -> DriverStation.reportError(fault.toString(), false);
case WARNING -> DriverStation.reportWarning(fault.toString(), false);
case INFO -> System.out.println(fault.toString());
}
}

/**
* Reports a fault.
*
* @param description The description of the fault.
* @param type The type of the fault.
*/
public static void report(String description, FaultType type) {
report(new Fault(description, type));
}

/**
* Registers a new fault supplier.
*
* @param supplier A supplier of an optional fault.
*/
public static void register(Supplier<Optional<Fault>> supplier) {
faultReporters.add(() -> supplier.get().ifPresent(FaultLogger::report));
}

/**
* Registers a new fault supplier.
*
* @param condition Whether a failure is occuring.
* @param description The failure's description.
*/
public static void register(BooleanSupplier condition, String description, FaultType type) {
faultReporters.add(
() -> {
if (condition.getAsBoolean()) {
report(description, type);
}
});
}

/**
* Registers a new TalonFX.
*
* @param talonFX The TalonFX.
*/
public static void register(TalonFX talonFX) {
String name = CTREUtil.getName(talonFX);

register(
() -> talonFX.getFault_Hardware().getValue(), name + ": Hardware Fault.", FaultType.ERROR);
register(
() -> talonFX.getFault_BootDuringEnable().getValue(),
name + ": Boot While Enabling.",
FaultType.WARNING);
register(
() -> talonFX.getFault_DeviceTemp().getValue(),
name + ": Device Temperature Too High.",
FaultType.WARNING);
register(
() -> talonFX.getFault_ProcTemp().getValue(),
name + ": Processor Temp Too High.",
FaultType.WARNING);
register(
() -> talonFX.getFault_Undervoltage().getValue(),
name + ": Voltage Too Low, Check For Brownouts.",
FaultType.WARNING);
}

/**
* Registers a new CANcoder.
*
* @param cancoder The CANcoder.
*/
public static void register(CANcoder cancoder) {
String name = CTREUtil.getName(cancoder);

register(
() -> cancoder.getFault_Hardware().getValue(), name + ": Hardware Fault.", FaultType.ERROR);
register(
() -> cancoder.getFault_BadMagnet().getValue(),
name + ": Bad Magnet Signal.",
FaultType.ERROR);
register(
() -> cancoder.getFault_BootDuringEnable().getValue(),
name + ": Boot While Enabling.",
FaultType.WARNING);
register(
() -> cancoder.getFault_Undervoltage().getValue(),
name + ": Voltage Too Low, Check For Brownouts.",
FaultType.WARNING);
}

/**
* Registers a new Pigeon.
*
* @param pigeon The Pigeon.
*/
public static void register(Pigeon2 pigeon) {
String name = CTREUtil.getName(pigeon);

register(
() -> pigeon.getFault_Hardware().getValue(), name + ": Hardware Fault.", FaultType.ERROR);
register(
() -> pigeon.getFault_BootDuringEnable().getValue(),
name + ": Boot While Enabling.",
FaultType.WARNING);
register(
() -> pigeon.getFault_Undervoltage().getValue(),
name + ": Voltage Too Low, Check For Brownouts.",
FaultType.WARNING);
}

// /**
// * Registers a new NavX.
// *
// * @param navx The NavX.
// */
// public static void register(AHRS navx) {
// register(() -> !navx.isConnected(), "NavX: Disconnected", FaultType.ERROR);
// }

// /**
// * Registers a new PhotonCamera. Detailed PhotonVision logs are located on the web UI, so
// this is just for very basic
// * telemetry to have in a dashboard when testing.
// *
// * @param photonCamera The PhotonCamera.
// */
// public static void register(PhotonCamera photonCamera) {
// register(() -> !photonCamera.isConnected(), photonCamera.getName() + ": Disconnected.",
// FaultType.ERROR);
// }
}
Loading

0 comments on commit b490171

Please sign in to comment.