/*
* Strongback
* Copyright 2015, Strongback and individual contributors by the @authors tag.
* See the COPYRIGHT.txt in the distribution for a full listing of individual
* contributors.
*
* Licensed under the MIT License; you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.strongback.command;
import org.strongback.Strongback;
import org.strongback.control.Controller;
import org.strongback.control.SoftwarePIDController;
/**
* A command that uses the supplied {@link Controller} to move toward the controller's {@link Controller#withTarget(double)
* target}. The controller is assumed to operate automatically and continuously, independently of this command. For example, it
* might be a hardware-based controller (e.g., PID control on the Talon SRX), or a software-based controller (e.g.,
* {@link SoftwarePIDController}) that is registered with Strongback's {@link Strongback#executor() executor} to run in the
* background. (See {@link UnmanagedControllerCommand} for a command that will explicitly run the controller only when commands
* use it.)
* <p>
* Although this command can be used directly via {@link Command#reuse(Controller, Runnable)}, it is also designed to be
* subclassed to create custom, reusable, and concrete commands tailored for your robot. Typically this involves only defining
* custom public constructors to make the commands easy to use, and inheriting all other functionality.
*
* @see Command#reuse(Controller, Runnable)
* @see Command#reuse(double, Controller, Runnable)
* @see UnmanagedControllerCommand
* @author Randall Hauch
*/
public class ControllerCommand extends Command {
protected final Controller controller;
private final Runnable initializer;
/**
* Create a command that uses the given shared and managed controller to move within the controller's tolerance of the
* target. The initializer can be used to update the controller's target, tolerance, and any other controller settings when
* the command is initialized.
*
* @param sharedController the PID+FF controller; may not be null
* @param initializer the controller initialization function, which should update the controller's target, tolerance, and
* any other setting; may be null
* @param requirements the {@link Requirable}s this {@link Command} requires
*/
protected ControllerCommand(Controller sharedController, Runnable initializer, Requirable... requirements) {
this(0.0, sharedController, initializer, requirements);
}
/**
* Create a command that uses the given shared and managed controller to move within the controller's tolerance of the
* target, timing out if the command takes longer than {@code durationInSeconds}. The initializer can be used to update the
* controller's target, tolerance, and any other controller settings when the command is initialized.
*
* @param timeoutInSeconds how long in seconds this command executes before terminating, zero is forever
* @param sharedController the shared controller; may not be null
* @param initializer the controller initialization function, which should update the controller's target, tolerance, and
* any other setting; may be null
* @param requirements the {@link Requirable}s this {@link Command} requires
*/
protected ControllerCommand(double timeoutInSeconds, Controller sharedController, Runnable initializer,
Requirable... requirements) {
super(timeoutInSeconds, requirements);
this.controller = sharedController;
this.initializer = initializer; // may be null
}
@Override
public final void initialize() {
super.initialize();
if (initializer != null) initializer.run();
controller.enable();
preExecute();
}
/**
* Called one time at the end of {@link #initialize()}, after the initializer has run and after the controller has been
* enabled. This method does nothing by default, but can be overridden in subclasses for specific behavior.
*/
protected void preExecute() {
// does nothing by default
}
@Override
public boolean execute() {
// All we have to do is determine whether the controller is within tolerance, in which case we're done ...
return controller.isWithinTolerance();
}
@Override
public void end() {
super.end();
}
}