blob: c1adb9aac006d90d8d3eefba5f4d19180a5d6d6f [file] [log] [blame]
James Kuszmaule3df1ed2023-02-20 16:21:17 -08001#include "frc971/control_loops/drivetrain/localization/utils.h"
James Kuszmaul9a1733a2023-02-19 16:51:47 -08002
3namespace frc971::control_loops::drivetrain {
4
5LocalizationUtils::LocalizationUtils(aos::EventLoop *event_loop)
James Kuszmaul19da3232024-03-01 21:28:43 -08006 : event_loop_(event_loop),
James Kuszmaulf6aa0382024-03-01 19:46:05 -08007 output_fetcher_(event_loop->TryMakeFetcher<Output>("/drivetrain")),
James Kuszmaul19612ab2024-02-17 20:45:58 -08008 position_fetcher_(event_loop->TryMakeFetcher<Position>("/drivetrain")),
James Kuszmaulf6aa0382024-03-01 19:46:05 -08009 combined_fetcher_(
10 event_loop->TryMakeFetcher<RioLocalizerInputs>("/drivetrain")),
James Kuszmaul9a1733a2023-02-19 16:51:47 -080011 clock_offset_fetcher_(
12 event_loop->MakeFetcher<aos::message_bridge::ServerStatistics>(
13 "/aos")),
14 joystick_state_fetcher_(
15 event_loop->MakeFetcher<aos::JoystickState>("/roborio/aos")) {}
16
James Kuszmaulf6aa0382024-03-01 19:46:05 -080017namespace {
18template <typename T>
19Eigen::Vector2d GetVoltage(T &fetcher, aos::monotonic_clock::time_point now) {
20 fetcher.Fetch();
21 // Determine if the robot is likely to be disabled currently.
22 const bool disabled =
23 (fetcher.get() == nullptr) ||
James Kuszmaul8ca5dc12024-04-05 17:31:15 -070024 (fetcher.context().monotonic_event_time + std::chrono::milliseconds(500) <
James Kuszmaulf6aa0382024-03-01 19:46:05 -080025 now);
26 return disabled ? Eigen::Vector2d::Zero()
27 : Eigen::Vector2d{fetcher->left_voltage(),
28 fetcher->right_voltage()};
29}
30} // namespace
James Kuszmaul9a1733a2023-02-19 16:51:47 -080031Eigen::Vector2d LocalizationUtils::VoltageOrZero(
32 aos::monotonic_clock::time_point now) {
James Kuszmaulf6aa0382024-03-01 19:46:05 -080033 if (output_fetcher_.valid()) {
34 return GetVoltage(output_fetcher_, now);
35 } else {
36 CHECK(combined_fetcher_.valid());
37 return GetVoltage(combined_fetcher_, now);
38 }
James Kuszmaul9a1733a2023-02-19 16:51:47 -080039}
James Kuszmaulf6aa0382024-03-01 19:46:05 -080040namespace {
41template <typename T>
42std::optional<Eigen::Vector2d> GetPosition(
43 T &fetcher, aos::monotonic_clock::time_point now) {
James Kuszmaul2700e0f2024-03-16 16:45:48 -070044 if (!fetcher.Fetch()) {
45 return std::nullopt;
46 }
James Kuszmaulf6aa0382024-03-01 19:46:05 -080047 const bool stale =
48 (fetcher.get() == nullptr) ||
49 (fetcher.context().monotonic_event_time + std::chrono::milliseconds(10) <
50 now);
51 return stale ? std::nullopt
52 : std::make_optional<Eigen::Vector2d>(fetcher->left_encoder(),
53 fetcher->right_encoder());
54}
55} // namespace
James Kuszmaul9a1733a2023-02-19 16:51:47 -080056
James Kuszmaul19612ab2024-02-17 20:45:58 -080057std::optional<Eigen::Vector2d> LocalizationUtils::Encoders(
58 aos::monotonic_clock::time_point now) {
James Kuszmaulf6aa0382024-03-01 19:46:05 -080059 if (position_fetcher_.valid()) {
60 return GetPosition(position_fetcher_, now);
61 } else {
62 CHECK(combined_fetcher_.valid());
63 return GetPosition(combined_fetcher_, now);
64 }
James Kuszmaul19612ab2024-02-17 20:45:58 -080065}
66
James Kuszmaul9a1733a2023-02-19 16:51:47 -080067bool LocalizationUtils::MaybeInAutonomous() {
68 joystick_state_fetcher_.Fetch();
69 return (joystick_state_fetcher_.get() != nullptr)
70 ? joystick_state_fetcher_->autonomous()
71 : true;
72}
73
James Kuszmaul4fe845a2023-03-26 12:57:30 -070074aos::Alliance LocalizationUtils::Alliance() {
75 joystick_state_fetcher_.Fetch();
76 return (joystick_state_fetcher_.get() != nullptr)
77 ? joystick_state_fetcher_->alliance()
78 : aos::Alliance::kInvalid;
James Kuszmaul4fe845a2023-03-26 12:57:30 -070079}
80
James Kuszmaul9a1733a2023-02-19 16:51:47 -080081std::optional<aos::monotonic_clock::duration> LocalizationUtils::ClockOffset(
82 std::string_view node) {
James Kuszmaul19da3232024-03-01 21:28:43 -080083 if (node == event_loop_->node()->name()->string_view()) {
84 return std::chrono::seconds(0);
85 }
James Kuszmaul9a1733a2023-02-19 16:51:47 -080086 std::optional<aos::monotonic_clock::duration> monotonic_offset;
87 clock_offset_fetcher_.Fetch();
88 if (clock_offset_fetcher_.get() != nullptr) {
89 for (const auto connection : *clock_offset_fetcher_->connections()) {
90 if (connection->has_node() && connection->node()->has_name() &&
91 connection->node()->name()->string_view() == node) {
92 if (connection->has_monotonic_offset()) {
93 monotonic_offset =
94 std::chrono::nanoseconds(connection->monotonic_offset());
95 } else {
96 // If we don't have a monotonic offset, that means we aren't
97 // connected.
98 return std::nullopt;
99 }
100 break;
101 }
102 }
103 }
104 CHECK(monotonic_offset.has_value());
105 return monotonic_offset;
106}
107
108// Technically, this should be able to do a single memcpy, but the extra
109// verbosity here seems appropriate.
110Eigen::Matrix<double, 4, 4> FlatbufferToTransformationMatrix(
111 const frc971::vision::calibration::TransformationMatrix &flatbuffer) {
112 CHECK_EQ(16u, CHECK_NOTNULL(flatbuffer.data())->size());
113 Eigen::Matrix<double, 4, 4> result;
114 result.setIdentity();
115 for (int row = 0; row < 4; ++row) {
116 for (int col = 0; col < 4; ++col) {
117 result(row, col) = (*flatbuffer.data())[row * 4 + col];
118 }
119 }
120 return result;
121}
122
123} // namespace frc971::control_loops::drivetrain