160 lesson: hold the heading the driver left

../_images/fig-l160-held.png

Let go of the turn stick and the robot keeps pointing where it was left. Push the turn stick and the driver has it back at once.

Before you start.

  • L150 is done.

  • AdvantageScope is installed on the same laptop. No gamepad is needed until the last step.

  • The robot, the Driver Station, a gamepad, and about 2 m by 2 m of clear floor for the last step.

the steps

L160S010: copy the starter into mytry

Copy. In lessons, click L160HeadingHoldOpMode once and copy it. Click mytry once and paste. In the Copy Class box, click OK. If Android Studio asks whether to add the file to Git, click Add.

Check.

  • mytry holds L160HeadingHoldOpMode, and the new file is open.

L160S020: switch your copy on

Change. Delete the line @Disabled, under the comment that names this step.

Check.

  • Under the step’s comment, the next line reads // 'public' so the robot can run this OpMode. 'public' allows access from any code.

L160S030: watch the nose creep

../_images/fig-l160-creep.png

The starter is L150’s finished OpMode. This run pretends the turn stick rests a little off center, the way a worn stick does.

Simulator. In the Terminal, run:

./gradlew :TeamCode:simRun --args="mytry.L160HeadingHoldOpMode --left_stick_y=-0.3 --right_stick_x=0.2"

AdvantageScope. Connect to the simulator as in L020, click 2D Field, and open the arcade folder, then Localizer and pinPoint.

Check.

  • turn reads -0.040, which is small.

  • The robot drives to the right, and it turns as it goes.

  • heading_deg started at 90 and keeps dropping.

L160S040: hold the heading

HeadingHold is written for you, in base. While the turn stick is pushed, it hands the stick straight back and the driver steers. On the loop the stick is let go, it remembers the heading. After that it hands back the turn that steers the robot back to that heading.

Its own deadband is 0.05, so a stick that is nearly centered counts as let go. turn at -0.040 is inside it.

Change. Press Ctrl+C in the Terminal to stop the simulator. Find the line CorbelsMecanum drivetrain; near the top of the class. Under it, type:

    CorbelsMecanum drivetrain;
    HeadingHold hold = new HeadingHold(Constants.foresightConfig.headingFeedback.get());

Constants.foresightConfig holds the follower’s own settings. headingFeedback is the part that steers the heading in autonomous. Tune the follower, and this hold gets the same tuning.

HeadingHold and Constants turn red. Click each one and press Option+Enter, as in L120. The popup for Constants names org.firstinspires.ftc.teamcode.pedro.Constants.

Change. In driveFromTheSticks(), find the comment that names this step. Under it, type:

        double turn = deadband(-rightStickX, band);
        turn = signedSquared(turn);
        Tracker.publish("arcade/turn", turn);
        // When on L160S040, see
        // https://msb-stitt.github.io/ftc31459-26-27-biobuzz/guide/tasks/l160.html#l160s040
        // for what to do here.
        turn = hold.turn(follower, turn);
        Tracker.publish("heading/holding", hold.target() != null);

The first new line swaps the stick’s turn for the hold’s. Both sticks calls below use turn, so both drive with it. Android Studio now underlines turn everywhere. That marks a variable that changes after it is made. It is not an error.

Simulator. Run the same command again, and connect AdvantageScope. Open the heading folder too.

Check.

  • holding is green.

  • The robot drives to the right, its nose still pointing up the field, and heading_deg stays at 90.

L160S050: drive it and then push it

Robot. Stop the simulator. Send the code, and run L160 Heading Hold from the Driver Station.

Check.

  • Drive a long diagonal with the left stick, and do not touch the turn stick.

  • The nose stays where it was.

  • Then take hold of the robot and twist it a little. It turns back on its own.

No gamepad. The two runs above need none. With --pad, a driver can turn, let go, and watch the hold take over.

If it didn’t, and LessonsTest.l160_theRobotHoldsItsHeadingWhenTheStickIsReleased fails with it steers back, nothing listens to the hold. Either the line is missing, or it reads hold.turn(follower, turn); without turn = in front, so its answer is thrown away.

If it didn’t, and it fails with while steering, the stick wins expected:<-1.0> but was:<1.0>, the hold got rightStickX instead of turn. That skips the minus sign that makes a push to the right turn clockwise.

If it didn’t, and on the floor the robot fights back and overshoots, that is the follower’s tuning, not this lesson. L117 tunes it. If the nose drifts slowly anyway, the hold is working and the follower’s heading is drifting with it.

The simulator turns the robot only when told to, so nothing there pushes it off its heading. The creep in L160S030 is a stick resting off center, not a bump.

What you just did. Three things want to turn the robot, and they take turns in a fixed order. The driver’s stick beats the hold. The hold beats doing nothing. The person with their hands on the gamepad wins, and everything else fills in when they let go.

Where next. L170 gives a button a pose, and the robot drives there by itself while the driver watches.