-
Notifications
You must be signed in to change notification settings - Fork 4
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
Encoders! #9
Conversation
public static final int bLeftMotorPort = 14; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra line?
Resources for the odometry portion of this PR
|
@@ -42,6 +43,7 @@ | |||
|
|||
// Controllers | |||
private XboxController controlXbox = new XboxController(0); | |||
private JoystickButton xboxAButton = new JoystickButton(controlXbox, XboxController.Button.kA.value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not use the controller directly, is that not possible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://docs.wpilib.org/en/stable/docs/software/commandbased/binding-commands-to-triggers.html
https://first.wpi.edu/FRC/roborio/beta/docs/java/edu/wpi/first/wpilibj/XboxController.html#getAButtonPressed--
I think the JoystickButton
class just wraps the XboxController
's button methods so you can do event based "when pressed" stuff instead of having to check periodically whether the button was pressed using getAButtonPressed()
and then going from there. Je crois que setting up button bindings via JoystickButton
is the reason for the controllerBindings
method.
// for the third. | ||
tankSubsystem.zeroPosition(); | ||
|
||
tankSubsystem.setCarDrivePowers(0.5, 0.0); | ||
} | ||
|
||
@Override | ||
public boolean isFinished() { | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
big lemon
@@ -20,6 +30,14 @@ | |||
private final WPI_TalonSRX rightMain; | |||
private final WPI_TalonSRX rightFollow; | |||
|
|||
private final AHRS ahrs; | |||
|
|||
private final DifferentialDrivePoseEstimator odometry; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in another comment I mentioned "all localization stuff"... we should take all the localization logic and put it in its own class and run it on its own thread. logically and from my experience, dead reckoning is more accurate the less time each loop is -- no matter your odometry method (e.g. circular), you're making an assumption about what happens between each tick, so reducing the tick interval reduces the fudginess of your guess.
if we use the periodic() method, the commandbased system actively waits until an interval is hit before calling periodics, it's something like 20ms by default? i can't remember
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I second the localization system approach.
rightMain.setSelectedSensorPosition(0); | ||
|
||
// https://first.wpi.edu/wpilib/allwpilib/docs/release/java/edu/wpi/first/wpilibj/estimator/DifferentialDrivePoseEstimator.html#resetPosition(edu.wpi.first.wpilibj.geometry.Pose2d,edu.wpi.first.wpilibj.geometry.Rotation2d) | ||
odometry.resetPosition(new Pose2d(), Rotation2d.fromDegrees(ahrs.getAngle())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not reset the gyro
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The gyroscope angle does not need to be reset here on the user's robot code. The library automatically takes care of offsetting the gyro angle.
And the angle was reset to 0 during testing so it seems to work.
@@ -70,7 +72,7 @@ public RobotContainer() { | |||
tankSubsystem = new TankSubsystem(); | |||
|
|||
// Instantiate commands | |||
tankCommand = new DriveTankCommand(tankSubsystem, 0, 0); | |||
tankCommand = new DriveTankCommand(tankSubsystem, 12); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this "12" related to the "12 inches" comment on L117?
I don't love magic numbers, but a comment here would be helpful if you don't want to make this a well-named constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the idea was for it to drive forward "12 inches" in autonomous to then measure that distance and check if the constant was working properly, but the different speeds on each side prevented that from really happening. I'll add a comment to this.
|
||
private final DifferentialDrivePoseEstimator odometry; | ||
|
||
public static final double ENCODER_TICKS_TO_INCHES = 32 / 142.40; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fortunately you have the .40
in this equation, otherwise the result is 0
. Ask me how I know and how many hours I spent hunting for this bug.
If you have integer division, you get an integer result.
double leftDistance = leftMain.getSelectedSensorPosition() * ENCODER_TICKS_TO_INCHES; | ||
double rightDistance = rightMain.getSelectedSensorPosition() * ENCODER_TICKS_TO_INCHES; | ||
|
||
odometry.update(gyroAngle, wheelVelocities, leftDistance, rightDistance); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this interface isn't great. We're passing in a DifferentialDriveWheelSpeeds
object and then separate positions for left and right wheels. These two interfaces should match. I know this isn't your interface, but keep this in mind.
|
||
odometry.update(gyroAngle, wheelVelocities, leftDistance, rightDistance); | ||
|
||
System.out.println(odometry.getEstimatedPosition()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe print out a little text for context in the logs/terminal?
|
public void setMotorVoltages(double left, double right) { | ||
// TODO: stub on purpose, see comment in FollowPathCommand | ||
// This doesn't really match our current interface, but neither does the other option; | ||
// Should a state on this subsystem be added to switch between voltage and percent output? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, instead of tankSubsystem
containing states and continually setting the motor controller output in periodic
, the motor controllers can be the ones to store the state and methods can just set their values. Instead of
private int leftPower;
private int rightPower;
public void setTankDrivePowers(double leftScale, double rightScale) {
this.leftPower = leftScale;
this.rightPower = rightScale;
}
@Override
public void periodic() {
// These must be in percent output mode
leftMain.set(leftPower);
rightMain.set(rightPower);
}
why not have
public void setTankDrivePowers(double leftScale, double rightScale) {
leftMain.set(leftScale);
rightMain.set(rightScale);
}
? This would also allow for more flexibility with the output mode, such as
public void setTankDrivePowers(double leftScale, double rightScale) {
leftMain.set(leftScale);
rightMain.set(rightScale);
}
public void setTankDriveVoltages(double leftVoltage, double rightVoltage) {
leftMain.setVoltage(leftVoltage);
rightMain.setVoltage(rightVoltage);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Allowing voltages would also resolve 1/2 of the current problems with the path following command.
Resources for the pathfinding portion of this PR
|
It seems like WPILib's path/trajectory things must be in meters (see PathWeaver export unit and all the WPILib trajectory docs) so I will convert the odometry to that as well. It seems like PathWeaver can have its interface be in feet or inches while exporting paths as meters, which should make the forced meterization of everything less painful. |
This commit will be overridden by using WPI's builtin odometry classes, but I am pushing it to keep it in history.
This can be tested and tuned over time
Wasn't able to test this that much because the drivetrain became possessed by ghosts, but can test next week on the actual drivetrain.
See comment in FollowPathCommand
Prepared to do https://docs.wpilib.org/en/stable/docs/software/wpilib-tools/robot-characterization/characterization-routine.html#running-the-characterization-routine and measure the rest on Sunday, then perhaps test finally!
These will probably have to be remeasured with the Robot Characterization tool. When testing pathfinding with these, the robot immediately swerves sharply to the left (which it shouldn't be doing). It might have something to do with the right encoder readings being inverted during characterization (left reports 4 meters, right reports -4), but I've tried setting various options in the config to try and fix that to no avail. Will definitely look into it further at some point.
Recharacterized using process described in https://www.chiefdelphi.com/t/the-future-of-pathweaver/393014/82. `Kp` might need to be tuned, as does `ENCODER_TICKS_TO_METERS` most likely.
Also push experimental changes to PID constants and auton testing, which still doesn't quite work
With the new REV version, CANSparkMaxes with the same can ID cannot be created (it throws errors which kill the robot program)
Hopefully these ones work better!
Closing(ish) thoughtsA lot of things made sense when I realized what A lot of these confusions could probably have been resolved sooner had I read the docs for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some constants to be fine tuned/changed, but Kevin's computer is not working so first merge.
I don't think constants need to be changed, I just wanted to test shuffleboard (which wasn't cooperating). I think launching it from driver station as opposed to vscode fixed the issue, so the branch can probably be deleted. |
KEVIN: Closing thoughts. A lot of things made sense when I realized what RamseteCommand and associated WPILib path following things actually did -- given a trajectory, the path following generates a list of left and right velocities for the drivetrain to follow the trajectory. My confusion from the PID oscillation stemmed from the assumption that the PID loop in the command was for position, so an oscillation would surely cause the robot to move back and forth; it never did because the PID loop was for velocity instead (this is why kI and kD were set to 0 in the example; accelerating to a target velocity is a use case for just a P controller). Oscillations due to a high kP were between 1.9m/s and 2.1m/s and not 1.9m and 2.1m so there was no back and forth driving. Furthermore, the confusion on why the robot stopped before the end position when constants were misconfigured can also be explained by realizing that the list of velocities probably ended, with the constants being incorrect leading to the robot not following the velocities properly and ending in an incorrect spot. A lot of these confusions could probably have been resolved sooner had I read the docs for RamseteController a little more carefully. * Initial testing * Add wheel circumference to hopefully calculate distance * Add position getting/setting, fix constants * Slow drive speed, zero sensors * Start odometry threading * Odometry package and class This commit will be overridden by using WPI's builtin odometry classes, but I am pushing it to keep it in history. * Use WPI odometry class * Small changes * navX AHRS * Merge left and right sensor methods to use odometry class * Change `new Pose2d()` to `getRobotPosition()` * Measure the constant! This can be tested and tuned over time * Bind A button to zero position * Change constant to inches, remeasure * Add better documentation * Remove joysticks from encoder branch * Readd odometry thread Wasn't able to test this that much because the drivetrain became possessed by ghosts, but can test next week on the actual drivetrain. * Talon -> Spark Max * Implement preliminary path following command See comment in FollowPathCommand * Remove states from `tankSubsystem` * Inches -> meters * Add secondary constructor to FollowPathCommand * Fix turning direction; remove CAN ID 0 * Edit to functional drivetrain state * Measure some constants Prepared to do https://docs.wpilib.org/en/stable/docs/software/wpilib-tools/robot-characterization/characterization-routine.html#running-the-characterization-routine and measure the rest on Sunday, then perhaps test finally! * Measure more constants! These will probably have to be remeasured with the Robot Characterization tool. When testing pathfinding with these, the robot immediately swerves sharply to the left (which it shouldn't be doing). It might have something to do with the right encoder readings being inverted during characterization (left reports 4 meters, right reports -4), but I've tried setting various options in the config to try and fix that to no avail. Will definitely look into it further at some point. * Revert constants, invert gyro, invert left motors * Fix inverted gyro error in resetPosition * New constants! Recharacterized using process described in https://www.chiefdelphi.com/t/the-future-of-pathweaver/393014/82. `Kp` might need to be tuned, as does `ENCODER_TICKS_TO_METERS` most likely. * Update WPILib and vendor packages to 2022 Also push experimental changes to PID constants and auton testing, which still doesn't quite work * Add preliminary shuffleboard code * Move odometry to `tankSubsystem` With the new REV version, CANSparkMaxes with the same can ID cannot be created (it throws errors which kill the robot program) * Measure new constants with sysid Hopefully these ones work better! * `Field2d`, new constants * Cleanup, remove elevator subsystem * Change angle entry to use a gyro complex widget Co-authored-by: pinkbluesky <[email protected]>
Resources
WPI_TalonSRX
docs (most methods to do with encoders are inTalonSRX
orBaseMotorController
whichWPI_TalonSRX
inherits)