/*
* 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.control;
import org.strongback.Executable;
import org.strongback.Executor;
import org.strongback.Strongback;
import org.strongback.command.Requirable;
/**
* A simple controller that can manage a component (typically a motor) based upon a desired {@link #withTarget(double) target value}
* and {@link #withTolerance(double) tolerance}.
*
* @author Randall Hauch
* @see PIDController
*/
public interface Controller extends Requirable {
/**
* Determine if this controller is {@link #enable() enabled}.
*
* @return <code>true</code> if enabled, or <code>false</code> otherwise
*/
public boolean isEnabled();
/**
* Enable this controller so that it does read inputs, compute errors, and generate outputs when {@link #computeOutput()} is
* called.
*
* @return this object so that methods can be chained; never null
*/
public Controller enable();
/**
* Disable this controller to <em>not</em> read inputs, compute errors, and generate outputs when {@link #computeOutput()}
* is called.
*
* @return this object so that methods can be chained; never null
*/
public Controller disable();
/**
* Get the current measured value for this controller.
* @return the current value
*/
public double getValue();
/**
* Get the target value for this controller.
* @return the target value
* @see #withTarget(double)
*/
public double getTarget();
/**
* Sets the target value for this controller.
*
* @param target the desired setpoint that this controller will use as a target
* @return this object so that methods can be chained; never null
* @see #getTarget()
*/
public Controller withTarget(double target);
/**
* Sets the absolute tolerance for this controller.
*
* @param tolerance the maximum absolute error which is tolerable in the units of the input object
* @return this object so that methods can be chained; never null
* @see #getTolerance()
*/
public Controller withTolerance(double tolerance);
/**
* Get the absolute tolerance for this controller.
* @return the target value
* @see #withTolerance(double)
*/
public double getTolerance();
/**
* Determines whether the supplied value is within the {@link #getTolerance() tolerance} of the {@link #getTarget() target}.
*
* @param value the proposed value
* @return <code>true</code> if the proposed value is within the tolerance of the target, or <code>false</code> otherwise
*/
public default boolean checkTolerance(double value) {
return Math.abs(value) <= (getTarget() - getTolerance());
}
/**
* Determines whether the input to the controller is currently within the {@link #getTolerance() tolerance} of the
* {@link #getTarget() target}.
*
* @return <code>true</code> if the current value is within the tolerance of the target, or <code>false</code> otherwise
*/
public default boolean isWithinTolerance() {
return checkTolerance(getValue());
}
/**
* Calculate the next controller output. This usually involves reading one or more inputs and computing the output based
* upon a model of the system.
*
* @return <code>true</code> if the execution completed because it resulted in a value that is within the tolerance of the
* setpoint, or <code>false</code> if this controller is not {@link #isEnabled() enabled} or has not yet reached the
* setpoint given the tolerance
*/
public boolean computeOutput();
/**
* Reset any error values stored from previous {@link #computeOutput() executions}.
*
* @return this object so that methods can be chained; never null
*/
public Controller reset();
/**
* Return whether the {@link Executable} instance returned by {@link #executable()} does anything useful. Software-based
* controllers may often return <code>true</code>, whereas many hardware-based controllers may return <code>false</code>.
* @return <code>true</code> if the {@link #executable()} does useful work and enables the controller to operate
* continually and automatically, or <code>false</code> if the {@link #executable()} does nothing.
*/
public default boolean hasExecutable() {
return true;
}
/**
* Get the {@link Executable} instance that will continuously {@link #computeOutput() execute} this controller to read
* inputs from the source and generate outputs to reach the {@link #getTarget() target}.
* <p>
* If this is used, then this same controller should <em>never</em> be used with commands. This is not checked, so robot
* programs are responsible for ensuring this does not happen.
*
* @return the {@link Executable} object that can be registered with an {@link Executor} (typically Strongback's
* {@link Strongback#executor() central executor}); never null and always the same instance for this controller
*/
public Executable executable();
}