mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
SCRIPT: wpiformat
This commit is contained in:
committed by
Peter Johnson
parent
ae6bdc9d25
commit
2109161534
@@ -145,14 +145,15 @@ void Application(std::string_view saveDir) {
|
||||
|
||||
wpi::glass::SetStorageName("datalogtool");
|
||||
wpi::glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
|
||||
: saveDir);
|
||||
: saveDir);
|
||||
|
||||
gui::AddWindowScaler([](float scale) { gDefaultScale = scale; });
|
||||
gui::AddLateExecute(DisplayGui);
|
||||
gui::Initialize("Datalog Tool", 925, 510);
|
||||
|
||||
gDownloadVisible =
|
||||
&wpi::glass::GetStorageRoot().GetChild("download").GetBool("visible", true);
|
||||
gDownloadVisible = &wpi::glass::GetStorageRoot()
|
||||
.GetChild("download")
|
||||
.GetBool("visible", true);
|
||||
|
||||
gui::Main();
|
||||
|
||||
|
||||
@@ -286,7 +286,8 @@ void Downloader::ThreadMain() {
|
||||
try {
|
||||
switch (m_state) {
|
||||
case kConnecting:
|
||||
if (auto team = wpi::util::parse_integer<unsigned int>(m_serverTeam, 10)) {
|
||||
if (auto team =
|
||||
wpi::util::parse_integer<unsigned int>(m_serverTeam, 10)) {
|
||||
// team number
|
||||
session = std::make_unique<sftp::Session>(
|
||||
fmt::format("roborio-{}-frc.local", team.value()), 22,
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace wpi::glass {
|
||||
class Storage;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
namespace pfd {
|
||||
class select_folder;
|
||||
|
||||
@@ -103,7 +103,7 @@ static void RebuildEntryTree() {
|
||||
parts.emplace_back(prefix);
|
||||
}
|
||||
wpi::util::split(mainpart, '/', -1, false,
|
||||
[&](auto part) { parts.emplace_back(part); });
|
||||
[&](auto part) { parts.emplace_back(part); });
|
||||
|
||||
// ignore a raw "/" key
|
||||
if (parts.empty()) {
|
||||
@@ -112,7 +112,8 @@ static void RebuildEntryTree() {
|
||||
|
||||
// get to leaf
|
||||
auto nodes = &gEntryTree;
|
||||
for (auto part : wpi::util::drop_back(std::span{parts.begin(), parts.end()})) {
|
||||
for (auto part :
|
||||
wpi::util::drop_back(std::span{parts.begin(), parts.end()})) {
|
||||
auto it =
|
||||
std::find_if(nodes->begin(), nodes->end(),
|
||||
[&](const auto& node) { return node.name == part; });
|
||||
@@ -439,7 +440,8 @@ void DisplayEntries() {
|
||||
static wpi::util::mutex gExportMutex;
|
||||
static std::vector<std::string> gExportErrors;
|
||||
|
||||
static void PrintEscapedCsvString(wpi::util::raw_ostream& os, std::string_view str) {
|
||||
static void PrintEscapedCsvString(wpi::util::raw_ostream& os,
|
||||
std::string_view str) {
|
||||
auto s = str;
|
||||
while (!s.empty()) {
|
||||
std::string_view fragment;
|
||||
@@ -461,8 +463,8 @@ static void ValueToCsv(wpi::util::raw_ostream& os, const Entry& entry,
|
||||
int64_t val;
|
||||
if (record.GetInteger(&val)) {
|
||||
std::time_t timeval = val / 1000000;
|
||||
wpi::util::print(os, "{:%Y-%m-%d %H:%M:%S}.{:06}", *std::localtime(&timeval),
|
||||
val % 1000000);
|
||||
wpi::util::print(os, "{:%Y-%m-%d %H:%M:%S}.{:06}",
|
||||
*std::localtime(&timeval), val % 1000000);
|
||||
return;
|
||||
}
|
||||
} else if (entry.type == "double") {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace wpi::glass {
|
||||
class Storage;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
void DisplayInputFiles();
|
||||
void DisplayEntries();
|
||||
|
||||
@@ -63,7 +63,8 @@ static std::string MakeTitle(NT_Inst inst, wpi::nt::Event event) {
|
||||
static void NtInitialize() {
|
||||
auto inst = wpi::nt::GetDefaultInstance();
|
||||
auto poller = wpi::nt::CreateListenerPoller(inst);
|
||||
wpi::nt::AddPolledListener(poller, inst, NT_EVENT_CONNECTION | NT_EVENT_IMMEDIATE);
|
||||
wpi::nt::AddPolledListener(poller, inst,
|
||||
NT_EVENT_CONNECTION | NT_EVENT_IMMEDIATE);
|
||||
wpi::nt::AddPolledLogger(poller, NT_LOG_INFO, 100);
|
||||
gui::AddEarlyExecute([inst, poller] {
|
||||
auto win = gui::GetSystemWindow();
|
||||
@@ -255,7 +256,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
wpi::glass::SetStorageName("outlineviewer");
|
||||
wpi::glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
|
||||
: saveDir);
|
||||
: saveDir);
|
||||
|
||||
gui::AddInit(NtInitialize);
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ void Application(std::string_view saveDir) {
|
||||
|
||||
wpi::glass::SetStorageName("sysid");
|
||||
wpi::glass::SetStorageDir(saveDir.empty() ? gui::GetPlatformSaveFileDir()
|
||||
: saveDir);
|
||||
: saveDir);
|
||||
|
||||
// Add messages from the global sysid logger into the Log window.
|
||||
gLogger.SetLogger([](unsigned int level, const char* file, unsigned int line,
|
||||
|
||||
@@ -37,7 +37,7 @@ static double Lerp(wpi::units::second_t time,
|
||||
const auto prev = next - 1;
|
||||
|
||||
return wpi::util::Lerp(prev->measurement, next->measurement,
|
||||
(time - prev->time) / (next->time - prev->time));
|
||||
(time - prev->time) / (next->time - prev->time));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,8 +79,8 @@ static std::vector<PreparedData> ConvertToPrepared(const MotorData& data) {
|
||||
|
||||
/**
|
||||
* To preserve a raw copy of the data, this method saves a raw version
|
||||
* in the dataset wpi::util::StringMap where the key of the raw data starts with "raw-"
|
||||
* before the name of the original data.
|
||||
* in the dataset wpi::util::StringMap where the key of the raw data starts with
|
||||
* "raw-" before the name of the original data.
|
||||
*
|
||||
* @tparam S The size of the array data that's being used
|
||||
*
|
||||
|
||||
@@ -32,9 +32,9 @@ void ArmSim::Update(wpi::units::volt_t voltage, wpi::units::second_t dt) {
|
||||
auto f = [=, this](
|
||||
const Eigen::Vector<double, 2>& x,
|
||||
const Eigen::Vector<double, 1>& u) -> Eigen::Vector<double, 2> {
|
||||
return Eigen::Vector<double, 2>{
|
||||
x(1), (m_A * x.block<1, 1>(1, 0) + m_B * u + m_c * wpi::util::sgn(x(1)) +
|
||||
m_d * std::cos(x(0) + m_offset))(0)};
|
||||
return Eigen::Vector<double, 2>{x(1), (m_A * x.block<1, 1>(1, 0) + m_B * u +
|
||||
m_c * wpi::util::sgn(x(1)) +
|
||||
m_d * std::cos(x(0) + m_offset))(0)};
|
||||
};
|
||||
|
||||
// Max error is large because an accurate sim isn't as important as the sim
|
||||
@@ -56,7 +56,8 @@ double ArmSim::GetVelocity() const {
|
||||
double ArmSim::GetAcceleration(wpi::units::volt_t voltage) const {
|
||||
Eigen::Vector<double, 1> u{voltage.value()};
|
||||
return (m_A * m_x.block<1, 1>(1, 0) + m_B * u +
|
||||
m_c * wpi::util::sgn(GetVelocity()) + m_d * std::cos(m_x(0) + m_offset))(0);
|
||||
m_c * wpi::util::sgn(GetVelocity()) +
|
||||
m_d * std::cos(m_x(0) + m_offset))(0);
|
||||
}
|
||||
|
||||
void ArmSim::Reset(double position, double velocity) {
|
||||
|
||||
@@ -28,8 +28,9 @@ void ElevatorSim::Update(wpi::units::volt_t voltage, wpi::units::second_t dt) {
|
||||
Eigen::Matrix<double, 2, 2> Ad;
|
||||
Eigen::Matrix<double, 2, 1> Bd;
|
||||
wpi::math::DiscretizeAB<2, 1>(m_A, m_B, dt, &Ad, &Bd);
|
||||
m_x = Ad * m_x + Bd * u +
|
||||
Bd * m_B.householderQr().solve(m_c * wpi::util::sgn(GetVelocity()) + m_d);
|
||||
m_x =
|
||||
Ad * m_x + Bd * u +
|
||||
Bd * m_B.householderQr().solve(m_c * wpi::util::sgn(GetVelocity()) + m_d);
|
||||
}
|
||||
|
||||
double ElevatorSim::GetPosition() const {
|
||||
|
||||
@@ -33,7 +33,7 @@ FeedbackGains sysid::CalculatePositionFeedbackGains(
|
||||
if (std::abs(Ka) < 1e-7) {
|
||||
// System has position state and velocity input
|
||||
wpi::math::LinearSystem<1, 1, 1> system{Matrix1d{0.0}, Matrix1d{1.0},
|
||||
Matrix1d{1.0}, Matrix1d{0.0}};
|
||||
Matrix1d{1.0}, Matrix1d{0.0}};
|
||||
|
||||
wpi::math::LinearQuadraticRegulator<1, 1> controller{
|
||||
system, {params.qp}, {params.r}, preset.period};
|
||||
@@ -43,16 +43,19 @@ FeedbackGains sysid::CalculatePositionFeedbackGains(
|
||||
return {Kv * controller.K(0, 0) * preset.outputConversionFactor, 0.0};
|
||||
}
|
||||
|
||||
auto system = wpi::math::LinearSystemId::IdentifyPositionSystem<wpi::units::meters>(
|
||||
Kv_t{Kv}, Ka_t{Ka});
|
||||
auto system =
|
||||
wpi::math::LinearSystemId::IdentifyPositionSystem<wpi::units::meters>(
|
||||
Kv_t{Kv}, Ka_t{Ka});
|
||||
|
||||
wpi::math::LinearQuadraticRegulator<2, 1> controller{
|
||||
system, {params.qp, params.qv}, {params.r}, preset.period};
|
||||
controller.LatencyCompensate(system, preset.period, preset.measurementDelay);
|
||||
|
||||
return {controller.K(0, 0) * preset.outputConversionFactor,
|
||||
controller.K(0, 1) * preset.outputConversionFactor /
|
||||
(preset.normalized ? 1 : wpi::units::second_t{preset.period}.value())};
|
||||
return {
|
||||
controller.K(0, 0) * preset.outputConversionFactor,
|
||||
controller.K(0, 1) * preset.outputConversionFactor /
|
||||
(preset.normalized ? 1
|
||||
: wpi::units::second_t{preset.period}.value())};
|
||||
}
|
||||
|
||||
FeedbackGains sysid::CalculateVelocityFeedbackGains(
|
||||
@@ -69,8 +72,9 @@ FeedbackGains sysid::CalculateVelocityFeedbackGains(
|
||||
return {0.0, 0.0};
|
||||
}
|
||||
|
||||
auto system = wpi::math::LinearSystemId::IdentifyVelocitySystem<wpi::units::meters>(
|
||||
Kv_t{Kv}, Ka_t{Ka});
|
||||
auto system =
|
||||
wpi::math::LinearSystemId::IdentifyVelocitySystem<wpi::units::meters>(
|
||||
Kv_t{Kv}, Ka_t{Ka});
|
||||
wpi::math::LinearQuadraticRegulator<1, 1> controller{
|
||||
system, {params.qv}, {params.r}, preset.period};
|
||||
controller.LatencyCompensate(system, preset.period, preset.measurementDelay);
|
||||
|
||||
@@ -49,7 +49,8 @@ static void CheckSize(const std::vector<PreparedData>& data, size_t window,
|
||||
* @return True, if the key corresponds to a raw dataset.
|
||||
*/
|
||||
static bool IsRaw(std::string_view key) {
|
||||
return wpi::util::contains(key, "raw") && !wpi::util::contains(key, "original");
|
||||
return wpi::util::contains(key, "raw") &&
|
||||
!wpi::util::contains(key, "original");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,7 +61,8 @@ static bool IsRaw(std::string_view key) {
|
||||
* @return True, if the key corresponds to a filtered dataset.
|
||||
*/
|
||||
static bool IsFiltered(std::string_view key) {
|
||||
return !wpi::util::contains(key, "raw") && !wpi::util::contains(key, "original");
|
||||
return !wpi::util::contains(key, "raw") &&
|
||||
!wpi::util::contains(key, "original");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,7 +158,8 @@ sysid::TrimStepVoltageData(std::vector<PreparedData>* data,
|
||||
auto accelBegins = std::find_if(
|
||||
data->begin(), data->end(), [&maxAccel](const auto& measurement) {
|
||||
return wpi::util::sgn(measurement.velocity) * measurement.acceleration >
|
||||
0.8 * wpi::util::sgn(maxAccel->velocity) * maxAccel->acceleration;
|
||||
0.8 * wpi::util::sgn(maxAccel->velocity) *
|
||||
maxAccel->acceleration;
|
||||
});
|
||||
|
||||
wpi::units::second_t velocityDelay;
|
||||
@@ -229,7 +232,8 @@ double sysid::GetMaxSpeed(
|
||||
return max;
|
||||
}
|
||||
|
||||
wpi::units::second_t sysid::GetMeanTimeDelta(const std::vector<PreparedData>& data) {
|
||||
wpi::units::second_t sysid::GetMeanTimeDelta(
|
||||
const std::vector<PreparedData>& data) {
|
||||
std::vector<wpi::units::second_t> dts;
|
||||
|
||||
for (const auto& pt : data) {
|
||||
@@ -342,8 +346,9 @@ void sysid::InitialTrimAndFilter(
|
||||
wpi::util::StringMap<std::vector<PreparedData>>* data,
|
||||
AnalysisManager::Settings* settings,
|
||||
std::vector<wpi::units::second_t>& positionDelays,
|
||||
std::vector<wpi::units::second_t>& velocityDelays, wpi::units::second_t& minStepTime,
|
||||
wpi::units::second_t& maxStepTime, std::string_view unit) {
|
||||
std::vector<wpi::units::second_t>& velocityDelays,
|
||||
wpi::units::second_t& minStepTime, wpi::units::second_t& maxStepTime,
|
||||
std::string_view unit) {
|
||||
auto& preparedData = *data;
|
||||
|
||||
// Find the maximum Step Test Duration of the dynamic tests
|
||||
|
||||
@@ -17,7 +17,8 @@ SimpleMotorSim::SimpleMotorSim(double Ks, double Kv, double Ka,
|
||||
Reset(initialPosition, initialVelocity);
|
||||
}
|
||||
|
||||
void SimpleMotorSim::Update(wpi::units::volt_t voltage, wpi::units::second_t dt) {
|
||||
void SimpleMotorSim::Update(wpi::units::volt_t voltage,
|
||||
wpi::units::second_t dt) {
|
||||
Eigen::Vector<double, 1> u{voltage.value()};
|
||||
|
||||
// Given dx/dt = Ax + Bu + c sgn(x),
|
||||
|
||||
@@ -30,8 +30,8 @@ static ImPlotPoint Getter(int idx, void* data) {
|
||||
template <typename Model>
|
||||
static std::vector<std::vector<ImPlotPoint>> PopulateTimeDomainSim(
|
||||
const std::vector<PreparedData>& data,
|
||||
const std::array<wpi::units::second_t, 4>& startTimes, size_t step, Model model,
|
||||
double* simSquaredErrorSum, double* squaredVariationSum,
|
||||
const std::array<wpi::units::second_t, 4>& startTimes, size_t step,
|
||||
Model model, double* simSquaredErrorSum, double* squaredVariationSum,
|
||||
int* timeSeriesPoints) {
|
||||
// Create the vector of ImPlotPoints that will contain our simulated data.
|
||||
std::vector<std::vector<ImPlotPoint>> pts;
|
||||
@@ -60,7 +60,8 @@ static std::vector<std::vector<ImPlotPoint>> PopulateTimeDomainSim(
|
||||
continue;
|
||||
}
|
||||
|
||||
model.Update(wpi::units::volt_t{pre.voltage}, now.timestamp - pre.timestamp);
|
||||
model.Update(wpi::units::volt_t{pre.voltage},
|
||||
now.timestamp - pre.timestamp);
|
||||
tmp.emplace_back((startTime + t).value(), model.GetVelocity());
|
||||
*simSquaredErrorSum += std::pow(now.velocity - model.GetVelocity(), 2);
|
||||
*squaredVariationSum += std::pow(now.velocity, 2);
|
||||
@@ -128,11 +129,11 @@ void AnalyzerPlot::SetRawData(const Storage& data, std::string_view unit,
|
||||
SetRawTimeData(slow, fast, abort);
|
||||
}
|
||||
|
||||
void AnalyzerPlot::SetData(const Storage& rawData, const Storage& filteredData,
|
||||
std::string_view unit,
|
||||
const AnalysisManager::FeedforwardGains& ffGains,
|
||||
const std::array<wpi::units::second_t, 4>& startTimes,
|
||||
AnalysisType type, std::atomic<bool>& abort) {
|
||||
void AnalyzerPlot::SetData(
|
||||
const Storage& rawData, const Storage& filteredData, std::string_view unit,
|
||||
const AnalysisManager::FeedforwardGains& ffGains,
|
||||
const std::array<wpi::units::second_t, 4>& startTimes, AnalysisType type,
|
||||
std::atomic<bool>& abort) {
|
||||
double simSquaredErrorSum = 0;
|
||||
double squaredVariationSum = 0;
|
||||
int timeSeriesPoints = 0;
|
||||
@@ -361,7 +362,8 @@ void AnalyzerPlot::SetData(const Storage& rawData, const Storage& filteredData,
|
||||
m_timestepData.fitLine[0] =
|
||||
ImPlotPoint{minTime.value(), wpi::units::millisecond_t{dtMean}.value()};
|
||||
|
||||
auto maxTime = wpi::units::math::max(slow.back().timestamp, fast.back().timestamp);
|
||||
auto maxTime =
|
||||
wpi::units::math::max(slow.back().timestamp, fast.back().timestamp);
|
||||
m_timestepData.fitLine[1] =
|
||||
ImPlotPoint{maxTime.value(), wpi::units::millisecond_t{dtMean}.value()};
|
||||
|
||||
|
||||
@@ -252,7 +252,8 @@ static void AddSamples(std::vector<MotorData::Run::Sample<T>>& samples,
|
||||
[](const auto& datapoint, double val) { return datapoint.first < val; });
|
||||
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
samples.emplace_back(wpi::units::second_t{it->first * 1.0e-6}, T{it->second});
|
||||
samples.emplace_back(wpi::units::second_t{it->first * 1.0e-6},
|
||||
T{it->second});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ void LogLoader::RebuildEntryTree() {
|
||||
parts.emplace_back(prefix);
|
||||
}
|
||||
wpi::util::split(mainpart, '/', -1, false,
|
||||
[&](auto part) { parts.emplace_back(part); });
|
||||
[&](auto part) { parts.emplace_back(part); });
|
||||
|
||||
// ignore a raw "/" key
|
||||
if (parts.empty()) {
|
||||
@@ -139,7 +139,8 @@ void LogLoader::RebuildEntryTree() {
|
||||
|
||||
// get to leaf
|
||||
auto nodes = &m_entryTree;
|
||||
for (auto part : wpi::util::drop_back(std::span{parts.begin(), parts.end()})) {
|
||||
for (auto part :
|
||||
wpi::util::drop_back(std::span{parts.begin(), parts.end()})) {
|
||||
auto it =
|
||||
std::find_if(nodes->begin(), nodes->end(),
|
||||
[&](const auto& node) { return node.name == part; });
|
||||
|
||||
@@ -148,7 +148,8 @@ void ApplyMedianFilter(std::vector<PreparedData>* data, int window);
|
||||
std::tuple<wpi::units::second_t, wpi::units::second_t, wpi::units::second_t>
|
||||
TrimStepVoltageData(std::vector<PreparedData>* data,
|
||||
AnalysisManager::Settings* settings,
|
||||
wpi::units::second_t minStepTime, wpi::units::second_t maxStepTime);
|
||||
wpi::units::second_t minStepTime,
|
||||
wpi::units::second_t maxStepTime);
|
||||
|
||||
/**
|
||||
* Compute the mean time delta of the given data.
|
||||
@@ -187,7 +188,8 @@ wpi::units::second_t GetMeanTimeDelta(const Storage& data);
|
||||
* @param period The period in seconds between samples taken by the user.
|
||||
*/
|
||||
template <int Derivative, int Samples>
|
||||
wpi::math::LinearFilter<double> CentralFiniteDifference(wpi::units::second_t period) {
|
||||
wpi::math::LinearFilter<double> CentralFiniteDifference(
|
||||
wpi::units::second_t period) {
|
||||
static_assert(Samples % 2 != 0, "Number of samples must be odd.");
|
||||
|
||||
// Generate stencil points from -(samples - 1)/2 to (samples - 1)/2
|
||||
|
||||
@@ -27,7 +27,7 @@ struct ImPlotPoint;
|
||||
|
||||
namespace wpi::glass {
|
||||
class Storage;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
namespace sysid {
|
||||
/**
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
namespace wpi::glass {
|
||||
class Storage;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
namespace wpi {
|
||||
namespace log {
|
||||
@@ -27,7 +27,7 @@ class DataLogReaderEntry;
|
||||
} // namespace log
|
||||
namespace util {
|
||||
class Logger;
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace wpi
|
||||
|
||||
namespace sysid {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace wpi::glass {
|
||||
class Storage;
|
||||
} // namespace glass
|
||||
} // namespace wpi::glass
|
||||
|
||||
namespace pfd {
|
||||
class open_file;
|
||||
@@ -27,7 +27,7 @@ class DataLogReaderThread;
|
||||
} // namespace log
|
||||
namespace util {
|
||||
class Logger;
|
||||
}
|
||||
} // namespace util
|
||||
} // namespace wpi
|
||||
|
||||
namespace sysid {
|
||||
|
||||
@@ -136,8 +136,8 @@ TEST(FilterTest, StepTrim) {
|
||||
}
|
||||
|
||||
template <int Derivative, int Samples, typename F, typename DfDx>
|
||||
void AssertCentralResults(F&& f, DfDx&& dfdx, wpi::units::second_t h, double min,
|
||||
double max) {
|
||||
void AssertCentralResults(F&& f, DfDx&& dfdx, wpi::units::second_t h,
|
||||
double min, double max) {
|
||||
static_assert(Samples % 2 != 0, "Number of samples must be odd.");
|
||||
|
||||
auto filter = sysid::CentralFiniteDifference<Derivative, Samples>(h);
|
||||
|
||||
@@ -150,7 +150,8 @@ inline cameracalibration::CameraModel load_camera_model(std::string path) {
|
||||
return camera_model;
|
||||
}
|
||||
|
||||
inline cameracalibration::CameraModel load_camera_model(wpi::util::json json_data) {
|
||||
inline cameracalibration::CameraModel load_camera_model(
|
||||
wpi::util::json json_data) {
|
||||
// Camera matrix
|
||||
Eigen::Matrix<double, 3, 3> camera_matrix;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user