48 { 3.66f, 4.067f + 2.5, 0.0f },
49 { -6.309f -1.1, -0.068f, 90.0f },
50 { 3.93f, -2.691f + 2.7, 180.0f },
51 { -6.039f + 1.4, -0.068f, -90.0f }
97 void MotionUpdate(
double dX_global,
double dY_global,
double dTheta,
double robot_theta_deg) {
98 const float dist = (float)std::hypot(dX_global, dY_global);
99 const float turn_factor = std::abs((
float)dTheta) * 0.05f;
105 float math_theta_deg = 90.0f - (float)robot_theta_deg;
106 const float theta_rad =
degToRad(math_theta_deg);
108 const float cos_t = std::cos(theta_rad);
109 const float sin_t = std::sin(theta_rad);
112 for (
int i = 0; i < NUM_PARTICLES; ++i) {
113 const float nF =
rng.gaussian(transStd);
114 const float nS =
rng.gaussian(transStd * 0.6f);
116 const float noise_X = nF * cos_t - nS * sin_t;
117 const float noise_Y = nF * sin_t + nS * cos_t;
130 void SensorUpdate(
const std::vector<float>& measurements,
float robot_theta_deg,
float current_confidence) {
134 float math_theta_deg = 90.0f - robot_theta_deg;
135 const float theta_rad =
degToRad(math_theta_deg);
136 const float cos_t = std::cos(theta_rad);
137 const float sin_t = std::sin(theta_rad);
139 const float dynamic_sensor_sig = 1.5f + (1.0f - std::clamp(current_confidence, 0.0f, 1.0f)) * 4.0f;
140 const float dynamic_margin = dynamic_sensor_sig * 3.0f;
142 for (
int i = 0; i < NUM_PARTICLES; ++i) {
145 for (
size_t s = 0; s < measurements.size(); ++s) {
146 if (measurements[s] < 0.0f)
continue;
150 float sensor_x =
particle_x[i] + sc.
y * cos_t + sc.
x * sin_t;
151 float sensor_y =
particle_y[i] + sc.
y * sin_t - sc.
x * cos_t;
153 float absolute_lemlib_deg = robot_theta_deg + sc.
angle;
154 float math_beam_deg = 90.0f - absolute_lemlib_deg;
155 const float beam_rad =
degToRad(math_beam_deg);
157 float v_x = std::cos(beam_rad);
158 float v_y = std::sin(beam_rad);
161 if (v_x > 1e-4f) d_x = (
FIELD_MAX - sensor_x) / v_x;
162 else if (v_x < -1e-4f) d_x = (
FIELD_MIN - sensor_x) / v_x;
165 if (v_y > 1e-4f) d_y = (
FIELD_MAX - sensor_y) / v_y;
166 else if (v_y < -1e-4f) d_y = (
FIELD_MIN - sensor_y) / v_y;
168 float expected = std::min(d_x, d_y);
169 float err = measurements[s] - expected;
171 if (err > dynamic_margin) {
173 }
else if (err < -dynamic_margin) {
176 w *= std::exp(-0.5f * err * err / (dynamic_sensor_sig * dynamic_sensor_sig));
184 const float w_avg = sum_w / NUM_PARTICLES;
190 if (sum_w > 1e-10f) {
191 for (
int i = 0; i < NUM_PARTICLES; ++i)
194 const float u = 1.0f / NUM_PARTICLES;
195 for (
int i = 0; i < NUM_PARTICLES; ++i)
216 const float inject_rate = std::clamp(1.0f - ratio, 0.0f, 0.20f);
217 const int num_inject = (int)(NUM_PARTICLES * inject_rate);
218 const int num_keep = NUM_PARTICLES - num_inject;
220 static float new_x[NUM_PARTICLES];
221 static float new_y[NUM_PARTICLES];
223 float step = 1.0f / (num_keep > 0 ? num_keep : 1);
224 float r =
rng.next_f32() * step;
229 for (
int m = 0; m < num_keep; ++m) {
230 float u = r + (float)m * step;
231 while (u > cum && j < NUM_PARTICLES - 1) {
239 for (
int m = num_keep; m < NUM_PARTICLES; ++m) {
244 const float uniform_w = 1.0f / NUM_PARTICLES;
245 for (
int i = 0; i < NUM_PARTICLES; ++i) {
256 lemlib::Pose prevOdom =
chassis.getPose();
257 uint32_t now = pros::millis();
259 int print_counter = 0;
260 bool first_run =
true;
263 lemlib::Pose currOdom =
chassis.getPose();
265 const double dX_global = currOdom.x - prevOdom.x;
266 const double dY_global = currOdom.y - prevOdom.y;
267 const double dTheta =
wrapAngle((
float)(currOdom.theta - prevOdom.theta));
269 if (std::abs(dX_global) > 0.001 || std::abs(dY_global) > 0.001 || std::abs(dTheta) > 0.1) {
271 MotionUpdate(dX_global, dY_global, dTheta, currOdom.theta);
273 std::vector<float> measurements(4, -1.0f);
274 bool has_valid_reading =
false;
276 auto try_read_sensor = [&](
auto& sensor,
int index) {
277 float val = sensor.get() / 25.4f;
279 measurements[index] = val;
280 has_valid_reading =
true;
289 if (has_valid_reading) {
297 for (
int i = 0; i < NUM_PARTICLES; ++i) {
307 float sumX = 0.0f, sumY = 0.0f, sumW = 0.0f;
308 float sumX2 = 0.0f, sumY2 = 0.0f;
309 const float CLUSTER_RADIUS = 15.0f;
311 for (
int i = 0; i < NUM_PARTICLES; ++i) {
315 if ((dx * dx + dy * dy) <= (CLUSTER_RADIUS * CLUSTER_RADIUS)) {
325 float mcl_std_dev = 999.0f;
326 float cluster_weight_ratio = 0.0f;
329 float raw_X = best_x;
330 float raw_Y = best_y;
338 float varX = (sumX2 / sumW) - (meanX * meanX);
339 float varY = (sumY2 / sumW) - (meanY * meanY);
340 mcl_std_dev = std::sqrt(std::max(0.0f, varX + varY));
342 cluster_weight_ratio = sumW;
346 const float EMA_ALPHA = 0.20f;
363 if (++print_counter >= 3) {
364 printf(
"MCL: %.2f %.2f | ODOM: %.2f %.2f | CONF: %.2f | STD: %.2f | RATIO: %.2f\n",
370 std::abs(dX_global) < 5 && std::abs(dY_global) < 5) {
372 double diff_x =
global_X - currOdom.x;
373 double diff_y =
global_Y - currOdom.y;
374 double correction_mag = std::hypot(diff_x, diff_y);
376 if (correction_mag > 1.0 && correction_mag < 12.0) {
385 if (ess < NUM_PARTICLES * 0.5f || ratio < 0.9f) {
391 pros::Task::delay_until(&now, 10);