Programming - The Robettes

advertisement
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 internet
import java.io.*; // read from and write to files (and to & from web sites)
import java.net.*; // internet utility library
import javax.servlet.*; // http web hosting library
import javax.mail.*;
// use this to spam your parents all night
• US F.I.R.S.T. library packages
import edu.wpi.first.wpilibj.*; // Talon, Limit, Joystick…
import edu.wpi.first.wpilibj.command.*;
• Split your Robot into 3 or more packages
import com.first.team2177.robot.*;
import com.first.team2177.robot.subsystems.*;
import com.first.team2177.robot.commands.*;
// the main stuff
// 2-4 physical subsets
// 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
RobotMap extends java.lang.Object (implied)
OI extends java.lang.Object (implied)
// package is ...team2177.robot.*
DriveTrain extends ...wpilib.SubSystem
ClimberSys extends …wpilib.SubSystem
DumperSys extends …wpilib.SubSystem
// package is …team2177.robot.Subsystems.*
CommandBase extends ...wpilib.Command;
AutonomousCmd extends CommandBase
TankDrive extends CommandBase
ArcadeDrive extends CommandBase
ClimbSetup extends CommandBase
ClimbPreclimb extends CommandBase
ClimbNextStep extends CommandBase
ClimbTower extends …wpilib.CommandGroup;
// package is ...team2177.robot.Commands.*
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, Long
Floats, Doubles
Booleans
• “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;
ClimberSys climber;
DumperSys dumper;
Joystick leftStick;
Joystick rightStick;
Joystick shootStick;
// each subsystem is its own type.
// 3 instances of the same type
// these value can change during a game, but more likely just once on startup
double driveBias = 0.7; // 0.5 would be a perfect left-right balance
double 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 parameter
long h = setArmHeight( fX() , fY() ); // double,double IN, long OUT
// calling methods from other classes -- i.e. ‘imported’ variables and types
driveTrain.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
OI
TankDrive
Robot
ArcadeDrive
Dumper
AutonomousCmd
RobotMap
ClimbSetup
ClimbPreClimb
ClimbTower
ClimbNextStep
ClimbNextStep
DriveTrain
DumperSys
ClimberSys
ClimbNextStep
Motor controllers, sensors,
etc
Control Classes
Subsystems
Commands
Command Groups
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 .wpilib
RobotMap & OI – no instances.
DriveTrain, ClimberSys , DumperSys - one instance each.
AutonomousCmd - one instance, started and stopped by .wpilib/Robot
TankDrive & ArcadeDrive – 1 & 2 instances, started by OI-designated buttons
ClimbSetup – one instance, created and started by ClimberSys (then optionally by OI/joystick)
ClimbPreclimb – one instance, created and started by OI/joystick
ClimbTower – one instance, created and started by OI/joystick
ClimbNextStep – 9 instances, created and started by ClimbTower
CommandBase – 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-5
for (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 robot
drivetrain, 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 motors
Talon 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 motors
Talon 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 defaultcommand 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 nearcontinuous .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
Download