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 : estimator{est} {
31 camera = estimator.GetCamera();
32 }
33
34 photon::PhotonPoseEstimator &estimator;
35 std::shared_ptr<photon::PhotonCamera> camera;
36 };
37
38 explicit PhotonVisionEstimators(std::vector<PhotonCameraEstimator> &estms,
39 Eigen::Matrix<double, 3, 1> singleTagStdDevs,
40 Eigen::Matrix<double, 3, 1> multiTagStdDevs)
41 : m_cameraEstimators{estms}, m_singleTagStdDevs{singleTagStdDevs},
42 m_multiTagStdDevs{multiTagStdDevs} {
43 for (auto &est : m_cameraEstimators) {
44 est.estimator.SetMultiTagFallbackStrategy(
45 photon::PoseStrategy::LOWEST_AMBIGUITY);
46 }
47 }
48
49 std::optional<photon::EstimatedRobotPose>
50 GetPoseFromCamera(frc::Pose3d prevPose, photon::PhotonPoseEstimator &est,
51 photon::PhotonCamera &camera, double maxAbmiguity = 0.2) {
52 est.SetReferencePose(prevPose);
53 auto camResult = camera.GetLatestResult();
54
55 std::optional<photon::EstimatedRobotPose> visionEst;
56
57 if (camResult.HasTargets() &&
58 (camResult.targets.size() > 1 ||
59 camResult.targets[0].GetPoseAmbiguity() <= maxAbmiguity)) {
60 visionEst = est.Update(camResult);
61 }
62
63 if (visionEst.has_value()) {
64 auto estimatedPose = visionEst.value().estimatedPose;
65 // Replace 100_m with actual field dimensions
66 if (estimatedPose.X() > 0_m && estimatedPose.X() <= 100_m &&
67 estimatedPose.Y() > 0_m && estimatedPose.Y() <= 100_m) {
68 return visionEst;
69 }
70 }
71
72 return std::nullopt;
73 }
74
75 // See:
76 // https://github.com/Hemlock5712/2023-Robot/blob/Joe-Test/src/main/java/frc/robot/subsystems/PoseEstimatorSubsystem.java
84 void UpdateEstimatedGlobalPose(frc::SwerveDrivePoseEstimator<4U> &estimator,
85 bool test) {
86 for (auto &est : m_cameraEstimators) {
87 auto camPose =
88 GetPoseFromCamera(frc::Pose3d(estimator.GetEstimatedPosition()),
89 est.estimator, *est.camera);
90 if (camPose.has_value()) {
91 auto pose = camPose.value();
92 AddVisionMeasurement(pose, estimator, est);
93 }
94 }
95 }
96
97 Eigen::Matrix<double, 3, 1>
98 GetEstimationStdDevs(photon::EstimatedRobotPose &pose,
99 PhotonCameraEstimator &photonEst) {
100 // TODO:
101 Eigen::Matrix<double, 3, 1> estStdDevs = m_singleTagStdDevs;
102 int numTags = 0;
103 units::meter_t avgDist = 0_m;
104 // ConsoleWriter.logVerbose("Vision", "targets used length
105 // %d", pose.targetsUsed.size());
106 for (const auto &tgt : pose.targetsUsed) {
107 auto tagPose =
108 photonEst.estimator.GetFieldLayout().GetTagPose(tgt.GetFiducialId());
109 if (tagPose.has_value()) {
110 numTags++;
111 avgDist += tagPose.value().ToPose2d().Translation().Distance(
112 pose.estimatedPose.ToPose2d().Translation());
113 }
114 }
115
116 if (numTags == 0) {
117 return estStdDevs;
118 }
119
120 avgDist /= numTags;
121 if (numTags > 1) {
122 // TODO:
123 estStdDevs = m_multiTagStdDevs;
124 }
125
126 if (numTags == 1 && avgDist > 4_m) {
127 estStdDevs = (Eigen::MatrixXd(3, 1) << std::numeric_limits<double>::max(),
128 std::numeric_limits<double>::max(),
129 std::numeric_limits<double>::max())
130 .finished();
131 } else {
132 estStdDevs = estStdDevs * (1 + (avgDist.value() * avgDist.value() / 30));
133 }
134
135 return estStdDevs;
136 }
137
138private:
139 void AddVisionMeasurement(photon::EstimatedRobotPose &estimate,
140 frc::SwerveDrivePoseEstimator<4U> &estimator,
141 PhotonCameraEstimator &photonEst) {
142 auto stdDevs = GetEstimationStdDevs(estimate, photonEst);
143 wpi::array<double, 3> newStdDevs{stdDevs(0), stdDevs(1), stdDevs(2)};
144 estimator.AddVisionMeasurement(estimate.estimatedPose.ToPose2d(),
145 estimate.timestamp, newStdDevs);
146 }
147
148 std::vector<PhotonCameraEstimator> &m_cameraEstimators;
149 Eigen::Matrix<double, 3, 1> m_singleTagStdDevs;
150 Eigen::Matrix<double, 3, 1> m_multiTagStdDevs;
151
152 units::second_t lastEstTimestamp{0_s};
153};
154} // namespace subzero
Combines estimated poses from an aritrary number of PhotonVision cameras and applies them to a Holono...
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)
std::optional< photon::EstimatedRobotPose > GetPoseFromCamera(frc::Pose3d prevPose, photon::PhotonPoseEstimator &est, photon::PhotonCamera &camera, double maxAbmiguity=0.2)
void UpdateEstimatedGlobalPose(frc::SwerveDrivePoseEstimator< 4U > &estimator, bool test)
Call in the drivetrain's Periodic method to update the estimated robot's position.