blob: 65df6541a12cc16d183ad3dbc64b3c20440adbd6 [file] [log] [blame]
James Kuszmaul1798c072022-02-13 15:32:11 -08001#include "y2022/control_loops/drivetrain/localizer.h"
2
3namespace y2022 {
4namespace control_loops {
5namespace drivetrain {
6
7Localizer::Localizer(
8 aos::EventLoop *event_loop,
9 const frc971::control_loops::drivetrain::DrivetrainConfig<double>
10 &dt_config)
11 : event_loop_(event_loop),
12 dt_config_(dt_config),
13 ekf_(dt_config),
14 localizer_output_fetcher_(
15 event_loop_->MakeFetcher<frc971::controls::LocalizerOutput>(
16 "/localizer")),
James Kuszmaulc76c19b2022-03-16 22:41:44 -070017 joystick_state_fetcher_(
18 event_loop_->MakeFetcher<aos::JoystickState>("/aos")),
James Kuszmaul1798c072022-02-13 15:32:11 -080019 clock_offset_fetcher_(
20 event_loop_->MakeFetcher<aos::message_bridge::ServerStatistics>(
21 "/aos")) {
22 ekf_.set_ignore_accel(true);
23
24 event_loop->OnRun([this, event_loop]() {
25 ekf_.ResetInitialState(event_loop->monotonic_now(),
26 HybridEkf::State::Zero(), ekf_.P());
27 });
28
29 target_selector_.set_has_target(false);
30}
31
32void Localizer::Reset(
33 aos::monotonic_clock::time_point t,
34 const frc971::control_loops::drivetrain::HybridEkf<double>::State &state) {
35 // Go through and clear out all of the fetchers so that we don't get behind.
36 localizer_output_fetcher_.Fetch();
37 ekf_.ResetInitialState(t, state.cast<float>(), ekf_.P());
38}
39
40void Localizer::Update(const Eigen::Matrix<double, 2, 1> &U,
41 aos::monotonic_clock::time_point now,
42 double left_encoder, double right_encoder,
43 double gyro_rate, const Eigen::Vector3d &accel) {
44 ekf_.UpdateEncodersAndGyro(left_encoder, right_encoder, gyro_rate,
45 U.cast<float>(), accel.cast<float>(), now);
James Kuszmaulc76c19b2022-03-16 22:41:44 -070046 joystick_state_fetcher_.Fetch();
47 if (joystick_state_fetcher_.get() != nullptr &&
48 joystick_state_fetcher_->autonomous()) {
49 // TODO(james): This is an inelegant way to avoid having the localizer mess
50 // up splines. Do better.
51 return;
52 }
James Kuszmaul1798c072022-02-13 15:32:11 -080053 if (localizer_output_fetcher_.Fetch()) {
54 clock_offset_fetcher_.Fetch();
55 bool message_bridge_connected = true;
56 std::chrono::nanoseconds monotonic_offset{0};
57 if (clock_offset_fetcher_.get() != nullptr) {
58 for (const auto connection : *clock_offset_fetcher_->connections()) {
59 if (connection->has_node() && connection->node()->has_name() &&
60 connection->node()->name()->string_view() == "imu") {
61 if (connection->has_monotonic_offset()) {
62 monotonic_offset =
63 std::chrono::nanoseconds(connection->monotonic_offset());
64 } else {
65 // If we don't have a monotonic offset, that means we aren't
66 // connected, in which case we should break the loop but shouldn't
67 // populate the offset.
68 message_bridge_connected = false;
69 }
70 break;
71 }
72 }
73 }
74 if (!message_bridge_connected) {
75 return;
76 }
77 aos::monotonic_clock::time_point capture_time(
78 std::chrono::nanoseconds(
79 localizer_output_fetcher_->monotonic_timestamp_ns()) -
80 monotonic_offset);
81 // TODO: Finish implementing simple x/y/theta updater with state_at_capture.
82 // TODO: Implement turret/camera processing logic on pi side.
James Kuszmaulba59dc92022-03-12 10:46:54 -080083 std::optional<State> state_at_capture =
James Kuszmaul1798c072022-02-13 15:32:11 -080084 ekf_.LastStateBeforeTime(capture_time);
James Kuszmaulba59dc92022-03-12 10:46:54 -080085 if (!state_at_capture.has_value()) {
86 state_at_capture = ekf_.OldestState();
87 if (!state_at_capture.has_value()) {
88 return;
89 }
90 }
91
James Kuszmaul1798c072022-02-13 15:32:11 -080092 Eigen::Matrix<float, HybridEkf::kNOutputs, HybridEkf::kNStates> H;
93 H.setZero();
94 H(0, StateIdx::kX) = 1;
95 H(1, StateIdx::kY) = 1;
96 H(2, StateIdx::kTheta) = 1;
97 const Eigen::Vector3f Z{
98 static_cast<float>(localizer_output_fetcher_->x()),
99 static_cast<float>(localizer_output_fetcher_->y()),
100 static_cast<float>(localizer_output_fetcher_->theta())};
101 Eigen::Matrix3f R = Eigen::Matrix3f::Zero();
102 R.diagonal() << 0.01, 0.01, 1e-4;
103 const Input U_correct = ekf_.MostRecentInput();
104 ekf_.Correct(
105 Eigen::Vector3f::Zero(), &U_correct, {},
106 [H, state_at_capture, Z](const State &,
107 const Input &) -> Eigen::Vector3f {
108 Eigen::Vector3f error = H * state_at_capture.value() - Z;
109 error(2) = aos::math::NormalizeAngle(error(2));
110 return error;
111 },
112 [H](const State &) { return H; }, R, now);
113 }
114}
115
116} // namespace drivetrain
117} // namespace control_loops
118} // namespace y2022