45 { 3.66f, 4.067f + 2.5, 0.0f },
46 { -6.309f -1.1, -0.068f, 90.0f },
47 { 3.93f, -2.691f + 2.7, 180.0f },
48 { -6.039f + 1.4, -0.068f, -90.0f }
94 void MotionUpdate(
double dX_global,
double dY_global,
double dTheta,
double robot_theta_deg) {
95 const float dist = (float)std::hypot(dX_global, dY_global);
96 const float turn_factor = std::abs((
float)dTheta) * 0.05f;
102 float math_theta_deg = 90.0f - (float)robot_theta_deg;
103 const float theta_rad =
degToRad(math_theta_deg);
105 const float cos_t = std::cos(theta_rad);
106 const float sin_t = std::sin(theta_rad);
109 for (
int i = 0; i < NUM_PARTICLES; ++i) {
110 const float nF =
rng.gaussian(transStd);
111 const float nS =
rng.gaussian(transStd * 0.6f);
113 const float noise_X = nF * cos_t - nS * sin_t;
114 const float noise_Y = nF * sin_t + nS * cos_t;
127 void SensorUpdate(
const std::vector<float>& measurements,
float robot_theta_deg,
float current_confidence) {
131 float math_theta_deg = 90.0f - robot_theta_deg;
132 const float theta_rad =
degToRad(math_theta_deg);
133 const float cos_t = std::cos(theta_rad);
134 const float sin_t = std::sin(theta_rad);
136 const float dynamic_sensor_sig = 1.5f + (1.0f - std::clamp(current_confidence, 0.0f, 1.0f)) * 4.0f;
137 const float dynamic_margin = dynamic_sensor_sig * 3.0f;
139 for (
int i = 0; i < NUM_PARTICLES; ++i) {
142 for (
size_t s = 0; s < measurements.size(); ++s) {
143 if (measurements[s] < 0.0f)
continue;
147 float sensor_x =
particle_x[i] + sc.
y * cos_t + sc.
x * sin_t;
148 float sensor_y =
particle_y[i] + sc.
y * sin_t - sc.
x * cos_t;
150 float absolute_lemlib_deg = robot_theta_deg + sc.
angle;
151 float math_beam_deg = 90.0f - absolute_lemlib_deg;
152 const float beam_rad =
degToRad(math_beam_deg);
154 float v_x = std::cos(beam_rad);
155 float v_y = std::sin(beam_rad);
158 if (v_x > 1e-4f) d_x = (
FIELD_MAX - sensor_x) / v_x;
159 else if (v_x < -1e-4f) d_x = (
FIELD_MIN - sensor_x) / v_x;
162 if (v_y > 1e-4f) d_y = (
FIELD_MAX - sensor_y) / v_y;
163 else if (v_y < -1e-4f) d_y = (
FIELD_MIN - sensor_y) / v_y;
165 float expected = std::min(d_x, d_y);
166 float err = measurements[s] - expected;
168 if (err > dynamic_margin) {
170 }
else if (err < -dynamic_margin) {
173 w *= std::exp(-0.5f * err * err / (dynamic_sensor_sig * dynamic_sensor_sig));
181 const float w_avg = sum_w / NUM_PARTICLES;
187 if (sum_w > 1e-10f) {
188 for (
int i = 0; i < NUM_PARTICLES; ++i)
191 const float u = 1.0f / NUM_PARTICLES;
192 for (
int i = 0; i < NUM_PARTICLES; ++i)
213 const float inject_rate = std::clamp(1.0f - ratio, 0.0f, 0.20f);
214 const int num_inject = (int)(NUM_PARTICLES * inject_rate);
215 const int num_keep = NUM_PARTICLES - num_inject;
217 static float new_x[NUM_PARTICLES];
218 static float new_y[NUM_PARTICLES];
220 float step = 1.0f / (num_keep > 0 ? num_keep : 1);
221 float r =
rng.next_f32() * step;
226 for (
int m = 0; m < num_keep; ++m) {
227 float u = r + (float)m * step;
228 while (u > cum && j < NUM_PARTICLES - 1) {
236 for (
int m = num_keep; m < NUM_PARTICLES; ++m) {
241 const float uniform_w = 1.0f / NUM_PARTICLES;
242 for (
int i = 0; i < NUM_PARTICLES; ++i) {
253 lemlib::Pose prevOdom =
chassis.getPose();
254 uint32_t now = pros::millis();
256 int print_counter = 0;
257 bool first_run =
true;
260 lemlib::Pose currOdom =
chassis.getPose();
262 const double dX_global = currOdom.x - prevOdom.x;
263 const double dY_global = currOdom.y - prevOdom.y;
264 const double dTheta =
wrapAngle((
float)(currOdom.theta - prevOdom.theta));
266 if (std::abs(dX_global) > 0.001 || std::abs(dY_global) > 0.001 || std::abs(dTheta) > 0.1) {
268 MotionUpdate(dX_global, dY_global, dTheta, currOdom.theta);
270 std::vector<float> measurements(4, -1.0f);
271 bool has_valid_reading =
false;
273 auto try_read_sensor = [&](
auto& sensor,
int index) {
274 float val = sensor.get() / 25.4f;
276 measurements[index] = val;
277 has_valid_reading =
true;
286 if (has_valid_reading) {
294 for (
int i = 0; i < NUM_PARTICLES; ++i) {
304 float sumX = 0.0f, sumY = 0.0f, sumW = 0.0f;
305 float sumX2 = 0.0f, sumY2 = 0.0f;
306 const float CLUSTER_RADIUS = 15.0f;
308 for (
int i = 0; i < NUM_PARTICLES; ++i) {
312 if ((dx * dx + dy * dy) <= (CLUSTER_RADIUS * CLUSTER_RADIUS)) {
322 float mcl_std_dev = 999.0f;
323 float cluster_weight_ratio = 0.0f;
326 float raw_X = best_x;
327 float raw_Y = best_y;
335 float varX = (sumX2 / sumW) - (meanX * meanX);
336 float varY = (sumY2 / sumW) - (meanY * meanY);
337 mcl_std_dev = std::sqrt(std::max(0.0f, varX + varY));
339 cluster_weight_ratio = sumW;
343 const float EMA_ALPHA = 0.20f;
360 if (++print_counter >= 3) {
361 printf(
"MCL: %.2f %.2f | ODOM: %.2f %.2f | CONF: %.2f | STD: %.2f | RATIO: %.2f\n",
367 std::abs(dX_global) < 5 && std::abs(dY_global) < 5) {
369 double diff_x =
global_X - currOdom.x;
370 double diff_y =
global_Y - currOdom.y;
371 double correction_mag = std::hypot(diff_x, diff_y);
373 if (correction_mag > 1.0 && correction_mag < 12.0) {
382 if (ess < NUM_PARTICLES * 0.5f || ratio < 0.9f) {
388 pros::Task::delay_until(&now, 10);