blob: b51e4ed2e9b22cffa37fd82fac638a925976dbcb [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.
Austin Schuh9f59c8a2016-03-20 21:09:05 -070057 double min_angle = -1.0;
ben54dbccb2016-03-20 14:42:28 -070058 int left_index = 0;
59 // First pick the widest target from the left.
60 for (int i = 0; i < left_target.target_size(); i++) {
Austin Schuh9f59c8a2016-03-20 21:09:05 -070061 const double h = left_target.target(i).left_corner_y() -
62 left_target.target(i).right_corner_y();
63 const double wid1 = TargetWidth(left_target.target(i).left_corner_x(),
64 left_target.target(i).left_corner_y(),
65 left_target.target(i).right_corner_x(),
66 left_target.target(i).right_corner_y());
67 const double angle = h / wid1;
68 if (min_angle == -1.0 || ::std::abs(angle) < ::std::abs(min_angle)) {
69 min_angle = angle;
ben54dbccb2016-03-20 14:42:28 -070070 left_index = i;
71 }
72 }
73 // Calculate the angle of the bottom edge for the left.
74 double h = left_target.target(left_index).left_corner_y() -
75 left_target.target(left_index).right_corner_y();
Austin Schuh9f59c8a2016-03-20 21:09:05 -070076
77 double good_ang = min_angle;
ben54dbccb2016-03-20 14:42:28 -070078 double min_ang_err = -1.0;
79 int right_index = -1;
80 // Now pick the bottom edge angle from the right that lines up best with the left.
81 for (int j = 0; j < right_target.target_size(); j++) {
82 double wid2 = TargetWidth(right_target.target(j).left_corner_x(),
83 right_target.target(j).left_corner_y(),
84 right_target.target(j).right_corner_x(),
85 right_target.target(j).right_corner_y());
86 h = right_target.target(j).left_corner_y() -
87 right_target.target(j).right_corner_y();
88 double ang = h/ wid2;
89 double ang_err = ::std::abs(good_ang - ang);
90 if (min_ang_err == -1.0 || min_ang_err > ang_err) {
91 min_ang_err = ang_err;
92 right_index = j;
93 }
94 }
95
96 *center_left =
97 CreateCenterFromTarget(left_target.target(left_index).left_corner_x(),
98 left_target.target(left_index).left_corner_y(),
99 left_target.target(left_index).right_corner_x(),
100 left_target.target(left_index).right_corner_y());
101 *center_right =
102 CreateCenterFromTarget(right_target.target(right_index).left_corner_x(),
103 right_target.target(right_index).left_corner_y(),
104 right_target.target(right_index).right_corner_x(),
105 right_target.target(right_index).right_corner_y());
106}
107
108
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400109void Main() {
110 StereoGeometry stereo(constants::GetValues().vision_name);
111 LOG(INFO, "calibration: %s\n",
112 stereo.calibration().ShortDebugString().c_str());
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400113
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700114 VisionData left_target;
115 aos::time::Time left_rx_time{0, 0};
116
117 VisionData right_target;
118 aos::time::Time right_rx_time{0, 0};
119
120 ::aos::vision::RXUdpSocket recv(8080);
121 char rawData[65507];
122 bool got_left = false;
123 bool got_right = false;
124
125 while (true) {
126 // TODO(austin): Don't malloc.
127 VisionData target;
128 int size = recv.Recv(rawData, 65507);
129 aos::time::Time now = aos::time::Time::Now();
130
131 if (target.ParseFromArray(rawData, size)) {
132 if (target.camera_index() == 0) {
133 left_target = target;
134 left_rx_time = now;
135 got_left = true;
136 } else {
137 right_target = target;
138 right_rx_time = now;
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400139 got_right = true;
140 }
141 } else {
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700142 LOG(ERROR, "oh noes: parse error\n");
143 continue;
144 }
145
146 if (now > left_rx_time + aos::time::Time::InMS(50)) {
147 got_left = false;
148 }
149 if (now > right_rx_time + aos::time::Time::InMS(50)) {
150 got_right = false;
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400151 }
152
153 if (got_left && got_right) {
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700154 bool left_image_valid = left_target.target_size() > 0;
155 bool right_image_valid = right_target.target_size() > 0;
156
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400157 auto new_vision_status = vision_status.MakeMessage();
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700158 new_vision_status->left_image_valid = left_image_valid;
159 new_vision_status->right_image_valid = right_image_valid;
160 if (left_image_valid && right_image_valid) {
ben54dbccb2016-03-20 14:42:28 -0700161 ::aos::vision::Vector<2> center0(0.0, 0.0);
162 ::aos::vision::Vector<2> center1(0.0, 0.0);
163 SelectTargets(left_target, right_target, &center0, &center1);
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700164 double distance, horizontal_angle, vertical_angle;
165 stereo.Process(center0, center1, &distance, &horizontal_angle,
166 &vertical_angle);
167 new_vision_status->left_image_timestamp = left_target.image_timestamp();
168 new_vision_status->right_image_timestamp = right_target.image_timestamp();
169 new_vision_status->left_send_timestamp = left_target.send_timestamp();
170 new_vision_status->right_send_timestamp = right_target.send_timestamp();
171 new_vision_status->horizontal_angle = horizontal_angle;
172 new_vision_status->vertical_angle = vertical_angle;
173 new_vision_status->distance = distance;
174 }
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400175 LOG_STRUCT(DEBUG, "vision", *new_vision_status);
176
177 if (!new_vision_status.Send()) {
178 LOG(ERROR, "Failed to send vision information\n");
179 }
180 }
Austin Schuhc65b0ea2016-03-16 22:09:19 -0700181
182 if (target.camera_index() == 0) {
183 LOG(DEBUG, "left_target: %s\n", left_target.ShortDebugString().c_str());
184 } else {
185 LOG(DEBUG, "right_target: %s\n", right_target.ShortDebugString().c_str());
186 }
Brian Silverman2ccf8c52016-03-15 00:22:26 -0400187 }
188}
189
190} // namespace vision
191} // namespace y2016
192
193int main(int /*argc*/, char ** /*argv*/) {
194 ::aos::InitNRT();
195 ::y2016::vision::Main();
196}