|
LightLib
PROS library for VEX V5: EKF/MCL localization, RAMSETE path following, high-level chassis API
|
Once odometry is initialized and tuned, the chassis stops thinking in "24 inches forward" and starts thinking in field coordinates: "go to `(48, 36)` heading north." This tutorial covers the odom-aware motion primitives.
Odometry fuses three sources to estimate the robot's pose (x, y, θ) in the field frame, every 10 ms:
The arc-integration math is short:
Because the IMU is ground truth for θ, the heading never drifts with encoder slip. Because the tracking wheels are unpowered, Δx_local / Δy_local don't drift with wheel slip either. The only error source is sensor noise, which is what the EKF cleans up.
The boomerang controller is what actually drives the robot to a point. Naïve "point at target → drive to it" fails when the target has a final heading you care about — the robot would drive straight at the point and stop facing the wrong way. Boomerang places a virtual "carrot" point a configurable distance behind the target along the desired final heading, drives toward the carrot, and the carrot recedes into the target as you approach. Result: the robot curves into the target and arrives facing the correct heading.
LightLib's pose convention:
+X is right, +Y is forward (toward the opposite alliance wall).θ is in degrees by default, CW-positive (matching IMU output).setPose() — typically robot's starting corner.Always setPose() at the top of every auton. Odometry from the previous match is meaningless once you place the robot in a new starting position.
The simplest odom motion targets a single pose:
The struct is light::odom:
If you don't care about the final heading, leave theta = ANGLE_NOT_SET (omit it from the brace-init): the robot will arrive at the point facing whichever direction was natural for the boomerang.
The robot will pivot so its back faces the target, then drive backwards.
Pass a std::vector<odom> and the robot chains motions through them with no stop in between:
This is not a smooth spline — each segment is its own boomerang motion, just with chained exits. For a continuous curve, use the trajectory follower (next tutorial).
pid_wait_until_point fires when the robot reaches a specific waypoint mid-sequence:
pid_wait_until_index(int) does the same by index in the path vector.
Three knobs in default_constants() control the curve shape:
look_ahead** — how far along the path the robot aims at any moment. Smaller = tighter tracking but more wiggly. Larger = smoother but cuts corners.boomerang_distance** — max distance the carrot can be from the target. Larger = wider arc into the target. Smaller = tighter approach.boomerang_dlead** — how aggressively the approach tightens at the end. 0 = arc smoothly into the target; 1 = sharp final correction. 0.625 is a reasonable starting value.If the robot circles past the target instead of curving in, reduce boomerang_distance. If it arrives at the right point but facing the wrong way, raise boomerang_dlead.
Ranges 0..1. Controls how much the robot prioritizes hitting the right heading vs. the right position. 1.0 = full priority on heading (recommended with tracking wheels). Values closer to 0 make the robot accept some heading error in exchange for faster XY convergence.
Sets the default angle-wrap rule for all subsequent odom turns:
Same enum as pid_turn_set's third arg: shortest, longest, cw, ccw, raw.
For very simple auton logic (or as a fallback if you don't want to deal with the odom struct):
It's a thin wrapper that builds a one-shot pid_odom_set and waits for it. Identical behavior, less ceremony. Use it when you don't need the chain / wait_until features.
Robot drifts off the path on the first move. Almost always means tracking wheels haven't been zeroed by light::reset() or starting pose hasn't been set. Always call setPose() at the top of every auton.
Robot arrives 6" off but heading is correct. Tracking wheel offsets are wrong. Re-measure the perpendicular distance from each wheel to the robot center and update the TrackingWheel constructors in main.cpp.
Robot curves smoothly to a point but stops short. Drive exit conditions are too loose. Tighten pid_odom_drive_exit_condition_set — specifically the small_error (likely 1_in is too generous; try 0.5_in).