mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[hal,wpilib] Rename FPGA clock to monotonic clock (#8672)
- Remove status return from HAL level (clock getting should never fail) - Remove 32-bit timestamp expand function - Make monotonic_clock.hpp (formerly fpga_clock.hpp) header-only and move to root hal include directory
This commit is contained in:
@@ -71,11 +71,11 @@ public final class HALUtil extends JNIWrapper {
|
|||||||
public static native int getTeamNumber();
|
public static native int getTeamNumber();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the microsecond-resolution timer on the FPGA.
|
* Reads the microsecond-resolution monotonic timer.
|
||||||
*
|
*
|
||||||
* @return The current time in microseconds according to the FPGA (since FPGA reset).
|
* @return The current monotonic time in microseconds.
|
||||||
*/
|
*/
|
||||||
public static native long getFPGATime();
|
public static native long getMonotonicTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the runtime type of the HAL.
|
* Returns the runtime type of the HAL.
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include "wpi/hal/HAL.h"
|
|
||||||
#include "wpi/util/print.hpp"
|
|
||||||
|
|
||||||
namespace wpi::hal {
|
|
||||||
const fpga_clock::time_point fpga_clock::min_time =
|
|
||||||
fpga_clock::time_point(fpga_clock::duration(
|
|
||||||
std::numeric_limits<fpga_clock::duration::rep>::min()));
|
|
||||||
|
|
||||||
fpga_clock::time_point fpga_clock::now() noexcept {
|
|
||||||
int32_t status = 0;
|
|
||||||
uint64_t currentTime = HAL_GetFPGATime(&status);
|
|
||||||
if (status != 0) {
|
|
||||||
wpi::util::print(
|
|
||||||
stderr,
|
|
||||||
"Call to HAL_GetFPGATime failed in fpga_clock::now() with status {}. "
|
|
||||||
"Initialization might have failed. Time will not be correct\n",
|
|
||||||
status);
|
|
||||||
std::fflush(stderr);
|
|
||||||
return epoch();
|
|
||||||
}
|
|
||||||
return time_point(std::chrono::microseconds(currentTime));
|
|
||||||
}
|
|
||||||
} // namespace wpi::hal
|
|
||||||
@@ -473,17 +473,14 @@ Java_org_wpilib_hardware_hal_HALUtil_getTeamNumber
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: org_wpilib_hardware_hal_HALUtil
|
* Class: org_wpilib_hardware_hal_HALUtil
|
||||||
* Method: getFPGATime
|
* Method: getMonotonicTime
|
||||||
* Signature: ()J
|
* Signature: ()J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
Java_org_wpilib_hardware_hal_HALUtil_getFPGATime
|
Java_org_wpilib_hardware_hal_HALUtil_getMonotonicTime
|
||||||
(JNIEnv* env, jclass)
|
(JNIEnv* env, jclass)
|
||||||
{
|
{
|
||||||
int32_t status = 0;
|
return HAL_GetMonotonicTime();
|
||||||
jlong returnValue = HAL_GetFPGATime(&status);
|
|
||||||
CheckStatus(env, status);
|
|
||||||
return returnValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -111,29 +111,11 @@ HAL_Bool HAL_GetBrownedOut(int32_t* status);
|
|||||||
int32_t HAL_GetCommsDisableCount(int32_t* status);
|
int32_t HAL_GetCommsDisableCount(int32_t* status);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the microsecond-resolution timer on the FPGA.
|
* Reads the microsecond-resolution monotonic timer.
|
||||||
*
|
*
|
||||||
* @param[out] status the error code, or 0 for success
|
* @return The current monotonic time in microseconds.
|
||||||
* @return The current time in microseconds according to the FPGA (since FPGA
|
|
||||||
* reset).
|
|
||||||
*/
|
*/
|
||||||
uint64_t HAL_GetFPGATime(int32_t* status);
|
uint64_t HAL_GetMonotonicTime(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an 32 bit FPGA time, expand it to the nearest likely 64 bit FPGA time.
|
|
||||||
*
|
|
||||||
* Note: This is making the assumption that the timestamp being converted is
|
|
||||||
* always in the past. If you call this with a future timestamp, it probably
|
|
||||||
* will make it in the past. If you wait over 70 minutes between capturing the
|
|
||||||
* bottom 32 bits of the timestamp and expanding it, you will be off by
|
|
||||||
* multiples of 1<<32 microseconds.
|
|
||||||
*
|
|
||||||
* @param[in] unexpandedLower 32 bit FPGA time
|
|
||||||
* @param[out] status the error code, or 0 for success
|
|
||||||
* @return The current time in microseconds according to the FPGA (since FPGA
|
|
||||||
* reset) as a 64 bit number.
|
|
||||||
*/
|
|
||||||
uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current state of the Robot Signal Light (RSL).
|
* Gets the current state of the Robot Signal Light (RSL).
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
|
|
||||||
/** WPILib Hardware Abstraction Layer (HAL) namespace */
|
|
||||||
namespace wpi::hal {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A std::chrono compatible wrapper around the FPGA Timer.
|
|
||||||
*/
|
|
||||||
class fpga_clock {
|
|
||||||
public:
|
|
||||||
using rep = std::chrono::microseconds::rep;
|
|
||||||
using period = std::chrono::microseconds::period;
|
|
||||||
using duration = std::chrono::microseconds;
|
|
||||||
using time_point = std::chrono::time_point<fpga_clock>;
|
|
||||||
|
|
||||||
static fpga_clock::time_point now() noexcept;
|
|
||||||
static constexpr bool is_steady = true;
|
|
||||||
|
|
||||||
static fpga_clock::time_point epoch() noexcept { return time_point(zero()); }
|
|
||||||
|
|
||||||
static fpga_clock::duration zero() noexcept { return duration(0); }
|
|
||||||
|
|
||||||
static const time_point min_time;
|
|
||||||
};
|
|
||||||
} // namespace wpi::hal
|
|
||||||
38
hal/src/main/native/include/wpi/hal/monotonic_clock.hpp
Normal file
38
hal/src/main/native/include/wpi/hal/monotonic_clock.hpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include "wpi/hal/HAL.h"
|
||||||
|
|
||||||
|
/** WPILib Hardware Abstraction Layer (HAL) namespace */
|
||||||
|
namespace wpi::hal {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A std::chrono compatible wrapper around the HAL monotonic timer.
|
||||||
|
*/
|
||||||
|
class monotonic_clock {
|
||||||
|
public:
|
||||||
|
using rep = std::chrono::microseconds::rep;
|
||||||
|
using period = std::chrono::microseconds::period;
|
||||||
|
using duration = std::chrono::microseconds;
|
||||||
|
using time_point = std::chrono::time_point<monotonic_clock>;
|
||||||
|
|
||||||
|
static time_point now() noexcept {
|
||||||
|
uint64_t currentTime = HAL_GetMonotonicTime();
|
||||||
|
return time_point(std::chrono::microseconds(currentTime));
|
||||||
|
}
|
||||||
|
static constexpr bool is_steady = true;
|
||||||
|
|
||||||
|
static time_point epoch() noexcept { return time_point(zero()); }
|
||||||
|
|
||||||
|
static duration zero() noexcept { return duration(0); }
|
||||||
|
|
||||||
|
static constexpr time_point min_time =
|
||||||
|
time_point(duration(std::numeric_limits<duration::rep>::min()));
|
||||||
|
};
|
||||||
|
} // namespace wpi::hal
|
||||||
@@ -75,7 +75,7 @@ void HAL_SetAlertActive(HAL_AlertHandle alertHandle, HAL_Bool active,
|
|||||||
// Already active, do nothing (avoids cost of getting time)
|
// Already active, do nothing (avoids cost of getting time)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int64_t now = HAL_GetFPGATime(status);
|
int64_t now = HAL_GetMonotonicTime();
|
||||||
int64_t expected = 0;
|
int64_t expected = 0;
|
||||||
// use compare-exchange to avoid potential race
|
// use compare-exchange to avoid potential race
|
||||||
alert->activeStartTime.compare_exchange_strong(expected, now);
|
alert->activeStartTime.compare_exchange_strong(expected, now);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#include "mockdata/DriverStationDataInternal.hpp"
|
#include "mockdata/DriverStationDataInternal.hpp"
|
||||||
#include "wpi/hal/DriverStationTypes.h"
|
#include "wpi/hal/DriverStationTypes.h"
|
||||||
#include "wpi/hal/Errors.h"
|
#include "wpi/hal/Errors.h"
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
#include "wpi/hal/simulation/MockHooks.h"
|
#include "wpi/hal/simulation/MockHooks.h"
|
||||||
#include "wpi/util/EventVector.hpp"
|
#include "wpi/util/EventVector.hpp"
|
||||||
#include "wpi/util/mutex.hpp"
|
#include "wpi/util/mutex.hpp"
|
||||||
@@ -155,16 +155,16 @@ int32_t HAL_SendError(HAL_Bool isError, int32_t errorCode, HAL_Bool isLVCode,
|
|||||||
static constexpr int KEEP_MSGS = 5;
|
static constexpr int KEEP_MSGS = 5;
|
||||||
std::scoped_lock lock(msgMutex);
|
std::scoped_lock lock(msgMutex);
|
||||||
static std::string prevMsg[KEEP_MSGS];
|
static std::string prevMsg[KEEP_MSGS];
|
||||||
static fpga_clock::time_point prevMsgTime[KEEP_MSGS];
|
static monotonic_clock::time_point prevMsgTime[KEEP_MSGS];
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
for (int i = 0; i < KEEP_MSGS; i++) {
|
for (int i = 0; i < KEEP_MSGS; i++) {
|
||||||
prevMsgTime[i] = fpga_clock::now() - std::chrono::seconds(2);
|
prevMsgTime[i] = monotonic_clock::now() - std::chrono::seconds(2);
|
||||||
}
|
}
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto curTime = fpga_clock::now();
|
auto curTime = monotonic_clock::now();
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < KEEP_MSGS; ++i) {
|
for (i = 0; i < KEEP_MSGS; ++i) {
|
||||||
if (prevMsg[i] == details) {
|
if (prevMsg[i] == details) {
|
||||||
|
|||||||
@@ -254,32 +254,8 @@ int32_t HAL_GetTeamNumber(void) {
|
|||||||
return HALSIM_GetRoboRioTeamNumber();
|
return HALSIM_GetRoboRioTeamNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HAL_GetFPGATime(int32_t* status) {
|
uint64_t HAL_GetMonotonicTime(void) {
|
||||||
return wpi::hal::GetFPGATime();
|
return wpi::hal::GetMonotonicTime();
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
|
|
||||||
// Capture the current FPGA time. This will give us the upper half of the
|
|
||||||
// clock.
|
|
||||||
uint64_t fpgaTime = HAL_GetFPGATime(status);
|
|
||||||
if (*status != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, we need to detect the case where the lower bits rolled over after we
|
|
||||||
// sampled. In that case, the upper bits will be 1 bigger than they should
|
|
||||||
// be.
|
|
||||||
|
|
||||||
// Break it into lower and upper portions.
|
|
||||||
uint32_t lower = fpgaTime & 0xffffffffull;
|
|
||||||
uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
|
|
||||||
|
|
||||||
// The time was sampled *before* the current time, so roll it back.
|
|
||||||
if (lower < unexpandedLower) {
|
|
||||||
--upper;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HAL_Bool HAL_GetSystemActive(int32_t* status) {
|
HAL_Bool HAL_GetSystemActive(int32_t* status) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ static std::atomic<uint64_t> programStepTime{0};
|
|||||||
|
|
||||||
namespace wpi::hal::init {
|
namespace wpi::hal::init {
|
||||||
void InitializeMockHooks() {
|
void InitializeMockHooks() {
|
||||||
wpi::util::SetNowImpl(GetFPGATime);
|
wpi::util::SetNowImpl(GetMonotonicTime);
|
||||||
}
|
}
|
||||||
} // namespace wpi::hal::init
|
} // namespace wpi::hal::init
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ void StepTiming(uint64_t delta) {
|
|||||||
programStepTime += delta;
|
programStepTime += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t GetFPGATime() {
|
uint64_t GetMonotonicTime() {
|
||||||
uint64_t curTime = programPauseTime;
|
uint64_t curTime = programPauseTime;
|
||||||
if (curTime == 0) {
|
if (curTime == 0) {
|
||||||
curTime = wpi::util::NowDefault();
|
curTime = wpi::util::NowDefault();
|
||||||
@@ -67,10 +67,6 @@ uint64_t GetFPGATime() {
|
|||||||
return curTime + programStepTime - programStartTime;
|
return curTime + programStepTime - programStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
double GetFPGATimestamp() {
|
|
||||||
return GetFPGATime() * 1.0e-6;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetProgramStarted(bool started) {
|
void SetProgramStarted(bool started) {
|
||||||
programStarted = started;
|
programStarted = started;
|
||||||
}
|
}
|
||||||
@@ -131,8 +127,7 @@ void HALSIM_StepTiming(uint64_t delta) {
|
|||||||
WaitNotifiers();
|
WaitNotifiers();
|
||||||
|
|
||||||
while (delta > 0) {
|
while (delta > 0) {
|
||||||
int32_t status = 0;
|
uint64_t curTime = HAL_GetMonotonicTime();
|
||||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
|
||||||
uint64_t nextTimeout = HALSIM_GetNextNotifierTimeout();
|
uint64_t nextTimeout = HALSIM_GetNextNotifierTimeout();
|
||||||
uint64_t step = (std::min)(delta, nextTimeout - curTime);
|
uint64_t step = (std::min)(delta, nextTimeout - curTime);
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ bool IsTimingPaused();
|
|||||||
|
|
||||||
void StepTiming(uint64_t delta);
|
void StepTiming(uint64_t delta);
|
||||||
|
|
||||||
uint64_t GetFPGATime();
|
uint64_t GetMonotonicTime();
|
||||||
|
|
||||||
double GetFPGATimestamp();
|
|
||||||
|
|
||||||
void SetProgramStarted();
|
void SetProgramStarted();
|
||||||
} // namespace wpi::hal
|
} // namespace wpi::hal
|
||||||
|
|||||||
@@ -93,8 +93,7 @@ void NotifierThread::Main() {
|
|||||||
|
|
||||||
// Wait until next alarm
|
// Wait until next alarm
|
||||||
const Alarm& alarm = m_alarmQueue.top();
|
const Alarm& alarm = m_alarmQueue.top();
|
||||||
int32_t status = 0;
|
uint64_t curTime = HAL_GetMonotonicTime();
|
||||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
|
||||||
if (alarm.notifier->alarmTime > curTime) {
|
if (alarm.notifier->alarmTime > curTime) {
|
||||||
m_cond.wait_for(
|
m_cond.wait_for(
|
||||||
lock, std::chrono::microseconds{alarm.notifier->alarmTime - curTime});
|
lock, std::chrono::microseconds{alarm.notifier->alarmTime - curTime});
|
||||||
@@ -114,8 +113,7 @@ void NotifierThread::Main() {
|
|||||||
|
|
||||||
void NotifierThread::ProcessAlarms(
|
void NotifierThread::ProcessAlarms(
|
||||||
wpi::util::SmallVectorImpl<HAL_NotifierHandle>* signaled) {
|
wpi::util::SmallVectorImpl<HAL_NotifierHandle>* signaled) {
|
||||||
int32_t status = 0;
|
uint64_t curTime = HAL_GetMonotonicTime();
|
||||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
|
||||||
|
|
||||||
// Process alarms
|
// Process alarms
|
||||||
while (!m_alarmQueue.empty() &&
|
while (!m_alarmQueue.empty() &&
|
||||||
@@ -264,7 +262,7 @@ void HAL_SetNotifierAlarm(HAL_NotifierHandle notifierHandle, uint64_t alarmTime,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!absolute) {
|
if (!absolute) {
|
||||||
alarmTime += HAL_GetFPGATime(status);
|
alarmTime += HAL_GetMonotonicTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t prevWakeup = UINT64_MAX;
|
uint64_t prevWakeup = UINT64_MAX;
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
#include "SystemServerInternal.hpp"
|
#include "SystemServerInternal.hpp"
|
||||||
#include "wpi/hal/AddressableLEDTypes.h"
|
#include "wpi/hal/AddressableLEDTypes.h"
|
||||||
#include "wpi/hal/Errors.h"
|
#include "wpi/hal/Errors.h"
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
|
||||||
#include "wpi/hal/handles/HandlesInternal.hpp"
|
#include "wpi/hal/handles/HandlesInternal.hpp"
|
||||||
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
#include "wpi/nt/NetworkTableInstance.hpp"
|
#include "wpi/nt/NetworkTableInstance.hpp"
|
||||||
#include "wpi/nt/RawTopic.hpp"
|
#include "wpi/nt/RawTopic.hpp"
|
||||||
|
|
||||||
@@ -133,9 +133,9 @@ void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {
|
|||||||
smartIoHandles->Free(handle, HAL_HandleEnum::AddressableLED);
|
smartIoHandles->Free(handle, HAL_HandleEnum::AddressableLED);
|
||||||
|
|
||||||
// Wait for no other object to hold this handle.
|
// Wait for no other object to hold this handle.
|
||||||
auto start = wpi::hal::fpga_clock::now();
|
auto start = wpi::hal::monotonic_clock::now();
|
||||||
while (port.use_count() != 1) {
|
while (port.use_count() != 1) {
|
||||||
auto current = wpi::hal::fpga_clock::now();
|
auto current = wpi::hal::monotonic_clock::now();
|
||||||
if (start + std::chrono::seconds(1) < current) {
|
if (start + std::chrono::seconds(1) < current) {
|
||||||
std::puts("AddressableLED handle free timeout");
|
std::puts("AddressableLED handle free timeout");
|
||||||
std::fflush(stdout);
|
std::fflush(stdout);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ void HAL_SetAlertActive(HAL_AlertHandle alertHandle, HAL_Bool active,
|
|||||||
// Already active, do nothing (avoids cost of getting time)
|
// Already active, do nothing (avoids cost of getting time)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int64_t now = HAL_GetFPGATime(status);
|
int64_t now = HAL_GetMonotonicTime();
|
||||||
int64_t expected = 0;
|
int64_t expected = 0;
|
||||||
// use compare-exchange to avoid potential race
|
// use compare-exchange to avoid potential race
|
||||||
alert->activeStartTime.compare_exchange_strong(expected, now);
|
alert->activeStartTime.compare_exchange_strong(expected, now);
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
#include "PortsInternal.hpp"
|
#include "PortsInternal.hpp"
|
||||||
#include "SmartIo.hpp"
|
#include "SmartIo.hpp"
|
||||||
#include "wpi/hal/Errors.h"
|
#include "wpi/hal/Errors.h"
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
|
||||||
#include "wpi/hal/handles/HandlesInternal.hpp"
|
#include "wpi/hal/handles/HandlesInternal.hpp"
|
||||||
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
|
|
||||||
namespace wpi::hal::init {
|
namespace wpi::hal::init {
|
||||||
void InitializeAnalogInput() {}
|
void InitializeAnalogInput() {}
|
||||||
@@ -73,9 +73,9 @@ void HAL_FreeAnalogInputPort(HAL_AnalogInputHandle analogPortHandle) {
|
|||||||
smartIoHandles->Free(analogPortHandle, HAL_HandleEnum::AnalogInput);
|
smartIoHandles->Free(analogPortHandle, HAL_HandleEnum::AnalogInput);
|
||||||
|
|
||||||
// Wait for no other object to hold this handle.
|
// Wait for no other object to hold this handle.
|
||||||
auto start = wpi::hal::fpga_clock::now();
|
auto start = wpi::hal::monotonic_clock::now();
|
||||||
while (port.use_count() != 1) {
|
while (port.use_count() != 1) {
|
||||||
auto current = wpi::hal::fpga_clock::now();
|
auto current = wpi::hal::monotonic_clock::now();
|
||||||
if (start + std::chrono::seconds(1) < current) {
|
if (start + std::chrono::seconds(1) < current) {
|
||||||
std::puts("DIO handle free timeout");
|
std::puts("DIO handle free timeout");
|
||||||
std::fflush(stdout);
|
std::fflush(stdout);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
#include "HALInternal.hpp"
|
#include "HALInternal.hpp"
|
||||||
#include "PortsInternal.hpp"
|
#include "PortsInternal.hpp"
|
||||||
#include "SmartIo.hpp"
|
#include "SmartIo.hpp"
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
|
|
||||||
using namespace wpi::hal;
|
using namespace wpi::hal;
|
||||||
|
|
||||||
@@ -74,9 +74,9 @@ void HAL_FreeCounter(HAL_CounterHandle counterHandle) {
|
|||||||
smartIoHandles->Free(counterHandle, HAL_HandleEnum::Counter);
|
smartIoHandles->Free(counterHandle, HAL_HandleEnum::Counter);
|
||||||
|
|
||||||
// Wait for no other object to hold this handle.
|
// Wait for no other object to hold this handle.
|
||||||
auto start = wpi::hal::fpga_clock::now();
|
auto start = wpi::hal::monotonic_clock::now();
|
||||||
while (port.use_count() != 1) {
|
while (port.use_count() != 1) {
|
||||||
auto current = wpi::hal::fpga_clock::now();
|
auto current = wpi::hal::monotonic_clock::now();
|
||||||
if (start + std::chrono::seconds(1) < current) {
|
if (start + std::chrono::seconds(1) < current) {
|
||||||
std::puts("DIO handle free timeout");
|
std::puts("DIO handle free timeout");
|
||||||
std::fflush(stdout);
|
std::fflush(stdout);
|
||||||
|
|||||||
@@ -13,8 +13,8 @@
|
|||||||
#include "PortsInternal.hpp"
|
#include "PortsInternal.hpp"
|
||||||
#include "SmartIo.hpp"
|
#include "SmartIo.hpp"
|
||||||
#include "wpi/hal/Errors.h"
|
#include "wpi/hal/Errors.h"
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
|
||||||
#include "wpi/hal/handles/HandlesInternal.hpp"
|
#include "wpi/hal/handles/HandlesInternal.hpp"
|
||||||
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
|
|
||||||
using namespace wpi::hal;
|
using namespace wpi::hal;
|
||||||
|
|
||||||
@@ -79,9 +79,9 @@ void HAL_FreeDIOPort(HAL_DigitalHandle dioPortHandle) {
|
|||||||
smartIoHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
|
smartIoHandles->Free(dioPortHandle, HAL_HandleEnum::DIO);
|
||||||
|
|
||||||
// Wait for no other object to hold this handle.
|
// Wait for no other object to hold this handle.
|
||||||
auto start = wpi::hal::fpga_clock::now();
|
auto start = wpi::hal::monotonic_clock::now();
|
||||||
while (port.use_count() != 1) {
|
while (port.use_count() != 1) {
|
||||||
auto current = wpi::hal::fpga_clock::now();
|
auto current = wpi::hal::monotonic_clock::now();
|
||||||
if (start + std::chrono::seconds(1) < current) {
|
if (start + std::chrono::seconds(1) < current) {
|
||||||
std::puts("DIO handle free timeout");
|
std::puts("DIO handle free timeout");
|
||||||
std::fflush(stdout);
|
std::fflush(stdout);
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
#include "PortsInternal.hpp"
|
#include "PortsInternal.hpp"
|
||||||
#include "SmartIo.hpp"
|
#include "SmartIo.hpp"
|
||||||
#include "wpi/hal/Errors.h"
|
#include "wpi/hal/Errors.h"
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
|
||||||
#include "wpi/hal/handles/HandlesInternal.hpp"
|
#include "wpi/hal/handles/HandlesInternal.hpp"
|
||||||
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
|
|
||||||
using namespace wpi::hal;
|
using namespace wpi::hal;
|
||||||
|
|
||||||
@@ -71,9 +71,9 @@ void HAL_FreeDutyCycle(HAL_DutyCycleHandle dutyCycleHandle) {
|
|||||||
smartIoHandles->Free(dutyCycleHandle, HAL_HandleEnum::DutyCycle);
|
smartIoHandles->Free(dutyCycleHandle, HAL_HandleEnum::DutyCycle);
|
||||||
|
|
||||||
// Wait for no other object to hold this handle.
|
// Wait for no other object to hold this handle.
|
||||||
auto start = wpi::hal::fpga_clock::now();
|
auto start = wpi::hal::monotonic_clock::now();
|
||||||
while (port.use_count() != 1) {
|
while (port.use_count() != 1) {
|
||||||
auto current = wpi::hal::fpga_clock::now();
|
auto current = wpi::hal::monotonic_clock::now();
|
||||||
if (start + std::chrono::seconds(1) < current) {
|
if (start + std::chrono::seconds(1) < current) {
|
||||||
std::puts("DIO handle free timeout");
|
std::puts("DIO handle free timeout");
|
||||||
std::fflush(stdout);
|
std::fflush(stdout);
|
||||||
|
|||||||
@@ -205,35 +205,11 @@ int32_t HAL_GetTeamNumber(void) {
|
|||||||
return teamNumber;
|
return teamNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HAL_GetFPGATime(int32_t* status) {
|
uint64_t HAL_GetMonotonicTime(void) {
|
||||||
wpi::hal::init::CheckInit();
|
wpi::hal::init::CheckInit();
|
||||||
return wpi::util::NowDefault();
|
return wpi::util::NowDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
|
|
||||||
// Capture the current FPGA time. This will give us the upper half of the
|
|
||||||
// clock.
|
|
||||||
uint64_t fpgaTime = HAL_GetFPGATime(status);
|
|
||||||
if (*status != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, we need to detect the case where the lower bits rolled over after we
|
|
||||||
// sampled. In that case, the upper bits will be 1 bigger than they should
|
|
||||||
// be.
|
|
||||||
|
|
||||||
// Break it into lower and upper portions.
|
|
||||||
uint32_t lower = fpgaTime & 0xffffffffull;
|
|
||||||
uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
|
|
||||||
|
|
||||||
// The time was sampled *before* the current time, so roll it back.
|
|
||||||
if (lower < unexpandedLower) {
|
|
||||||
--upper;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
|
|
||||||
}
|
|
||||||
|
|
||||||
HAL_Bool HAL_GetSystemActive(int32_t* status) {
|
HAL_Bool HAL_GetSystemActive(int32_t* status) {
|
||||||
wpi::hal::init::CheckInit();
|
wpi::hal::init::CheckInit();
|
||||||
*status = HAL_HANDLE_ERROR;
|
*status = HAL_HANDLE_ERROR;
|
||||||
@@ -296,14 +272,9 @@ HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
|
|||||||
|
|
||||||
// WPILIB_NetworkCommunication_Reserve(nullptr);
|
// WPILIB_NetworkCommunication_Reserve(nullptr);
|
||||||
|
|
||||||
int32_t status = 0;
|
|
||||||
|
|
||||||
wpi::hal::InitializeDriverStation();
|
wpi::hal::InitializeDriverStation();
|
||||||
|
|
||||||
dsStartTime = HAL_GetFPGATime(&status);
|
dsStartTime = HAL_GetMonotonicTime();
|
||||||
if (status != 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpi::hal::WaitForInitialPacket();
|
wpi::hal::WaitForInitialPacket();
|
||||||
|
|
||||||
|
|||||||
@@ -84,8 +84,7 @@ void NotifierThread::Main() {
|
|||||||
|
|
||||||
// Wait until next alarm
|
// Wait until next alarm
|
||||||
const Alarm& alarm = m_alarmQueue.top();
|
const Alarm& alarm = m_alarmQueue.top();
|
||||||
int32_t status = 0;
|
uint64_t curTime = HAL_GetMonotonicTime();
|
||||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
|
||||||
if (alarm.notifier->alarmTime > curTime) {
|
if (alarm.notifier->alarmTime > curTime) {
|
||||||
m_cond.wait_for(
|
m_cond.wait_for(
|
||||||
lock, std::chrono::microseconds{alarm.notifier->alarmTime - curTime});
|
lock, std::chrono::microseconds{alarm.notifier->alarmTime - curTime});
|
||||||
@@ -99,8 +98,7 @@ void NotifierThread::Main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NotifierThread::ProcessAlarms() {
|
void NotifierThread::ProcessAlarms() {
|
||||||
int32_t status = 0;
|
uint64_t curTime = HAL_GetMonotonicTime();
|
||||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
|
||||||
|
|
||||||
while (!m_alarmQueue.empty() &&
|
while (!m_alarmQueue.empty() &&
|
||||||
m_alarmQueue.top().notifier->alarmTime <= curTime) {
|
m_alarmQueue.top().notifier->alarmTime <= curTime) {
|
||||||
@@ -190,7 +188,7 @@ void HAL_SetNotifierAlarm(HAL_NotifierHandle notifierHandle, uint64_t alarmTime,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!absolute) {
|
if (!absolute) {
|
||||||
alarmTime += HAL_GetFPGATime(status);
|
alarmTime += HAL_GetMonotonicTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t prevWakeup = UINT64_MAX;
|
uint64_t prevWakeup = UINT64_MAX;
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
#include "PortsInternal.hpp"
|
#include "PortsInternal.hpp"
|
||||||
#include "SmartIo.hpp"
|
#include "SmartIo.hpp"
|
||||||
#include "wpi/hal/Errors.h"
|
#include "wpi/hal/Errors.h"
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
|
||||||
#include "wpi/hal/handles/HandlesInternal.hpp"
|
#include "wpi/hal/handles/HandlesInternal.hpp"
|
||||||
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
|
|
||||||
using namespace wpi::hal;
|
using namespace wpi::hal;
|
||||||
|
|
||||||
@@ -83,9 +83,9 @@ void HAL_FreePWMPort(HAL_DigitalHandle pwmPortHandle) {
|
|||||||
smartIoHandles->Free(pwmPortHandle, HAL_HandleEnum::PWM);
|
smartIoHandles->Free(pwmPortHandle, HAL_HandleEnum::PWM);
|
||||||
|
|
||||||
// Wait for no other object to hold this handle.
|
// Wait for no other object to hold this handle.
|
||||||
auto start = wpi::hal::fpga_clock::now();
|
auto start = wpi::hal::monotonic_clock::now();
|
||||||
while (port.use_count() != 1) {
|
while (port.use_count() != 1) {
|
||||||
auto current = wpi::hal::fpga_clock::now();
|
auto current = wpi::hal::monotonic_clock::now();
|
||||||
if (start + std::chrono::seconds(1) < current) {
|
if (start + std::chrono::seconds(1) < current) {
|
||||||
std::puts("PWM handle free timeout");
|
std::puts("PWM handle free timeout");
|
||||||
std::fflush(stdout);
|
std::fflush(stdout);
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ HAL_PowerDistributionHandle HAL_InitializePowerDistribution(
|
|||||||
|
|
||||||
// Ensure we have been alive for long enough to receive a few Power packets.
|
// Ensure we have been alive for long enough to receive a few Power packets.
|
||||||
do {
|
do {
|
||||||
uint64_t currentTime = HAL_GetFPGATime(status);
|
uint64_t currentTime = HAL_GetMonotonicTime();
|
||||||
if (*status != 0) {
|
|
||||||
return HAL_kInvalidHandle;
|
|
||||||
}
|
|
||||||
if (currentTime >= waitTime) {
|
if (currentTime >= waitTime) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ functions:
|
|||||||
HAL_GetRuntimeType:
|
HAL_GetRuntimeType:
|
||||||
HAL_GetSystemActive:
|
HAL_GetSystemActive:
|
||||||
HAL_GetBrownedOut:
|
HAL_GetBrownedOut:
|
||||||
HAL_GetFPGATime:
|
HAL_GetMonotonicTime:
|
||||||
HAL_ExpandFPGATime:
|
|
||||||
HAL_GetRSLState:
|
HAL_GetRSLState:
|
||||||
HAL_GetSystemTimeValid:
|
HAL_GetSystemTimeValid:
|
||||||
HAL_Initialize:
|
HAL_Initialize:
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class DriveTime(commands2.Command):
|
|||||||
|
|
||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
"""Called when the command is initially scheduled."""
|
"""Called when the command is initially scheduled."""
|
||||||
self.startTime = wpilib.Timer.getFPGATimestamp()
|
self.startTime = wpilib.Timer.getTimestamp()
|
||||||
self.drive.arcadeDrive(0, 0)
|
self.drive.arcadeDrive(0, 0)
|
||||||
|
|
||||||
def execute(self) -> None:
|
def execute(self) -> None:
|
||||||
@@ -43,4 +43,4 @@ class DriveTime(commands2.Command):
|
|||||||
|
|
||||||
def isFinished(self) -> bool:
|
def isFinished(self) -> bool:
|
||||||
"""Returns true when the command should end"""
|
"""Returns true when the command should end"""
|
||||||
return wpilib.Timer.getFPGATimestamp() - self.startTime >= self.duration
|
return wpilib.Timer.getTimestamp() - self.startTime >= self.duration
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class TurnTime(commands2.Command):
|
|||||||
|
|
||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
"""Called when the command is initially scheduled."""
|
"""Called when the command is initially scheduled."""
|
||||||
self.startTime = wpilib.Timer.getFPGATimestamp()
|
self.startTime = wpilib.Timer.getTimestamp()
|
||||||
self.drive.arcadeDrive(0, 0)
|
self.drive.arcadeDrive(0, 0)
|
||||||
|
|
||||||
def execute(self) -> None:
|
def execute(self) -> None:
|
||||||
@@ -45,4 +45,4 @@ class TurnTime(commands2.Command):
|
|||||||
|
|
||||||
def isFinished(self) -> bool:
|
def isFinished(self) -> bool:
|
||||||
"""Returns true when the command should end"""
|
"""Returns true when the command should end"""
|
||||||
return wpilib.Timer.getFPGATimestamp() - self.startTime >= self.duration
|
return wpilib.Timer.getTimestamp() - self.startTime >= self.duration
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class DriveTime(commands2.Command):
|
|||||||
|
|
||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
"""Called when the command is initially scheduled."""
|
"""Called when the command is initially scheduled."""
|
||||||
self.startTime = wpilib.Timer.getFPGATimestamp()
|
self.startTime = wpilib.Timer.getTimestamp()
|
||||||
self.drive.arcadeDrive(0, 0)
|
self.drive.arcadeDrive(0, 0)
|
||||||
|
|
||||||
def execute(self) -> None:
|
def execute(self) -> None:
|
||||||
@@ -43,4 +43,4 @@ class DriveTime(commands2.Command):
|
|||||||
|
|
||||||
def isFinished(self) -> bool:
|
def isFinished(self) -> bool:
|
||||||
"""Returns true when the command should end"""
|
"""Returns true when the command should end"""
|
||||||
return wpilib.Timer.getFPGATimestamp() - self.startTime >= self.duration
|
return wpilib.Timer.getTimestamp() - self.startTime >= self.duration
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class TurnTime(commands2.Command):
|
|||||||
|
|
||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
"""Called when the command is initially scheduled."""
|
"""Called when the command is initially scheduled."""
|
||||||
self.startTime = wpilib.Timer.getFPGATimestamp()
|
self.startTime = wpilib.Timer.getTimestamp()
|
||||||
self.drive.arcadeDrive(0, 0)
|
self.drive.arcadeDrive(0, 0)
|
||||||
|
|
||||||
def execute(self) -> None:
|
def execute(self) -> None:
|
||||||
@@ -45,4 +45,4 @@ class TurnTime(commands2.Command):
|
|||||||
|
|
||||||
def isFinished(self) -> bool:
|
def isFinished(self) -> bool:
|
||||||
"""Returns true when the command should end"""
|
"""Returns true when the command should end"""
|
||||||
return wpilib.Timer.getFPGATimestamp() - self.startTime >= self.duration
|
return wpilib.Timer.getTimestamp() - self.startTime >= self.duration
|
||||||
|
|||||||
@@ -1333,8 +1333,7 @@ void FMSSimModel::Update() {
|
|||||||
|
|
||||||
double matchTime = HALSIM_GetDriverStationMatchTime();
|
double matchTime = HALSIM_GetDriverStationMatchTime();
|
||||||
if (!IsDSDisabled() && enabled) {
|
if (!IsDSDisabled() && enabled) {
|
||||||
int32_t status = 0;
|
double curTime = HAL_GetMonotonicTime() * 1.0e-6;
|
||||||
double curTime = HAL_GetFPGATime(&status) * 1.0e-6;
|
|
||||||
if (m_startMatchTime == -1.0) {
|
if (m_startMatchTime == -1.0) {
|
||||||
m_startMatchTime = matchTime + curTime;
|
m_startMatchTime = matchTime + curTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ class TimingModel : public wpi::glass::Model {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static void DisplayTiming() {
|
static void DisplayTiming() {
|
||||||
int32_t status = 0;
|
uint64_t curTime = HAL_GetMonotonicTime();
|
||||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
|
||||||
|
|
||||||
if (ImGui::Button("Run")) {
|
if (ImGui::Button("Run")) {
|
||||||
HALSIM_ResumeTiming();
|
HALSIM_ResumeTiming();
|
||||||
@@ -50,7 +49,7 @@ static void DisplayTiming() {
|
|||||||
}
|
}
|
||||||
ImGui::PopButtonRepeat();
|
ImGui::PopButtonRepeat();
|
||||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 4);
|
ImGui::PushItemWidth(ImGui::GetFontSize() * 4);
|
||||||
ImGui::LabelText("FPGA Time", "%.3f", curTime / 1000000.0);
|
ImGui::LabelText("Time", "%.3f", curTime / 1000000.0);
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
static std::vector<HALSIM_NotifierInfo> notifiers;
|
static std::vector<HALSIM_NotifierInfo> notifiers;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ void TimedRobot::StartCompetition() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loopStartTimeUs = RobotController::GetFPGATime();
|
m_loopStartTimeUs = RobotController::GetMonotonicTime();
|
||||||
std::chrono::microseconds currentTime{m_loopStartTimeUs};
|
std::chrono::microseconds currentTime{m_loopStartTimeUs};
|
||||||
|
|
||||||
callback.func();
|
callback.func();
|
||||||
@@ -76,7 +76,7 @@ void TimedRobot::EndCompetition() {
|
|||||||
|
|
||||||
TimedRobot::TimedRobot(wpi::units::second_t period)
|
TimedRobot::TimedRobot(wpi::units::second_t period)
|
||||||
: IterativeRobotBase(period) {
|
: IterativeRobotBase(period) {
|
||||||
m_startTime = std::chrono::microseconds{RobotController::GetFPGATime()};
|
m_startTime = std::chrono::microseconds{RobotController::GetMonotonicTime()};
|
||||||
AddPeriodic([=, this] { LoopFunc(); }, period);
|
AddPeriodic([=, this] { LoopFunc(); }, period);
|
||||||
|
|
||||||
int32_t status = 0;
|
int32_t status = 0;
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ MotorSafety& MotorSafety::operator=(MotorSafety&& rhs) {
|
|||||||
|
|
||||||
void MotorSafety::Feed() {
|
void MotorSafety::Feed() {
|
||||||
std::scoped_lock lock(m_thisMutex);
|
std::scoped_lock lock(m_thisMutex);
|
||||||
m_stopTime = Timer::GetFPGATimestamp() + m_expiration;
|
m_stopTime = Timer::GetMonotonicTimestamp() + m_expiration;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotorSafety::SetExpiration(wpi::units::second_t expirationTime) {
|
void MotorSafety::SetExpiration(wpi::units::second_t expirationTime) {
|
||||||
@@ -130,7 +130,7 @@ wpi::units::second_t MotorSafety::GetExpiration() const {
|
|||||||
|
|
||||||
bool MotorSafety::IsAlive() const {
|
bool MotorSafety::IsAlive() const {
|
||||||
std::scoped_lock lock(m_thisMutex);
|
std::scoped_lock lock(m_thisMutex);
|
||||||
return !m_enabled || m_stopTime > Timer::GetFPGATimestamp();
|
return !m_enabled || m_stopTime > Timer::GetMonotonicTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MotorSafety::SetSafetyEnabled(bool enabled) {
|
void MotorSafety::SetSafetyEnabled(bool enabled) {
|
||||||
@@ -157,7 +157,7 @@ void MotorSafety::Check() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stopTime < Timer::GetFPGATimestamp()) {
|
if (stopTime < Timer::GetMonotonicTimestamp()) {
|
||||||
WPILIB_ReportError(
|
WPILIB_ReportError(
|
||||||
err::Timeout,
|
err::Timeout,
|
||||||
"{}... Output not updated often enough. See "
|
"{}... Output not updated often enough. See "
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ PeriodicOpMode::Callback::Callback(std::function<void()> func,
|
|||||||
period{period},
|
period{period},
|
||||||
expirationTime(
|
expirationTime(
|
||||||
startTime + offset + period +
|
startTime + offset + period +
|
||||||
(std::chrono::microseconds{wpi::RobotController::GetFPGATime()} -
|
(std::chrono::microseconds{wpi::RobotController::GetMonotonicTime()} -
|
||||||
startTime) /
|
startTime) /
|
||||||
period * period) {}
|
period * period) {}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ PeriodicOpMode::~PeriodicOpMode() {
|
|||||||
PeriodicOpMode::PeriodicOpMode(wpi::units::second_t period)
|
PeriodicOpMode::PeriodicOpMode(wpi::units::second_t period)
|
||||||
: m_period{period},
|
: m_period{period},
|
||||||
m_watchdog(period, [this] { PrintLoopOverrunMessage(); }) {
|
m_watchdog(period, [this] { PrintLoopOverrunMessage(); }) {
|
||||||
m_startTime = std::chrono::microseconds{RobotController::GetFPGATime()};
|
m_startTime = std::chrono::microseconds{RobotController::GetMonotonicTime()};
|
||||||
AddPeriodic([=, this] { LoopFunc(); }, period);
|
AddPeriodic([=, this] { LoopFunc(); }, period);
|
||||||
|
|
||||||
int32_t status = 0;
|
int32_t status = 0;
|
||||||
@@ -116,7 +116,7 @@ void PeriodicOpMode::OpModeRun(int64_t opModeId) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loopStartTimeUs = RobotController::GetFPGATime();
|
m_loopStartTimeUs = RobotController::GetMonotonicTime();
|
||||||
std::chrono::microseconds currentTime{m_loopStartTimeUs};
|
std::chrono::microseconds currentTime{m_loopStartTimeUs};
|
||||||
|
|
||||||
callback.func();
|
callback.func();
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
using namespace wpi;
|
using namespace wpi;
|
||||||
|
|
||||||
std::function<uint64_t()> RobotController::m_timeSource = [] {
|
std::function<uint64_t()> RobotController::m_timeSource = [] {
|
||||||
return RobotController::GetFPGATime();
|
return RobotController::GetMonotonicTime();
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string RobotController::GetSerialNumber() {
|
std::string RobotController::GetSerialNumber() {
|
||||||
@@ -47,11 +47,8 @@ uint64_t RobotController::GetTime() {
|
|||||||
return m_timeSource();
|
return m_timeSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t RobotController::GetFPGATime() {
|
uint64_t RobotController::GetMonotonicTime() {
|
||||||
int32_t status = 0;
|
return HAL_GetMonotonicTime();
|
||||||
uint64_t time = HAL_GetFPGATime(&status);
|
|
||||||
WPILIB_CheckErrorStatus(status, "GetFPGATime");
|
|
||||||
return time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wpi::units::volt_t RobotController::GetBatteryVoltage() {
|
wpi::units::volt_t RobotController::GetBatteryVoltage() {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ void Wait(wpi::units::second_t seconds) {
|
|||||||
std::this_thread::sleep_for(std::chrono::duration<double>(seconds.value()));
|
std::this_thread::sleep_for(std::chrono::duration<double>(seconds.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
wpi::units::second_t GetTime() {
|
wpi::units::second_t GetSystemTime() {
|
||||||
using std::chrono::duration;
|
using std::chrono::duration;
|
||||||
using std::chrono::duration_cast;
|
using std::chrono::duration_cast;
|
||||||
using std::chrono::system_clock;
|
using std::chrono::system_clock;
|
||||||
@@ -92,9 +92,10 @@ wpi::units::second_t Timer::GetTimestamp() {
|
|||||||
return wpi::units::second_t{wpi::RobotController::GetTime() * 1.0e-6};
|
return wpi::units::second_t{wpi::RobotController::GetTime() * 1.0e-6};
|
||||||
}
|
}
|
||||||
|
|
||||||
wpi::units::second_t Timer::GetFPGATimestamp() {
|
wpi::units::second_t Timer::GetMonotonicTimestamp() {
|
||||||
// FPGA returns the timestamp in microseconds
|
// Monotonic timestamp is in microseconds
|
||||||
return wpi::units::second_t{wpi::RobotController::GetFPGATime() * 1.0e-6};
|
return wpi::units::second_t{wpi::RobotController::GetMonotonicTime() *
|
||||||
|
1.0e-6};
|
||||||
}
|
}
|
||||||
|
|
||||||
wpi::units::second_t Timer::GetMatchTime() {
|
wpi::units::second_t Timer::GetMatchTime() {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Tracer::Tracer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Tracer::ResetTimer() {
|
void Tracer::ResetTimer() {
|
||||||
m_startTime = wpi::hal::fpga_clock::now();
|
m_startTime = wpi::hal::monotonic_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tracer::ClearEpochs() {
|
void Tracer::ClearEpochs() {
|
||||||
@@ -26,7 +26,7 @@ void Tracer::ClearEpochs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Tracer::AddEpoch(std::string_view epochName) {
|
void Tracer::AddEpoch(std::string_view epochName) {
|
||||||
auto currentTime = wpi::hal::fpga_clock::now();
|
auto currentTime = wpi::hal::monotonic_clock::now();
|
||||||
m_epochs[epochName] = currentTime - m_startTime;
|
m_epochs[epochName] = currentTime - m_startTime;
|
||||||
m_startTime = currentTime;
|
m_startTime = currentTime;
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,7 @@ void Tracer::PrintEpochs(wpi::util::raw_ostream& os) {
|
|||||||
using std::chrono::duration_cast;
|
using std::chrono::duration_cast;
|
||||||
using std::chrono::microseconds;
|
using std::chrono::microseconds;
|
||||||
|
|
||||||
auto now = wpi::hal::fpga_clock::now();
|
auto now = wpi::hal::monotonic_clock::now();
|
||||||
if (now - m_lastEpochsPrintTime > kMinPrintPeriod) {
|
if (now - m_lastEpochsPrintTime > kMinPrintPeriod) {
|
||||||
m_lastEpochsPrintTime = now;
|
m_lastEpochsPrintTime = now;
|
||||||
for (const auto& epoch : m_epochs) {
|
for (const auto& epoch : m_epochs) {
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ void Watchdog::Impl::UpdateAlarm() {
|
|||||||
|
|
||||||
void Watchdog::Impl::Main() {
|
void Watchdog::Impl::Main() {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int32_t status = 0;
|
|
||||||
HAL_NotifierHandle notifier = m_notifier.load();
|
HAL_NotifierHandle notifier = m_notifier.load();
|
||||||
if (notifier == 0) {
|
if (notifier == 0) {
|
||||||
break;
|
break;
|
||||||
@@ -95,7 +94,7 @@ void Watchdog::Impl::Main() {
|
|||||||
if (WPI_WaitForObject(notifier) == 0) {
|
if (WPI_WaitForObject(notifier) == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
uint64_t curTime = HAL_GetFPGATime(&status);
|
uint64_t curTime = HAL_GetMonotonicTime();
|
||||||
|
|
||||||
std::unique_lock lock(m_mutex);
|
std::unique_lock lock(m_mutex);
|
||||||
|
|
||||||
@@ -163,11 +162,11 @@ Watchdog& Watchdog::operator=(Watchdog&& rhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wpi::units::second_t Watchdog::GetTime() const {
|
wpi::units::second_t Watchdog::GetTime() const {
|
||||||
return Timer::GetFPGATimestamp() - m_startTime;
|
return Timer::GetMonotonicTimestamp() - m_startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Watchdog::SetTimeout(wpi::units::second_t timeout) {
|
void Watchdog::SetTimeout(wpi::units::second_t timeout) {
|
||||||
m_startTime = Timer::GetFPGATimestamp();
|
m_startTime = Timer::GetMonotonicTimestamp();
|
||||||
m_tracer.ClearEpochs();
|
m_tracer.ClearEpochs();
|
||||||
|
|
||||||
std::scoped_lock lock(m_impl->m_mutex);
|
std::scoped_lock lock(m_impl->m_mutex);
|
||||||
@@ -203,7 +202,7 @@ void Watchdog::Reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Watchdog::Enable() {
|
void Watchdog::Enable() {
|
||||||
m_startTime = Timer::GetFPGATimestamp();
|
m_startTime = Timer::GetMonotonicTimestamp();
|
||||||
m_tracer.ClearEpochs();
|
m_tracer.ClearEpochs();
|
||||||
|
|
||||||
std::scoped_lock lock(m_impl->m_mutex);
|
std::scoped_lock lock(m_impl->m_mutex);
|
||||||
|
|||||||
@@ -64,9 +64,10 @@ class TimedRobot : public IterativeRobotBase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the system clock time in microseconds for the start of the current
|
* Return the system clock time in microseconds for the start of the current
|
||||||
* periodic loop. This is in the same time base as Timer.GetFPGATimestamp(),
|
* periodic loop. This is in the same time base as
|
||||||
* but is stable through a loop. It is updated at the beginning of every
|
* Timer.GetMonotonicTimestamp(), but is stable through a loop. It is updated
|
||||||
* periodic callback (including the normal periodic loop).
|
* 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
|
* @return Robot running time in microseconds, as of the start of the current
|
||||||
* periodic function.
|
* periodic function.
|
||||||
@@ -107,11 +108,11 @@ class TimedRobot : public IterativeRobotBase {
|
|||||||
std::chrono::microseconds period, std::chrono::microseconds offset)
|
std::chrono::microseconds period, std::chrono::microseconds offset)
|
||||||
: func{std::move(func)},
|
: func{std::move(func)},
|
||||||
period{period},
|
period{period},
|
||||||
expirationTime(
|
expirationTime(startTime + offset + period +
|
||||||
startTime + offset + period +
|
(std::chrono::microseconds{
|
||||||
(std::chrono::microseconds{wpi::RobotController::GetFPGATime()} -
|
wpi::RobotController::GetMonotonicTime()} -
|
||||||
startTime) /
|
startTime) /
|
||||||
period * period) {}
|
period * period) {}
|
||||||
|
|
||||||
bool operator>(const Callback& rhs) const {
|
bool operator>(const Callback& rhs) const {
|
||||||
return expirationTime > rhs.expirationTime;
|
return expirationTime > rhs.expirationTime;
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class MotorSafety {
|
|||||||
bool m_enabled = false;
|
bool m_enabled = false;
|
||||||
|
|
||||||
// The FPGA clock value when the motor has expired
|
// The FPGA clock value when the motor has expired
|
||||||
wpi::units::second_t m_stopTime = Timer::GetFPGATimestamp();
|
wpi::units::second_t m_stopTime = Timer::GetMonotonicTimestamp();
|
||||||
|
|
||||||
mutable wpi::util::mutex m_thisMutex;
|
mutable wpi::util::mutex m_thisMutex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -91,9 +91,10 @@ class PeriodicOpMode : public OpMode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the system clock time in microseconds for the start of the current
|
* Return the system clock time in microseconds for the start of the current
|
||||||
* periodic loop. This is in the same time base as Timer.getFPGATimestamp(),
|
* periodic loop. This is in the same time base as
|
||||||
* but is stable through a loop. It is updated at the beginning of every
|
* Timer::GetMonotonicTimestamp(), but is stable through a loop. It is updated
|
||||||
* periodic callback (including the normal periodic loop).
|
* 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
|
* @return Robot running time in microseconds, as of the start of the current
|
||||||
* periodic function.
|
* periodic function.
|
||||||
|
|||||||
@@ -60,22 +60,21 @@ class RobotController {
|
|||||||
static void SetTimeSource(std::function<uint64_t()> supplier);
|
static void SetTimeSource(std::function<uint64_t()> supplier);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the microsecond timestamp. By default, the time is based on the FPGA
|
* Read the microsecond timestamp. By default, the time is based on the
|
||||||
* hardware clock in microseconds since the FPGA started. However, the return
|
* monotonic clock. However, the return value of this method may be modified
|
||||||
* value of this method may be modified to use any time base, including
|
* to use any time base, including non-monotonic and non-continuous time
|
||||||
* non-monotonic and non-continuous time bases.
|
* bases.
|
||||||
*
|
*
|
||||||
* @return The current time in microseconds.
|
* @return The current time in microseconds.
|
||||||
*/
|
*/
|
||||||
static uint64_t GetTime();
|
static uint64_t GetTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the microsecond-resolution timer on the FPGA.
|
* Read the microsecond-resolution monotonic timer.
|
||||||
*
|
*
|
||||||
* @return The current time in microseconds according to the FPGA (since FPGA
|
* @return The current monotonic time in microseconds.
|
||||||
* reset).
|
|
||||||
*/
|
*/
|
||||||
static uint64_t GetFPGATime();
|
static uint64_t GetMonotonicTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the battery voltage.
|
* Read the battery voltage.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ void Wait(wpi::units::second_t seconds);
|
|||||||
* @return The time, just in case you want the robot to start autonomous at 8pm
|
* @return The time, just in case you want the robot to start autonomous at 8pm
|
||||||
* on Saturday.
|
* on Saturday.
|
||||||
*/
|
*/
|
||||||
wpi::units::second_t GetTime();
|
wpi::units::second_t GetSystemTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A timer class.
|
* A timer class.
|
||||||
@@ -119,24 +119,22 @@ class Timer {
|
|||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the clock time in seconds. By default, the time is based on the FPGA
|
* Return the clock time in seconds. By default, the time is the time returned
|
||||||
* hardware clock in seconds since the FPGA started. However, the return value
|
* by GetMonotonicTimestamp(). However, the return value of this method may be
|
||||||
* of this method may be modified to use any time base, including
|
* modified to use any time base, including non-monotonic time bases.
|
||||||
* non-monotonic time bases.
|
|
||||||
*
|
*
|
||||||
* @returns Robot running time in seconds.
|
* @returns Robot running time in seconds.
|
||||||
*/
|
*/
|
||||||
static wpi::units::second_t GetTimestamp();
|
static wpi::units::second_t GetTimestamp();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the FPGA system clock time in seconds.
|
* Return the monotonic clock time in seconds.
|
||||||
*
|
*
|
||||||
* Return the time from the FPGA hardware clock in seconds since the FPGA
|
* Return the time from the monotonic clock in seconds.
|
||||||
* started. Rolls over after 71 minutes.
|
|
||||||
*
|
*
|
||||||
* @returns Robot running time in seconds.
|
* @returns Monotonic time in seconds.
|
||||||
*/
|
*/
|
||||||
static wpi::units::second_t GetFPGATimestamp();
|
static wpi::units::second_t GetMonotonicTimestamp();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the approximate match time. The FMS does not send an official match
|
* Return the approximate match time. The FMS does not send an official match
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "wpi/hal/cpp/fpga_clock.hpp"
|
#include "wpi/hal/monotonic_clock.hpp"
|
||||||
#include "wpi/util/StringMap.hpp"
|
#include "wpi/util/StringMap.hpp"
|
||||||
|
|
||||||
namespace wpi::util {
|
namespace wpi::util {
|
||||||
@@ -65,9 +65,9 @@ class Tracer {
|
|||||||
private:
|
private:
|
||||||
static constexpr std::chrono::milliseconds kMinPrintPeriod{1000};
|
static constexpr std::chrono::milliseconds kMinPrintPeriod{1000};
|
||||||
|
|
||||||
wpi::hal::fpga_clock::time_point m_startTime;
|
wpi::hal::monotonic_clock::time_point m_startTime;
|
||||||
wpi::hal::fpga_clock::time_point m_lastEpochsPrintTime =
|
wpi::hal::monotonic_clock::time_point m_lastEpochsPrintTime =
|
||||||
wpi::hal::fpga_clock::epoch();
|
wpi::hal::monotonic_clock::epoch();
|
||||||
|
|
||||||
wpi::util::StringMap<std::chrono::nanoseconds> m_epochs;
|
wpi::util::StringMap<std::chrono::nanoseconds> m_epochs;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ classes:
|
|||||||
GetTeamNumber:
|
GetTeamNumber:
|
||||||
SetTimeSource:
|
SetTimeSource:
|
||||||
GetTime:
|
GetTime:
|
||||||
GetFPGATime:
|
GetMonotonicTime:
|
||||||
IsSysActive:
|
IsSysActive:
|
||||||
IsBrownedOut:
|
IsBrownedOut:
|
||||||
GetRSLState:
|
GetRSLState:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
functions:
|
functions:
|
||||||
Wait:
|
Wait:
|
||||||
GetTime:
|
GetSystemTime:
|
||||||
classes:
|
classes:
|
||||||
wpi::Timer:
|
wpi::Timer:
|
||||||
methods:
|
methods:
|
||||||
@@ -10,7 +10,7 @@ classes:
|
|||||||
Start:
|
Start:
|
||||||
Restart:
|
Restart:
|
||||||
Stop:
|
Stop:
|
||||||
GetFPGATimestamp:
|
GetMonotonicTimestamp:
|
||||||
GetMatchTime:
|
GetMatchTime:
|
||||||
HasElapsed:
|
HasElapsed:
|
||||||
AdvanceIfElapsed:
|
AdvanceIfElapsed:
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ from ._wpilib import (
|
|||||||
getDeployDirectory,
|
getDeployDirectory,
|
||||||
getErrorMessage,
|
getErrorMessage,
|
||||||
getOperatingDirectory,
|
getOperatingDirectory,
|
||||||
getTime,
|
getSystemTime,
|
||||||
setCurrentThreadPriority,
|
setCurrentThreadPriority,
|
||||||
wait,
|
wait,
|
||||||
)
|
)
|
||||||
@@ -202,7 +202,7 @@ __all__ = [
|
|||||||
"getDeployDirectory",
|
"getDeployDirectory",
|
||||||
"getErrorMessage",
|
"getErrorMessage",
|
||||||
"getOperatingDirectory",
|
"getOperatingDirectory",
|
||||||
"getTime",
|
"getSystemTime",
|
||||||
"setCurrentThreadPriority",
|
"setCurrentThreadPriority",
|
||||||
"wait",
|
"wait",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -112,9 +112,9 @@ TEST_F(TimerTest, AdvanceIfElapsed) {
|
|||||||
EXPECT_FALSE(timer.AdvanceIfElapsed(400_ms));
|
EXPECT_FALSE(timer.AdvanceIfElapsed(400_ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TimerTest, GetFPGATimestamp) {
|
TEST_F(TimerTest, GetMonotonicTimestamp) {
|
||||||
auto start = wpi::Timer::GetFPGATimestamp();
|
auto start = wpi::Timer::GetMonotonicTimestamp();
|
||||||
wpi::sim::StepTiming(500_ms);
|
wpi::sim::StepTiming(500_ms);
|
||||||
auto end = wpi::Timer::GetFPGATimestamp();
|
auto end = wpi::Timer::GetMonotonicTimestamp();
|
||||||
EXPECT_EQ(start + 500_ms, end);
|
EXPECT_EQ(start + 500_ms, end);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class TimedRobot extends IterativeRobotBase {
|
|||||||
startTime
|
startTime
|
||||||
+ offset
|
+ offset
|
||||||
+ this.period
|
+ this.period
|
||||||
+ (RobotController.getFPGATime() - startTime) / this.period * this.period;
|
+ (RobotController.getMonotonicTime() - startTime) / this.period * this.period;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -89,7 +89,7 @@ public class TimedRobot extends IterativeRobotBase {
|
|||||||
*/
|
*/
|
||||||
protected TimedRobot(double period) {
|
protected TimedRobot(double period) {
|
||||||
super(period);
|
super(period);
|
||||||
m_startTimeUs = RobotController.getFPGATime();
|
m_startTimeUs = RobotController.getMonotonicTime();
|
||||||
addPeriodic(this::loopFunc, period);
|
addPeriodic(this::loopFunc, period);
|
||||||
NotifierJNI.setNotifierName(m_notifier, "TimedRobot");
|
NotifierJNI.setNotifierName(m_notifier, "TimedRobot");
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ public class TimedRobot extends IterativeRobotBase {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
long currentTime = RobotController.getFPGATime();
|
long currentTime = RobotController.getMonotonicTime();
|
||||||
m_loopStartTimeUs = currentTime;
|
m_loopStartTimeUs = currentTime;
|
||||||
|
|
||||||
callback.func.run();
|
callback.func.run();
|
||||||
@@ -182,7 +182,7 @@ public class TimedRobot extends IterativeRobotBase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the system clock time in microseconds for the start of the current periodic loop. This
|
* Return the system clock time in microseconds 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
|
* is in the same time base as Timer.getMonotonicTimestamp(), but is stable through a loop. It is
|
||||||
* updated at the beginning of every periodic callback (including the normal periodic loop).
|
* 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.
|
* @return Robot running time in microseconds, as of the start of the current periodic function.
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public abstract class MotorSafety {
|
|||||||
|
|
||||||
private double m_expiration = kDefaultSafetyExpiration;
|
private double m_expiration = kDefaultSafetyExpiration;
|
||||||
private boolean m_enabled;
|
private boolean m_enabled;
|
||||||
private double m_stopTime = Timer.getFPGATimestamp();
|
private double m_stopTime = Timer.getMonotonicTimestamp();
|
||||||
private final Object m_thisMutex = new Object();
|
private final Object m_thisMutex = new Object();
|
||||||
private static final Set<MotorSafety> m_instanceList = new LinkedHashSet<>();
|
private static final Set<MotorSafety> m_instanceList = new LinkedHashSet<>();
|
||||||
private static final Object m_listMutex = new Object();
|
private static final Object m_listMutex = new Object();
|
||||||
@@ -83,7 +83,7 @@ public abstract class MotorSafety {
|
|||||||
*/
|
*/
|
||||||
public void feed() {
|
public void feed() {
|
||||||
synchronized (m_thisMutex) {
|
synchronized (m_thisMutex) {
|
||||||
m_stopTime = Timer.getFPGATimestamp() + m_expiration;
|
m_stopTime = Timer.getMonotonicTimestamp() + m_expiration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ public abstract class MotorSafety {
|
|||||||
*/
|
*/
|
||||||
public boolean isAlive() {
|
public boolean isAlive() {
|
||||||
synchronized (m_thisMutex) {
|
synchronized (m_thisMutex) {
|
||||||
return !m_enabled || m_stopTime > Timer.getFPGATimestamp();
|
return !m_enabled || m_stopTime > Timer.getMonotonicTimestamp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ public abstract class MotorSafety {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stopTime < Timer.getFPGATimestamp()) {
|
if (stopTime < Timer.getMonotonicTimestamp()) {
|
||||||
DriverStation.reportError(
|
DriverStation.reportError(
|
||||||
getDescription()
|
getDescription()
|
||||||
+ "... Output not updated often enough. See https://docs.wpilib.org/motorsafety for more information.",
|
+ "... Output not updated often enough. See https://docs.wpilib.org/motorsafety for more information.",
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public abstract class PeriodicOpMode implements OpMode {
|
|||||||
startTime
|
startTime
|
||||||
+ offset
|
+ offset
|
||||||
+ this.period
|
+ this.period
|
||||||
+ (RobotController.getFPGATime() - startTime) / this.period * this.period;
|
+ (RobotController.getMonotonicTime() - startTime) / this.period * this.period;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -120,7 +120,7 @@ public abstract class PeriodicOpMode implements OpMode {
|
|||||||
* @param period period (in seconds) for callbacks to the periodic() function
|
* @param period period (in seconds) for callbacks to the periodic() function
|
||||||
*/
|
*/
|
||||||
protected PeriodicOpMode(double period) {
|
protected PeriodicOpMode(double period) {
|
||||||
m_startTimeUs = RobotController.getFPGATime();
|
m_startTimeUs = RobotController.getMonotonicTime();
|
||||||
m_period = period;
|
m_period = period;
|
||||||
m_watchdog = new Watchdog(period, this::printLoopOverrunMessage);
|
m_watchdog = new Watchdog(period, this::printLoopOverrunMessage);
|
||||||
|
|
||||||
@@ -157,8 +157,8 @@ public abstract class PeriodicOpMode implements OpMode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the system clock time in micrseconds for the start of the current periodic loop. This is
|
* 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
|
* in the same time base as Timer.getMonotonicTimestamp(), but is stable through a loop. It is
|
||||||
* at the beginning of every periodic callback (including the normal periodic loop).
|
* 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.
|
* @return Robot running time in microseconds, as of the start of the current periodic function.
|
||||||
*/
|
*/
|
||||||
@@ -290,8 +290,8 @@ public abstract class PeriodicOpMode implements OpMode {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
long currentTime = RobotController.getFPGATime();
|
long currentTime = RobotController.getMonotonicTime();
|
||||||
m_loopStartTimeUs = RobotController.getFPGATime();
|
m_loopStartTimeUs = RobotController.getMonotonicTime();
|
||||||
|
|
||||||
callback.func.run();
|
callback.func.run();
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.wpilib.units.measure.Voltage;
|
|||||||
|
|
||||||
/** Contains functions for roboRIO functionality. */
|
/** Contains functions for roboRIO functionality. */
|
||||||
public final class RobotController {
|
public final class RobotController {
|
||||||
private static LongSupplier m_timeSource = RobotController::getFPGATime;
|
private static LongSupplier m_timeSource = RobotController::getMonotonicTime;
|
||||||
|
|
||||||
private RobotController() {
|
private RobotController() {
|
||||||
throw new UnsupportedOperationException("This is a utility class!");
|
throw new UnsupportedOperationException("This is a utility class!");
|
||||||
@@ -69,9 +69,9 @@ public final class RobotController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the microsecond timestamp. By default, the time is based on the FPGA hardware clock in
|
* Read the microsecond timestamp. By default, the time is based on the monotonic clock. However,
|
||||||
* microseconds since the FPGA started. However, the return value of this method may be modified
|
* the return value of this method may be modified to use any time base, including non-monotonic
|
||||||
* to use any time base, including non-monotonic and non-continuous time bases.
|
* and non-continuous time bases.
|
||||||
*
|
*
|
||||||
* @return The current time in microseconds.
|
* @return The current time in microseconds.
|
||||||
*/
|
*/
|
||||||
@@ -80,9 +80,9 @@ public final class RobotController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the microsecond timestamp. By default, the time is based on the FPGA hardware clock in
|
* Read the microsecond timestamp. By default, the time is based on the monotonic clock. However,
|
||||||
* microseconds since the FPGA started. However, the return value of this method may be modified
|
* the return value of this method may be modified to use any time base, including non-monotonic
|
||||||
* to use any time base, including non-monotonic and non-continuous time bases.
|
* and non-continuous time bases.
|
||||||
*
|
*
|
||||||
* @return The current time in a measure.
|
* @return The current time in a measure.
|
||||||
*/
|
*/
|
||||||
@@ -91,21 +91,21 @@ public final class RobotController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the microsecond timer from the FPGA.
|
* Read the microsecond monotonic timer.
|
||||||
*
|
*
|
||||||
* @return The current time in microseconds according to the FPGA.
|
* @return The current monotonic time in microseconds.
|
||||||
*/
|
*/
|
||||||
public static long getFPGATime() {
|
public static long getMonotonicTime() {
|
||||||
return HALUtil.getFPGATime();
|
return HALUtil.getMonotonicTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the microsecond timer in a measure from the FPGA.
|
* Read the microsecond monotonic timer in a measure.
|
||||||
*
|
*
|
||||||
* @return The current time according to the FPGA in a measure.
|
* @return The current monotonic time in a measure.
|
||||||
*/
|
*/
|
||||||
public static Time getMeasureFPGATime() {
|
public static Time getMeasureMonotonicTime() {
|
||||||
return Microseconds.of(HALUtil.getFPGATime());
|
return Microseconds.of(HALUtil.getMonotonicTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import org.wpilib.units.measure.Time;
|
|||||||
*/
|
*/
|
||||||
public class Timer {
|
public class Timer {
|
||||||
/**
|
/**
|
||||||
* Return the clock time in seconds. By default, the time is based on the FPGA hardware clock in
|
* Return the clock time in seconds. By default, the time is the time returned by
|
||||||
* seconds since the FPGA started. However, the return value of this method may be modified to use
|
* getMonotonicTimestamp(). However, the return value of this method may be modified to use any
|
||||||
* any time base, including non-monotonic time bases.
|
* time base, including non-monotonic time bases.
|
||||||
*
|
*
|
||||||
* @return Robot running time in seconds.
|
* @return Robot running time in seconds.
|
||||||
*/
|
*/
|
||||||
@@ -28,13 +28,12 @@ public class Timer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the system clock time in seconds. Return the time from the FPGA hardware clock in
|
* Return the monotonic clock time in seconds.
|
||||||
* seconds since the FPGA started.
|
|
||||||
*
|
*
|
||||||
* @return Robot running time in seconds.
|
* @return Monotonic time in seconds.
|
||||||
*/
|
*/
|
||||||
public static double getFPGATimestamp() {
|
public static double getMonotonicTimestamp() {
|
||||||
return RobotController.getFPGATime() / 1000000.0;
|
return RobotController.getMonotonicTime() / 1000000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class Tracer {
|
|||||||
|
|
||||||
/** Restarts the epoch timer. */
|
/** Restarts the epoch timer. */
|
||||||
public final void resetTimer() {
|
public final void resetTimer() {
|
||||||
m_startTime = RobotController.getFPGATime();
|
m_startTime = RobotController.getMonotonicTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -53,7 +53,7 @@ public class Tracer {
|
|||||||
* @param epochName The name to associate with the epoch.
|
* @param epochName The name to associate with the epoch.
|
||||||
*/
|
*/
|
||||||
public void addEpoch(String epochName) {
|
public void addEpoch(String epochName) {
|
||||||
long currentTime = RobotController.getFPGATime();
|
long currentTime = RobotController.getMonotonicTime();
|
||||||
m_epochs.put(epochName, currentTime - m_startTime);
|
m_epochs.put(epochName, currentTime - m_startTime);
|
||||||
m_startTime = currentTime;
|
m_startTime = currentTime;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ public class Tracer {
|
|||||||
* @param output the stream that the output is sent to
|
* @param output the stream that the output is sent to
|
||||||
*/
|
*/
|
||||||
public void printEpochs(Consumer<String> output) {
|
public void printEpochs(Consumer<String> output) {
|
||||||
long now = RobotController.getFPGATime();
|
long now = RobotController.getMonotonicTime();
|
||||||
if (now - m_lastEpochsPrintTime > kMinPrintPeriod) {
|
if (now - m_lastEpochsPrintTime > kMinPrintPeriod) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
m_lastEpochsPrintTime = now;
|
m_lastEpochsPrintTime = now;
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
|
|||||||
* @return The time in seconds since the watchdog was last fed.
|
* @return The time in seconds since the watchdog was last fed.
|
||||||
*/
|
*/
|
||||||
public double getTime() {
|
public double getTime() {
|
||||||
return Timer.getFPGATimestamp() - m_startTime;
|
return Timer.getMonotonicTimestamp() - m_startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +109,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
|
|||||||
* @param timeout The watchdog's timeout in seconds with microsecond resolution.
|
* @param timeout The watchdog's timeout in seconds with microsecond resolution.
|
||||||
*/
|
*/
|
||||||
public void setTimeout(double timeout) {
|
public void setTimeout(double timeout) {
|
||||||
m_startTime = Timer.getFPGATimestamp();
|
m_startTime = Timer.getMonotonicTimestamp();
|
||||||
m_tracer.clearEpochs();
|
m_tracer.clearEpochs();
|
||||||
|
|
||||||
m_queueMutex.lock();
|
m_queueMutex.lock();
|
||||||
@@ -184,7 +184,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
|
|||||||
|
|
||||||
/** Enables the watchdog timer. */
|
/** Enables the watchdog timer. */
|
||||||
public void enable() {
|
public void enable() {
|
||||||
m_startTime = Timer.getFPGATimestamp();
|
m_startTime = Timer.getMonotonicTimestamp();
|
||||||
m_tracer.clearEpochs();
|
m_tracer.clearEpochs();
|
||||||
|
|
||||||
m_queueMutex.lock();
|
m_queueMutex.lock();
|
||||||
@@ -247,7 +247,7 @@ public class Watchdog implements Closeable, Comparable<Watchdog> {
|
|||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
long curTime = HALUtil.getFPGATime();
|
long curTime = HALUtil.getMonotonicTime();
|
||||||
|
|
||||||
m_queueMutex.lock();
|
m_queueMutex.lock();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class LEDPatternTest {
|
|||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
void tearDown() {
|
void tearDown() {
|
||||||
RobotController.setTimeSource(RobotController::getFPGATime);
|
RobotController.setTimeSource(RobotController::getMonotonicTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -127,10 +127,10 @@ class TimerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ResourceLock("timing")
|
@ResourceLock("timing")
|
||||||
void getFPGATimestampTest() {
|
void getMonotonicTimestampTest() {
|
||||||
double start = Timer.getFPGATimestamp();
|
double start = Timer.getMonotonicTimestamp();
|
||||||
SimHooks.stepTiming(0.5);
|
SimHooks.stepTiming(0.5);
|
||||||
double end = Timer.getFPGATimestamp();
|
double end = Timer.getMonotonicTimestamp();
|
||||||
assertEquals(start + 0.5, end, 1e-9);
|
assertEquals(start + 0.5, end, 1e-9);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,9 +272,9 @@ public class PoseEstimator<T> {
|
|||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
||||||
* your own time source by calling {@link
|
* your own time source by calling {@link
|
||||||
* PoseEstimator#updateWithTime(double,Rotation2d,Object)} then you must use a timestamp with
|
* PoseEstimator#updateWithTime(double,Rotation2d,Object)} then you must use a timestamp with
|
||||||
* an epoch since FPGA startup (i.e., the epoch of this timestamp is the same epoch as {@link
|
* the same epoch as {@link org.wpilib.system.Timer#getMonotonicTimestamp()}.) This means that
|
||||||
* org.wpilib.system.Timer#getFPGATimestamp()}.) This means that you should use {@link
|
* you should use {@link org.wpilib.system.Timer#getMonotonicTimestamp()} as your time source
|
||||||
* org.wpilib.system.Timer#getFPGATimestamp()} as your time source or sync the epochs.
|
* or sync the epochs.
|
||||||
*/
|
*/
|
||||||
public void addVisionMeasurement(Pose2d visionRobotPose, double timestamp) {
|
public void addVisionMeasurement(Pose2d visionRobotPose, double timestamp) {
|
||||||
// Step 0: If this measurement is old enough to be outside the pose buffer's timespan, skip.
|
// Step 0: If this measurement is old enough to be outside the pose buffer's timespan, skip.
|
||||||
@@ -344,9 +344,9 @@ public class PoseEstimator<T> {
|
|||||||
* @param visionRobotPose The pose of the robot as measured by the vision camera.
|
* @param visionRobotPose The pose of the robot as measured by the vision camera.
|
||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
||||||
* your own time source by calling {@link #updateWithTime}, then you must use a timestamp with
|
* your own time source by calling {@link #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 {@link
|
* the same epoch as {@link org.wpilib.system.Timer#getMonotonicTimestamp()}). This means that
|
||||||
* org.wpilib.system.Timer#getFPGATimestamp()}). This means that you should use {@link
|
* you should use {@link org.wpilib.system.Timer#getMonotonicTimestamp()} as your time source
|
||||||
* org.wpilib.system.Timer#getFPGATimestamp()} as your time source in this case.
|
* in this case.
|
||||||
* @param visionMeasurementStdDevs Standard deviations of the vision pose measurement (x position
|
* @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
|
* in meters, y position in meters, and heading in radians). Increase these numbers to trust
|
||||||
* the vision pose measurement less.
|
* the vision pose measurement less.
|
||||||
|
|||||||
@@ -283,9 +283,9 @@ public class PoseEstimator3d<T> {
|
|||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
||||||
* your own time source by calling {@link
|
* your own time source by calling {@link
|
||||||
* PoseEstimator3d#updateWithTime(double,Rotation3d,Object)} then you must use a timestamp
|
* PoseEstimator3d#updateWithTime(double,Rotation3d,Object)} then you must use a timestamp
|
||||||
* with an epoch since FPGA startup (i.e., the epoch of this timestamp is the same epoch as
|
* with the same epoch as {@link org.wpilib.system.Timer#getMonotonicTimestamp()}.) This means
|
||||||
* {@link org.wpilib.system.Timer#getFPGATimestamp()}.) This means that you should use {@link
|
* that you should use {@link org.wpilib.system.Timer#getMonotonicTimestamp()} as your time
|
||||||
* org.wpilib.system.Timer#getFPGATimestamp()} as your time source or sync the epochs.
|
* source or sync the epochs.
|
||||||
*/
|
*/
|
||||||
public void addVisionMeasurement(Pose3d visionRobotPose, double timestamp) {
|
public void addVisionMeasurement(Pose3d visionRobotPose, double timestamp) {
|
||||||
// Step 0: If this measurement is old enough to be outside the pose buffer's timespan, skip.
|
// Step 0: If this measurement is old enough to be outside the pose buffer's timespan, skip.
|
||||||
@@ -359,9 +359,9 @@ public class PoseEstimator3d<T> {
|
|||||||
* @param visionRobotPose The pose of the robot as measured by the vision camera.
|
* @param visionRobotPose The pose of the robot as measured by the vision camera.
|
||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
* @param timestamp The timestamp of the vision measurement in seconds. Note that if you don't use
|
||||||
* your own time source by calling {@link #updateWithTime}, then you must use a timestamp with
|
* your own time source by calling {@link #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 {@link
|
* the same epoch as {@link org.wpilib.system.Timer#getMonotonicTimestamp()}). This means that
|
||||||
* org.wpilib.system.Timer#getFPGATimestamp()}). This means that you should use {@link
|
* you should use {@link org.wpilib.system.Timer#getMonotonicTimestamp()} as your time source
|
||||||
* org.wpilib.system.Timer#getFPGATimestamp()} as your time source in this case.
|
* in this case.
|
||||||
* @param visionMeasurementStdDevs Standard deviations of the vision pose measurement (x position
|
* @param visionMeasurementStdDevs Standard deviations of the vision pose measurement (x position
|
||||||
* in meters, y position in meters, z position in meters, and angle in radians). Increase
|
* in meters, y position in meters, z position in meters, and angle in radians). Increase
|
||||||
* these numbers to trust the vision pose measurement less.
|
* these numbers to trust the vision pose measurement less.
|
||||||
|
|||||||
@@ -280,10 +280,9 @@ class WPILIB_DLLEXPORT PoseEstimator {
|
|||||||
* camera.
|
* camera.
|
||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
||||||
* that if you don't use your own time source by calling UpdateWithTime(),
|
* 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.,
|
* then you must use a timestamp with the same epoch as
|
||||||
* the epoch of this timestamp is the same epoch as
|
* wpi::Timer::GetMonotonicTimestamp(). This means that you should use
|
||||||
* wpi::math::Timer::GetTimestamp(). This means that you should use
|
* wpi::Timer::GetMonotonicTimestamp() as your time source in this case.
|
||||||
* wpi::math::Timer::GetTimestamp() as your time source in this case.
|
|
||||||
*/
|
*/
|
||||||
void AddVisionMeasurement(const Pose2d& visionRobotPose,
|
void AddVisionMeasurement(const Pose2d& visionRobotPose,
|
||||||
wpi::units::second_t timestamp) {
|
wpi::units::second_t timestamp) {
|
||||||
@@ -365,10 +364,9 @@ class WPILIB_DLLEXPORT PoseEstimator {
|
|||||||
* camera.
|
* camera.
|
||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
||||||
* that if you don't use your own time source by calling UpdateWithTime(),
|
* 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.,
|
* then you must use a timestamp with the same epoch as
|
||||||
* the epoch of this timestamp is the same epoch as
|
* wpi::Timer::GetMonotonicTimestamp(). This means that you should use
|
||||||
* wpi::math::Timer::GetTimestamp(). This means that you should use
|
* wpi::Timer::GetMonotonicTimestamp() as your time source in this case.
|
||||||
* wpi::math::Timer::GetTimestamp() as your time source in this case.
|
|
||||||
* @param visionMeasurementStdDevs Standard deviations of the vision pose
|
* @param visionMeasurementStdDevs Standard deviations of the vision pose
|
||||||
* measurement (x position in meters, y position in meters, and heading in
|
* measurement (x position in meters, y position in meters, and heading in
|
||||||
* radians). Increase these numbers to trust the vision pose measurement
|
* radians). Increase these numbers to trust the vision pose measurement
|
||||||
|
|||||||
@@ -288,10 +288,9 @@ class WPILIB_DLLEXPORT PoseEstimator3d {
|
|||||||
* camera.
|
* camera.
|
||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
||||||
* that if you don't use your own time source by calling UpdateWithTime(),
|
* 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.,
|
* then you must use a timestamp with the same epoch as
|
||||||
* the epoch of this timestamp is the same epoch as
|
* wpi::Timer::GetMonotonicTimestamp(). This means that you should use
|
||||||
* wpi::math::Timer::GetFPGATimestamp(). This means that you should use
|
* wpi::Timer::GetMonotonicTimestamp() as your time source in this case.
|
||||||
* wpi::math::Timer::GetFPGATimestamp() as your time source in this case.
|
|
||||||
*/
|
*/
|
||||||
void AddVisionMeasurement(const Pose3d& visionRobotPose,
|
void AddVisionMeasurement(const Pose3d& visionRobotPose,
|
||||||
wpi::units::second_t timestamp) {
|
wpi::units::second_t timestamp) {
|
||||||
@@ -379,10 +378,9 @@ class WPILIB_DLLEXPORT PoseEstimator3d {
|
|||||||
* camera.
|
* camera.
|
||||||
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
* @param timestamp The timestamp of the vision measurement in seconds. Note
|
||||||
* that if you don't use your own time source by calling UpdateWithTime(),
|
* 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.,
|
* then you must use a timestamp with the same epoch as
|
||||||
* the epoch of this timestamp is the same epoch as
|
* wpi::Timer::GetMonotonicTimestamp(). This means that you should use
|
||||||
* wpi::math::Timer::GetFPGATimestamp(). This means that you should use
|
* wpi::Timer::GetMonotonicTimestamp() as your time source in this case.
|
||||||
* wpi::math::Timer::GetFPGATimestamp() as your time source in this case.
|
|
||||||
* @param visionMeasurementStdDevs Standard deviations of the vision pose
|
* @param visionMeasurementStdDevs Standard deviations of the vision pose
|
||||||
* measurement (x position in meters, y position in meters, and heading in
|
* measurement (x position in meters, y position in meters, and heading in
|
||||||
* radians). Increase these numbers to trust the vision pose measurement
|
* radians). Increase these numbers to trust the vision pose measurement
|
||||||
|
|||||||
Reference in New Issue
Block a user