37 {72, 72, 72, -72}, {72, -72, -72, -72}, {-72, -72, -72, 72}, {-72, 72, 72, 72},
38 {20.9, 46.25, 24.4, 46.25}, {24.4, 46.25, 24.4, 49.75}, {24.4, 49.75, 20.9, 49.75}, {20.9, 49.75, 20.9, 46.25},
39 {-24.4, 46.25, -20.9, 46.25}, {-20.9, 46.25, -20.9, 49.75}, {-20.9, 49.75, -24.4, 49.75}, {-24.4, 49.75, -24.4, 46.25},
40 {20.9, -49.75, 24.4, -49.75}, {24.4, -49.75, 24.4, -46.25}, {24.4, -46.25, 20.9, -46.25}, {20.9, -46.25, 20.9, -49.75},
41 {-24.4, -49.75, -20.9, -49.75}, {-20.9, -49.75, -20.9, -46.25}, {-20.9, -46.25, -24.4, -46.25}, {-24.4, -46.25, -24.4, -49.75},
42 {-72, 45.5, -67, 45.5}, {-67, 45.5, -67, 50.5}, {-67, 50.5, -72, 50.5}, {-72, 50.5, -72, 45.5},
43 {67, 45.5, 72, 45.5}, {72, 45.5, 72, 50.5}, {72, 50.5, 67, 50.5}, {67, 50.5, 67, 45.5},
44 {-72, -50.5, -67, -50.5}, {-67, -50.5, -67, -45.5}, {-67, -45.5, -72, -45.5}, {-72, -45.5, -72, -50.5},
45 {67, -50.5, 72, -50.5}, {72, -50.5, 72, -45.5}, {72, -45.5, 67, -45.5}, {67, -45.5, 67, -50.5},
82 double minDist = 10000.0;
83 double bestWeight = 1.0;
85 double ray_end_x = sensX + dx * SENSOR_MAX_RANGE_IN;
86 double ray_end_y = sensY + dy * SENSOR_MAX_RANGE_IN;
87 double r_min_x = std::min(sensX, ray_end_x);
88 double r_max_x = std::max(sensX, ray_end_x);
89 double r_min_y = std::min(sensY, ray_end_y);
90 double r_max_y = std::max(sensY, ray_end_y);
94 if (r_max_x < box.min_x || r_min_x > box.
max_x ||
95 r_max_y < box.min_y || r_min_y > box.
max_y)
continue;
98 double r_px = seg.
x0 - sensX;
99 double r_py = seg.
y0 - sensY;
100 double r_cross_s = dx * seg.
dy - dy * seg.
dx;
102 if (std::abs(r_cross_s) < 1e-4)
continue;
104 double t = (r_px * seg.
dy - r_py * seg.
dx) / r_cross_s;
105 double u = (r_px * dy - r_py * dx) / r_cross_s;
107 if (u >= 0.0 && u <= 1.0 && t > 0.0) {
110 bestWeight = 0.5 + 0.5 * std::abs(dx * seg.
nx + dy * seg.
ny);
115 if (minDist <= 0 || minDist > SENSOR_MAX_RANGE_IN)
return {-1.0, 1.0};
116 return {minDist, bestWeight};
162 lemlib::Pose prevOdom =
chassis.getPose();
165 lemlib::Pose currOdom =
chassis.getPose();
166 double dX_global = currOdom.x - prevOdom.x;
167 double dY_global = currOdom.y - prevOdom.y;
168 double dTheta =
wrapAngleDeg(currOdom.theta - prevOdom.theta);
171 double robot_rad =
degToRad(currOdom.theta);
172 double robot_cos = std::cos(robot_rad);
173 double robot_sin = std::sin(robot_rad);
175 double cosP = std::cos(
degToRad(prevOdom.theta));
176 double sinP = std::sin(
degToRad(prevOdom.theta));
177 double dF = dX_global * sinP + dY_global * cosP;
178 double dS = dX_global * cosP - dY_global * sinP;
183 double dist = std::hypot(dF, dS);
190 p.x += dx_l * robot_sin + dy_l * robot_cos;
191 p.y += dx_l * robot_cos - dy_l * robot_sin;
195 std::vector<MCLDistanceSensor*> active;
196 for (
auto& s :
Sensors) { s.Measure();
if (s.measurement > 0) active.push_back(&s); }
198 if (!active.empty()) {
199 double max_log = -1e9;
200 std::vector<double> logs(NUM_PARTICLES);
203 struct SensorPrecomp {
204 MCLDistanceSensor* s;
205 double dx, dy, offsetX, offsetY;
208 std::vector<SensorPrecomp> precomps;
209 for (
auto* s : active) {
212 sc.dx = robot_sin * s->cos_off + robot_cos * s->sin_off;
213 sc.dy = robot_cos * s->cos_off - robot_sin * s->sin_off;
214 sc.offsetX = s->LocalY * robot_sin + s->LocalX * robot_cos;
215 sc.offsetY = s->LocalY * robot_cos - s->LocalX * robot_sin;
216 precomps.push_back(sc);
219 for (
int i = 0; i < NUM_PARTICLES; ++i) {
225 for (
const auto& sc : precomps) {
226 double sensX =
particles[i].x + sc.offsetX;
227 double sensY =
particles[i].y + sc.offsetY;
231 if (hit.
dist < 0)
continue;
232 double err = sc.s->measurement - hit.
dist;
234 if (std::abs(err) > 18.0)
continue;
236 valid_measurements[valid_count++] = {hit.
dist, sc.s->measurement, hit.
weight};
240 double p_abs = gaussian_prob * hit.
weight;
241 logL += std::log(std::max(p_abs, 1e-6));
244 if (valid_count > 1) {
245 for (
int a = 0; a < valid_count; ++a) {
246 for (
int b = a + 1; b < valid_count; ++b) {
247 double predDiff = valid_measurements[a].
pred - valid_measurements[b].
pred;
248 double measDiff = valid_measurements[a].
meas - valid_measurements[b].
meas;
249 double diffErr = measDiff - predDiff;
251 double w = std::min(valid_measurements[a].weight, valid_measurements[b].weight);
254 logL += std::log(std::max(rel_prob * w, 1e-6));
260 if (logL > max_log) max_log = logL;
264 for (
int i = 0; i < NUM_PARTICLES; ++i) {
265 particles[i].weight = std::exp(logs[i] - max_log);
273 for (
auto& p :
particles) p.weight /= (sumW > 1e-9 ? sumW : 1.0);
276 double mX = 0, mY = 0, neff_s = 0;
278 mX += p.x * p.weight;
279 mY += p.y * p.weight;
280 neff_s += p.weight * p.weight;
288 double neff = (neff_s > 0) ? (1.0 / neff_s) : 0;
295 int keep = NUM_PARTICLES * (1.0 - injectP);
296 double r = std::uniform_real_distribution<double>(0, 1.0 / keep)(
Random), c =
particles[0].weight;
299 for (
int i = 0; i < keep; ++i) {
300 double U = r + (double)i / keep;
301 while (U > c && idx < NUM_PARTICLES - 1) c +=
particles[++idx].weight;
310 std::normal_distribution<double> fX(currOdom.x, 10.0);
311 std::normal_distribution<double> fY(currOdom.y, 10.0);
313 for (
int i = keep; i < NUM_PARTICLES; ++i) {
321 static uint32_t last_print = pros::millis();
322 if (pros::millis() - last_print > 500) {
323 last_print = pros::millis();
325 printf(
"Odom = (%.2f, %.2f, %.2f)\n", currOdom.x, currOdom.y, currOdom.theta);
329 for (
int i = 0; i < NUM_PARTICLES; ++i) {
331 if (i != NUM_PARTICLES - 1) printf(
", ");