blob: 09860373a6e7077e94ec9947e56054a10b91ae4f [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) ||
24 (fetcher.context().monotonic_event_time + std::chrono::milliseconds(10) <
25 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) {
44 fetcher.Fetch();
45 const bool stale =
46 (fetcher.get() == nullptr) ||
47 (fetcher.context().monotonic_event_time + std::chrono::milliseconds(10) <
48 now);
49 return stale ? std::nullopt
50 : std::make_optional<Eigen::Vector2d>(fetcher->left_encoder(),
51 fetcher->right_encoder());
52}
53} // namespace
James Kuszmaul9a1733a2023-02-19 16:51:47 -080054
James Kuszmaul19612ab2024-02-17 20:45:58 -080055std::optional<Eigen::Vector2d> LocalizationUtils::Encoders(
56 aos::monotonic_clock::time_point now) {
James Kuszmaulf6aa0382024-03-01 19:46:05 -080057 if (position_fetcher_.valid()) {
58 return GetPosition(position_fetcher_, now);
59 } else {
60 CHECK(combined_fetcher_.valid());
61 return GetPosition(combined_fetcher_, now);
62 }
James Kuszmaul19612ab2024-02-17 20:45:58 -080063}
64
James Kuszmaul9a1733a2023-02-19 16:51:47 -080065bool LocalizationUtils::MaybeInAutonomous() {
66 joystick_state_fetcher_.Fetch();
67 return (joystick_state_fetcher_.get() != nullptr)
68 ? joystick_state_fetcher_->autonomous()
69 : true;
70}
71
James Kuszmaul4fe845a2023-03-26 12:57:30 -070072aos::Alliance LocalizationUtils::Alliance() {
73 joystick_state_fetcher_.Fetch();
74 return (joystick_state_fetcher_.get() != nullptr)
75 ? joystick_state_fetcher_->alliance()
76 : aos::Alliance::kInvalid;
James Kuszmaul4fe845a2023-03-26 12:57:30 -070077}
78
James Kuszmaul9a1733a2023-02-19 16:51:47 -080079std::optional<aos::monotonic_clock::duration> LocalizationUtils::ClockOffset(
80 std::string_view node) {
James Kuszmaul19da3232024-03-01 21:28:43 -080081 if (node == event_loop_->node()->name()->string_view()) {
82 return std::chrono::seconds(0);
83 }
James Kuszmaul9a1733a2023-02-19 16:51:47 -080084 std::optional<aos::monotonic_clock::duration> monotonic_offset;
85 clock_offset_fetcher_.Fetch();
86 if (clock_offset_fetcher_.get() != nullptr) {
87 for (const auto connection : *clock_offset_fetcher_->connections()) {
88 if (connection->has_node() && connection->node()->has_name() &&
89 connection->node()->name()->string_view() == node) {
90 if (connection->has_monotonic_offset()) {
91 monotonic_offset =
92 std::chrono::nanoseconds(connection->monotonic_offset());
93 } else {
94 // If we don't have a monotonic offset, that means we aren't
95 // connected.
96 return std::nullopt;
97 }
98 break;
99 }
100 }
101 }
102 CHECK(monotonic_offset.has_value());
103 return monotonic_offset;
104}
105
106// Technically, this should be able to do a single memcpy, but the extra
107// verbosity here seems appropriate.
108Eigen::Matrix<double, 4, 4> FlatbufferToTransformationMatrix(
109 const frc971::vision::calibration::TransformationMatrix &flatbuffer) {
110 CHECK_EQ(16u, CHECK_NOTNULL(flatbuffer.data())->size());
111 Eigen::Matrix<double, 4, 4> result;
112 result.setIdentity();
113 for (int row = 0; row < 4; ++row) {
114 for (int col = 0; col < 4; ++col) {
115 result(row, col) = (*flatbuffer.data())[row * 4 + col];
116 }
117 }
118 return result;
119}
120
121} // namespace frc971::control_loops::drivetrain