blob: 45ca43710fb29ea362274fe6c2f5c8881fd9871f [file] [log] [blame]
James Kuszmaul313e9ce2024-02-11 17:47:33 -08001#ifndef Y2024_LOCALIZER_LOCALIZER_H_
2#define Y2024_LOCALIZER_LOCALIZER_H_
3
4#include <array>
5#include <map>
6
7#include "aos/network/message_bridge_client_generated.h"
8#include "aos/network/message_bridge_server_generated.h"
9#include "frc971/constants/constants_sender_lib.h"
10#include "frc971/control_loops/drivetrain/hybrid_ekf.h"
11#include "frc971/control_loops/drivetrain/improved_down_estimator.h"
12#include "frc971/control_loops/drivetrain/localization/localizer_output_generated.h"
13#include "frc971/control_loops/drivetrain/localization/utils.h"
James Kuszmaul86116c22024-03-15 22:50:34 -070014#include "frc971/control_loops/drivetrain/localizer_generated.h"
James Kuszmaul313e9ce2024-02-11 17:47:33 -080015#include "frc971/imu_reader/imu_watcher.h"
16#include "frc971/vision/target_map_generated.h"
17#include "y2024/constants/constants_generated.h"
18#include "y2024/localizer/status_generated.h"
19#include "y2024/localizer/visualization_static.h"
20
21namespace y2024::localizer {
22
23class Localizer {
24 public:
25 static constexpr size_t kNumCameras = 4;
26 using Pose = frc971::control_loops::Pose;
27 typedef Eigen::Matrix<double, 4, 4> Transform;
28 typedef frc971::control_loops::drivetrain::HybridEkf<double> HybridEkf;
29 typedef HybridEkf::State State;
30 typedef HybridEkf::Output Output;
31 typedef HybridEkf::Input Input;
32 typedef HybridEkf::StateIdx StateIdx;
33 Localizer(aos::EventLoop *event_loop);
34
35 private:
36 class Corrector : public HybridEkf::ExpectedObservationFunctor {
37 public:
38 // Indices used for each of the members of the output vector for this
39 // Corrector.
40 enum OutputIdx {
41 kHeading = 0,
42 kDistance = 1,
43 kSkew = 2,
44 };
45 Corrector(const State &state_at_capture, const Transform &H_field_target,
46 const Transform &H_robot_camera,
47 const Transform &H_camera_target);
48
49 using HMatrix = Eigen::Matrix<double, Localizer::HybridEkf::kNOutputs,
50 Localizer::HybridEkf::kNStates>;
51
52 Output H(const State &, const Input &) final;
53 HMatrix DHDX(const State &) final { return H_; }
54 const Eigen::Vector3d &observed() const { return observed_; }
55 const Eigen::Vector3d &expected() const { return expected_; }
56 const Pose &expected_robot_pose() const { return expected_robot_pose_; }
57 const Pose &expected_camera_pose() const { return expected_camera_; }
58 const Pose &observed_camera_pose() const { return observed_camera_; }
59
60 static Eigen::Vector3d HeadingDistanceSkew(const Pose &relative_pose);
61
62 static Corrector CalculateHeadingDistanceSkewH(
63 const State &state_at_capture, const Transform &H_field_target,
64 const Transform &H_robot_camera, const Transform &H_camera_target);
65
66 static void PopulateMeasurement(const Eigen::Vector3d &vector,
67 MeasurementStatic *builder) {
68 builder->set_heading(vector(kHeading));
69 builder->set_distance(vector(kDistance));
70 builder->set_skew(vector(kSkew));
71 }
72
73 private:
74 Corrector(const Pose &expected_robot_pose, const Pose &observed_camera,
75 const Pose &expected_camera, const Eigen::Vector3d &expected,
76 const Eigen::Vector3d &observed, const HMatrix &H)
77 : expected_robot_pose_(expected_robot_pose),
78 observed_camera_(observed_camera),
79 expected_camera_(expected_camera),
80 expected_(expected),
81 observed_(observed),
82 H_(H) {}
83 // For debugging.
84 const Pose expected_robot_pose_;
85 const Pose observed_camera_;
86 const Pose expected_camera_;
87 // Actually used.
88 const Eigen::Vector3d expected_;
89 const Eigen::Vector3d observed_;
90 const HMatrix H_;
91 };
92
James Kuszmaul86116c22024-03-15 22:50:34 -070093 // A corrector that just does x/y/theta based corrections rather than doing
94 // heading/distance/skew corrections.
95 class XyzCorrector : public HybridEkf::ExpectedObservationFunctor {
96 public:
97 // Indices used for each of the members of the output vector for this
98 // Corrector.
99 enum OutputIdx {
100 kX = 0,
101 kY = 1,
102 kTheta = 2,
103 };
104 XyzCorrector(const State &state_at_capture, const Eigen::Vector3d &Z)
105 : state_at_capture_(state_at_capture), Z_(Z) {
106 H_.setZero();
107 H_(kX, StateIdx::kX) = 1;
108 H_(kY, StateIdx::kY) = 1;
109 H_(kTheta, StateIdx::kTheta) = 1;
110 }
111 Output H(const State &, const Input &) final;
112 Eigen::Matrix<double, HybridEkf::kNOutputs, HybridEkf::kNStates> DHDX(
113 const State &) final {
114 return H_;
115 }
116
117 private:
118 Eigen::Matrix<double, HybridEkf::kNOutputs, HybridEkf::kNStates> H_;
119 const State state_at_capture_;
120 const Eigen::Vector3d &Z_;
121 };
122
James Kuszmaul313e9ce2024-02-11 17:47:33 -0800123 struct CameraState {
124 aos::Sender<VisualizationStatic> debug_sender;
125 Transform extrinsics = Transform::Zero();
126 aos::util::ArrayErrorCounter<RejectionReason, RejectionCount>
127 rejection_counter;
128 size_t total_candidate_targets = 0;
129 size_t total_accepted_targets = 0;
130 };
131
James Kuszmaul86116c22024-03-15 22:50:34 -0700132 // Returns true if we should use a lower weight for the specified april tag.
133 // This is used for tags where we do not trust the placement as much.
134 bool DeweightAprilTag(uint64_t target_id);
James Kuszmaul313e9ce2024-02-11 17:47:33 -0800135 static std::array<CameraState, kNumCameras> MakeCameras(
136 const Constants &constants, aos::EventLoop *event_loop);
137 void HandleTarget(int camera_index,
138 const aos::monotonic_clock::time_point capture_time,
139 const frc971::vision::TargetPoseFbs &target,
140 TargetEstimateDebugStatic *debug_builder);
141 void HandleImu(aos::monotonic_clock::time_point sample_time_pico,
142 aos::monotonic_clock::time_point sample_time_pi,
143 std::optional<Eigen::Vector2d> encoders, Eigen::Vector3d gyro,
144 Eigen::Vector3d accel);
145 void RejectImage(int camera_index, RejectionReason reason,
146 TargetEstimateDebugStatic *builder);
147
148 void SendOutput();
149 static flatbuffers::Offset<frc971::control_loops::drivetrain::LocalizerState>
150 PopulateState(const State &X_hat, flatbuffers::FlatBufferBuilder *fbb);
151 flatbuffers::Offset<ImuStatus> PopulateImu(
152 flatbuffers::FlatBufferBuilder *fbb) const;
153 void SendStatus();
154 static flatbuffers::Offset<CumulativeStatistics> StatisticsForCamera(
155 const CameraState &camera, flatbuffers::FlatBufferBuilder *fbb);
156 static void StatisticsForCamera(const CameraState &camera,
157 CumulativeStatisticsStatic *builder);
158
159 bool UseAprilTag(uint64_t target_id);
James Kuszmaul86116c22024-03-15 22:50:34 -0700160 void HandleControl(
161 const frc971::control_loops::drivetrain::LocalizerControl &msg);
James Kuszmaul313e9ce2024-02-11 17:47:33 -0800162
163 aos::EventLoop *const event_loop_;
164 frc971::constants::ConstantsFetcher<Constants> constants_fetcher_;
165 const frc971::control_loops::drivetrain::DrivetrainConfig<double> dt_config_;
166 std::array<CameraState, kNumCameras> cameras_;
167 const std::array<Transform, kNumCameras> camera_extrinsics_;
168 const std::map<uint64_t, Transform> target_poses_;
169
170 frc971::control_loops::drivetrain::DrivetrainUkf down_estimator_;
171 HybridEkf ekf_;
172 HybridEkf::ExpectedObservationAllocator<Corrector> observations_;
James Kuszmaul86116c22024-03-15 22:50:34 -0700173 HybridEkf::ExpectedObservationAllocator<XyzCorrector> xyz_observations_;
James Kuszmaul313e9ce2024-02-11 17:47:33 -0800174
175 frc971::controls::ImuWatcher imu_watcher_;
176 frc971::control_loops::drivetrain::LocalizationUtils utils_;
177
178 aos::Sender<Status> status_sender_;
179 aos::Sender<frc971::controls::LocalizerOutput> output_sender_;
180 aos::monotonic_clock::time_point t_ = aos::monotonic_clock::min_time;
181 size_t clock_resets_ = 0;
182
183 size_t total_candidate_targets_ = 0;
184 size_t total_accepted_targets_ = 0;
185
186 // For the status message.
187 std::optional<Eigen::Vector2d> last_encoder_readings_;
188
189 aos::Fetcher<aos::message_bridge::ServerStatistics>
190 server_statistics_fetcher_;
191 aos::Fetcher<aos::message_bridge::ClientStatistics>
192 client_statistics_fetcher_;
James Kuszmaul86116c22024-03-15 22:50:34 -0700193 aos::Fetcher<frc971::control_loops::drivetrain::LocalizerControl>
194 control_fetcher_;
James Kuszmaul313e9ce2024-02-11 17:47:33 -0800195};
196} // namespace y2024::localizer
197#endif // Y2024_LOCALIZER_LOCALIZER_H_