Skip to content

Commit ae7a9d3

Browse files
authored
Merge pull request #87 from strykeforce/telemetry-registrable
Add Registrable interface to Telemetry
2 parents 3ace184 + 459d402 commit ae7a9d3

File tree

7 files changed

+141
-5
lines changed

7 files changed

+141
-5
lines changed

src/main/java/org/strykeforce/swerve/SwerveDrive.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
import org.jetbrains.annotations.NotNull;
1717
import org.slf4j.Logger;
1818
import org.slf4j.LoggerFactory;
19+
import org.strykeforce.telemetry.Registrable;
20+
import org.strykeforce.telemetry.TelemetryService;
1921

2022
/** Control a Third Coast swerve drive. */
21-
public class SwerveDrive {
23+
public class SwerveDrive implements Registrable {
2224

2325
private static final Logger logger = LoggerFactory.getLogger(SwerveDrive.class);
2426

@@ -271,4 +273,11 @@ public void setModuleStates(SwerveModuleState[] desiredStates) {
271273
swerveModules[i].setDesiredState(desiredStates[i], true);
272274
}
273275
}
276+
277+
@Override
278+
public void registerWith(@NotNull TelemetryService telemetryService) {
279+
for (SwerveModule swerveModule : swerveModules) {
280+
swerveModule.registerWith(telemetryService);
281+
}
282+
}
274283
}

src/main/java/org/strykeforce/swerve/SwerveModule.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
import edu.wpi.first.math.geometry.Translation2d;
44
import edu.wpi.first.math.kinematics.SwerveModuleState;
5+
import org.strykeforce.telemetry.Registrable;
56

67
/** Represents a Third Coast swerve module. */
7-
public interface SwerveModule {
8+
public interface SwerveModule extends Registrable {
89

910
/**
1011
* Gets the maximum attainable speed of the drive.

src/main/java/org/strykeforce/swerve/TalonSwerveModule.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
import edu.wpi.first.math.kinematics.SwerveModuleState;
1313
import edu.wpi.first.math.util.Units;
1414
import edu.wpi.first.wpilibj.Preferences;
15+
import org.jetbrains.annotations.NotNull;
1516
import org.slf4j.Logger;
1617
import org.slf4j.LoggerFactory;
18+
import org.strykeforce.telemetry.TelemetryService;
1719

1820
/**
1921
* A swerve module that uses Talons for azimuth and drive motors. Uses a {@link Builder} to
@@ -201,6 +203,12 @@ private int getWheelIndex() {
201203
return 3;
202204
}
203205

206+
@Override
207+
public void registerWith(@NotNull TelemetryService telemetryService) {
208+
telemetryService.register(azimuthTalon);
209+
telemetryService.register(driveTalon);
210+
}
211+
204212
@Override
205213
public String toString() {
206214
return "TalonSwerveModule{" + getWheelIndex() + '}';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.strykeforce.telemetry
2+
3+
/**
4+
* A class that has one or more [Measurable] objects that should be registered with the [TelemetryService].
5+
*
6+
*/
7+
interface Registrable {
8+
9+
/**
10+
* Register this class with a [TelemetryService].
11+
*
12+
* This method should be called once during robot initialization before the [TelemetryService] is started.
13+
*
14+
* @param telemetryService the initialized TelemetryService to register with
15+
* @throws IllegalStateException if TelemetryService is currently running
16+
*/
17+
fun registerWith(telemetryService: TelemetryService)
18+
}

src/main/kotlin/org/strykeforce/telemetry/TelemetryService.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22

33
package org.strykeforce.telemetry
44

5+
import com.ctre.phoenix.motorcontrol.can.BaseTalon
56
import com.ctre.phoenix.motorcontrol.can.TalonFX
67
import com.ctre.phoenix.motorcontrol.can.TalonSRX
78
import mu.KotlinLogging
9+
import org.strykeforce.telemetry.measurable.BaseTalonMeasurable
810
import org.strykeforce.telemetry.measurable.Measurable
911
import org.strykeforce.telemetry.measurable.TalonSRXMeasurable
1012
import org.strykeforce.thirdcoast.talon.TalonFXMeasurable
@@ -95,7 +97,17 @@ class TelemetryService(private val telemetryControllerFactory: Function<Inventor
9597
fun registerAll(collection: Collection<Measurable>) = collection.forEach(this::register)
9698

9799
/**
98-
* Convenience method to register a `TalonSRX` for telemetry sending.
100+
* Convenience method to register a [BaseTalon] for telemetry sending.
101+
*
102+
* @param talon the BaseTalon to register for data collection
103+
* @throws IllegalStateException if TelemetryService is running.
104+
*/
105+
fun register(talon: BaseTalon) {
106+
register(BaseTalonMeasurable(talon))
107+
}
108+
109+
/**
110+
* Convenience method to register a [TalonSRX] for telemetry sending.
99111
*
100112
* @param talon the TalonSRX to register for data collection
101113
* @throws IllegalStateException if TelemetryService is running.
@@ -105,7 +117,7 @@ class TelemetryService(private val telemetryControllerFactory: Function<Inventor
105117
}
106118

107119
/**
108-
* Convenience method to register a `TalonFX` for telemetry sending.
120+
* Convenience method to register a [TalonFX] for telemetry sending.
109121
*
110122
* @param talon the TalonSRX to register for data collection
111123
* @throws IllegalStateException if TelemetryService is running.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package org.strykeforce.telemetry.measurable
2+
3+
import com.ctre.phoenix.motorcontrol.can.BaseTalon
4+
5+
/** Represents a [BaseTalon] telemetry-enable [Measurable] item. */
6+
class BaseTalonMeasurable @JvmOverloads constructor(
7+
private val talon: BaseTalon, override val description: String = "BaseTalon ${talon.deviceID}"
8+
) : Measurable {
9+
override val deviceId = talon.deviceID
10+
11+
override val measures = setOf(Measure(
12+
CLOSED_LOOP_TARGET, "Closed-loop Setpoint (PID 0)"
13+
) { talon.getClosedLoopTarget(0) },
14+
Measure(
15+
org.strykeforce.thirdcoast.talon.STATOR_CURRENT, "Stator Current"
16+
) { talon.statorCurrent },
17+
Measure(
18+
org.strykeforce.thirdcoast.talon.SUPPLY_CURRENT, "Supply Current"
19+
) { talon.supplyCurrent },
20+
Measure(OUTPUT_VOLTAGE, "Output Voltage") { talon.motorOutputVoltage },
21+
Measure(OUTPUT_PERCENT, "Output Percentage") { talon.motorOutputPercent },
22+
Measure(SELECTED_SENSOR_POSITION, "Selected Sensor Position (PID 0)") {
23+
talon.getSelectedSensorPosition(0)
24+
},
25+
Measure(SELECTED_SENSOR_VELOCITY, "Selected Sensor Velocity (PID 0)") {
26+
talon.getSelectedSensorVelocity(0)
27+
},
28+
Measure(
29+
ACTIVE_TRAJECTORY_POSITION, "Active Trajectory Position"
30+
) { talon.activeTrajectoryPosition },
31+
Measure(
32+
ACTIVE_TRAJECTORY_VELOCITY, "Active Trajectory Velocity"
33+
) { talon.activeTrajectoryVelocity },
34+
Measure(CLOSED_LOOP_ERROR, "Closed Loop Error (PID 0)") {
35+
talon.getClosedLoopError(0)
36+
},
37+
Measure(BUS_VOLTAGE, "Bus Voltage") { talon.busVoltage },
38+
Measure(ERROR_DERIVATIVE, "Error Derivative (PID 0)") { talon.getErrorDerivative(0) },
39+
Measure(
40+
INTEGRAL_ACCUMULATOR, "Integral Accumulator (PID 0)"
41+
) { talon.getIntegralAccumulator(0) },
42+
Measure(TEMPERATURE, "Controller Temperature") { talon.temperature })
43+
44+
45+
override fun equals(other: Any?): Boolean {
46+
if (this === other) return true
47+
if (javaClass != other?.javaClass) return false
48+
49+
other as BaseTalonMeasurable
50+
51+
if (deviceId != other.deviceId) return false
52+
53+
return true
54+
}
55+
56+
override fun hashCode() = deviceId
57+
}

src/main/kotlin/org/strykeforce/telemetry/measurable/MeasurableSubsystem.kt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,37 @@
11
package org.strykeforce.telemetry.measurable
22

33
import edu.wpi.first.wpilibj2.command.SubsystemBase
4+
import org.strykeforce.telemetry.Registrable
5+
import org.strykeforce.telemetry.TelemetryService
46

5-
abstract class MeasurableSubsystem() : SubsystemBase(), Measurable {
7+
/**
8+
* A [Subsystem] that can send telemetry to the Third Coast grapher.
9+
*
10+
* To implement, override the [Measurable.measures] method, for example:
11+
*
12+
* <code><pre>
13+
* @Override
14+
* public Set<Measure> getMeasures() {
15+
* return Set.of(
16+
* new Measure("Gyro Rotation2d (deg)", () -> swerveDrive.getHeading().getDegrees()),
17+
* new Measure("Gyro Angle (deg)", swerveDrive::getGyroAngle),
18+
* new Measure("Odometry X", () -> swerveDrive.getPoseMeters().getX()),
19+
* new Measure("Odometry Y", () -> swerveDrive.getPoseMeters().getY()),
20+
* );
21+
* }</pre></code>
22+
*
23+
* The robot will call [registerWith] during initialization, default behavior is to register this
24+
* subsystem with the [TelemetryService]. If you wish to additionally register internal classes with
25+
* the telemetry service, override the [registerWith] method, for example:
26+
*
27+
* <code><pre>
28+
* @Override
29+
* public void registerWith(TelemetryService: telemetryService) {
30+
* super.registerWith(telemetryService);
31+
* telemetryService.register(talon);
32+
* }</pre></code>
33+
*/
34+
abstract class MeasurableSubsystem() : SubsystemBase(), Measurable, Registrable {
635

736
override val description = name
837

@@ -16,4 +45,6 @@ abstract class MeasurableSubsystem() : SubsystemBase(), Measurable {
1645
val result = type.compareTo(other.type)
1746
return if (result != 0) result else deviceId.compareTo(other.deviceId)
1847
}
48+
49+
override fun registerWith(telemetryService: TelemetryService) = telemetryService.register(this)
1950
}

0 commit comments

Comments
 (0)