mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpilib] Add timestamp getters with configurable time base (#7378)
This commit is contained in:
@@ -82,7 +82,7 @@ public class OnBoardIO {
|
||||
return m_buttonB.get();
|
||||
}
|
||||
|
||||
double currentTime = Timer.getFPGATimestamp();
|
||||
double currentTime = Timer.getTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
DriverStation.reportError("Button B was not configured", true);
|
||||
m_nextMessageTime = currentTime + MESSAGE_INTERVAL;
|
||||
@@ -100,7 +100,7 @@ public class OnBoardIO {
|
||||
return m_buttonC.get();
|
||||
}
|
||||
|
||||
double currentTime = Timer.getFPGATimestamp();
|
||||
double currentTime = Timer.getTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
DriverStation.reportError("Button C was not configured", true);
|
||||
m_nextMessageTime = currentTime + MESSAGE_INTERVAL;
|
||||
@@ -117,7 +117,7 @@ public class OnBoardIO {
|
||||
if (m_greenLed != null) {
|
||||
m_greenLed.set(value);
|
||||
} else {
|
||||
double currentTime = Timer.getFPGATimestamp();
|
||||
double currentTime = Timer.getTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
DriverStation.reportError("Green LED was not configured", true);
|
||||
m_nextMessageTime = currentTime + MESSAGE_INTERVAL;
|
||||
@@ -134,7 +134,7 @@ public class OnBoardIO {
|
||||
if (m_redLed != null) {
|
||||
m_redLed.set(value);
|
||||
} else {
|
||||
double currentTime = Timer.getFPGATimestamp();
|
||||
double currentTime = Timer.getTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
DriverStation.reportError("Red LED was not configured", true);
|
||||
m_nextMessageTime = currentTime + MESSAGE_INTERVAL;
|
||||
|
||||
@@ -34,7 +34,7 @@ bool OnBoardIO::GetButtonBPressed() {
|
||||
return m_buttonB->Get();
|
||||
}
|
||||
|
||||
auto currentTime = frc::Timer::GetFPGATimestamp();
|
||||
auto currentTime = frc::Timer::GetTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
FRC_ReportError(frc::err::Error, "{}", "Button B was not configured");
|
||||
m_nextMessageTime = currentTime + kMessageInterval;
|
||||
@@ -47,7 +47,7 @@ bool OnBoardIO::GetButtonCPressed() {
|
||||
return m_buttonC->Get();
|
||||
}
|
||||
|
||||
auto currentTime = frc::Timer::GetFPGATimestamp();
|
||||
auto currentTime = frc::Timer::GetTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
FRC_ReportError(frc::err::Error, "{}", "Button C was not configured");
|
||||
m_nextMessageTime = currentTime + kMessageInterval;
|
||||
@@ -59,7 +59,7 @@ void OnBoardIO::SetGreenLed(bool value) {
|
||||
if (m_greenLed) {
|
||||
m_greenLed->Set(value);
|
||||
} else {
|
||||
auto currentTime = frc::Timer::GetFPGATimestamp();
|
||||
auto currentTime = frc::Timer::GetTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
FRC_ReportError(frc::err::Error, "{}", "Green LED was not configured");
|
||||
m_nextMessageTime = currentTime + kMessageInterval;
|
||||
@@ -71,7 +71,7 @@ void OnBoardIO::SetRedLed(bool value) {
|
||||
if (m_redLed) {
|
||||
m_redLed->Set(value);
|
||||
} else {
|
||||
auto currentTime = frc::Timer::GetFPGATimestamp();
|
||||
auto currentTime = frc::Timer::GetTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
FRC_ReportError(frc::err::Error, "{}", "Red LED was not configured");
|
||||
m_nextMessageTime = currentTime + kMessageInterval;
|
||||
|
||||
@@ -149,7 +149,7 @@ void Alert::Set(bool active) {
|
||||
}
|
||||
|
||||
if (active) {
|
||||
m_activeStartTime = frc::RobotController::GetFPGATime();
|
||||
m_activeStartTime = frc::RobotController::GetTime();
|
||||
m_activeAlerts->emplace(m_activeStartTime, m_text);
|
||||
} else {
|
||||
m_activeAlerts->erase({m_activeStartTime, m_text});
|
||||
|
||||
@@ -678,7 +678,7 @@ void DriverStation::StartDataLog(wpi::log::DataLog& log, bool logJoysticks) {
|
||||
void ReportJoystickUnpluggedErrorV(fmt::string_view format,
|
||||
fmt::format_args args) {
|
||||
auto& inst = GetInstance();
|
||||
auto currentTime = Timer::GetFPGATimestamp();
|
||||
auto currentTime = Timer::GetTimestamp();
|
||||
if (currentTime > inst.nextMessageTime) {
|
||||
ReportErrorV(err::Error, "", 0, "", format, args);
|
||||
inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
|
||||
@@ -689,7 +689,7 @@ void ReportJoystickUnpluggedWarningV(fmt::string_view format,
|
||||
fmt::format_args args) {
|
||||
auto& inst = GetInstance();
|
||||
if (DriverStation::IsFMSAttached() || !inst.silenceJoystickWarning) {
|
||||
auto currentTime = Timer::GetFPGATimestamp();
|
||||
auto currentTime = Timer::GetTimestamp();
|
||||
if (currentTime > inst.nextMessageTime) {
|
||||
ReportErrorV(warn::Warning, "", 0, "", format, args);
|
||||
inst.nextMessageTime = currentTime + kJoystickUnpluggedMessageInterval;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "frc/RobotController.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <hal/CAN.h>
|
||||
@@ -15,6 +16,10 @@
|
||||
|
||||
using namespace frc;
|
||||
|
||||
std::function<uint64_t()> RobotController::m_timeSource = [] {
|
||||
return RobotController::GetFPGATime();
|
||||
};
|
||||
|
||||
int RobotController::GetFPGAVersion() {
|
||||
int32_t status = 0;
|
||||
int version = HAL_GetFPGAVersion(&status);
|
||||
@@ -49,6 +54,14 @@ int32_t RobotController::GetTeamNumber() {
|
||||
return HAL_GetTeamNumber();
|
||||
}
|
||||
|
||||
void RobotController::SetTimeSource(std::function<uint64_t()> supplier) {
|
||||
m_timeSource = supplier;
|
||||
}
|
||||
|
||||
uint64_t RobotController::GetTime() {
|
||||
return m_timeSource();
|
||||
}
|
||||
|
||||
uint64_t RobotController::GetFPGATime() {
|
||||
int32_t status = 0;
|
||||
uint64_t time = HAL_GetFPGATime(&status);
|
||||
|
||||
@@ -46,6 +46,8 @@ void TimedRobot::StartCompetition() {
|
||||
break;
|
||||
}
|
||||
|
||||
m_loopStartTimeUs = RobotController::GetFPGATime();
|
||||
|
||||
callback.func();
|
||||
|
||||
// Increment the expiration time by the number of full periods it's behind
|
||||
@@ -97,6 +99,10 @@ TimedRobot::~TimedRobot() {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t TimedRobot::GetLoopStartTime() {
|
||||
return m_loopStartTimeUs;
|
||||
}
|
||||
|
||||
void TimedRobot::AddPeriodic(std::function<void()> callback,
|
||||
units::second_t period, units::second_t offset) {
|
||||
m_callbacks.emplace(
|
||||
|
||||
@@ -36,7 +36,7 @@ Timer::Timer() {
|
||||
|
||||
units::second_t Timer::Get() const {
|
||||
if (m_running) {
|
||||
return (GetFPGATimestamp() - m_startTime) + m_accumulatedTime;
|
||||
return (GetTimestamp() - m_startTime) + m_accumulatedTime;
|
||||
} else {
|
||||
return m_accumulatedTime;
|
||||
}
|
||||
@@ -44,12 +44,12 @@ units::second_t Timer::Get() const {
|
||||
|
||||
void Timer::Reset() {
|
||||
m_accumulatedTime = 0_s;
|
||||
m_startTime = GetFPGATimestamp();
|
||||
m_startTime = GetTimestamp();
|
||||
}
|
||||
|
||||
void Timer::Start() {
|
||||
if (!m_running) {
|
||||
m_startTime = GetFPGATimestamp();
|
||||
m_startTime = GetTimestamp();
|
||||
m_running = true;
|
||||
}
|
||||
}
|
||||
@@ -88,6 +88,10 @@ bool Timer::IsRunning() const {
|
||||
return m_running;
|
||||
}
|
||||
|
||||
units::second_t Timer::GetTimestamp() {
|
||||
return units::second_t{frc::RobotController::GetTime() * 1.0e-6};
|
||||
}
|
||||
|
||||
units::second_t Timer::GetFPGATimestamp() {
|
||||
// FPGA returns the timestamp in microseconds
|
||||
return units::second_t{frc::RobotController::GetFPGATime() * 1.0e-6};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include <units/temperature.h>
|
||||
@@ -78,6 +79,24 @@ class RobotController {
|
||||
*/
|
||||
static int32_t GetTeamNumber();
|
||||
|
||||
/**
|
||||
* Sets a new source to provide the clock time in microseconds. Changing this
|
||||
* affects the return value of {@code GetTime}.
|
||||
*
|
||||
* @param supplier Function to return the time in microseconds.
|
||||
*/
|
||||
static void SetTimeSource(std::function<uint64_t()> supplier);
|
||||
|
||||
/**
|
||||
* Read the microsecond timestamp. By default, the time is based on the FPGA
|
||||
* hardware clock in microseconds since the FPGA started. However, the return
|
||||
* value of this method may be modified to use any time base, including
|
||||
* non-monotonic and non-continuous time bases.
|
||||
*
|
||||
* @return The current time in microseconds.
|
||||
*/
|
||||
static uint64_t GetTime();
|
||||
|
||||
/**
|
||||
* Read the microsecond-resolution timer on the FPGA.
|
||||
*
|
||||
@@ -320,6 +339,9 @@ class RobotController {
|
||||
* @return The status of the CAN bus
|
||||
*/
|
||||
static CANStatus GetCANStatus();
|
||||
|
||||
private:
|
||||
static std::function<uint64_t()> m_timeSource;
|
||||
};
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -56,6 +56,17 @@ class TimedRobot : public IterativeRobotBase {
|
||||
|
||||
~TimedRobot() override;
|
||||
|
||||
/**
|
||||
* Return the system clock time in micrseconds for the start of the current
|
||||
* periodic loop. This is in the same time base as Timer.GetFPGATimestamp(),
|
||||
* but is stable through a loop. It is updated at the beginning of every
|
||||
* periodic callback (including the normal periodic loop).
|
||||
*
|
||||
* @return Robot running time in microseconds, as of the start of the current
|
||||
* periodic function.
|
||||
*/
|
||||
uint64_t GetLoopStartTime();
|
||||
|
||||
/**
|
||||
* Add a callback to run at a specific period with a starting time offset.
|
||||
*
|
||||
@@ -103,6 +114,7 @@ class TimedRobot : public IterativeRobotBase {
|
||||
|
||||
hal::Handle<HAL_NotifierHandle, HAL_CleanNotifier> m_notifier;
|
||||
std::chrono::microseconds m_startTime;
|
||||
uint64_t m_loopStartTimeUs = 0;
|
||||
|
||||
wpi::priority_queue<Callback, std::vector<Callback>, std::greater<Callback>>
|
||||
m_callbacks;
|
||||
|
||||
@@ -118,6 +118,16 @@ class Timer {
|
||||
*/
|
||||
bool IsRunning() const;
|
||||
|
||||
/**
|
||||
* Return the clock time in seconds. By default, the time is based on the FPGA
|
||||
* hardware clock in seconds since the FPGA started. However, the return value
|
||||
* of this method may be modified to use any time base, including
|
||||
* non-monotonic time bases.
|
||||
*
|
||||
* @returns Robot running time in seconds.
|
||||
*/
|
||||
static units::second_t GetTimestamp();
|
||||
|
||||
/**
|
||||
* Return the FPGA system clock time in seconds.
|
||||
*
|
||||
|
||||
@@ -106,7 +106,7 @@ void Drivetrain::UpdateOdometry() {
|
||||
// latency delay -- on a real robot, this must be calculated based either on
|
||||
// known latency or timestamps.
|
||||
m_poseEstimator.AddVisionMeasurement(visionMeasurement2d,
|
||||
frc::Timer::GetFPGATimestamp());
|
||||
frc::Timer::GetTimestamp());
|
||||
}
|
||||
|
||||
void Drivetrain::SimulationPeriodic() {
|
||||
|
||||
@@ -67,5 +67,5 @@ void Drivetrain::UpdateOdometry() {
|
||||
m_poseEstimator.AddVisionMeasurement(
|
||||
ExampleGlobalMeasurementSensor::GetEstimatedGlobalPose(
|
||||
m_poseEstimator.GetEstimatedPosition()),
|
||||
frc::Timer::GetFPGATimestamp() - 0.3_s);
|
||||
frc::Timer::GetTimestamp() - 0.3_s);
|
||||
}
|
||||
|
||||
@@ -41,5 +41,5 @@ void Drivetrain::UpdateOdometry() {
|
||||
m_poseEstimator.AddVisionMeasurement(
|
||||
ExampleGlobalMeasurementSensor::GetEstimatedGlobalPose(
|
||||
m_poseEstimator.GetEstimatedPosition()),
|
||||
frc::Timer::GetFPGATimestamp() - 0.3_s);
|
||||
frc::Timer::GetTimestamp() - 0.3_s);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class Alert implements AutoCloseable {
|
||||
}
|
||||
|
||||
if (active) {
|
||||
m_activeStartTime = RobotController.getFPGATime();
|
||||
m_activeStartTime = RobotController.getTime();
|
||||
m_activeAlerts.add(new PublishedAlert(m_activeStartTime, m_text));
|
||||
} else {
|
||||
m_activeAlerts.remove(new PublishedAlert(m_activeStartTime, m_text));
|
||||
|
||||
@@ -1328,7 +1328,7 @@ public final class DriverStation {
|
||||
* the DS.
|
||||
*/
|
||||
private static void reportJoystickUnpluggedError(String message) {
|
||||
double currentTime = Timer.getFPGATimestamp();
|
||||
double currentTime = Timer.getTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
reportError(message, false);
|
||||
m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
|
||||
@@ -1341,7 +1341,7 @@ public final class DriverStation {
|
||||
*/
|
||||
private static void reportJoystickUnpluggedWarning(String message) {
|
||||
if (isFMSAttached() || !m_silenceJoystickWarning) {
|
||||
double currentTime = Timer.getFPGATimestamp();
|
||||
double currentTime = Timer.getTimestamp();
|
||||
if (currentTime > m_nextMessageTime) {
|
||||
reportWarning(message, false);
|
||||
m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
|
||||
|
||||
@@ -191,7 +191,7 @@ public interface LEDPattern {
|
||||
|
||||
return (reader, writer) -> {
|
||||
int bufLen = reader.getLength();
|
||||
long now = WPIUtilJNI.now();
|
||||
long now = RobotController.getTime();
|
||||
|
||||
// index should move by (buf.length) / (period)
|
||||
double t = (now % (long) periodMicros) / periodMicros;
|
||||
@@ -242,7 +242,7 @@ public interface LEDPattern {
|
||||
|
||||
return (reader, writer) -> {
|
||||
int bufLen = reader.getLength();
|
||||
long now = WPIUtilJNI.now();
|
||||
long now = RobotController.getTime();
|
||||
|
||||
// every step in time that's a multiple of microsPerLED will increment the offset by 1
|
||||
var offset = now / microsPerLED;
|
||||
@@ -271,7 +271,7 @@ public interface LEDPattern {
|
||||
final long onTimeMicros = (long) onTime.in(Microseconds);
|
||||
|
||||
return (reader, writer) -> {
|
||||
if (WPIUtilJNI.now() % totalTimeMicros < onTimeMicros) {
|
||||
if (RobotController.getTime() % totalTimeMicros < onTimeMicros) {
|
||||
applyTo(reader, writer);
|
||||
} else {
|
||||
kOff.applyTo(reader, writer);
|
||||
@@ -323,7 +323,7 @@ public interface LEDPattern {
|
||||
reader,
|
||||
(i, r, g, b) -> {
|
||||
// How far we are in the cycle, in the range [0, 1)
|
||||
double t = (WPIUtilJNI.now() % periodMicros) / (double) periodMicros;
|
||||
double t = (RobotController.getTime() % periodMicros) / (double) periodMicros;
|
||||
double phase = t * 2 * Math.PI;
|
||||
|
||||
// Apply the cosine function and shift its output from [-1, 1] to [0, 1]
|
||||
|
||||
@@ -118,7 +118,7 @@ public abstract class RobotBase implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public double getTimestamp() {
|
||||
return WPIUtilJNI.now() * 1.0e-6;
|
||||
return Timer.getTimestamp();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -19,9 +19,12 @@ import edu.wpi.first.units.measure.Current;
|
||||
import edu.wpi.first.units.measure.Temperature;
|
||||
import edu.wpi.first.units.measure.Time;
|
||||
import edu.wpi.first.units.measure.Voltage;
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
/** Contains functions for roboRIO functionality. */
|
||||
public final class RobotController {
|
||||
private static LongSupplier m_timeSource = RobotController::getFPGATime;
|
||||
|
||||
private RobotController() {
|
||||
throw new UnsupportedOperationException("This is a utility class!");
|
||||
}
|
||||
@@ -76,6 +79,38 @@ public final class RobotController {
|
||||
return HALUtil.getTeamNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new source to provide the clock time in microseconds. Changing this affects the return
|
||||
* value of {@code getTime} in Java.
|
||||
*
|
||||
* @param supplier Function to return the time in microseconds.
|
||||
*/
|
||||
public static void setTimeSource(LongSupplier supplier) {
|
||||
m_timeSource = supplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the microsecond timestamp. By default, the time is based on the FPGA hardware clock in
|
||||
* microseconds since the FPGA started. However, the return value of this method may be modified
|
||||
* to use any time base, including non-monotonic and non-continuous time bases.
|
||||
*
|
||||
* @return The current time in microseconds.
|
||||
*/
|
||||
public static long getTime() {
|
||||
return m_timeSource.getAsLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the microsecond timestamp. By default, the time is based on the FPGA hardware clock in
|
||||
* microseconds since the FPGA started. However, the return value of this method may be modified
|
||||
* to use any time base, including non-monotonic and non-continuous time bases.
|
||||
*
|
||||
* @return The current time in a measure.
|
||||
*/
|
||||
public static Time getMeasureTime() {
|
||||
return Microseconds.of(m_timeSource.getAsLong());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the microsecond timer from the FPGA.
|
||||
*
|
||||
|
||||
@@ -73,6 +73,7 @@ public class TimedRobot extends IterativeRobotBase {
|
||||
private final int m_notifier = NotifierJNI.initializeNotifier();
|
||||
|
||||
private long m_startTimeUs;
|
||||
private long m_loopStartTimeUs;
|
||||
|
||||
private final PriorityQueue<Callback> m_callbacks = new PriorityQueue<>();
|
||||
|
||||
@@ -128,6 +129,8 @@ public class TimedRobot extends IterativeRobotBase {
|
||||
break;
|
||||
}
|
||||
|
||||
m_loopStartTimeUs = RobotController.getFPGATime();
|
||||
|
||||
callback.func.run();
|
||||
|
||||
// Increment the expiration time by the number of full periods it's behind
|
||||
@@ -159,6 +162,17 @@ public class TimedRobot extends IterativeRobotBase {
|
||||
NotifierJNI.stopNotifier(m_notifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system clock time in micrseconds for the start of the current periodic loop. This is
|
||||
* in the same time base as Timer.getFPGATimestamp(), but is stable through a loop. It is updated
|
||||
* at the beginning of every periodic callback (including the normal periodic loop).
|
||||
*
|
||||
* @return Robot running time in microseconds, as of the start of the current periodic function.
|
||||
*/
|
||||
public long getLoopStartTime() {
|
||||
return m_loopStartTimeUs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback to run at a specific period.
|
||||
*
|
||||
|
||||
@@ -11,6 +11,17 @@ package edu.wpi.first.wpilibj;
|
||||
* get() won't return a negative duration.
|
||||
*/
|
||||
public class Timer {
|
||||
/**
|
||||
* Return the clock time in seconds. By default, the time is based on the FPGA hardware clock in
|
||||
* seconds since the FPGA started. However, the return value of this method may be modified to use
|
||||
* any time base, including non-monotonic time bases.
|
||||
*
|
||||
* @return Robot running time in seconds.
|
||||
*/
|
||||
public static double getTimestamp() {
|
||||
return RobotController.getTime() / 1000000.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the system clock time in seconds. Return the time from the FPGA hardware clock in
|
||||
* seconds since the FPGA started.
|
||||
@@ -60,7 +71,7 @@ public class Timer {
|
||||
}
|
||||
|
||||
private double getMsClock() {
|
||||
return RobotController.getFPGATime() / 1000.0;
|
||||
return RobotController.getTime() / 1000.0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -43,10 +43,10 @@ import edu.wpi.first.networktables.StringSubscriber;
|
||||
import edu.wpi.first.networktables.StringTopic;
|
||||
import edu.wpi.first.networktables.Subscriber;
|
||||
import edu.wpi.first.networktables.Topic;
|
||||
import edu.wpi.first.util.WPIUtilJNI;
|
||||
import edu.wpi.first.util.function.BooleanConsumer;
|
||||
import edu.wpi.first.util.function.FloatConsumer;
|
||||
import edu.wpi.first.util.function.FloatSupplier;
|
||||
import edu.wpi.first.wpilibj.RobotController;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BooleanSupplier;
|
||||
@@ -180,7 +180,7 @@ public class SendableBuilderImpl implements NTSendableBuilder {
|
||||
/** Update the network table values by calling the getters for all properties. */
|
||||
@Override
|
||||
public void update() {
|
||||
long time = WPIUtilJNI.now();
|
||||
long time = RobotController.getTime();
|
||||
for (Property<?, ?> property : m_properties) {
|
||||
property.update(m_controllable, time);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import static edu.wpi.first.wpilibj.util.Color.kYellow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import edu.wpi.first.util.WPIUtilJNI;
|
||||
import edu.wpi.first.wpilibj.util.Color;
|
||||
import edu.wpi.first.wpilibj.util.Color8Bit;
|
||||
import java.util.Map;
|
||||
@@ -36,6 +35,8 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LEDPatternTest {
|
||||
long m_mockTime;
|
||||
|
||||
// Applies a pattern of White, Yellow, Purple to LED triplets
|
||||
LEDPattern m_whiteYellowPurple =
|
||||
(reader, writer) -> {
|
||||
@@ -59,14 +60,13 @@ class LEDPatternTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
WPIUtilJNI.enableMockTime();
|
||||
WPIUtilJNI.setMockTime(0L);
|
||||
m_mockTime = 0;
|
||||
RobotController.setTimeSource(() -> m_mockTime);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
WPIUtilJNI.setMockTime(0L);
|
||||
WPIUtilJNI.disableMockTime();
|
||||
RobotController.setTimeSource(RobotController::getFPGATime);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -220,7 +220,7 @@ class LEDPatternTest {
|
||||
var scroll = base.scrollAtRelativeSpeed(Value.per(Microsecond).of(1 / 256.0));
|
||||
|
||||
for (int time = 0; time < 500; time++) {
|
||||
WPIUtilJNI.setMockTime(time);
|
||||
m_mockTime = time;
|
||||
scroll.applyTo(buffer);
|
||||
|
||||
for (int led = 0; led < buffer.getLength(); led++) {
|
||||
@@ -254,7 +254,7 @@ class LEDPatternTest {
|
||||
var scroll = base.scrollAtRelativeSpeed(Value.per(Microsecond).of(-1 / 256.0));
|
||||
|
||||
for (int time = 0; time < 500; time++) {
|
||||
WPIUtilJNI.setMockTime(time);
|
||||
m_mockTime = time;
|
||||
scroll.applyTo(buffer);
|
||||
|
||||
for (int led = 0; led < buffer.getLength(); led++) {
|
||||
@@ -290,7 +290,7 @@ class LEDPatternTest {
|
||||
var scroll = base.scrollAtAbsoluteSpeed(MetersPerSecond.of(16), Centimeters.of(2));
|
||||
|
||||
for (int time = 0; time < 500; time++) {
|
||||
WPIUtilJNI.setMockTime(time * 1_250); // 1.25ms per LED
|
||||
m_mockTime = time * 1_250; // 1.25ms per LED
|
||||
scroll.applyTo(buffer);
|
||||
|
||||
for (int led = 0; led < buffer.getLength(); led++) {
|
||||
@@ -326,7 +326,7 @@ class LEDPatternTest {
|
||||
var scroll = base.scrollAtAbsoluteSpeed(MetersPerSecond.of(-16), Centimeters.of(2));
|
||||
|
||||
for (int time = 0; time < 500; time++) {
|
||||
WPIUtilJNI.setMockTime(time * 1_250); // 1.25ms per LED
|
||||
m_mockTime = time * 1_250; // 1.25ms per LED
|
||||
scroll.applyTo(buffer);
|
||||
|
||||
for (int led = 0; led < buffer.getLength(); led++) {
|
||||
@@ -539,7 +539,7 @@ class LEDPatternTest {
|
||||
var buffer = new AddressableLEDBuffer(1);
|
||||
|
||||
for (int t = 0; t < 8; t++) {
|
||||
WPIUtilJNI.setMockTime(t * 1_000_000L); // time travel 1 second
|
||||
m_mockTime = t * 1_000_000L; // time travel 1 second
|
||||
pattern.applyTo(buffer);
|
||||
|
||||
Color color = buffer.getLED(0);
|
||||
@@ -571,7 +571,7 @@ class LEDPatternTest {
|
||||
var buffer = new AddressableLEDBuffer(1);
|
||||
|
||||
for (int t = 0; t < 8; t++) {
|
||||
WPIUtilJNI.setMockTime(t * 1_000_000L); // time travel 1 second
|
||||
m_mockTime = t * 1_000_000L; // time travel 1 second
|
||||
pattern.applyTo(buffer);
|
||||
|
||||
Color color = buffer.getLED(0);
|
||||
@@ -623,31 +623,31 @@ class LEDPatternTest {
|
||||
var buffer = new AddressableLEDBuffer(1);
|
||||
|
||||
{
|
||||
WPIUtilJNI.setMockTime(0); // start
|
||||
m_mockTime = 0; // start
|
||||
pattern.applyTo(buffer);
|
||||
assertColorEquals(kWhite, buffer.getLED(0));
|
||||
}
|
||||
|
||||
{
|
||||
WPIUtilJNI.setMockTime(1); // midway (down)
|
||||
m_mockTime = 1; // midway (down)
|
||||
pattern.applyTo(buffer);
|
||||
assertColorEquals(midGray, buffer.getLED(0));
|
||||
}
|
||||
|
||||
{
|
||||
WPIUtilJNI.setMockTime(2); // bottom
|
||||
m_mockTime = 2; // bottom
|
||||
pattern.applyTo(buffer);
|
||||
assertColorEquals(kBlack, buffer.getLED(0));
|
||||
}
|
||||
|
||||
{
|
||||
WPIUtilJNI.setMockTime(3); // midway (up)
|
||||
m_mockTime = 3; // midway (up)
|
||||
pattern.applyTo(buffer);
|
||||
assertColorEquals(midGray, buffer.getLED(0));
|
||||
}
|
||||
|
||||
{
|
||||
WPIUtilJNI.setMockTime(4); // back to start
|
||||
m_mockTime = 4; // back to start
|
||||
pattern.applyTo(buffer);
|
||||
assertColorEquals(kWhite, buffer.getLED(0));
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ public class Drivetrain {
|
||||
|
||||
// Apply vision measurements. For simulation purposes only, we don't input a latency delay -- on
|
||||
// a real robot, this must be calculated based either on known latency or timestamps.
|
||||
m_poseEstimator.addVisionMeasurement(visionMeasurement2d, Timer.getFPGATimestamp());
|
||||
m_poseEstimator.addVisionMeasurement(visionMeasurement2d, Timer.getTimestamp());
|
||||
}
|
||||
|
||||
/** This function is called periodically during simulation. */
|
||||
|
||||
@@ -167,6 +167,6 @@ public class Drivetrain {
|
||||
m_poseEstimator.addVisionMeasurement(
|
||||
ExampleGlobalMeasurementSensor.getEstimatedGlobalPose(
|
||||
m_poseEstimator.getEstimatedPosition()),
|
||||
Timer.getFPGATimestamp() - 0.3);
|
||||
Timer.getTimestamp() - 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,6 @@ public class Drivetrain {
|
||||
m_poseEstimator.addVisionMeasurement(
|
||||
ExampleGlobalMeasurementSensor.getEstimatedGlobalPose(
|
||||
m_poseEstimator.getEstimatedPosition()),
|
||||
Timer.getFPGATimestamp() - 0.3);
|
||||
Timer.getTimestamp() - 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ public class TimerTest extends AbstractComsSetup {
|
||||
@Test
|
||||
public void delayTest() {
|
||||
// Given
|
||||
long startTime = RobotController.getFPGATime();
|
||||
long startTime = RobotController.getTime();
|
||||
|
||||
// When
|
||||
Timer.delay(TIMER_RUNTIME / 1000000);
|
||||
long endTime = RobotController.getFPGATime();
|
||||
long endTime = RobotController.getTime();
|
||||
long difference = endTime - startTime;
|
||||
|
||||
// Then
|
||||
|
||||
@@ -228,8 +228,8 @@ class WPILIB_DLLEXPORT PoseEstimator {
|
||||
* that if you don't use your own time source by calling UpdateWithTime(),
|
||||
* then you must use a timestamp with an epoch since FPGA startup (i.e.,
|
||||
* the epoch of this timestamp is the same epoch as
|
||||
* frc::Timer::GetFPGATimestamp(). This means that you should use
|
||||
* frc::Timer::GetFPGATimestamp() as your time source in this case.
|
||||
* frc::Timer::GetTimestamp(). This means that you should use
|
||||
* frc::Timer::GetTimestamp() as your time source in this case.
|
||||
*/
|
||||
void AddVisionMeasurement(const Pose2d& visionRobotPose,
|
||||
units::second_t timestamp) {
|
||||
@@ -311,8 +311,8 @@ class WPILIB_DLLEXPORT PoseEstimator {
|
||||
* that if you don't use your own time source by calling UpdateWithTime(),
|
||||
* then you must use a timestamp with an epoch since FPGA startup (i.e.,
|
||||
* the epoch of this timestamp is the same epoch as
|
||||
* frc::Timer::GetFPGATimestamp(). This means that you should use
|
||||
* frc::Timer::GetFPGATimestamp() as your time source in this case.
|
||||
* frc::Timer::GetTimestamp(). This means that you should use
|
||||
* frc::Timer::GetTimestamp() as your time source in this case.
|
||||
* @param visionMeasurementStdDevs Standard deviations of the vision pose
|
||||
* measurement (x position in meters, y position in meters, and heading in
|
||||
* radians). Increase these numbers to trust the vision pose measurement
|
||||
|
||||
Reference in New Issue
Block a user