SubZero Common
Common library components for an FRC CommandRobot
Loading...
Searching...
No Matches
PhotonVisionEstimators.h
Go to the documentation of this file.
1#pragma once
2
3#include <frc/apriltag/AprilTagFieldLayout.h>
4#include <frc/apriltag/AprilTagFields.h>
5#include <frc/estimator/SwerveDrivePoseEstimator.h>
6#include <photon/PhotonCamera.h>
7#include <photon/PhotonPoseEstimator.h>
8
9#include <limits>
10#include <memory>
11#include <utility>
12#include <vector>
13
14namespace subzero {
15
22public:
28 public:
29 explicit PhotonCameraEstimator(photon::PhotonPoseEstimator &est,
30 photon::PhotonCamera &cam)
31 : estimator{est}, camera{cam} {}
32
33 photon::PhotonPoseEstimator &estimator;
34 photon::PhotonCamera &camera; // Changed to reference
35 };
36
37 explicit PhotonVisionEstimators(std::vector<PhotonCameraEstimator> &estms,
38 Eigen::Matrix<double, 3, 1> singleTagStdDevs,
39 Eigen::Matrix<double, 3, 1> multiTagStdDevs)
40 : m_cameraEstimators{estms}, m_singleTagStdDevs{singleTagStdDevs},
41 m_multiTagStdDevs{multiTagStdDevs} {
42 for (auto &est : m_cameraEstimators) {
43 est.estimator.SetMultiTagFallbackStrategy(
44 photon::PoseStrategy::LOWEST_AMBIGUITY);
45 }
46 }
47
48 std::vector<photon::EstimatedRobotPose>
49 GetPosesFromCamera(frc::Pose3d prevPose, photon::PhotonPoseEstimator &est,
50 photon::PhotonCamera &camera, double maxAmbiguity = 0.2) {
51 est.SetReferencePose(prevPose);
52
53 std::vector<photon::EstimatedRobotPose> validPoses;
54
55 // Photon now returns all of the poses that we haven't integrated
56 // rather than just the latest, so we must return all that are valid
57 for (const auto &result : camera.GetAllUnreadResults()) {
58 // Check if the result has valid targets
59 if (result.HasTargets() &&
60 (result.targets.size() > 1 ||
61 result.targets[0].GetPoseAmbiguity() <= maxAmbiguity)) {
62 // Attempt to update the pose estimator with the result
63 std::optional<photon::EstimatedRobotPose> visionEst =
64 est.Update(result);
65
66 // If a valid pose is produced, check its boundaries
67 if (visionEst.has_value()) {
68 auto estimatedPose = visionEst.value().estimatedPose;
69 if (estimatedPose.X() > 0_m && estimatedPose.X() <= 100_m &&
70 estimatedPose.Y() > 0_m && estimatedPose.Y() <= 100_m) {
71 // Add the valid pose to the vector
72 validPoses.push_back(visionEst.value());
73 }
74 }
75 }
76 }
77
78 return validPoses;
79 }
80
88 void UpdateEstimatedGlobalPose(frc::SwerveDrivePoseEstimator<4U> &estimator,
89 bool test) {
90 for (auto &est : m_cameraEstimators) {
91 auto camPoses =
92 GetPosesFromCamera(frc::Pose3d(estimator.GetEstimatedPosition()),
93 est.estimator, est.camera);
94 // if (camPose.has_value()) {
95 // auto pose = camPose.value();
96 // AddVisionMeasurement(pose, estimator, est);
97 // }
98
99 if (camPoses.size() > 0) {
100 for (auto &pose : camPoses) {
101 AddVisionMeasurement(pose, estimator, est);
102 }
103 }
104 }
105 }
106
107 Eigen::Matrix<double, 3, 1>
108 GetEstimationStdDevs(photon::EstimatedRobotPose &pose,
109 PhotonCameraEstimator &photonEst) {
110 // TODO:
111 Eigen::Matrix<double, 3, 1> estStdDevs = m_singleTagStdDevs;
112 int numTags = 0;
113 units::meter_t avgDist = 0_m;
114 for (const auto &tgt : pose.targetsUsed) {
115 auto tagPose =
116 photonEst.estimator.GetFieldLayout().GetTagPose(tgt.GetFiducialId());
117 if (tagPose.has_value()) {
118 numTags++;
119 avgDist += tagPose.value().ToPose2d().Translation().Distance(
120 pose.estimatedPose.ToPose2d().Translation());
121 }
122 }
123
124 if (numTags == 0) {
125 return estStdDevs;
126 }
127
128 avgDist /= numTags;
129 if (numTags > 1) {
130 estStdDevs = m_multiTagStdDevs;
131 }
132
133 if (numTags == 1 && avgDist > 4_m) {
134 estStdDevs = (Eigen::MatrixXd(3, 1) << std::numeric_limits<double>::max(),
135 std::numeric_limits<double>::max(),
136 std::numeric_limits<double>::max())
137 .finished();
138 } else {
139 estStdDevs = estStdDevs * (1 + (avgDist.value() * avgDist.value() / 30));
140 }
141
142 return estStdDevs;
143 }
144
145private:
146 void AddVisionMeasurement(photon::EstimatedRobotPose &estimate,
147 frc::SwerveDrivePoseEstimator<4U> &estimator,
148 PhotonCameraEstimator &photonEst) {
149 auto stdDevs = GetEstimationStdDevs(estimate, photonEst);
150 wpi::array<double, 3> newStdDevs{stdDevs(0), stdDevs(1), stdDevs(2)};
151 estimator.AddVisionMeasurement(estimate.estimatedPose.ToPose2d(),
152 estimate.timestamp, newStdDevs);
153 }
154
155 std::vector<PhotonCameraEstimator> &m_cameraEstimators;
156 Eigen::Matrix<double, 3, 1> m_singleTagStdDevs;
157 Eigen::Matrix<double, 3, 1> m_multiTagStdDevs;
158
159 units::second_t lastEstTimestamp{0_s};
160};
161
162} // namespace subzero
PhotonCameraEstimator(photon::PhotonPoseEstimator &est, photon::PhotonCamera &cam)
std::vector< photon::EstimatedRobotPose > GetPosesFromCamera(frc::Pose3d prevPose, photon::PhotonPoseEstimator &est, photon::PhotonCamera &camera, double maxAmbiguity=0.2)
PhotonVisionEstimators(std::vector< PhotonCameraEstimator > &estms, Eigen::Matrix< double, 3, 1 > singleTagStdDevs, Eigen::Matrix< double, 3, 1 > multiTagStdDevs)
Eigen::Matrix< double, 3, 1 > GetEstimationStdDevs(photon::EstimatedRobotPose &pose, PhotonCameraEstimator &photonEst)
void UpdateEstimatedGlobalPose(frc::SwerveDrivePoseEstimator< 4U > &estimator, bool test)
Call in the drivetrain's Periodic method to update the estimated robot's position.