Android Programming FTC Programming Tips New Android Studio

  • Slides: 25
Download presentation
Android Programming FTC Programming Tips

Android Programming FTC Programming Tips

New Android Studio Current Android Studio is 3. 2 https: //developer. android. com/studio/index. html

New Android Studio Current Android Studio is 3. 2 https: //developer. android. com/studio/index. html Update the FTC APP to 4. 0 (18. 09. 12) https: //github. com/ftctechnh/ftc_app/tree/beta

On. Bot Java is a very convenient way to program in Java without having

On. Bot Java is a very convenient way to program in Java without having to learn the Android Studio Tool Pros for On. Bot Java Code is on the Robot, not one student laptop Connection is via Wi. Fi and a Browser. No repeated connects/disconnects via USB No large download/installation Code changes are quick – Android Studio can take a few minutes to build. Between matches every minute counts. Pros for Android Studio Auto Complete and function documentation/references Ability to work with Git. Hub for version control and code sharing Ability to work with Java Native Interface and extra libraries

On. Bot Java On the Robot Controller, touch the three dots in the upper

On. Bot Java On the Robot Controller, touch the three dots in the upper right hand corner and select Program & Manage This page will show the Wi. Fi Direct Network, the passcode, and web URL for your browser. Connect to the Wi. Fi Direct Network and enter the passcode. Then put in the web URL in your browser. This will disconnect you from Home/School Wi. Fi disconnecting you from the internet. It is possible to have your phone connect to your Home/School Wi. Fi and use the IP address that it assigned. This is not recommended on event day or during final testing as it introduce additional latencies.

Op. Modes There are two types of Op. Modes: Linear and Regular The Linear

Op. Modes There are two types of Op. Modes: Linear and Regular The Linear Op. Mode is the easiest to use, especially for Autonomous. Regular Op. Mode generally requires understanding state machines when doing an Autonomous. For Tele. Op, the regular Op. Mode may be more useful

Autonomous Programming Tips Instead of having four different Autonomous Programs for four different starting

Autonomous Programming Tips Instead of having four different Autonomous Programs for four different starting positins (Red 1, Red 2, Blue 1, Blue 2), use the joystick to select your autonomous. Benefit is that you just maintain one program, can leverage commonality, and more advanced programming such as subclassing and libraries are not needed.

Autonomous Programming Tips private void Red 1() { package org. firstinspires. ftc. teamcode; }

Autonomous Programming Tips private void Red 1() { package org. firstinspires. ftc. teamcode; } import com. qualcomm. robotcore. eventloop. opmode. Autonomous; import com. qualcomm. robotcore. eventloop. opmode. Linear. Op. Mode; import org. firstinspires. ftc. robotcore. external. Telemetry; private void Red 2() { } @Autonomous(name="Basic: Multi. Auto" , group="Basic") public class Multi. Auto. Example extends Linear. Op. Mode { private void Blue 1() { public enum Auto. Mode { AUTO_MODE_NOT_SELECTED , AUTO_MODE_RED 1, AUTO_MODE_RED 2, AUTO_MODE_BLUE 1 , AUTO_MODE_BLUE 2 } } private void Blue 2() { } @Override public void run. Op. Mode() throws Interrupted. Exception { Auto. Mode auto. Mode; private Auto. Mode Select. Auto. Mode() { Auto. Mode auto. Mode = Auto. Mode. AUTO_MODE_NOT_SELECTED ; Telemetry. Item mode = telemetry. add. Data("Auto. Mode", "Not Selected" ); telemetry. set. Auto. Clear(false); Telemetry. Item status = telemetry. add. Data("Status", "Initialized"); telemetry. update(); while (auto. Mode == Auto. Mode. AUTO_MODE_NOT_SELECTED ) { if (gamepad 1. a) { auto. Mode = Auto. Mode. AUTO_MODE_RED 1 ; } if (gamepad 1. b) { auto. Mode = Auto. Mode. AUTO_MODE_RED 2 ; } if (gamepad 1. x) { auto. Mode = Auto. Mode. AUTO_MODE_BLUE 1 ; } if (gamepad 1. y) { auto. Mode = Auto. Mode. AUTO_MODE_BLUE 2 ; } idle(); } mode. set. Value(auto. Mode. to. String()); telemetry. update(); // Wait for the user to release the button while (gamepad 1. a || gamepad 1. b || gamepad 1. x || gamepad 1. y) { idle(); } return auto. Mode; auto. Mode = Select. Auto. Mode(); status. set. Value( "Initialized"); telemetry. update(); wait. For. Start(); telemetry. clear. All(); switch (auto. Mode) { case AUTO_MODE_RED 1: Red 1(); break; case AUTO_MODE_RED 2: Red 2(); break; case AUTO_MODE_BLUE 1 : Blue 1(); break; case AUTO_MODE_BLUE 2 : Blue 2(); break; case AUTO_MODE_NOT_SELECTED : // This one should not happen break; } }

Autonomous Programming Tips Frequently it is useful to have a delayed start that it

Autonomous Programming Tips Frequently it is useful to have a delayed start that it is adjustable. This allows you to coordinate with your alliance partner as for when to move By having an adjustable delayed start, you don’t have modify the code

Autonomous Programming Tips private Integer Select. Delay. Time() { Integer delay. Time. Milliseconds =

Autonomous Programming Tips private Integer Select. Delay. Time() { Integer delay. Time. Milliseconds = 5000; Telemetry. Item delay = telemetry. add. Data("Delay", "%d (Not Set)" , delay. Time. Milliseconds); telemetry. update(); @Override public void run. Op. Mode() throws Interrupted. Exception { Auto. Mode auto. Mode; Integer delay. Time. Milliseconds; telemetry. set. Auto. Clear(false); Telemetry. Item status = telemetry. add. Data("Status", "Initialized"); telemetry. update(); while (gamepad 1. a == false) { if (gamepad 1. left_bumper) { delay. Time. Milliseconds -= 1000; if (delay. Time. Milliseconds < 0) { delay. Time. Milliseconds = 0; } // Wait for the bumper to be released while (gamepad 1. left_bumper) { idle(); } } if (gamepad 1. right_bumper) { delay. Time. Milliseconds += 1000; if (delay. Time. Milliseconds > 20000) { delay. Time. Milliseconds = 20000; } while (gamepad 1. right_bumper) { idle(); } } delay. set. Value( "%d (Not Set)" , delay. Time. Milliseconds); telemetry. update(); } delay. set. Value( "%d", delay. Time. Milliseconds); telemetry. update(); auto. Mode = Select. Auto. Mode(); delay. Time. Milliseconds = Select. Delay. Time(); status. set. Value( "Initialized"); telemetry. update(); wait. For. Start(); telemetry. clear. All(); status = telemetry. add. Data("Status", "Delaying"); sleep(delay. Time. Milliseconds); status. set. Value( "Running"); telemetry. update(); switch (auto. Mode) { case AUTO_MODE_RED 1: Red 1(); break; case AUTO_MODE_RED 2: Red 2(); break; case AUTO_MODE_BLUE 1 : Blue 1(); break; case AUTO_MODE_BLUE 2 : Blue 2(); break; case AUTO_MODE_NOT_SELECTED : // This one should not happen break; } // Wait for user to release the a button while (gamepad 1. a) { idle(); } return delay. Time. Milliseconds; } } }

Autonomous Programming Tips Help yourself and FTA/CSA by adding Log messages. These log messages

Autonomous Programming Tips Help yourself and FTA/CSA by adding Log messages. These log messages can provide “forensics” as to why something didn’t work They can also help monitor sensor/encoder values There are 5 log levels, although the debug log should be suffice Error – Log. e(String tag, String msg) Warning – Log. w(String tag, String msg) Information – Log. i(String tag, String msg) Debug – Log. d(String tag, String msg) Verbose – Log. v(String tag, String msg) For tag, you can use your team number or name or java class

Autonomous Programming Tips The different levels and tag allows for filtering of the log

Autonomous Programming Tips The different levels and tag allows for filtering of the log messages when running with Android Studio and wireless debugging. The Robot Controller App does not have a filtering mechanism Put a log message immediately after the wait. For. Start and at the end of run. Op. Mode. Put log messages at the start and end of a task/goal. Avoid putting log messages inside loops as this can overfill the logs unless debugging an issue

Autonomous Programming Tips private void Red 1() { Log. d("Aluminati", "Red 1 Started"); Log.

Autonomous Programming Tips private void Red 1() { Log. d("Aluminati", "Red 1 Started"); Log. d("Aluminati", "Red 1 Completed"); @Override public void run. Op. Mode() throws Interrupted. Exception { Auto. Mode auto. Mode; Integer delay. Time. Milliseconds; } telemetry. set. Auto. Clear(false); Telemetry. Item status = telemetry. add. Data("Status", "run. Op. Mode Started"); telemetry. update(); private void Red 2() { Log. d("Aluminati", "Red 2 Started"); Log. d("Aluminati", "Set Auto Mode"); auto. Mode = Select. Auto. Mode(); Log. d("Aluminati", "Set Delay Time"); delay. Time. Milliseconds = Select. Delay. Time(); Log. d("Aluminati", "Initialized"); status. set. Value("Initialized"); telemetry. update(); wait. For. Start(); Log. d("Aluminati", "Started - Running " + auto. Mode. to. String() + " Delaying " + delay. Time. Milliseconds. to. String()); telemetry. clear. All(); status = telemetry. add. Data("Status", "Delaying"); sleep(delay. Time. Milliseconds); status. set. Value("Running"); telemetry. update(); Log. d("Aluminati", "Red 2 Completed"); } private void Blue 1() { Log. d("Aluminati", "Blue 1 Started"); Log. d("Aluminati", "Blue 1 Completed"); } private void Blue 2() { Log. d("Aluminati", "Blue 2 Started"); Log. d("Aluminati", "Blue 2 Completed"); } switch (auto. Mode) { case AUTO_MODE_RED 1: Red 1(); break; case AUTO_MODE_RED 2: Red 2(); break; case AUTO_MODE_BLUE 1: Blue 1(); break; case AUTO_MODE_BLUE 2: Blue 2(); break; case AUTO_MODE_NOT_SELECTED: // This one should not happen break; } Log. d("Aluminati", "run. Op. Mode completed"); }

Autonomous Programming Tips Don’t use encoder counts but distance in centimeters or inches Four

Autonomous Programming Tips Don’t use encoder counts but distance in centimeters or inches Four numbers are needed Wheel Circumference Motor Encoder Counts for 1 rotation Gear Ratio Scale Factor The wheel circumference is the diameter of the wheel multiplied by π The Motor Encoder Counts is dependent on the Motor, Encoder, Motor Controller, and you robot configuration setting

Autonomous Programming Tips

Autonomous Programming Tips

Autonomous Programming Tips

Autonomous Programming Tips

Autonomous Programming Tips Motors have the following Run Modes: STOP_AND_RESET_ENCODER This mode stops the

Autonomous Programming Tips Motors have the following Run Modes: STOP_AND_RESET_ENCODER This mode stops the motor by removing power to the motor and sets the encoder value to 0 RUN_WITHOUT_ENCODER The motors will run at the power provider without any PID RUN_USING_ENCODER The motor is to do its best to run at targeted velocity. This is a PID mode RUN_TO_POSITION The motor is to attempt to rotate in whatever direction is necessary to cause the encoder reading to advance or retreat from its current setting to the setting which has been provided through the set. Target. Position method. This is a PID mode

Autonomous Programming Tips While it may seem that RUN_TO_POSITION should be used, there can

Autonomous Programming Tips While it may seem that RUN_TO_POSITION should be used, there can be some challenges with multiple motors and trying to get all to same position at same time. Most drive trains use to 2 or 4 motors The other method is to use RUN_USING_ENCODERS. This will “balance” the power between motors similar to RUN_TO_POSITION but you only “monitor” one motor encoder.

Autonomous Programming Tips @Autonomous(name="Basic: Multi. Auto" , group="Basic") public class Multi. Auto. Example extends

Autonomous Programming Tips @Autonomous(name="Basic: Multi. Auto" , group="Basic") public class Multi. Auto. Example extends Linear. Op. Mode { public enum Auto. Mode { AUTO_MODE_NOT_SELECTED , AUTO_MODE_RED 1, AUTO_MODE_RED 2, AUTO_MODE_BLUE 1 , AUTO_MODE_BLUE 2 } private static final Double wheel. Circumference = 4. 0 * Math. PI; private static final Double gear. Ratio = 3. 0/2. 0; private static final Double counts. Per. Rotation = 1120. 0; private static final Double scale. Factor = 1. 0; private static final Double counts. Per. Inch = counts. Per. Rotation / wheel. Circumference / gear. Ratio * scale. Factor; private Dc. Motor drive. FR; private Dc. Motor drive. FL; private Dc. Motor drive. BR; private Dc. Motor drive. BL; private boolean robot. Ready = false; private void reset. Encoders() { drive. FR. set. Mode(Dc. Motor. Run. Mode. STOP_AND_RESET_ENCODER ); drive. BR. set. Mode(Dc. Motor. Run. Mode. STOP_AND_RESET_ENCODER ); drive. FL. set. Mode(Dc. Motor. Run. Mode. STOP_AND_RESET_ENCODER ); drive. BL. set. Mode(Dc. Motor. Run. Mode. STOP_AND_RESET_ENCODER ); } private void run. Using. Encoders() { drive. FR. set. Mode(Dc. Motor. Run. Mode. RUN_USING_ENCODER ); drive. BR. set. Mode(Dc. Motor. Run. Mode. RUN_USING_ENCODER ); drive. FL. set. Mode(Dc. Motor. Run. Mode. RUN_USING_ENCODER ); drive. BL. set. Mode(Dc. Motor. Run. Mode. RUN_USING_ENCODER ); } while (op. Mode. Is. Active() && Math. abs(drive. FL. get. Current. Position()) < Math. abs(counts)) { idle(); } set. Drive. Power( 0. 0, 0. 0); Log. d("Aluminati", "Drive. Inch Completed" ); } private void init. Run() { robot. Ready = true; drive. FR = hardware. Map. dc. Motor. get("drive. FR"); drive. BR = hardware. Map. dc. Motor. get("drive. BR"); drive. FL = hardware. Map. dc. Motor. get("drive. FL"); drive. BL = hardware. Map. dc. Motor. get("drive. BL"); if (drive. BL == null || drive. BR == null || drive. FL == null || drive. FR == null) { telemetry. add. Data("Status", "WARNING - Motor is NULL - Not Ready!!" ); telemetry. update(); robot. Ready = false; } else { drive. FR. set. Direction(Dc. Motor. Direction. REVERSE); drive. BR. set. Direction(Dc. Motor. Direction. REVERSE); } } @Override public void run. Op. Mode() throws Interrupted. Exception { Auto. Mode auto. Mode; Integer delay. Time. Milliseconds; telemetry. set. Auto. Clear(false); Telemetry. Item status = telemetry. add. Data("Status", "run. Op. Mode Started" ); telemetry. update(); Log. d("Aluminati", "Set Auto Mode" ); auto. Mode = Select. Auto. Mode(); Log. d("Aluminati", "Set Delay Time" ); delay. Time. Milliseconds = Select. Delay. Time(); Log. d("Aluminati", "Initialized"); init. Run(); status. set. Value( "Initialized"); telemetry. update(); wait. For. Start(); if (robot. Ready == false) { return; } Log. d("Aluminati", "Started - Running " + auto. Mode. to. String() + " Delaying " + delay. Time. Milliseconds. to. String()); private void set. Drive. Power(double power. Left, double power. Right) { drive. FR. set. Power(power. Right); drive. BR. set. Power(power. Right); drive. FL. set. Power(power. Left); drive. BL. set. Power(power. Left); } private void Drive. Inch(Double inches, Double power) { Log. d("Aluminati", "Drive " + inches. to. String() + " inches at power " + power. to. String()); Double counts = inches * counts. Per. Inch; reset. Encoders(); run. Using. Encoders(); set. Drive. Power(power, power); …

Autonomous Programming Tips Use the drive. Inch method for your autonomous program drive. Inch(72.

Autonomous Programming Tips Use the drive. Inch method for your autonomous program drive. Inch(72. 0, 0. 9) will drive forward 72” with power set to 0. 9. drive. Inch(36. 0, -0. 7) will drive backward 36” with power set to 0. 7 The power will define whether the motion is forward or backwards since absolute values are used for the counts.

Autonomous Programming Tips Turning consistently is on of the hardest tasks in autonomous. Friction/slippage

Autonomous Programming Tips Turning consistently is on of the hardest tasks in autonomous. Friction/slippage makes turning inconsistent. Using gyros will improve turning consistency but this discussion will not use gyros A four wheel robot with omni front wheels while result in more consistent turning. A six wheel robot with “connected” double motors will result in more consistent turning.

Autonomous Programming Tips When turning, the robot is going to “circumscribe” a circle. Use

Autonomous Programming Tips When turning, the robot is going to “circumscribe” a circle. Use math to compute the “arc distance” for a specified number of degrees to turn. This number is dependent on width/diameter of your robot. Compute the diameter by measuring the distance from the center of the left to the center of the right wheel.

Autonomous Programming Tips

Autonomous Programming Tips

Autonomous Programming Tips Just like going forward, RUN_WITH_ENCODERS will be used. In this case,

Autonomous Programming Tips Just like going forward, RUN_WITH_ENCODERS will be used. In this case, one side will be given negative power and other side positive power in order to rotate the robot. Which is positive or negative is dependent on the which motor is used to monitor the counts. Left Motor – Counts positive turning right Right Motor – Count positive turning left

Autonomous Programming Tips Assuming the left motor is used for the counts, then the

Autonomous Programming Tips Assuming the left motor is used for the counts, then the turning function is defined as private static final Double robot. Diameter = 16. 0; private static final Double turn. Scale. Factor = 1. 0; private static final Double counts. Per. Degree = (robot. Diameter * Math. PI) * counts. Per. Inch / 360. 0 * turn. Scale. Factor ; private void Turn(Double degrees, Double power) { Log. d("Aluminati", "Turn " + degrees. to. String() + " degrees at power " + power. to. String()); double counts = degrees * counts. Per. Degree ; reset. Encoders(); run. Using. Encoders(); if (degrees < 0) { // Turning Left set. Drive. Power(-power, power); } else { set. Drive. Power(power, -power); } while (op. Mode. Is. Active() && Math. abs(drive. BL. get. Current. Position()) < Math. abs(counts)) { idle(); } set. Drive. Power( 0. 0, 0. 0); Log. d("Aluminati", "Turn Completed" ); } Due to friction and other factors, multiple tests should be ran to determine scale factor Challenge in computing an accurate scale factor is accurately measuring how much the robot turned

Autonomous Programming Tips One of the hardest things in autonomous is to get the

Autonomous Programming Tips One of the hardest things in autonomous is to get the robot to turn consistently. It is best to use the encoder from a center wheel in a 6 wheel robot. If front has omni wheels in a four wheel robot, then an encoder from the rear wheel is best. Frequently it is best to determine a “number” that gets the desired turn That is, you may need to turn 210 degrees to consistently get 180 degrees. Even better is to use a calibrated gyro when turning.