|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
|
|
Thread Tools | Rate Thread | Display Modes |
|
|
|
#1
|
|||||
|
|||||
|
Java Conditional Command
Here is an idea I had recently for conditional wait commands. Thoughts?
With just a couple of static imports you could be writing CommandGroups that look like this. Code:
package org.usfirst.frc.team2363.robot.commands;
import static org.usfirst.frc.team2363.robot.Robot.drivetrain;
import static org.usfirst.frc.team2363.robot.commands.ConditionalWaitCommand.Operation.*;
import static org.usfirst.frc.team2363.robot.commands.ConditionalWaitCommand.*;
import edu.wpi.first.wpilibj.command.CommandGroup;
public class DriveToLine extends CommandGroup {
public DriveToLine() {
addSequential(new DriveCommand(0.5));
addSequential(waitUntil(drivetrain.getDistance(), GREATER_THAN, 50));
addSequential(new DriveCommand(0));
}
}
Code:
package org.usfirst.frc.team2363.robot.commands;
import edu.wpi.first.wpilibj.command.Command;
public class ConditionalWaitCommand extends Command {
public enum Operation {
LESS_THAN, LESS_THAN_EQUAL, EQUAL, GREATER_THAN_EQUAL, GREATER_THAN
}
public interface IProvidesValue {
double getValue();
}
public static ConditionalWaitCommand waitUntil(IProvidesValue operand1, Operation operation, double operand2) {
return new ConditionalWaitCommand(operand1, operation, operand2, true);
}
public static ConditionalWaitCommand waitWhile(IProvidesValue operand1, Operation operation, double operand2) {
return new ConditionalWaitCommand(operand1, operation, operand2, false);
}
private IProvidesValue operand1;
private Operation operation;
private double operand2;
private boolean isUntil;
private ConditionalWaitCommand(IProvidesValue operand1, Operation operation, double operand2, boolean isUntil) {
this.operand1 = operand1;
this.operation = operation;
this.operand2 = operand2;
this.isUntil = isUntil;
}
@Override
protected void initialize() { }
@Override
protected void execute() { }
protected boolean isFinished() {
switch (operation) {
case EQUAL:
if (operand1.getValue() == operand2) {
return isUntil;
}
case GREATER_THAN:
if (operand1.getValue() > operand2) {
return isUntil;
}
case GREATER_THAN_EQUAL:
if (operand1.getValue() >= operand2) {
return isUntil;
}
case LESS_THAN:
if (operand1.getValue() < operand2) {
return isUntil;
}
case LESS_THAN_EQUAL:
if (operand1.getValue() <= operand2) {
return isUntil;
}
}
return !isUntil;
}
@Override
protected void end() { }
@Override
protected void interrupted() { }
}
Code:
package org.usfirst.frc.team2363.robot.subsystems;
import org.usfirst.frc.team2363.robot.commands.ConditionalWaitCommand.IProvidesValue;
import edu.wpi.first.wpilibj.Encoder;
import edu.wpi.first.wpilibj.command.Subsystem;
public class Drivetrain extends Subsystem {
private Distance distance;
private Encoder encoder = new Encoder(1, 2);
public void initDefaultCommand() { }
public IProvidesValue getDistance() {
if (distance == null) {
distance = new Distance();
}
return distance;
}
private class Distance implements IProvidesValue {
@Override
public double getValue() {
return encoder.getDistance();
}
}
}
|
|
#2
|
|||
|
|||
|
Re: Java Conditional Command
Quote:
If you're using Java 8, you could simplify most of your code by using lambdas rather than hard-code the comparison operations. For example, your ConditionalWaitCommand can use the `java.util.function.Predicate` functional interface to define when it is completed: Code:
public class ConditionalWaitCommand extends Command {
public static ConditionalWaitCommand waitUntil( Predicate isComplete ) {
}
private final Predicate isComplete;
private ConditionalWaitCommand(Predicate isComplete) {
this.isComplete = isComplete;
}
@Override
protected void initialize() { }
@Override
protected void execute() {
return isComplete().test();
}
protected boolean isFinished() { }
@Override
protected void end() { }
@Override
protected void interrupted() { }
}
Code:
public class DriveToLine extends CommandGroup {
public DriveToLine() {
addSequential(new DriveCommand(0.5));
addSequential(waitUntil(drivetrain.getDistance() > 50));
addSequential(new DriveCommand(0));
}
}
Here's what that might look like to create a command instance that drives at 50% power while the distance is greater than 50, and once that condition has occurred then stop: Code:
Drivetrain driveTrain = ...
Command myCommand = ConditionalCommand.runUntil(driveTrain.drive(0.5),
drivetrain.getDistance() > 50.0,
driveTrain.stop());
Code:
public class ConditionalCommand extends Command {
public static ConditionalCommand waitUntil( Runnable initial, Predicate isComplete, Runnable uponComplete ) {
return new ConditionalCommand(initial, isComplete, uponComplete);
}
public static ConditionalCommand waitUntil( Predicate isComplete, Runnable uponComplete ) {
return new ConditionalCommand(initial, isComplete, uponComplete);
}
private final Runnable initial;
private final Predicate isComplete;
private final Runnable uponComplete;
private boolean completed;
private ConditionalCommand(Predicate isComplete) {
this.isComplete = isComplete;
}
@Override
protected void initialize() {
if ( initial != null ) initial.run();
}
@Override
protected void execute() {
if ( isComplete().test() ) {
if ( uponComplete != null ) uponComplete.run();
completed = true;
}
}
protected boolean isFinished() {
return completed;
}
@Override
protected void end() { }
@Override
protected void interrupted() { }
}
|
|
#3
|
|||||
|
|||||
|
Re: Java Conditional Command
Quote:
GeeTwo, it works because getDistance() returns an object not a value. So the getValue() call on the object at the time of the comparison will get the current value. Last edited by notmattlythgoe : 15-11-2015 at 16:26. |
|
#4
|
|||||
|
|||||
|
Re: Java Conditional Command
Quote:
That suggests to me that you would want to have polymorphic forms of the command, including one which allows both operands to be objects. This could then be used to do things like (for example) returning the original drive direction by driving faster with the left wheel than the right, then equalizing after a Code:
waitUntil(leftAxle.getDistance(), GREATER_THAN_EQUAL, rightAxle.getDistance()) |
|
#5
|
|||||
|
|||||
|
Re: Java Conditional Command
Quote:
|
|
#6
|
|||||
|
|||||
|
Re: Java Conditional Command
Ease of debugging. An exception that tells you that one of the operands ought to be an object is more informative than a no such method error at compile. It can also be caught and allowed to run if that's what the programmer really wants. Sort of like a "do you really want to delete this? dialog.
|
|
#7
|
|||||
|
|||||
|
Re: Java Conditional Command
Quote:
|
|
#8
|
|||||
|
|||||
|
Re: Java Conditional Command
Seeing the syntax error, the normal reaction (at least on my team) would be to check for a typo of a failed import, because these are the usual causes of our syntax errors after punctuation. It would take a longer time to figure out a syntax error than a "NeitherOperandIsObject" exception.
|
|
#9
|
|||||
|
|||||
|
Re: Java Conditional Command
Quote:
Code:
The method waitUntil(IProvidesValue, Operation, IProvidesValue) in the type ConditionalWaitCommand is not applicable for the arguments (double, Operation, double) |
|
#10
|
||||
|
||||
|
Re: Java Conditional Command
Quote:
Code:
addSequential(waitUntil(driveTrain::getDistance, GREATER_THAN, 50)); Quote:
Code:
public static <T, U> ConditionalCommand waitUntil(Supplier<T> left, BiPredicate<T, U> tester, Supplier<U> right)
public static <T, U> ConditionalCommand waitUntil(Supplier<T> left, BiPredicate<T, U> tester, U right)
Code:
waitUntil(driveTrain::getDistance, GREATER_THAN, 50); Code:
GREATER_THAN = (left, right) -> left > right |
|
#11
|
|||||
|
|||||
|
Re: Java Conditional Command
Sam,
Any chance of getting some of these types of concepts into the WPILib at some point? I'm really liking the method reference strategy. Last edited by notmattlythgoe : 16-11-2015 at 11:22. |
|
#12
|
||||
|
||||
|
Re: Java Conditional Command
I would be surprised if it made it in this year with kickoff so close.
It would also need to look similar in C++ with whatever it uses for lambdas and method references |
|
#13
|
|||||
|
|||||
|
Re: Java Conditional Command
Yeah, I doubted anything additional would make it in this year. I meant more for future years.
|
|
#14
|
||||
|
||||
|
Re: Java Conditional Command
Maybe. It doesn't seem like a huge project but it might not be a priority for next year
|
|
#15
|
|||
|
|||
|
Re: Java Conditional Command
Quote:
See the announcement on CD, and the Using Strongback online book. Best regards |
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|