# 180 lesson: one OpMode a driver could take to a match :::{figure} ../_static/figures/fig-l180-aiming.png :name: fig-l180-aiming ::: One teleop with all of it in. The sticks drive field relative and hold the heading they were left at. The right bumper means the robot's own directions. A points the robot at 45 degrees while the driver drives. Y sends the robot to its spot until a stick moves. And your own localizer from L120 runs beside the robot's. ::::{only} mentor **Before you start.** - L170 is done, and so is L120, whose `L120EncoderLocalizer` this runs. - AdvantageScope is installed on the same laptop. No gamepad is needed until the last step. - The robot, the Driver Station, a gamepad, and about 3 m by 3 m of clear floor for the last step. :::: ## the steps ### L180S010: copy the starter into mytry **Copy.** In `lessons`, click `L180CombinedOpMode` 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 `L180CombinedOpMode`, and the new file is open. ### L180S020: 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.` ### L180S030: run your localizer again **Change.** Find `shadowLocalizers()` and the comment that names this step. Under it, type the same two lines as in L120: ```{code-block} java :emphasize-lines: 4-5 // When on L180S030, see // https://msb-stitt.github.io/ftc31459-26-27-biobuzz/guide/tasks/l180.html#l180s030 // for what to do here. shadowLocalizers.add("driveWheelEncoders", new L120EncoderLocalizer(new HardwareWheelSource(hardware))); ``` `HardwareWheelSource` turns red. Click it and press Option+Enter, as in L120. `L120EncoderLocalizer` does not turn red. It is your own, from L120, and it sits in `mytry` too. Keep the name `driveWheelEncoders`. AdvantageScope shows each localizer under its name, so a run of this OpMode and a run of L120 line up. **Check.** - Nothing in the file is red. ### L180S040: read what you are about to drive Nothing else in the starter is new. Read `loop()`, `driveFromTheSticks()` and the methods of the drive to the target, and find the lesson each part came from. - Both drive sticks go through `deadband` and then `squared`, from L060. - `forward` and `strafe` are turned through the heading so they mean the field, from L140. - The right bumper picks the robot's own directions, from L150. - `hold.turn` keeps the heading the turn stick was left at, from L160. - Y schedules the drive to `target`, and any stick takes it back, from L170. A is the one part that is new here, and it is `HeadingHold` again. A press of A schedules `aimAtFortyFive`, a command that runs `aimAtFortyFiveDegrees()` once. It cancels any drive to the target, and `hold.aimAt` gives the hold a heading the driver did not leave, 45 degrees. The hold turns the robot there, and the left stick still drives. Push the turn stick and the driver has the turn back. When a stick takes the robot back from Y, `hold.release()` in `giveTheDriverTheWheels()` forgets the heading the hold had before Y. Read the code without it: the hold would turn the robot back to that old heading. **Simulator.** In the Terminal, run this. It holds A and pushes the left stick a little forward: ``` ./gradlew :TeamCode:simRun --args="mytry.L180CombinedOpMode --a=true --left_stick_y=-0.3" ``` **AdvantageScope.** Connect to the simulator as in L020, and click **2D Field**. Open the `heading` folder. Then open `Localizer` and both folders in it. **Check.** - `target_deg` reads 45. - The robot turns until its arrow points up and to the right, and `pinPoint/heading_deg` comes to about 45. - All the while it drives to the right, and `pinPoint/x_in` climbs. - `driveWheelEncoders` is there, and it follows `pinPoint`: the same heading, and x and y within a tenth of an inch. ### L180S050: drive all four **Robot.** Stop the simulator. Send the code, and run `L180 Combined` from the Driver Station. **Check.** - Try them in this order: field relative, the bumper held, A, and Y. - Each one does what its own lesson did, and switching between them needs nothing but a thumb. - On the robot, `driveWheelEncoders` follows `pinPoint` as the robot drives. ::::{only} mentor **No gamepad.** The run above needs none. With `--pad`, a driver can try all four in turn. **If it didn't**, and `LessonsTest.l180_everythingTogether` fails with `the shadow localizer is still running`, nothing was published under `Localizer/driveWheelEncoders/`. The two lines are missing, or the name is spelled differently. With the name typed as `encoders`, this was the message, and the other two tests passed. **If it didn't**, and one of the four misbehaves on its own, go back to that lesson's page. This page adds no arithmetic, so a fault here is a fault there. The other two tests, `l180_aPointsAt45DegreesWhileTheDriverKeepsDriving` and `l180_theTurnStickTakesAimingBack`, check the given A code. They pass on the starter. **What you just did.** You wrote two lines and got a competition teleop. Every part lives in one place, so putting them together is choosing an order rather than writing code. The order is the design. The driver's turn stick beats A's aim, and A's aim takes the place of the held heading. The follower drives only when nobody else has asked. The driver beats everything, and the robot fills in what the driver leaves. **Where next.** [L190](l190.md) stops asking the wheels for power and starts asking them for a speed. ::::