[telemetry] Add Telemetry and Tunable APIs#7773
[telemetry] Add Telemetry and Tunable APIs#7773PeterJohnson wants to merge 33 commits intowpilibsuite:2027from
Conversation
wpiutil/src/main/java/edu/wpi/first/util/telemetry/TelemetryTable.java
Outdated
Show resolved
Hide resolved
alan412
left a comment
There was a problem hiding this comment.
I don't see any locking to make sure this works from multiple threads.
I also don't understand why there are a lot of individual functions with things like "log" naming.
What do you mean by this? Are you asking why everything is called |
I wasn't clear here. This is in reference to TelemetryBackEnd.java |
I haven't finished implementing the backends, but basically all the backends have type safety and type-specific functionality. So writing a double to a datalog file or NetworkTables is different than writing a string (or an integer). If you're asking why they are uniquely named instead of overloaded, overloading is bad practice with virtual functions (particularly in C++). A bunch of overloaded "log" functions on the user-facing side makes sense for ease of use, but is a potential footgun on the backend. |
It should be thread safe as written already. The backends will have locking/atomics included as needed (there are some synchronized blocks there already in the start of the DataLogSendableBackend implementation). We use ConcurrentMap etc to avoid explicit locking on the frontend (e.g. TelemetryTable caching uses ConcurrentMap), at least in Java--in C++, we'll use explicit mutexes. |
6eb5395 to
405791b
Compare
2fba581 to
aaff88f
Compare
telemetry/src/main/java/edu/wpi/first/telemetry/TelemetryLoggable.java
Outdated
Show resolved
Hide resolved
wpilibj/src/main/java/org/wpilib/hardware/accelerometer/ADXL345_I2C.java
Show resolved
Hide resolved
wpilibj/src/main/java/org/wpilib/hardware/accelerometer/ADXL345_I2C.java
Show resolved
Hide resolved
wpilibj/src/main/java/edu/wpi/first/wpilibj/smartdashboard/MechanismObject2d.java
Outdated
Show resolved
Hide resolved
| } // namespace frc | ||
|
|
||
| template <> | ||
| struct wpi::Struct<frc::ADXL345_I2C::AllAxes> { |
There was a problem hiding this comment.
Shouldn't this go into a separate file to match the other struct definitions?
wpilibc/src/main/native/include/frc/smartdashboard/MechanismRoot2d.h
Outdated
Show resolved
Hide resolved
|
|
||
| TEST(Mechanism2dTest, Canvas) { | ||
| void TearDown() override { wpi::TelemetryRegistry::Reset(); } | ||
|
|
There was a problem hiding this comment.
| template <typename T> | |
| void ExpectLastValue(std::string_view path, const T& expected) { | |
| auto value = mock->GetLastValue<T>(path); | |
| ASSERT_TRUE(value); | |
| EXPECT_EQ(expected, *value); | |
| } | |
This should work and would reduce boilerplate, though it doesn't work for the types that gtest won't nicely format if the assertion fails. (If it doesn't recognize the type it outputs the hexademical of the raw memory contents- I remember encountering that for failing quaternion equality checks)
90b409e to
189ea22
Compare
spacey-sooty
left a comment
There was a problem hiding this comment.
A log(name, measure) overload which includes unit metadata also be nice
|
Unit support will be implemented in a different way--the registry supports registering global type-specific handlers so we don't have to have telemetry depend on every library we want to provide overloads for. |
Significantly simplified version of #6453. The design approach here is to make Telemetry purely imperative/immediate and write only. Read capabilities would be added as a separate Tunable implementation.
Telemetryis a utility class with only static functions to allow simple use such asTelemetry.log("name", value);(alaSystem.out.println()), and is intended as the primary user-facing class. Nested (structured) telemetry is available viaTelemetryTable, instances of which can be gotten by callingTelemetry.getTable()(orTelemetryTable.getTable()for further nesting).The
Sendableconcept equivalent isTelemetryLoggable(not a great name, but naming is hard). Unlike the currentSendable/SmartDashboard.putData(), this is designed to be immediate, not callback-based. TheupdateTelemetry(TelemetryTable)function of aTelemetryLoggableshould immediately log the desired data to the providedTelemetryTableand not store the table for later use.While we aim to fast-path most types through specific overloads, we do have a generic
Object-taking overload to avoid potential overload ambiguity (particularly betweenStructSerializableandProtobufSerializable, where many types implement both) and provide a fallback toString path. There's a type registry mechanism to register specific type handlers; the intent here is to use this for things like Unit types, where you might want to both set a property (indicating the unit type) and provide the value as a double.Backends can be configured at any level; the most specific backend is used based on longest prefix match of the telemetry path (this allows for e.g. setting up NT logging at the top level, but making some tables DataLog-only). Backends are provided for both NetworkTables and DataLog, and there's also a discard backend (that throws away any logged data) as well as a mock backend (for unit testing).
The initial backend implementation takes the type of the first
log()call as the "forever" type for that particular name. Trying to later log to the same name with a different type is ignored and emits a warning. Changing types dynamically both significantly increases implementation complexity and will likely result in difficult-to-debug behavior in downstream tooling; it's hard to see the user benefits to supporting this.Dependency wise, the telemetry library only depends on wpiutil.
TODO:
Fixes #5513
Closes #5912
Closes #5481
Closes #5413