Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
fcb0386
add code from approved PR by james
maxspier Jul 17, 2023
81dd9c7
that was supposed to be here
maxspier Jul 17, 2023
db7eb64
Ryan's feedback. Over under 70 lint messages?
maxspier Jul 17, 2023
1837647
Rename CSMSMPID.java to CanSparkMaxSmartMotionPIDController.java
maxspier Jul 17, 2023
b41a5b9
typo (accidental wpackage instead of package)
maxspier Jul 17, 2023
b589b22
Made it so it changes the state whenever you input a new setpoint
maxspier Jul 18, 2023
ac72e46
first batch fix
maxspier Jul 30, 2023
6ebaf64
do not merge yet
maxspier Jul 30, 2023
e3965f4
do not merge: also where do we store this
maxspier Aug 1, 2023
48dd06a
ready for new review now
maxspier Aug 1, 2023
fa1d671
Delete csmsmpidcontroller to make room for others
maxspier Aug 1, 2023
21b05d0
Create CanSparkMaxSmartMotionNonRotationalPIDController.java
maxspier Aug 1, 2023
7ce2fba
Update CanSparkMaxSmartMotionRotationalPIDController.java
maxspier Aug 16, 2023
14db653
fixed run loop
maxspier Aug 16, 2023
c6f6d36
fix run loop and logging errors
maxspier Aug 16, 2023
5bbdf08
Update CanSparkMaxSmartMotionRotationalPIDController.java degrees to eu
maxspier Aug 17, 2023
4de9cf4
"Please lint my branch" he said
JayAgra Aug 18, 2023
7a2d5b6
make pidstate class and fix part of the errors
maxspier Aug 20, 2023
ddbb139
not done yet but placeholder for now
Sep 9, 2023
5bbebca
hehe added run loop
Sep 9, 2023
1f7c1bc
fix exception
Sep 9, 2023
9b8bdbb
e
Sep 9, 2023
761553a
ready for pr
Sep 9, 2023
1a4285e
change 2 methods from public to protected
maxspier Sep 13, 2023
28e426e
Add documentation for OffsetPoint.java
maxspier Sep 13, 2023
01d079e
Delete class
maxspier Sep 13, 2023
d8dcc62
Rename pidstate.java to PIDSTATE.java
maxspier Sep 13, 2023
e08dfda
Refactoring changes needed to be made with the renaming of pidstate t…
maxspier Sep 13, 2023
dd4ca19
Added method to constructor
maxspier Sep 13, 2023
e82f043
Add documentation
maxspier Sep 13, 2023
fc78f8f
fix final method with change
maxspier Sep 14, 2023
ed5d4d0
ryans changes
maxspier Sep 14, 2023
65ee961
fix the antigrav code
maxspier Sep 14, 2023
f5b38a9
Fix compile errors with the abstract class
maxspier Sep 14, 2023
1ea1b55
fix more compile errors
maxspier Sep 14, 2023
98dd22b
fix spacing
maxspier Sep 14, 2023
9bdb154
Fix compile errors and add new exceptions and adresss some comments
maxspier Sep 14, 2023
277e4bf
fix static variables
maxspier Sep 14, 2023
89c5df7
Rename the variable to make it more simple
maxspier Sep 14, 2023
2a26fce
add override method
maxspier Sep 15, 2023
a016497
java enum naming fix
maxspier Sep 15, 2023
65f3aa5
removed newlines
maxspier Sep 15, 2023
cb3c948
add another toString method
maxspier Sep 15, 2023
885b37c
add default neutral mode for motors
Sep 28, 2023
6456782
i forgot imports
Sep 28, 2023
4724223
added method to disable antigrav
Sep 28, 2023
ad12708
removed unused imports
maxspier Oct 2, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.team766.controllers;

import com.ctre.phoenix.motorcontrol.NeutralMode;

public class CanSparkMaxSmartMotionLinearPIDController extends ExtendableCanSparkMaxSmartMotionPIDController {

private final double constantAntigravPower;

public CanSparkMaxSmartMotionLinearPIDController(final String configName, final double absEncoderOffset, final double absEncoderOffsetForZeroEncoderUnits, final OffsetPoint first, final OffsetPoint second, final double antigravityPower, final NeutralMode defaultNeutralMode) {
super(configName, absEncoderOffset, absEncoderOffsetForZeroEncoderUnits, first, second, defaultNeutralMode);
constantAntigravPower = antigravityPower;
}

public void runPIDs(){
updateAntigrav(constantAntigravPower);
run();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.team766.controllers;

import java.util.*;
import com.ctre.phoenix.motorcontrol.NeutralMode;

public class CanSparkMaxSmartMotionRotationalPIDController extends ExtendableCanSparkMaxSmartMotionPIDController {

private final double degreesToEncoderUnitsRatio;
private final double antiGravK;
Comment thread
maxspier marked this conversation as resolved.

public CanSparkMaxSmartMotionRotationalPIDController(final String configName, final double absEncoderOffset, final double absEncoderOffsetForZeroEncoderUnits, final OffsetPoint first, final OffsetPoint second, double degToEncoderUnitsRatio, double antigravityCoefficent, NeutralMode defaultNeutralMode) {
super(configName, absEncoderOffset, absEncoderOffsetForZeroEncoderUnits, first, second, defaultNeutralMode);
antiGravK = antigravityCoefficent;
degreesToEncoderUnitsRatio = degToEncoderUnitsRatio;
}


private double euToDegrees(final double eu) {
return eu * degreesToEncoderUnitsRatio;
}

public void runPIDs(){
updateAntigrav(antiGravK * Math.sin(euToDegrees(getHallSensorPosition())));
run();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
package com.team766.controllers;

import com.team766.config.ConfigFileReader;
import com.team766.hal.RobotProvider;
import edu.wpi.first.math.MathUtil;
import com.revrobotics.SparkMaxAbsoluteEncoder;
import com.revrobotics.SparkMaxPIDController;
import com.revrobotics.CANSparkMax.ControlType;
import com.revrobotics.CANSparkMax.IdleMode;
import com.revrobotics.SparkMaxAbsoluteEncoder.Type;
import com.ctre.phoenix.motorcontrol.NeutralMode;
import com.revrobotics.CANSparkMax;
import com.team766.hal.MotorController;
import com.team766.controllers.PIDState.*;
import com.team766.framework.Exceptions.*;


public abstract class ExtendableCanSparkMaxSmartMotionPIDController {
Comment thread
maxspier marked this conversation as resolved.
/*
* These are the hardware variables for the hardware we have on the robot.
* It includes a CanSparkMax, MotorController of any type, and a SparkMaxAbsoluteEncoder.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes it sound like the CanSparkMax and MotorController are different devices

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought they were? Motorcontroller is like the rev neo and CSM is the motorcontroller. This is bad naming. We should fix it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are the same device. They are even the same Java object - it is a CANSparkMaxMotorController, which extends CanSparkMax and implements MotorController, so it can be cast to either of those types

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e. why you can do csm = (CANSparkMax) mc; in the constructor

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. From past testing, this is what works with Maroon Framework. We could try it the other way, but I'm afraid that removing the MotorController declaration won't allow us to set power to the motors correctly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ryan's right; you can actually do away with mc as csm points to the same object, just specifically casted to expose extra CanSparkMax methods/properties.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whatever methods and properties MotorController has, CANSparkMax would too.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get this - but I think that the way we use the motor stuff from the config file makes this work better.

* @author Max Spier - 9/9/2023
*/
private MotorController mc;
private CANSparkMax csm;
private SparkMaxAbsoluteEncoder abs;

/*
* These are PID related variables that we will store locally to run PIDs
* We also create an object for the PIDController
* @author Max Spier - 9/9/2023
*/
private SparkMaxPIDController pid;
private double deadzone = 0;
private double setPointPosition = 0;
private double comboOfTimesInsideDeadzone = 0;
private double minPos = 0;
private double maxPos = 0;

/*
* These are some variables that we can use so that we can reset the motor controller
* We use this so that we can get an accurate ratio for the hall encoder units to absolute encoder units.
* @author Max Spier - 9/9/2023
*/
private double encoderUnitsPerOneAbsolute = 0;
Comment thread
maxspier marked this conversation as resolved.

private double curAntigrav = 0;

private NeutralMode defaultNeutralMode;


/*
* The state of the PID controller so that we know whether to call the respective method for each state.
* For more documentation, see the PIDState class.
* @author Max Spier - 9/9/2023
*/

private PIDState theState = PIDState.OFF;

/*
* Default constructor for the class. This is used to create a new CanSparkMaxSmartMotionPIDController object
* @param configName the configuration name for the motorcontroller
* @param absEncoderOffset the offset (ranging from 0.000 - 0.999) of the absolute encoder
* @param absEncoderOffsetForZeroEncoderUnits the offset that the absolute encoder should have in order for the relative encoder on the motorcontroller to equal zero.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in what case would absEncoderOffsetForZeroEncoderUnits not be 0?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want the arm to have 0 hall encoder units when the absolute encoder is at 0.362, so 0.362 is the absEncoderOffsetForZeroEncoderUnits value.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why wouldn't we set absEncoderOffset so that 0 is 0?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could if we wanted, but this makes it easier if, for example, a person installs the encoder wrong and it is off by 0.203 units, so we can use this to reset that. Even if we wanted 0 to be 0, it isn't much more work to add that in, and later we could also overload the constructor to make that default 0.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the motor encoder does not have a persistent offset - it just measures changes in position. you call mc.setSensorPosition(relEncoder); in the constructor to set it to whatever starting value you want, and then the value changes from there as the sensor detects changes in position.

so the only way to install it wrong would be to have it inverted (so moving the mechanism results in increasing values instead of decreasing and vice versa).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I don't understand what your saying -- lets talk on Saturday

* @param first the first offsetpoint used to reset the encoders - for more info see the OffsetPoint class
* @param second the second offsetpoint used to reset the encoders - for more info see the OffsetPoint class
* @author Max Spier - 9/9/2023
*/


public ExtendableCanSparkMaxSmartMotionPIDController(final String configName, final double absEncoderOffset, final double absEncoderOffsetForZeroEncoderUnits, final OffsetPoint first, final OffsetPoint second, final NeutralMode defaultNeutralMode) {
try {
this.defaultNeutralMode = defaultNeutralMode;
mc = RobotProvider.instance.getMotor(configName);
csm = (CANSparkMax) mc;
pid = csm.getPIDController();
abs = csm.getAbsoluteEncoder(Type.kDutyCycle);
abs.setZeroOffset(absEncoderOffset);

double absoluteDifference = second.getAbsoluteValue() - first.getAbsoluteValue();
double motorEncoderDiference = second.getMotorEncoderValue() - first.getMotorEncoderValue();

encoderUnitsPerOneAbsolute = motorEncoderDiference / absoluteDifference;

double relEncoder = absToEu(abs.getPosition() - absEncoderOffsetForZeroEncoderUnits);

mc.setSensorPosition(relEncoder);

mc.setNeutralMode(defaultNeutralMode);
} catch (IllegalArgumentException ill) {
throw new AbstractPIDRuntimeException("Error instantiating the PID controller: " + ill);
}
}

/*
* Method to convert the absolute encoder units into hall encoder units
* @author Max Spier - 9/9/2023
*/
private double absToEu(final double abs) {

if(encoderUnitsPerOneAbsolute == 0){
throw new AbstractPIDArithmeticDevideByZeroException("Error: encoderUnitsPerOneAbsolute is zero.");
}
return encoderUnitsPerOneAbsolute * abs;
}

/*
* This is a method to get the hall sensor position from the motorcontroller, so we can use it in the antigravity calculations in the subclass.
* @return the value of the hall sensor position
* @author Max Spier - 9/13/2023
*/
protected double getHallSensorPosition(){
return mc.getSensorPosition();
}

/*
* Method to change all PIDF values at once
* @params p-ff the values to set each one for the PIDController
* @author Max Spier - 9/9/2023
*/
public void setPIDF(final double p, final double i, final double d, final double ff) {
pid.setP(p);
pid.setI(i);
pid.setD(d);
pid.setFF(ff);
}

/*
* Method to change the P value of the PIDController
* @param p the value of P to set for the PIDController
* @author Max Spier - 9/9/2023
*/
public void setP(final double p) {
pid.setP(p);
}

/*
* Method to change the I value of the PIDController
* @param i the value of I to set for the PIDController
* @author Max Spier - 9/9/2023
*/
public void setI(final double i) {
pid.setI(i);
}

/*
* Method to change the D value of the PIDController
* @param d the value of D to set for the PIDController
* @author Max Spier - 9/9/2023
*/
public void setD(final double d) {
pid.setD(d);
}

/*
* Method to change the FF value of the PIDController
* @param ff the value of FF to set for the PIDController
* @author Max Spier - 9/9/2023
*/
public void setFF(final double ff) {
pid.setFF(ff);
}

/*
* Method to update the value of the deadzone for the PIDController
* This deadzone is in hall encoder units.
* @param dz the value of the deadzone in hall encoder units
* @author Max Spier - 9/9/2023
*/
public void setDeadzone(final double dz) {
deadzone = dz;
}

/*
* This is a method to update the minimum and maximum output ranges of motorpower for the mechanism
* @param min the minimum value for motor power (make sure that it is negative if you want the mechanism to be able to go both directions)
* @param max the maximum value for motor power (make sure that it is positive if you want the mechanism to be able to go both directions)
* @author Max Spier - 9/9/2023
*/
public void setOutputRange(final double min, final double max) {
pid.setOutputRange(min, max);
}

/*
* This is the method to set the minimum and maximum locations of the mechanism.
* Please check your subclasses documentation for what units this is supposed to be in (usually whichever one is used as an input for the setSetpoint method)
* @author Max Spier - 9/9/2023
*/
public void setMinMaxLocation(final double min, final double max) {
maxPos = max;
minPos = min;
}

/*
* This method is used to set the maximum velocity of the mechanism for use with PID
* @param max the value of the maximum amount of velocity for the motorcontroller
* The method also sets the minimum velocity to zero, as a failsafe.
* @author Max Spier - 9/9/2023
*/
public void setMaxVelocity(final double max) {
pid.setSmartMotionMaxVelocity(max, 0);
pid.setSmartMotionMinOutputVelocity(0, 0);
}

/*
* This is the method to set the maximum acelleration of the robot for the PIDController
* @param max the value for the maximum acelleration
* @author Max Spier - 9/9/2023
*/
public void setMaxAccel(final double max) {
pid.setSmartMotionMaxAccel(max, 0);
}

/*
* This is the method where you update the setpoint position from the subclass
* @param x the setpoint
* @author Max Spier - 9/9/2023
*/
public void setNewSetpoint(double x){
x = MathUtil.clamp(x, minPos, maxPos);
setPointPosition = x;
}

/*
* Failsafe for the PIDController to stop it.
* @author Max Spier - 9/9/2023
*/
public void stop() {
theState = PIDState.OFF;
}

/*
* This method does the antigrav
* @author Max Spier - 9/9/2023
*/
private void antigrav(){
mc.set(curAntigrav);
}

/*
* This method sets the antigrav power amount.
* It gets the value for this from the subclass
* @param passedValueFromSubclass the power to set the motorcontroller for antigrav
* @author Max Spier - 9/9/2023
*/
protected void updateAntigrav(double passedValueFromSubclass){
curAntigrav = passedValueFromSubclass;
}

public void disableAntigrav(){
curAntigrav = 0;
deadzone = 0;
}

/*
Comment thread
maxspier marked this conversation as resolved.
* This is the run loop that actually runs the PID Controller
* You need to call this as frequently as possible when running the mechanism
* @author Max Spier - 9/9/2023
*/
public void run() {
switch (theState) {
case OFF:
mc.set(0);
break;
case ANTIGRAV:
if (setPointPosition <= (deadzone + mc.getSensorPosition()) && setPointPosition >= (mc.getSensorPosition() - deadzone)) {
antigrav();
} else {
theState = PIDState.PID;
}
case PID:
if (setPointPosition <= (deadzone + mc.getSensorPosition()) && setPointPosition >= (mc.getSensorPosition() - deadzone)) {
comboOfTimesInsideDeadzone++;
} else {
comboOfTimesInsideDeadzone = 0;
pid.setReference(setPointPosition, ControlType.kSmartMotion);
}

if (comboOfTimesInsideDeadzone >= 6) {
theState = PIDState.ANTIGRAV;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a flag to disable antigrav if its not needed

also, I realized Brake mode is missing

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finished brake

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finished all

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you did not push your changes

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no i did

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does it look?

}
break;
default:
throw new AbstractPIDRuntimeException("Invalid state error");
}
}

public String toString(){
return "Setpoint: " + setPointPosition + " Current Position: " + mc.getSensorPosition() + " Current State: " + theState;
}
}
31 changes: 31 additions & 0 deletions src/main/java/com/team766/controllers/OffsetPoint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.team766.controllers;
/*
* This is a class to make an offset point for the PID controller to be able to reset encoders.
* You input the absoluteEncoderValue that equals the motorEncoderValue.
* @author Max Spier - 9/12/23
*/
public class OffsetPoint {
Comment thread
maxspier marked this conversation as resolved.
Comment thread
maxspier marked this conversation as resolved.

private double absoluteValue, motorValue;

public OffsetPoint(final double absoluteEncoderValue, final double motorEncoderValue) {
absoluteValue = absoluteEncoderValue;
motorValue = motorEncoderValue;
}

public double getAbsoluteValue() {
return absoluteValue;
}

public double getMotorEncoderValue() {
return motorValue;
}

/*
*@Override
*@author Max Spier - 9/15/2023
*/
public String toString(){
return "Absolute Value: " + absoluteValue + " Motor Value: " + motorValue;
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/team766/controllers/PIDState.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.team766.controllers;

public enum PIDState {
PID,
OFF,
ANTIGRAV
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.team766.framework.Exceptions;

public class AbstractPIDArithmeticDevideByZeroException extends RuntimeException{
public AbstractPIDArithmeticDevideByZeroException (String errorMessage) {
super(errorMessage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.team766.framework.Exceptions;

public class AbstractPIDRuntimeException extends RuntimeException {
Comment thread
maxspier marked this conversation as resolved.
public AbstractPIDRuntimeException (String errorMessage) {
super(errorMessage);
}
}