The Basics of Java Programming and Command-Based Robot Projects TheRobettes.com

Preview:

Citation preview

The Basics of Java Programming and Command-Based Robot Projects

TheRobettes.com

Agenda• Packages and Classes• Variables and Objects• Methods• Command-Robot Concepts• If/Else Statements• For Loops and While Loops• Key Command-Robot Classes • Glossary, Q&A, Conclusions

Packages and Classes• All java code belongs to a specific class.

• Packages are sets of related Classes

• Every project starts with one ‘main’ class/method

• More detailed classes are defined and called on to handle various specific duties.

Packages and Classes - examples• Generic classes that sort and organize

import java.util.*;import com.first.team2177.common.*;

• Standard java classes for ‘streams’ and internetimport java.io.*; // read from and write to files (and to & from web sites)import java.net.*; // internet utility libraryimport javax.servlet.*; // http web hosting libraryimport javax.mail.*; // use this to spam your parents all night

• US F.I.R.S.T. library packagesimport edu.wpi.first.wpilibj.*; // Talon, Limit, Joystick…import edu.wpi.first.wpilibj.command.*;

• Split your Robot into 3 or more packagesimport com.first.team2177.robot.*; // the main stuffimport com.first.team2177.robot.subsystems.*; // 2-4 physical subsetsimport com.first.team2177.robot.commands.*; // 5-15 ‘actions’ that the subsystem

need to do

Packages and Classes – examples 2• The actual class-list of our Ultimate robot.

Robot extends ...wpilib.IterativeRobot // package is ...team2177.robot.*RobotMap extends java.lang.Object (implied)OI extends java.lang.Object (implied)

DriveTrain extends ...wpilib.SubSystem // package is …team2177.robot.Subsystems.*

ClimberSys extends …wpilib.SubSystemDumperSys extends …wpilib.SubSystem

CommandBase extends ...wpilib.Command; // package is ...team2177.robot.Commands.*

AutonomousCmd extends CommandBase TankDrive extends CommandBase ArcadeDrive extends CommandBase ClimbSetup extends CommandBase ClimbPreclimb extends CommandBase ClimbNextStep extends CommandBase ClimbTower extends …wpilib.CommandGroup;

Variables and Objects• Variables hold a value or setting.• Variables give a name & type to what the value is for. • Variables can be passed between classes & methods.• Variables can keep the same value, or be changed.

• There are several basic java variable types.Integers, LongFloats, DoublesBooleans

• “Object” variables hold a reference to a java-Class.• String variable are Objects, but work like a basic

type.

Variables and Objects - examples• In our project, ‘CommandBase’ defines many variables

that are used by other ‘Action’ classes.DriveTrain drivetrain; // each subsystem is its own type.ClimberSys climber;DumperSys dumper;

Joystick leftStick; // 3 instances of the same typeJoystick rightStick;Joystick shootStick;

// these value can change during a game, but more likely just once on startupdouble driveBias = 0.7; // 0.5 would be a perfect left-right balancedouble practiceSpeedFactor = 1.0; // 1.0 = full-power, down to .6 or .7 for freshmem….boolean isPitTesting = false; // if true, the Climber system needs to reduce lift-power

// "debug" logging variables java.util.Vector messageTank; long starttime = System.currentTimeMillis() / 1000;

Methods• Groups of statements performed as a set.Defined by a name, (parameters), and a return type.Class MySampleClass {

boolean isButtonPressed() { statements…; return joyStick.getButtonPressed(1);}void startOrStop(boolean) { statements; …; }long setArmHeight(double left, double right) { …; }Talon getActiveMotor() { …; return leftFrontMotor; }void doSomething() { // sample statement …

// calling ‘local’ methods -- i.e. from MySampleClass, or else any class it extended…startOrStop( isButtonPressed() ); // bool return used as a bool parameterlong h = setArmHeight( fX() , fY() ); // double,double IN, long OUT// calling methods from other classes -- i.e. ‘imported’ variables and typesdriveTrain.tankDrive( joystick.getY(), joystick2.getY() ); // double-double

} // end of doSomething method} // end of MySampleClass

Methods – debug()• Being ‘static’ (global), this can be called from any

class (if imported).i.e. CommandBase.debug(“my message”);

• When called locally, including by a subclasses, only the method name is needed.

public static void debug(String msg) {

if (messageTank.contains(msg) == false) {

messageTank.add(msg); // the parameter text.

// print the given message, along with the (first)occurrence-time long time = (System.currentTimeMillis() / 1000) - starttime; String debugTime = "" + (time / 60) + ':' + (time % 60) + " "; System.out.print(debugTime + msg); }}

Command-Based Robot Concepts

• “It will make simple programs more complicated and the more complicated programs simpler.”

• Organized into Subsystem and Command• Easier to make adjustments throughout the

season• Code is more spread out throughout the

classes

RobotOI RobotMap

DriveTrain ClimberSysDumperSys

TankDrive ArcadeDrive ClimbSetup ClimbPreClimb ClimbTower

ClimbNextStep

Dumper

Control ClassesSubsystemsCommandsCommand Groups

AutonomousCmd

ClimbNextStep

ClimbNextStep

Motor controllers, sensors, etc

Command-Robot Concepts – examples

• ‘Robot’ creates our Autonomous & CommandBase • CommandBase creates each of our subsystems.• CmdBase->OI->init() then creates teleOp commands.• ClimbTower and Autonomous are groups, they also

create other Cmds.Robot - one instance, created by .wpilibRobotMap & OI – no instances.DriveTrain, ClimberSys , DumperSys - one instance each.AutonomousCmd - one instance, started and stopped by .wpilib/RobotTankDrive & ArcadeDrive – 1 & 2 instances, started by OI-designated buttonsClimbSetup – one instance, created and started by ClimberSys (then optionally by OI/joystick)ClimbPreclimb – one instance, created and started by OI/joystickClimbTower – one instance, created and started by OI/joystickClimbNextStep – 9 instances, created and started by ClimbTowerCommandBase – 14 (extended) instances.

Command-Robot Concepts – code sample

• Calling “new” [ClassName](); truns a Class into an Object.Here is the one global method of OI which generates our teleOp commands.

static void init(Joystick leftStick, Joystick rightStick, Joystick shootStick) { // this is just condense slightly.// define the climb-actions based on top 3 “shooter” buttons { left, middle, right }Button climbSetupbutton = new JoystickButton(shootStick, 4); // left button

climbSetupbutton.whenPressed(new ClimbSetup()); // besides being ‘default ‘, now also allow user to select this action

climbSetupbutton = new JoystickButton(shootStick, 3); // middle button climbSetupbutton.whenPressed(new ClimbPreclimb()); // user-action, perform when within the tower perimeter

Button climbExecuteButton = new JoystickButton(shootStick, 5); // right button climbExecuteButton.whenPressed(new ClimbTower()); // in position & verified, "GO"

/** Drive-Style Options* use left-driver’s top 3 buttons { left, middle, right } * to select between T-A-BS = Tank - Arcade – BananaSplit (aka Kaj)*//*left*/ new JoystickButton(leftStick, 4).whenPressed(new TankDriving()); /*middle*/ new JoystickButton(leftStick, 3).whenPressed(new ArcadeDriving(false)); /*right*/ new JoystickButton(leftStick, 5).whenPressed(new ArcadeDriving(true)); // true signals the right-stick for the

rotation }

If/Else Statements• One, two, or many ‘conditions’ can cause different actions.

public void exampleCode(int motorSpeed) {boolean buttonPressed = joystick.getRawButton(4);if ( buttonPressed ) {

doThis(1.0); // because of {}, ‘this’ and

doMore(); // ‘more’ are always executed back to back.

}else if ( booleanA && booleanB )

sideMotor.set( -1.0 );else if ( limitSwitch.isPressed() || motorSpeed==0 )

sideMotor.set( 1.0);else

defaultAction();}

If/Else Statements – Sample Code• Our ‘preclimb’ command-code uses multiple ifs.

public class ClimbPreclimb extends CommandBase {boolean isOnTarget = false; // this is used by both different methods below

public void execute() { if (climber.shoulderPoint() < 1900) // Early on-- Raise the shoulder(&winch) quicker, and the elbow slower. climber.NudgeArms( .50, .25, .35 ); else if (isOnTarget) // Once raised -- Stall the shoulder-motor with positive-lift, this is to avoid ‘bouncing’

climber.NudgeArms( .1, 0, 0 ); else {// Default-Action, “lower” to the target set-points.

isOnTarget = climber.SetTargetPositions("RaiseHooks - elbow-up", .6, 2600, 951, 1300 );if (isOnTarget) // a nested test, log when we have completed this movement debugPrint(“now at preclimb positions " + climber.shoulderPoint() + ", …. ");

}protected void interrupted() {

isOnTarget = false; // this reset is needed when we repeatedly go between driving and preclimb }}

While Loops• While loops run while a certain condition is true. void raiseRobotArm() {

while (armHeight < 30) // condition{

// loop actions…outputPower = …statement…; armHeight =

setArm( outputPower );}

}

While Loops – Sample Code• Our ‘ClimbSetup’ Command performs back-to-back loops. public void execute() { if (climber.winchPoint() > 900) { // only perform these loops once, on startup.

// Early on, Loosen the straps and Raise the shoulder, to assure that the elbow can be reversed-to-down.

// target is effectively a forward-leaning high-five position while (climber.shoulderPoint() < 2500 || climber.winchPoint() < 2600 ) {

climber.setTargetPositions("pre-driving-1", 0.5, 2700, 1417, 2809 ); } // Once raised, Swing the shoulder & elbow 'down', match speeds to minimize slack.

while (climber.winchPoint() > 800) {climber.nudgeArms( -.15, -.60, -.55 );}

} // end of if // …always…, get to and maintain the proper ready-for-preclimb position climber.setTargetPositions("driving", 0.3, 839, 2612, 700 )); } // end of method

For Loops• For loops run for a certain count of times. (here the count is the condition)

void runAutonomous() {// for each ‘N’, 1-5for (int N=1; N<=5; N++)

// something has to eventually change N to end the loop…// here N++ is a statement that does an N+1

each time.{

// loop actions… fireCannon( N );

} // end of for loop} // end of runAutonomous()

For Loops - example• What if you needed to steer this ?

final int ROWS = 4;final int AXELS = 30;…initialize…() {

DriveWheel wheels[][] = new DriveWheels[AXELS][ROWS]; for (int row = 0; row < ROWS; row++ )

for (int axel = 0; axel < AXELS; axel++ )wheels[axel][row] = new

DriveWheel( (row*AXELS) + axel );}

Key Command-Robot Classes • Subsystem• Command• CommandGroup

Key Classes – SubSystems

• The various parts of your robotdrivetrain, climber, dumper.

• Make a class for each subsystem– File, new file, Command-Based Robot, Subsystem

• Add sensor variables, to get readings (read=input).// i.e. long count = myEncoder.get();

• Add motor variables, to set motions (write=output).// i.e. myTalon.set( voltage );

• Add action methods, to be used by Commands.– // i.e. MyCommand() { mySubSystem.doSomething(); }

Key Classes – Subsystems – DriveChassis example

• Private variables for sensors and motorsTalon leftFront, rightFront, etc.Encoder leftSpeed, rightSpeed;

• Public action methods, for use by the Commands.void tankDrive(double left, double right) {…}void arcadeDrive(double momentum, double angle) {…}

Key Classes – Subsystems – Climber example

• Private variables for sensors and motorsTalon shoulder = new Talon( RobotMap.SHOULDER_MOTOR);Talon elbow =…;Talon winch1, winch2;“Potentiometer” shoulderPot = new AnalogChannel( RobotMap.SHOULDER_POT);Potentiometer elbowPot = …;Potentiometer winchPot = …;

• Private action methods, for local (climber) use.void setShoulderPosition(long) {…}void setElbowPosition(long) {…}void setWinchPosition(long) {…}

• Public action methods, for use by the Commands.void nudge(double shoulderPwr, double elbowPwr, double

winchPwr) {…}void setPos(long shoulderTgt, long elbowTgt, long winchTgt) {…}long get___Position() { return ___Pot.getAverageValue(); }

Key Classes – Commands

• Classes that use the functions of the subsystems to perform operations

• Make a class for each command– File, new file, Command-Based Robot, command

• One(1) Autonomous command may use every Subsystem

• Each Subsystem usually creates one default-command for TeleOp.

• The OI class can make commands that exchange control of a Subsystem.

Key Classes – Commands – ‘execute’ code

• Typically each command will ‘require’ a SubSystem in its constructor.

public class TankDriving extends CommandBase {public TankDriving() {

requires(drivetrain); // requires(Subsystem) is defined by .wpilib.Command } // end of method} // end of class

• ‘execute()’ has to be defined by every Command.What execute defines are statements performed by a near-continuous .wpilib-defined while loop.

// Called repeatedly when this Command is scheduled to run protected void execute() {

drivetrain.tankDrive( leftStick.getY(), rightStick.getY() ); }

Key Classes – Commands – ‘isFinished’ code

• We define ‘isFinished’ in our CommandBase, to just return false.

So generally an OI-joystick action is the only thing to interrupt the execute()-loop

• We needed to define isFinished() within our ClimbNextStep.This is because they are each needed back-to-back while actually climbing.public void execute() { // simplified

isFinished = climber.SetTargetPositions(cmdName, liftPower, shoulderTgt, elbowTgt, winchTgt);}

// interrupt one ClimbNextStep command so the next can begin.public boolean isFinished() { return isFinished; }

Key Classes – Commands – other code

• These methods must be defined somewhere every Command.• We do so as shown within our CommandBase class. // Called just before this Command runs the first time protected void initialize() { }

// Make this return true when this Command no longer needs to run execute() protected boolean isFinished() { return false; }

// Called once after isFinished returns true protected void end() { }

// Called when another command which requires one or more of the same // subsystems is scheduled to run protected void interrupted() { }

Key Classes - Command Groups

• A class that performs a chain of commands.• Key library methods

addSequential(Command)addParallel(Command)

Key Classes - Command Groups – ClimbTower code

• We start this group in tele-op mode…Effectively when the group needs to be executed, .wpilib code will execute each command at the right time, ‘while needed’.

ClimbTower() { // this method gets called by ‘new ClimbTower()’. Within OI-init().

// Lift onto level-1 bar addSequential(new ClimbNextStep("lift-1", 1.0, 1800, 999, 150 )); addSequential(new WaitCommand( 1 )); // pause to stop swinging

// Lift arms to level-2 bar (elbow towards 'up') addSequential(new ClimbNextStep("pre-up-1", .35, 3098, 999, 3550 ));// raise shoulder, addSequential(new ClimbNextStep("pre-up-2", .35, 3098, 1536, 3788 ));// straighten elbow addSequential(new ClimbNextStep("pre-up-3", .35, 2872, 1517, 3550 ));// swing shoulder forward addSequential(new ClimbNextStep("lift-2", 1.0, 1800, 999, 150 )); addSequential(new WaitCommand( 7 )); // WaitCommand is defined in .wpilib… // … then prepare for and lift onto level 3, it is similar steps as level-2 above, just different numbers….

Key Classes - Command Groups – ClimbTower code

• Examples of Next-Step positions…addSequential(new ClimbNextStep("pre-up-1", lowPower, #, #, #...)

addSequential(new ClimbNextStep("pre-up-3", lowPower, #, #, #...

addSequential(new ClimbNextStep("lift-2", fullPower, #, #, # ));

Glossary, Q&A• More or less complicated java key-words…package import public private protected new static final void (…and concepts) precision type-cast array scope

• Time for

Recommended