blob: 07f9aff15f6f781d4acd55cc49c043b642627b9d [file] [log] [blame]
James Kuszmaul9a1733a2023-02-19 16:51:47 -08001#ifndef FRC971_CONTROL_LOOPS_DRIVETRAIN_LOCALIZATION_UTILS_H_
2#define FRC971_CONTROL_LOOPS_DRIVETRAIN_LOCALIZATION_UTILS_H_
3#include <Eigen/Dense>
4
5#include "aos/events/event_loop.h"
6#include "aos/network/message_bridge_server_generated.h"
7#include "frc971/control_loops/drivetrain/drivetrain_output_generated.h"
James Kuszmaul19612ab2024-02-17 20:45:58 -08008#include "frc971/control_loops/drivetrain/drivetrain_position_generated.h"
9#include "frc971/control_loops/drivetrain/hybrid_ekf.h"
10#include "frc971/control_loops/pose.h"
James Kuszmaul9a1733a2023-02-19 16:51:47 -080011#include "frc971/input/joystick_state_generated.h"
12#include "frc971/vision/calibration_generated.h"
13
14namespace frc971::control_loops::drivetrain {
15// This class provides a variety of checks that have generally proved useful for
16// the localizer but which have no clear place to live otherwise.
17// Specifically, it tracks:
18// * Drivetrain voltages, including checks for whether the Output message
19// has timed out.
20// * Offsets between monotonic clocks on different devices.
21// * Whether we are in autonomous mode.
James Kuszmaul19612ab2024-02-17 20:45:58 -080022// * Drivetrain encoder voltages, as reported by the roborio.
James Kuszmaul9a1733a2023-02-19 16:51:47 -080023class LocalizationUtils {
24 public:
25 LocalizationUtils(aos::EventLoop *event_loop);
26
27 // Returns the latest drivetrain output voltage, or zero if no output is
28 // available (which happens when the robot is disabled; when the robot is
29 // disabled, the voltage is functionally zero). Return value will be
30 // [left_voltage, right_voltage]
31 Eigen::Vector2d VoltageOrZero(aos::monotonic_clock::time_point now);
32
James Kuszmaul19612ab2024-02-17 20:45:58 -080033 // Returns the latest drivetrain encoder values (in meters), or nullopt if no
34 // position message is available (or if the message is stale).
35 // Returns encoders as [left_position, right_position]
36 std::optional<Eigen::Vector2d> Encoders(aos::monotonic_clock::time_point now);
37
James Kuszmaul9a1733a2023-02-19 16:51:47 -080038 // Returns true if either there is no JoystickState message available or if
39 // we are currently in autonomous mode.
40 bool MaybeInAutonomous();
James Kuszmaul4fe845a2023-03-26 12:57:30 -070041 aos::Alliance Alliance();
James Kuszmaul9a1733a2023-02-19 16:51:47 -080042
43 // Returns the offset between our node and the specified node (or nullopt if
44 // no offset is available). The sign of this will be such that the time on
45 // the remote node = time on our node + ClockOffset().
46 std::optional<aos::monotonic_clock::duration> ClockOffset(
47 std::string_view node);
48
49 private:
James Kuszmaul19da3232024-03-01 21:28:43 -080050 aos::EventLoop *const event_loop_;
James Kuszmaul9a1733a2023-02-19 16:51:47 -080051 aos::Fetcher<frc971::control_loops::drivetrain::Output> output_fetcher_;
James Kuszmaul19612ab2024-02-17 20:45:58 -080052 aos::Fetcher<frc971::control_loops::drivetrain::Position> position_fetcher_;
James Kuszmaul9a1733a2023-02-19 16:51:47 -080053 aos::Fetcher<aos::message_bridge::ServerStatistics> clock_offset_fetcher_;
54 aos::Fetcher<aos::JoystickState> joystick_state_fetcher_;
55};
56
57// Converts a flatbuffer TransformationMatrix to an Eigen matrix.
58Eigen::Matrix<double, 4, 4> FlatbufferToTransformationMatrix(
59 const frc971::vision::calibration::TransformationMatrix &flatbuffer);
60
James Kuszmaul19612ab2024-02-17 20:45:58 -080061// This approximates the Jacobian of a vector of [heading, distance, skew]
62// of a target with respect to the full state of a drivetrain EKF.
63// Note that the only nonzero values in the returned matrix will be in the
64// columns corresponding to the X, Y, and Theta components of the state.
65// This is suitable for use as the H matrix in the kalman updates of the EKF,
66// although due to the approximation it should not be used to actually
67// calculate the expected measurement.
68// target_pose is the global pose of the target that we have identified.
69// camera_pose is the current estimate of the global pose of
70// the camera that can see the target.
71template <typename Scalar>
72Eigen::Matrix<double, 3, HybridEkf<Scalar>::kNStates>
73HMatrixForCameraHeadingDistanceSkew(const TypedPose<Scalar> &target_pose,
74 const TypedPose<Scalar> &camera_pose) {
75 // For all of the below calculations, we will assume to a first
76 // approximation that:
77 //
78 // dcamera_theta / dtheta ~= 1
79 // dcamera_x / dx ~= 1
80 // dcamera_y / dy ~= 1
81 //
82 // For cameras sufficiently far from the robot's origin, or if the robot were
83 // spinning extremely rapidly, this would not hold.
84
85 // To calculate dheading/d{x,y,theta}:
86 // heading = arctan2(target_pos - camera_pos) - camera_theta
87 Eigen::Matrix<Scalar, 3, 1> target_pos = target_pose.abs_pos();
88 Eigen::Matrix<Scalar, 3, 1> camera_pos = camera_pose.abs_pos();
89 Scalar diffx = target_pos.x() - camera_pos.x();
90 Scalar diffy = target_pos.y() - camera_pos.y();
91 Scalar norm2 = diffx * diffx + diffy * diffy;
92 Scalar dheadingdx = diffy / norm2;
93 Scalar dheadingdy = -diffx / norm2;
94 Scalar dheadingdtheta = -1.0;
95
96 // To calculate ddistance/d{x,y}:
97 // distance = sqrt(diffx^2 + diffy^2)
98 Scalar distance = ::std::sqrt(norm2);
99 Scalar ddistdx = -diffx / distance;
100 Scalar ddistdy = -diffy / distance;
101
102 // Skew = target.theta - camera.theta - heading
103 // = target.theta - arctan2(target_pos - camera_pos)
104 Scalar dskewdx = -dheadingdx;
105 Scalar dskewdy = -dheadingdy;
106 Eigen::Matrix<Scalar, 3, HybridEkf<Scalar>::kNStates> H;
107 H.setZero();
108 H(0, HybridEkf<Scalar>::kX) = dheadingdx;
109 H(0, HybridEkf<Scalar>::kY) = dheadingdy;
110 H(0, HybridEkf<Scalar>::kTheta) = dheadingdtheta;
111 H(1, HybridEkf<Scalar>::kX) = ddistdx;
112 H(1, HybridEkf<Scalar>::kY) = ddistdy;
113 H(2, HybridEkf<Scalar>::kX) = dskewdx;
114 H(2, HybridEkf<Scalar>::kY) = dskewdy;
115 return H;
116}
117
James Kuszmaul9a1733a2023-02-19 16:51:47 -0800118} // namespace frc971::control_loops::drivetrain
119
120#endif // FRC971_CONTROL_LOOPS_DRIVETRAIN_LOCALIZATION_UTILS_H_