Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ValueProvider observers and PID fixes #53

Merged
merged 2 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 80 additions & 75 deletions src/main/java/com/team766/config/AbstractConfigValue.java
Original file line number Diff line number Diff line change
@@ -1,95 +1,100 @@
package com.team766.config;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import com.team766.library.AbstractObservable;
import com.team766.library.SettableValueProvider;
import com.team766.logging.Category;
import com.team766.logging.Logger;
import com.team766.logging.LoggerExceptionUtils;
import com.team766.logging.Severity;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

public abstract class AbstractConfigValue<E> implements SettableValueProvider<E> {
protected String m_key;
private E m_cachedValue;
private boolean m_cachedHasValue;
private int m_cachedGeneration = -1;
public abstract class AbstractConfigValue<E> extends AbstractObservable<Optional<E>>
implements SettableValueProvider<E> {
protected String m_key;
private E m_cachedValue;
private boolean m_cachedHasValue;

private static ArrayList<AbstractConfigValue<?>> c_accessedValues = new ArrayList<AbstractConfigValue<?>>();
private static ArrayList<AbstractConfigValue<?>> c_accessedValues =
new ArrayList<AbstractConfigValue<?>>();

static Collection<AbstractConfigValue<?>> accessedValues() {
return Collections.unmodifiableCollection(c_accessedValues);
}
static Collection<AbstractConfigValue<?>> accessedValues() {
return Collections.unmodifiableCollection(c_accessedValues);
}

static void resetStatics() {
c_accessedValues.clear();
}
static void resetStatics() {
c_accessedValues.clear();
}

protected AbstractConfigValue(final String key) {
m_key = key;
c_accessedValues.add(this);
// Querying for this config setting's key will add a placeholder entry
// in the config file if this setting does not already exist there.
ConfigFileReader.instance.getRawValue(m_key);
}
protected AbstractConfigValue(final String key) {
m_key = key;
c_accessedValues.add(this);
// Querying for this config setting's key will add a placeholder entry
// in the config file if this setting does not already exist there.
ConfigFileReader.instance.getRawValue(m_key);
update();
}

private void sync() {
if (ConfigFileReader.instance.getGeneration() != m_cachedGeneration) {
m_cachedGeneration = ConfigFileReader.instance.getGeneration();
var rawValue = ConfigFileReader.instance.getRawValue(m_key);
m_cachedHasValue = rawValue != null;
if (m_cachedHasValue) {
try {
m_cachedValue = parseJsonValue(rawValue);
} catch (Exception ex) {
Logger.get(Category.CONFIGURATION).logRaw(Severity.ERROR,
"Failed to parse " + m_key + " from the config file: "
+ LoggerExceptionUtils.exceptionToString(ex));
m_cachedValue = null;
m_cachedHasValue = false;
}
}
}
}
void update() {
rcahoon marked this conversation as resolved.
Show resolved Hide resolved
var rawValue = ConfigFileReader.instance.getRawValue(m_key);
m_cachedHasValue = rawValue != null;
if (m_cachedHasValue) {
try {
m_cachedValue = parseJsonValue(rawValue);
} catch (Exception ex) {
Logger.get(Category.CONFIGURATION)
.logRaw(
Severity.ERROR,
"Failed to parse "
+ m_key
+ " from the config file: "
+ LoggerExceptionUtils.exceptionToString(ex));
m_cachedValue = null;
m_cachedHasValue = false;
}
}
notifyObservers(m_cachedHasValue ? Optional.of(m_cachedValue) : Optional.empty());
}

public String getKey() {
return m_key;
}
public String getKey() {
return m_key;
}

@Override
public boolean hasValue() {
sync();
return m_cachedHasValue;
}
@Override
public boolean hasValue() {
return m_cachedHasValue;
}

@Override
public E get() {
sync();
if (!m_cachedHasValue) {
throw new IllegalArgumentException(m_key + " not found in the config file");
}
return m_cachedValue;
}
@Override
public E get() {
if (!m_cachedHasValue) {
throw new IllegalArgumentException(m_key + " not found in the config file");
}
return m_cachedValue;
}

public void set(final E value) {
ConfigFileReader.instance.setValue(m_key, value);
}
public void set(final E value) {
ConfigFileReader.instance.setValue(m_key, value);
notifyObservers(Optional.of(value));
}

public void clear() {
ConfigFileReader.instance.setValue(m_key, null);
}
public void clear() {
ConfigFileReader.instance.setValue(m_key, null);
notifyObservers(Optional.empty());
}

protected abstract E parseJsonValue(Object configValue);
protected abstract E parseJsonValue(Object configValue);

@Override
public String toString() {
sync();
if (!m_cachedHasValue) {
return "<unset>";
}
if (m_cachedValue == null) {
return "<null>";
}
return m_cachedValue.toString();
}
}
@Override
public String toString() {
if (!m_cachedHasValue) {
return "<unset>";
}
if (m_cachedValue == null) {
return "<null>";
}
return m_cachedValue.toString();
}
}
13 changes: 4 additions & 9 deletions src/main/java/com/team766/config/ConfigFileReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ public class ConfigFileReader {

private static final String KEY_DELIMITER = ".";

// This is incremented each time the config file is reloaded to ensure that ConfigValues use the
// most recent setting.
private int m_generation = 0;

private String m_fileName;
private String m_backupFileName; // if set, will also save here
private JSONObject m_values = new JSONObject();
Expand Down Expand Up @@ -81,12 +77,11 @@ public void reloadFromJson(final String jsonString) {
"Could not parse config value for " + param.getKey(), ex);
}
}
// All values parsed successfully; now actually apply the new values.
m_values = newValues;
++m_generation;
}

public int getGeneration() {
return m_generation;
for (AbstractConfigValue<?> param : AbstractConfigValue.accessedValues()) {
param.update();
}
}

public boolean containsKey(final String key) {
Expand Down
115 changes: 73 additions & 42 deletions src/main/java/com/team766/controllers/PIDController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.team766.config.ConfigFileReader;
import com.team766.hal.RobotProvider;
import com.team766.library.SetValueProvider;
import com.team766.library.SettableValueProvider;
import com.team766.library.ValueProvider;
import com.team766.logging.Category;
import com.team766.logging.Logger;
Expand Down Expand Up @@ -40,13 +39,13 @@ public class PIDController {
private int printCounter = 0;
private boolean print = false;

private final ValueProvider<Double> Kp;
private final ValueProvider<Double> Ki;
private final ValueProvider<Double> Kd;
private final ValueProvider<Double> Kff;
private final ValueProvider<Double> maxoutput_low;
private final ValueProvider<Double> maxoutput_high;
private final ValueProvider<Double> endthreshold;
private ValueProvider<Double> Kp;
private ValueProvider<Double> Ki;
private ValueProvider<Double> Kd;
private ValueProvider<Double> Kff;
private ValueProvider<Double> maxoutput_low;
private ValueProvider<Double> maxoutput_high;
private ValueProvider<Double> endthreshold;

private double setpoint = Double.NaN;

Expand Down Expand Up @@ -76,6 +75,20 @@ public static PIDController loadFromConfig(String configPrefix) {
ConfigFileReader.getInstance().getDouble(configPrefix + THRESHOLD_KEY));
}

/**
* Default constructor. PID gains should be set later using mutator methods.
*/
public PIDController() {
this(
new SetValueProvider<Double>(),
new SetValueProvider<Double>(),
new SetValueProvider<Double>(),
new SetValueProvider<Double>(),
new SetValueProvider<Double>(),
new SetValueProvider<Double>(),
new SetValueProvider<Double>());
}

/**
*
* @param P P constant
Expand All @@ -92,14 +105,7 @@ public PIDController(
final double outputmax_low,
final double outputmax_high,
final double threshold) {
Kp = new SetValueProvider<Double>(P);
Ki = new SetValueProvider<Double>(I);
Kd = new SetValueProvider<Double>(D);
Kff = new SetValueProvider<Double>();
maxoutput_low = new SetValueProvider<Double>(outputmax_low);
maxoutput_high = new SetValueProvider<Double>(outputmax_high);
endthreshold = new SetValueProvider<Double>(threshold);
setTimeProvider(RobotProvider.getTimeProvider());
this(P, I, D, 0.0, outputmax_low, outputmax_high, threshold);
}

public PIDController(
Expand All @@ -110,8 +116,14 @@ public PIDController(
final double outputmax_low,
final double outputmax_high,
final double threshold) {
this(P, I, D, outputmax_low, outputmax_high, threshold);
((SetValueProvider<Double>) Kff).set(FF);
Kp = new SetValueProvider<Double>(P);
Ki = new SetValueProvider<Double>(I);
Kd = new SetValueProvider<Double>(D);
Kff = new SetValueProvider<Double>(FF);
maxoutput_low = new SetValueProvider<Double>(outputmax_low);
maxoutput_high = new SetValueProvider<Double>(outputmax_high);
endthreshold = new SetValueProvider<Double>(threshold);
setTimeProvider(RobotProvider.getTimeProvider());
}

private void setTimeProvider(final TimeProviderI timeProvider_) {
Expand Down Expand Up @@ -204,30 +216,41 @@ public void disable() {
* @param D Derivative value used in the PID controller
*/
public void setConstants(final double P, final double I, final double D) {
((SettableValueProvider<Double>) Kp).set(P);
((SettableValueProvider<Double>) Ki).set(I);
((SettableValueProvider<Double>) Kd).set(D);
needsUpdate = true;
Kp = new SetValueProvider<Double>(P);
Ki = new SetValueProvider<Double>(I);
Kd = new SetValueProvider<Double>(D);
}

public void setP(final double P) {
((SettableValueProvider<Double>) Kp).set(P);
needsUpdate = true;
setP(new SetValueProvider<Double>(P));
}

public void setP(final ValueProvider<Double> P) {
Kp = P;
}

public void setI(final double I) {
((SettableValueProvider<Double>) Ki).set(I);
needsUpdate = true;
setI(new SetValueProvider<Double>(I));
}

public void setI(final ValueProvider<Double> I) {
Ki = I;
}

public void setD(final double D) {
((SettableValueProvider<Double>) Kd).set(D);
needsUpdate = true;
setD(new SetValueProvider<Double>(D));
}

public void setD(final ValueProvider<Double> D) {
Kd = D;
}

public void setFF(final double FF) {
((SettableValueProvider<Double>) Kff).set(FF);
needsUpdate = true;
setFF(new SetValueProvider<Double>(FF));
}

public void setFF(final ValueProvider<Double> FF) {
Kff = FF;
}

/**
Expand Down Expand Up @@ -347,20 +370,28 @@ public double getCurrentError() {
return cur_error;
}

public void setMaxoutputHigh(final Double in) {
if (in == null) {
((SettableValueProvider<Double>) maxoutput_high).clear();
} else {
((SettableValueProvider<Double>) maxoutput_high).set(in);
}
public void clearMaxoutputHigh() {
maxoutput_high = new SetValueProvider<Double>();
}

public void setMaxoutputLow(final Double in) {
if (in == null) {
((SettableValueProvider<Double>) maxoutput_low).clear();
} else {
((SettableValueProvider<Double>) maxoutput_low).set(in);
}
public void setMaxoutputHigh(final double in) {
maxoutput_high = new SetValueProvider<Double>(in);
}

public void setMaxoutputHigh(final ValueProvider<Double> in) {
maxoutput_high = in;
}

public void clearMaxoutputLow() {
maxoutput_low = new SetValueProvider<Double>();
}

public void setMaxoutputLow(final double in) {
maxoutput_low = new SetValueProvider<Double>(in);
}

public void setMaxoutputLow(final ValueProvider<Double> in) {
maxoutput_low = in;
}

public double getSetpoint() {
Expand Down
Loading
Loading