blob: b861335f53d49a6b414fad9d4b421152add63815 [file] [log] [blame]
Brian Silverman2ccf8c52016-03-15 00:22:26 -04001#include <stdlib.h>
2#include <netdb.h>
3#include <unistd.h>
4
5#include <vector>
6#include <memory>
7
8#include "aos/linux_code/init.h"
9#include "aos/common/time.h"
10#include "aos/common/logging/logging.h"
11#include "aos/common/logging/queue_logging.h"
12#include "aos/vision/events/udp.h"
13
14#include "y2016/vision/vision.q.h"
15#include "y2016/vision/vision_data.pb.h"
16#include "y2016/vision/stereo_geometry.h"
17#include "y2016/constants.h"
18
19namespace y2016 {
20namespace vision {
21
ben54dbccb2016-03-20 14:42:28 -070022::aos::vision::Vector<2> CreateCenterFromTarget(double lx, double ly, double rx, double ry) {
23 return ::aos::vision::Vector<2>((lx + rx) / 2.0, (ly + ry) / 2.0);
24}
25
26double TargetWidth(double lx, double ly, double rx, double ry) {
27 double dx = lx - rx;
28 double dy = ly - ry;
Austin Schuh098e4872016-03-20 16:51:24 -070029 return ::std::hypot(dx, dy);
ben54dbccb2016-03-20 14:42:28 -070030}
31
32void SelectTargets(const VisionData &left_target,
33 const VisionData &right_target,
34 ::aos::vision::Vector<2> *center_left,
35 ::aos::vision::Vector<2> *center_right) {
36 // No good targets. Let the caller decide defaults.
37 if (right_target.target_size() == 0 || left_target.target_size() == 0) {
38 return;
39 }
40
41 // Only one option, we have to go with it.
42 if (right_target.target_size() == 1 && left_target.target_size() == 1) {
43 *center_left =
44 CreateCenterFromTarget(left_target.target(0).left_corner_x(),
45 left_target.target(0).left_corner_y(),
46 left_target.target(0).right_corner_x(),
47 left_target.target(0).right_corner_y());
48 *center_right =
49 CreateCenterFromTarget(right_target.target(0).left_corner_x(),
50 right_target.target(0).left_corner_y(),
51 right_target.target(0).right_corner_x(),
52 right_target.target(0).right_corner_y());
53 return;
54 }
55
56 // Now we have to make a decision.
57 double max_wid = -1.0;
58 int left_index = 0;
59 // First pick the widest target from the left.
60 for (int i = 0; i < left_target.target_size(); i++) {
61 double wid1 = TargetWidth(left_target.target(i).left_corner_x(),
62 left_target.target(i).left_corner_y(),
63 left_target.target(i).right_corner_x(),
64 left_target.target(i).right_corner_y());
65 if (max_wid == -1.0 || wid1 > max_wid) {
66 max_wid = wid1;
67 left_index = i;
68 }
69 }
70 // Calculate the angle of the bottom edge for the left.
71 double h = left_target.target(left_index).left_corner_y() -
72 left_target.target(left_index).right_corner_y();
73 double good_ang = h / max_wid;
74 double min_ang_err = -1.0;
75 int right_index = -1;
76 // Now pick the bottom edge angle from the right that lines up best with the left.
77 for (int j = 0; j < right_target.target_size(); j++) {
78 double wid2 = TargetWidth(right_target.target(j).left_corner_x(),
79 right_target.target(j).left_corner_y(),
80 right_target.target(j).right_corner_x(),
81 right_target.target(j).right_corner_y());
82 h = right_target.target(j).left_corner_y() -
83 right_target.target(j).right_corner_y();
84 double ang = h/ wid2;
85 double ang_err = ::std::abs(good_ang - ang);
86 if (min_ang_err == -1.0 || min_ang_err > ang_err) {
87 min_ang_err = ang_err;
88 right_index = j;
89 }
90 }
91
92 *center_left =
93 CreateCenterFromTarget(left_target.target(left_index).left_corner_x(),
94 left_target.target(left_index).left_corner_y(),
95 left_target.target(left_index).right_corner_x(),
96 left_target.target(left_index).right_corner_y());
97 *center_right =
98 CreateCenterFromTarget(right_target.target(right_index).left_corner_x(),
99 right_target.target(right_index).left_corner_y(),
100 right_target.target(right_index).right_corner_x(),
101 right_target.target(right_index).right_corner_y());
102}
103
104
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400105void Main() {
106 StereoGeometry stereo(constants::GetValues().vision_name);
107 LOG(INFO, "calibration: %s\n",
108 stereo.calibration().ShortDebugString().c_str());
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400109
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700110 VisionData left_target;
111 aos::time::Time left_rx_time{0, 0};
112
113 VisionData right_target;
114 aos::time::Time right_rx_time{0, 0};
115
116 ::aos::vision::RXUdpSocket recv(8080);
117 char rawData[65507];
118 bool got_left = false;
119 bool got_right = false;
120
121 while (true) {
122 // TODO(austin): Don't malloc.
123 VisionData target;
124 int size = recv.Recv(rawData, 65507);
125 aos::time::Time now = aos::time::Time::Now();
126
127 if (target.ParseFromArray(rawData, size)) {
128 if (target.camera_index() == 0) {
129 left_target = target;
130 left_rx_time = now;
131 got_left = true;
132 } else {
133 right_target = target;
134 right_rx_time = now;
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400135 got_right = true;
136 }
137 } else {
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700138 LOG(ERROR, "oh noes: parse error\n");
139 continue;
140 }
141
142 if (now > left_rx_time + aos::time::Time::InMS(50)) {
143 got_left = false;
144 }
145 if (now > right_rx_time + aos::time::Time::InMS(50)) {
146 got_right = false;
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400147 }
148
149 if (got_left && got_right) {
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700150 bool left_image_valid = left_target.target_size() > 0;
151 bool right_image_valid = right_target.target_size() > 0;
152
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400153 auto new_vision_status = vision_status.MakeMessage();
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700154 new_vision_status->left_image_valid = left_image_valid;
155 new_vision_status->right_image_valid = right_image_valid;
156 if (left_image_valid && right_image_valid) {
ben54dbccb2016-03-20 14:42:28 -0700157 ::aos::vision::Vector<2> center0(0.0, 0.0);
158 ::aos::vision::Vector<2> center1(0.0, 0.0);
159 SelectTargets(left_target, right_target, &center0, &center1);
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700160 double distance, horizontal_angle, vertical_angle;
161 stereo.Process(center0, center1, &distance, &horizontal_angle,
162 &vertical_angle);
163 new_vision_status->left_image_timestamp = left_target.image_timestamp();
164 new_vision_status->right_image_timestamp = right_target.image_timestamp();
165 new_vision_status->left_send_timestamp = left_target.send_timestamp();
166 new_vision_status->right_send_timestamp = right_target.send_timestamp();
167 new_vision_status->horizontal_angle = horizontal_angle;
168 new_vision_status->vertical_angle = vertical_angle;
169 new_vision_status->distance = distance;
170 }
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400171 LOG_STRUCT(DEBUG, "vision", *new_vision_status);
172
173 if (!new_vision_status.Send()) {
174 LOG(ERROR, "Failed to send vision information\n");
175 }
176 }
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700177
178 if (target.camera_index() == 0) {
179 LOG(DEBUG, "left_target: %s\n", left_target.ShortDebugString().c_str());
180 } else {
181 LOG(DEBUG, "right_target: %s\n", right_target.ShortDebugString().c_str());
182 }
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400183 }
184}
185
186} // namespace vision
187} // namespace y2016
188
189int main(int /*argc*/, char ** /*argv*/) {
190 ::aos::InitNRT();
191 ::y2016::vision::Main();
192}