11package org .firstinspires .ftc .teamcode .pedroPathing ;
22
3- import static org .firstinspires .ftc .teamcode .pedroPathing .Tuning .changes ;
4- import static org .firstinspires .ftc .teamcode .pedroPathing .Tuning .drawOnlyCurrent ;
5- import static org .firstinspires .ftc .teamcode .pedroPathing .Tuning .draw ;
6- import static org .firstinspires .ftc .teamcode .pedroPathing .Tuning .follower ;
7- import static org .firstinspires .ftc .teamcode .pedroPathing .Tuning .stopRobot ;
8- import static org .firstinspires .ftc .teamcode .pedroPathing .Tuning .telemetryM ;
3+ import static com .pedropathing .math .MathFunctions .quadraticFit ;
4+ import static org .firstinspires .ftc .teamcode .pedroPathing .Tuning .*;
95
6+ import android .annotation .SuppressLint ;
107import com .bylazar .configurables .PanelsConfigurables ;
118import com .bylazar .configurables .annotations .Configurable ;
129import com .bylazar .configurables .annotations .IgnoreConfigurable ;
1512import com .bylazar .field .Style ;
1613import com .bylazar .telemetry .PanelsTelemetry ;
1714import com .bylazar .telemetry .TelemetryManager ;
18- import com .pedropathing .ErrorCalculator ;
1915import com .pedropathing .follower .Follower ;
2016import com .pedropathing .geometry .*;
2117import com .pedropathing .math .*;
2420import com .pedropathing .util .*;
2521import com .qualcomm .robotcore .eventloop .opmode .OpMode ;
2622import com .qualcomm .robotcore .eventloop .opmode .TeleOp ;
23+ import com .qualcomm .robotcore .util .ElapsedTime ;
2724
2825import java .util .ArrayList ;
2926import java .util .List ;
@@ -52,6 +49,7 @@ public Tuning() {
5249 super ("Select a Tuning OpMode" , s -> {
5350 s .folder ("Localization" , l -> {
5451 l .add ("Localization Test" , LocalizationTest ::new );
52+ l .add ("Offsets Tuner" , OffsetsTuner ::new );
5553 l .add ("Forward Tuner" , ForwardTuner ::new );
5654 l .add ("Lateral Tuner" , LateralTuner ::new );
5755 l .add ("Turn Tuner" , TurnTuner ::new );
@@ -61,6 +59,7 @@ public Tuning() {
6159 a .add ("Lateral Velocity Tuner" , LateralVelocityTuner ::new );
6260 a .add ("Forward Zero Power Acceleration Tuner" , ForwardZeroPowerAccelerationTuner ::new );
6361 a .add ("Lateral Zero Power Acceleration Tuner" , LateralZeroPowerAccelerationTuner ::new );
62+ a .add ("Predictive Braking" , PredictiveBrakingTuner ::new );
6463 });
6564 s .folder ("Manual" , p -> {
6665 p .add ("Translational Tuner" , TranslationalTuner ::new );
@@ -1212,6 +1211,233 @@ public void loop() {
12121211 }
12131212}
12141213
1214+ /**
1215+ * This is the OffsetsTuner OpMode. This tracks the movement of the robot as it turns 180 degrees,
1216+ * and calculates what the robot's strafeX and forwardY offsets should be. Ensure that your strafeX and forwardY offsets
1217+ * are set to 0 before running this OpMode. After running, input the displayed offsets into your localizer constants.
1218+ *
1219+ * @author Havish Sripada - 12808 RevAmped Robotics
1220+ * @author Baron Henderson
1221+ */
1222+ class OffsetsTuner extends OpMode {
1223+ @ Override
1224+ public void init () {
1225+ follower .setStartingPose (new Pose (72 ,72 ));
1226+ follower .update ();
1227+ drawOnlyCurrent ();
1228+ }
1229+
1230+ /** This initializes the PoseUpdater as well as the Panels telemetry. */
1231+ @ Override
1232+ public void init_loop () {
1233+ telemetryM .debug ("Prerequisite: Make sure both your offsets are set to 0 in your localizer constants." );
1234+ telemetryM .debug ("Turn your robot " + Math .PI + " radians. Your offsets in inches will be shown on the telemetry." );
1235+ telemetryM .update (telemetry );
1236+
1237+ drawOnlyCurrent ();
1238+ }
1239+
1240+ /**
1241+ * This updates the robot's pose estimate, and updates the Panels telemetry with the
1242+ * calculated offsets and draws the robot.
1243+ */
1244+ @ Override
1245+ public void loop () {
1246+ follower .update ();
1247+
1248+ telemetryM .debug ("Total Angle: " + follower .getTotalHeading ());
1249+
1250+ telemetryM .debug ("The following values are the offsets in inches that should be applied to your localizer." );
1251+ telemetryM .debug ("strafeX: " + ((72.0 -follower .getPose ().getX ()) / 2.0 ));
1252+ telemetryM .debug ("forwardY: " + ((72.0 -follower .getPose ().getY ()) / 2.0 ));
1253+ telemetryM .update (telemetry );
1254+
1255+ draw ();
1256+ }
1257+ }
1258+
1259+ /**
1260+ * This is the Predictive Braking Tuner. It runs the robot forward and backward at various power
1261+ * levels, recording the robot’s velocity and position immediately before braking. The motors are
1262+ * then set to zero-power brake mode, which represents the fastest theoretical braking the robot
1263+ * can achieve. Once the robot comes to a complete stop, the tuner measures the stopping distance.
1264+ * Using the collected data, it generates a velocity-vs-stopping-distance graph and fits a
1265+ * quadratic curve to model the braking behavior.
1266+ *
1267+ * @author Ashay Sarda - 19745 Turtle Walkers
1268+ * @author Jacob Ophoven - 18535 Frozen Code
1269+ * @version 1.0, 12/26/2025
1270+ */
1271+ class PredictiveBrakingTuner extends OpMode {
1272+ private static final double [] TEST_POWERS =
1273+ {1 , 1 , 1 , 0.9 , 0.9 , 0.8 , 0.7 , 0.6 , 0.5 , 0.4 , 0.3 , 0.2 };
1274+
1275+ private static final int DRIVE_TIME_MS = 1000 ;
1276+ private static final int BRAKE_WAIT_MS = 500 ;
1277+
1278+ private enum State {
1279+ START_MOVE ,
1280+ WAIT_DRIVE_TIME ,
1281+ APPLY_BRAKE ,
1282+ WAIT_BRAKE_TIME ,
1283+ RECORD ,
1284+ DONE
1285+ }
1286+
1287+ private static class BrakeRecord {
1288+ double timeMs ;
1289+ Pose pose ;
1290+ double velocity ;
1291+
1292+ BrakeRecord (double timeMs , Pose pose , double velocity ) {
1293+ this .timeMs = timeMs ;
1294+ this .pose = pose ;
1295+ this .velocity = velocity ;
1296+ }
1297+ }
1298+
1299+ private State state = State .START_MOVE ;
1300+
1301+ private final ElapsedTime timer = new ElapsedTime ();
1302+
1303+ private int iteration = 0 ;
1304+
1305+ private Vector startPosition ;
1306+ private double measuredVelocity ;
1307+
1308+ private final List <double []> velocityToBrakingDistance = new ArrayList <>();
1309+ private final List <BrakeRecord > brakeData = new ArrayList <>();
1310+
1311+ @ Override
1312+ public void init () {}
1313+
1314+ @ Override
1315+ public void init_loop () {
1316+ telemetryM .debug ("The robot will move forwards and backwards starting at max speed and slowing down." );
1317+ telemetryM .debug ("Make sure you have enough room. Leave at least 4-5 feet." );
1318+ telemetryM .debug ("After stopping, kFriction and kBraking will be displayed." );
1319+ telemetryM .debug ("Make sure to turn the timer off." );
1320+ telemetryM .debug ("Press B on game pad 1 to stop." );
1321+ telemetryM .update (telemetry );
1322+ follower .update ();
1323+ drawOnlyCurrent ();
1324+ }
1325+
1326+ @ Override
1327+ public void start () {
1328+ timer .reset ();
1329+ follower .update ();
1330+ follower .startTeleOpDrive (true );
1331+ }
1332+
1333+ @ SuppressLint ("DefaultLocale" )
1334+ @ Override
1335+ public void loop () {
1336+ follower .update ();
1337+
1338+ if (gamepad1 .b ) {
1339+ stopRobot ();
1340+ requestOpModeStop ();
1341+ return ;
1342+ }
1343+
1344+ switch (state ) {
1345+ case START_MOVE : {
1346+ if (iteration >= TEST_POWERS .length ) {
1347+ state = State .DONE ;
1348+ break ;
1349+ }
1350+
1351+ double currentPower = TEST_POWERS [iteration ];
1352+ follower .setMaxPower (currentPower );
1353+ if (iteration % 2 != 0 ) {
1354+ follower .setTeleOpDrive (-1 , 0 , 0 , true );
1355+ } else {
1356+ follower .setTeleOpDrive (1 , 0 , 0 , true );
1357+ }
1358+
1359+ timer .reset ();
1360+ state = State .WAIT_DRIVE_TIME ;
1361+ break ;
1362+ }
1363+
1364+ case WAIT_DRIVE_TIME : {
1365+ if (timer .milliseconds () >= DRIVE_TIME_MS ) {
1366+ measuredVelocity = follower .getVelocity ().getMagnitude ();
1367+ startPosition = follower .getPose ().getAsVector ();
1368+ state = State .APPLY_BRAKE ;
1369+ }
1370+ break ;
1371+ }
1372+
1373+ case APPLY_BRAKE : {
1374+ stopRobot ();
1375+
1376+ timer .reset ();
1377+ state = State .WAIT_BRAKE_TIME ;
1378+ break ;
1379+ }
1380+
1381+ case WAIT_BRAKE_TIME : {
1382+ double t = timer .milliseconds ();
1383+ Pose currentPose = follower .getPose ();
1384+ double currentVelocity = follower .getVelocity ().getMagnitude ();
1385+
1386+ brakeData .add (new BrakeRecord (t , currentPose , currentVelocity ));
1387+
1388+ if (timer .milliseconds () >= BRAKE_WAIT_MS || follower .getVelocity ().getMagnitude () <= .05 ) {
1389+ state = State .RECORD ;
1390+ }
1391+ break ;
1392+ }
1393+
1394+ case RECORD : {
1395+ Vector endPosition = follower .getPose ().getAsVector ();
1396+ double brakingDistance = endPosition .minus (startPosition ).getMagnitude ();
1397+
1398+ velocityToBrakingDistance .add (new double []{measuredVelocity , brakingDistance });
1399+
1400+ telemetryM .debug ("Test " + iteration ,
1401+ String .format ("v=%.3f d=%.3f" , measuredVelocity ,
1402+ brakingDistance ));
1403+ telemetryM .update (telemetry );
1404+
1405+ iteration ++;
1406+ state = State .START_MOVE ;
1407+
1408+ break ;
1409+ }
1410+
1411+ case DONE : {
1412+ stopRobot ();
1413+
1414+ double [] coefficients = quadraticFit (velocityToBrakingDistance );
1415+
1416+ telemetryM .debug ("Tuning Complete" );
1417+ telemetryM .debug ("Braking Profile:" );
1418+ telemetryM .debug ("kQuadratic" , coefficients [1 ]);
1419+ telemetryM .debug ("kLinear" , coefficients [0 ]);
1420+ telemetryM .update (telemetry );
1421+ telemetryM .debug ("Tuning Complete" );
1422+ telemetryM .debug ("Braking Profile:" );
1423+ telemetryM .debug ("kQuadraticFriction" , coefficients [1 ]);
1424+ telemetryM .debug ("kLinearBraking" , coefficients [0 ]);
1425+ for (BrakeRecord record : brakeData ) {
1426+ Pose p = record .pose ;
1427+ telemetryM .debug (String .format ("t=%.0f ms, x=%.2f, y=%.2f, θ=%.2f, v=%.2f" ,
1428+ record .timeMs , p .getX (), p .getY (),
1429+ p .getHeading (),
1430+ record .velocity ));
1431+ }
1432+ telemetryM .update ();
1433+ break ;
1434+ }
1435+ }
1436+
1437+ telemetry .update ();
1438+ }
1439+ }
1440+
12151441/**
12161442 * This is the Drawing class. It handles the drawing of stuff on Panels Dashboard, like the robot.
12171443 *
0 commit comments