blob: 54fcb3012d6c4883514afe1c7d2619e8d1628667 [file] [log] [blame]
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08001#ifndef Y2022_VISION_CAMERA_READER_H_
2#define Y2022_VISION_CAMERA_READER_H_
3
4#include <math.h>
5
6#include <opencv2/calib3d.hpp>
7#include <opencv2/features2d.hpp>
Henry Speiser1f34eea2022-01-30 14:35:21 -08008#include <opencv2/imgcodecs.hpp>
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -08009#include <opencv2/imgproc.hpp>
10
Henry Speiser1f34eea2022-01-30 14:35:21 -080011#include "aos/events/shm_event_loop.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080012#include "aos/flatbuffer_merge.h"
13#include "aos/network/team_number.h"
James Kuszmaule3df1ed2023-02-20 16:21:17 -080014#include "frc971/control_loops/drivetrain/localization/localizer_output_generated.h"
milind-u2f101fc2023-01-21 12:28:49 -080015#include "frc971/vision/calibration_generated.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080016#include "frc971/vision/v4l2_reader.h"
17#include "frc971/vision/vision_generated.h"
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080018#include "y2022/vision/calibration_data.h"
Jim Ostrowski2a483b32022-02-15 18:19:14 -080019#include "y2022/vision/gpio.h"
milind-u92195982022-01-22 20:29:31 -080020#include "y2022/vision/target_estimate_generated.h"
Milind Upadhyayf61e1482022-02-11 20:42:55 -080021#include "y2022/vision/target_estimator.h"
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080022
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080023namespace y2022::vision {
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080024
25using namespace frc971::vision;
Milind Upadhyayd67e9cf2022-03-13 13:56:57 -070026using frc971::controls::LedOutput;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080027
Jim Ostrowski2a483b32022-02-15 18:19:14 -080028// TODO<jim>: Probably need to break out LED control to separate process
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080029class CameraReader {
30 public:
Milind Upadhyaya31f0272022-04-03 13:55:22 -070031 static const calibration::CameraCalibration *FindCameraCalibration(
32 const calibration::CalibrationData *calibration_data,
33 std::string_view node_name, int team_number);
34
35 static cv::Mat CameraIntrinsics(
36 const calibration::CameraCalibration *camera_calibration) {
37 cv::Mat result(3, 3, CV_32F,
38 const_cast<void *>(static_cast<const void *>(
39 camera_calibration->intrinsics()->data())));
40 result.convertTo(result, CV_64F);
41 CHECK_EQ(result.total(), camera_calibration->intrinsics()->size());
42 return result;
43 }
44
45 static cv::Mat CameraExtrinsics(
46 const calibration::CameraCalibration *camera_calibration) {
47 // TODO(james): What's the principled way to handle non-z-axis turrets?
48 const frc971::vision::calibration::TransformationMatrix *transform =
49 camera_calibration->has_turret_extrinsics()
50 ? camera_calibration->turret_extrinsics()
51 : camera_calibration->fixed_extrinsics();
52
53 cv::Mat result(4, 4, CV_32F,
54 const_cast<void *>(
55 static_cast<const void *>(transform->data()->data())));
56 result.convertTo(result, CV_64F);
57 CHECK_EQ(result.total(), transform->data()->size());
58 return result;
59 }
60
61 static cv::Mat CameraDistCoeffs(
62 const calibration::CameraCalibration *camera_calibration) {
63 const cv::Mat result(5, 1, CV_32F,
64 const_cast<void *>(static_cast<const void *>(
65 camera_calibration->dist_coeffs()->data())));
66 CHECK_EQ(result.total(), camera_calibration->dist_coeffs()->size());
67 return result;
68 }
69
70 static std::pair<cv::Mat, cv::Mat> ComputeUndistortMaps(
71 const cv::Mat intrinsics, const cv::Mat dist_coeffs) {
72 std::pair<cv::Mat, cv::Mat> undistort_maps;
73 static const cv::Size kImageSize = {640, 480};
74 cv::initUndistortRectifyMap(intrinsics, dist_coeffs, cv::Mat(), intrinsics,
75 kImageSize, CV_16SC2, undistort_maps.first,
76 undistort_maps.second);
77 return undistort_maps;
78 }
79
80 static cv::Mat UndistortImage(cv::Mat image_distorted,
81 std::pair<cv::Mat, cv::Mat> undistort_maps) {
82 cv::Mat image;
83 cv::remap(image_distorted, image, undistort_maps.first,
84 undistort_maps.second, cv::INTER_LINEAR);
85 return image;
86 }
87
Henry Speiser1f34eea2022-01-30 14:35:21 -080088 CameraReader(aos::ShmEventLoop *event_loop,
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080089 const calibration::CalibrationData *calibration_data,
90 V4L2Reader *reader)
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080091 : event_loop_(event_loop),
Jim Ostrowski007e2ea2022-01-30 13:13:26 -080092 calibration_data_(calibration_data),
Milind Upadhyaya31f0272022-04-03 13:55:22 -070093 camera_calibration_(FindCameraCalibration(
94 calibration_data_, event_loop_->node()->name()->string_view(),
95 aos::network::GetTeamNumber())),
96 undistort_maps_(
97 ComputeUndistortMaps(CameraIntrinsics(), CameraDistCoeffs())),
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -080098 reader_(reader),
99 image_sender_(event_loop->MakeSender<CameraImage>("/camera")),
Milind Upadhyayf61e1482022-02-11 20:42:55 -0800100 target_estimator_(CameraIntrinsics(), CameraExtrinsics()),
milind-u92195982022-01-22 20:29:31 -0800101 target_estimate_sender_(
102 event_loop->MakeSender<TargetEstimate>("/camera")),
Milind Upadhyayd67e9cf2022-03-13 13:56:57 -0700103 localizer_output_fetcher_(
104 event_loop->MakeFetcher<frc971::controls::LocalizerOutput>(
105 "/localizer")),
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800106 read_image_timer_(event_loop->AddTimer([this]() { ReadImage(); })),
Jim Ostrowskia49d20e2022-02-26 18:34:05 -0800107 gpio_imu_pin_(GPIOControl(GPIO_PIN_SCLK_IMU, kGPIOIn)),
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800108 gpio_pwm_control_(GPIOPWMControl(GPIO_PIN_SCK_PWM, duty_cycle_)),
109 gpio_disable_control_(
110 GPIOControl(GPIO_PIN_MOSI_DISABLE, kGPIOOut, kGPIOLow)) {
Philipp Schradera6712522023-07-05 20:25:11 -0700111 event_loop->OnRun([this]() {
112 read_image_timer_->Schedule(event_loop_->monotonic_now());
113 });
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800114 }
115
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800116 void SetDutyCycle(double duty_cycle) {
117 duty_cycle_ = duty_cycle;
118 gpio_pwm_control_.setPWMDutyCycle(duty_cycle_);
119 }
120
121 double GetDutyCycle() { return duty_cycle_; }
122
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800123 private:
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800124 // Processes an image (including sending the results).
Milind Upadhyay3c1a5c02022-03-27 16:27:19 -0700125 void ProcessImage(cv::Mat image_mat_distorted,
126 int64_t image_monotonic_timestamp_ns);
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800127
128 // Reads an image, and then performs all of our processing on it.
129 void ReadImage();
130
131 cv::Mat CameraIntrinsics() const {
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700132 return CameraIntrinsics(camera_calibration_);
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800133 }
134
milind-u92195982022-01-22 20:29:31 -0800135 cv::Mat CameraExtrinsics() const {
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700136 return CameraExtrinsics(camera_calibration_);
milind-u92195982022-01-22 20:29:31 -0800137 }
138
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800139 cv::Mat CameraDistCoeffs() const {
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700140 return CameraDistCoeffs(camera_calibration_);
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800141 }
142
Henry Speiser1f34eea2022-01-30 14:35:21 -0800143 aos::ShmEventLoop *const event_loop_;
Jim Ostrowski007e2ea2022-01-30 13:13:26 -0800144 const calibration::CalibrationData *const calibration_data_;
145 const calibration::CameraCalibration *const camera_calibration_;
Milind Upadhyaya31f0272022-04-03 13:55:22 -0700146 std::pair<cv::Mat, cv::Mat> undistort_maps_;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800147 V4L2Reader *const reader_;
148 aos::Sender<CameraImage> image_sender_;
Milind Upadhyayf61e1482022-02-11 20:42:55 -0800149 TargetEstimator target_estimator_;
milind-u92195982022-01-22 20:29:31 -0800150 aos::Sender<TargetEstimate> target_estimate_sender_;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800151
Milind Upadhyayd67e9cf2022-03-13 13:56:57 -0700152 LedOutput prev_led_output_ = LedOutput::ON;
153 aos::Fetcher<frc971::controls::LocalizerOutput> localizer_output_fetcher_;
154
milind-u92195982022-01-22 20:29:31 -0800155 // We schedule this immediately to read an image. Having it on a timer
156 // means other things can run on the event loop in between.
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800157 aos::TimerHandler *const read_image_timer_;
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800158
159 double duty_cycle_ = 0.0;
Jim Ostrowskia49d20e2022-02-26 18:34:05 -0800160 GPIOControl gpio_imu_pin_;
Jim Ostrowski2a483b32022-02-15 18:19:14 -0800161 GPIOPWMControl gpio_pwm_control_;
162 GPIOControl gpio_disable_control_;
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800163};
164
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800165} // namespace y2022::vision
Jim Ostrowskiff7b3de2022-01-22 22:20:26 -0800166#endif // Y2022_VISION_CAMERA_READER_H_