Class Frame<T>
- Direct Known Subclasses:
ByteArrayFrame
,DoubleFrame
,LongFrame
For applications like latency compensation, we often need both sensor/device data and a timestamp of when the data was received.
Frames provide this by holding the most recently received raw data and the timestamps they were received at and allowing retrieval of both data and timestamps
in one FrameData
object via getFrameData()
, avoiding race conditions involving reading data and timestamp separately.
Additionally, they allow for synchronous reads through waitForFrames(double, Frame...)
by notifying when new data has been received.
In Java, non-primitive data types cannot be easily passed by value -- instead the language prefers immutable record type objects for compound data structures.
However, in an FRC application, this would mean a ton of objects getting thrown to the garbage collector from every time a Frame gets updated rendering the previous
value object stale.
To get around this, implementing subclasses such as DoubleFrame
, LongFrame
, and ByteArrayFrame
on update copy the new value to a primitive field (or in the case of ByteArrayFrame, an array of primitives).
As primitives in Java have value semantics, this avoids instantiation of new objects on every update, and the final object value is only instantiated
on a getValue()
call via a constructor-supplied raw-to-finished data conversion function.
Often, the conversion function is simply the constructor of the final object.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionReturns an immutable FrameData<T> class containing both value and timestamp.double
Gets the timestamp in seconds of when this value was updated.abstract T
getValue()
Returns the value of the data frame.static double
maxTimestamp
(FrameData<?>[] data) Returns the max timestamp from a tuple ofFrameData
objects.protected void
update
(double timestamp) Updates the Frame's value, notifying any listeners of new data.static FrameData<?>[]
waitForFrames
(double timeout, Frame<?>... frames) Waits for all Frames to have transmitted a value.
-
Constructor Details
-
Frame
public Frame(double timestamp) Constructs a new Frame object.- Parameters:
timestamp
- The initial timestamp at which the value was received in seconds.
-
-
Method Details
-
update
protected void update(double timestamp) Updates the Frame's value, notifying any listeners of new data. Implementing classes should call this function in a synch block in their own update methods.- Parameters:
timestamp
- the new timestamp of the received data, in seconds
-
getFrameData
Returns an immutable FrameData<T> class containing both value and timestamp. This bypasses the race condition possible via callinggetValue()
followed bygetTimestamp()
individually.- Returns:
- frame data
-
getValue
Returns the value of the data frame.- Returns:
- the value the data frame holds.
-
getTimestamp
public double getTimestamp()Gets the timestamp in seconds of when this value was updated. The time base is relative to the FPGA timestamp.- Returns:
- the timestamp in seconds.
-
waitForFrames
Waits for all Frames to have transmitted a value. Either returns an array ofFrameData
representing the data from corresponding frames passed in (in the order they are passed in) or null if timeout or interrupt is hit.// Keep in mind this code sample will likely cause timing overruns if on the main thread of your robot code. // wait for up to 40 ms for position and velocity to come in from two Canandcoders FrameData<?>[] data = Frame.waitForFrames(0.040, enc.getPositionFrame(), enc.getVelocityFrame(), enc1.getPositionFrame()); if (data == null) { System.out.printf("waitForFrames timed out before receiving all data\n"); } else { // blind casts are needed to pull the data out of the array FrameData<Double> posFrame = (FrameData<Double>) data[0]; FrameData<Double> velFrame = (FrameData<Double>) data[1]; FrameData<Double> posFram1 = (FrameData<Double>) data[2]; // fetches the maximum timestamp across all received timestamps (the "latest" value) double latest = Frame.maxTimestamp(data); // prints the received frame value and how far behind the latest received CAN timestamp it was System.out.printf("posFrame: %.3f, %.3f ms\n", posFrame.getValue(), (latest - posFrame.getTimestamp()) * 1000); System.out.printf("velFrame: %.3f, %.3f ms\n", velFrame.getValue(), (latest - velFrame.getTimestamp()) * 1000); System.out.printf("posFram1: %.3f, %.3f ms\n", posFram1.getValue(), (latest - posFram1.getTimestamp()) * 1000); }
- Parameters:
timeout
- maximum seconds to wait for before giving upframes
-Frame
handles to wait on. Position in argument list corresponds to position in the returned FrameData array.- Returns:
- an array of
FrameData
; representing the data from corresponding frames passed in or null if timeout or interrupt is hit.
-
maxTimestamp
Returns the max timestamp from a tuple ofFrameData
objects. Most useful for getting the "latest" CAN timestamp from a result ofwaitForFrames(double, com.reduxrobotics.frames.Frame<?>...)
.- Parameters:
data
- frame data array fromwaitForFrames(double, com.reduxrobotics.frames.Frame<?>...)
- Returns:
- the maximum timestamp
-