Autonomous Problem - Motor Controllers Starting & Stopping (Java)

JAVA COMMAND BASED HELP NEEDED!

Today, while testing our simple autonomous code (we just have it set to move forward 1.5 meters), we noticed a bit of a problem. The robot wasn’t running as smoothly as it does in teleop. When we put it on blocks to diagnose the problem, we noticed that it was running at the indicated speed, temporarily stopping, and then resuming. We assume that this is for each scheduler run, and we’re not sure why this is happening as the command we are running is not ending.

We have a suspicion it has something to do with the new CommandScheduler - I’m not entirely sure where to put “CommandScheduler.getInstance().run().” I have a suspicion that it may have to do with something related to CAN, as we are getting warnings in our console log regarding CAN devices quite frequently (although they are found, I’m not entirely sure what the errors are about).

I remember having a similar problem in testing two years back, and I’m not quite sure what we did to fix the problem. Does anyone have any suggestions or comments? Any help would be greatly appreciated!

Does you auto require the drivebase?

Well yes, it basically just runs a wrapper command for drivetrain.drive with a certain speed.`

@Override
public void autonomousInit() {

autonomousCommand = startingLoc.getSelected();

if (autonomousCommand != null) {
  autonomousCommand.schedule();
}
CommandScheduler.getInstance().run();

}

/**

  • This function is called periodically during autonomous.
    */
    @Override
    public void autonomousPeriodic() {
    CommandScheduler.getInstance().run();
    }

(With startingLoc.getSelected() being a call to a wrapper command for drivetrain.drive(.5, .5))

Again, this works flawlessly in teleop when we use our joystick, however this code is buggy.

Please post all the code.

Do you use theDifferentialDrive class in teleop? If so the safety feature might be disabling your motors in auto. (purely hypothetical guess based on what I’ve seen before)

`package frc.robot;

import edu.wpi.cscore.UsbCamera;
import edu.wpi.cscore.VideoMode.PixelFormat;
import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.TimedRobot;
import edu.wpi.first.wpilibj.I2C.Port;
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
import edu.wpi.first.wpilibj2.command.RamseteCommand;
import frc.robot.autonomous.BasicLeftAuto;
import frc.robot.autonomous.BasicMiddleAuto;
import frc.robot.autonomous.BasicRightAuto;
import frc.robot.autonomous.PathWeaverTrajectories;
import frc.robot.commands.AutoDrive;
import frc.robot.subsystems.Climber;
import frc.robot.subsystems.DriveTrain;
import frc.robot.subsystems.LawnMower;
import frc.robot.subsystems.LightStrip;
import frc.robot.subsystems.WheelOfFortuneContestant;
import frc.robot.subsystems.LightsArduino;
import java.util.ArrayList;
import libs.IO.ThrustmasterJoystick;
import libs.IO.XboxController;

/**

  • The VM is configured to automatically run this class, and to call the
  • functions corresponding to each mode, as described in the TimedRobot
  • documentation. If you change the name of this class or the package after
  • creating this project, you must also update the build.gradle file in the
  • project…
    */
    public class Robot extends TimedRobot {

// Declare subsystems
public static DriveTrain drivetrain;
public static LawnMower lawnmower;
public static WheelOfFortuneContestant wheeloffortunecontestant;
private static double currentAngle;
public static LightsArduino lights;
public static LightStrip lightStrip;
public static Climber climber;

//FMS Game Data for Position Control
public static String gameData;

//Declare joysticks
public static ThrustmasterJoystick mainController;
public static XboxController auxController;

//Declare Shuffleboard Dropdowns for autonomous
public static SendableChooser startingLoc = new SendableChooser<>();
public static SendableChooser preLoaded = new SendableChooser<>();
//public static SendableChooser alliance = new SendableChooser<>();

//Declare autonomous command
private Command autonomousCommand;

//USB Camera declarations
public static CameraServer camserv;
public static UsbCamera camPrimary;
public static UsbCamera camSecondary;
/**

  • This function is run when the robot is first started up and should be
  • used for any initialization code.
    */

@Override
public void robotInit() {
drivetrain = new DriveTrain();
lawnmower = new LawnMower();
wheeloffortunecontestant = new WheelOfFortuneContestant();
climber = new Climber();

//lights
//lights = new LightsArduino(Port.kMXP, RobotMap.lightsI2CAddress);
//lightStrip = new LightStrip(RobotMap.lightsPWM, RobotMap.numOfLEDs);


drivetrain.calibrateGyro();
drivetrain.resetEncoders();
gameData = "";

//init joysticks
mainController = new ThrustmasterJoystick(RobotMap.ActualJoystick);
auxController = new XboxController(RobotMap.JoystickPortXBoxAux);
configButtonControls();

//Camera initializations
camserv = CameraServer.getInstance();

camPrimary = camserv.startAutomaticCapture("cam1", 0); //intake
//camera.setResolution(160, 90);
camPrimary.setFPS(14);
camPrimary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras

camSecondary = camserv.startAutomaticCapture("cam2", 2); //shooter
//camera.setResolution(160, 90);
camSecondary.setFPS(14);
camSecondary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras

startingLoc.addOption("Left", new BasicLeftAuto());
startingLoc.addOption("Middle", new BasicMiddleAuto());
startingLoc.addOption("Right", new BasicRightAuto());
startingLoc.addOption("Opposite", new AutoDrive(-0.5, 1.5));

/*
startingLoc.addOption("Left", new SequentialCommandGroup(
  PathWeaverTrajectories.getRamseteCommand(createTrajectory(PathWeaverTrajectories.BlueTrajectories[0])),
  new AutoBallDump(),
  PathWeaverTrajecotires.getRamseteCommand(createTrajectory(PathWeaverTrajectories.BlueTrajectories[3]))
));
startingLoc.addOption("Middle", new SequentialCommandGroup(
  PathWeaverTrajectories.getRamseteCommand(createTrajectory(PathWeaverTrajectories.BlueTrajectories[1])),
  new AutoBallDump(),
  PathWeaverTrajectories.getRamseteCommand(createTrajectory(PathWeaverTrajectories.BlueTrajectories[3]))
));
startingLoc.addOption("Right", new SequentialCommandGroup(
  PathWeaverTrajectories.getRamseteCommand(createTrajectory(PathWeaverTrajectories.BlueTrajectories[2])),
  new AutoBallDump(),
  PathWeaverTrajectories.getRamseteCommand(createTrajectory(PathWeaverTrajectories.BlueTrajectories[3]))
));
*/

preLoaded.addOption("0", 0);
preLoaded.addOption("1", 1);
preLoaded.addOption("2", 2);
preLoaded.addOption("3", 3);

/*
alliance.addOption("Blue", "Blue");
alliance.addOption("Red", "Red");
*/
CommandScheduler.getInstance().run();

}
/**

  • This function is called every robot packet, no matter the mode. Use
  • this for items like diagnostics that you want ran during disabled,
  • autonomous, teleoperated and test.
  • This runs after the mode specific periodic functions, but before

  • LiveWindow and SmartDashboard integrated updating.
    */
    @Override
    public void robotPeriodic() {
    gameData = DriverStation.getInstance().getGameSpecificMessage();
    //changePrimaryCamera();
    //allCameraChange();
//Gyro stuff
if(drivetrain.getGyroReading()%360 == 0)
{
  currentAngle = drivetrain.getGyroReading();
} else {
  currentAngle = Math.abs(drivetrain.getGyroReading()%360);
}

SmartDashboard.putNumber("Gyro Reading", drivetrain.getGyroReading());
SmartDashboard.putNumber("Balls in Lawn Mower", lawnmower.getCounter());
SmartDashboard.putBoolean("Conveyor Not Moving", lawnmower.positionOverride());
SmartDashboard.putData("Starting Location", startingLoc);
SmartDashboard.putData("Balls Pre-Loaded", preLoaded);
SmartDashboard.putNumber("Encoder left", drivetrain.leftPosition.get());
SmartDashboard.putNumber("Encoder right", drivetrain.rightPosition.get());

CommandScheduler.getInstance().run();

}

/**

  • This autonomous (along with the chooser code above) shows how to select
  • between different autonomous modes using the dashboard. The sendable
  • chooser code works with the Java SmartDashboard. If you prefer the
  • LabVIEW Dashboard, remove all of the chooser code and uncomment the
  • getString line to get the auto name from the text box below the Gyro
  • You can add additional auto modes by adding additional comparisons to

  • the switch structure below with additional strings. If using the
  • SendableChooser make sure to add them to the chooser code above as well.
    */
    @Override
    public void autonomousInit() {
autonomousCommand = startingLoc.getSelected();

if (autonomousCommand != null) {
  autonomousCommand.schedule();
}
CommandScheduler.getInstance().run();

}

/**

  • This function is called periodically during autonomous.
    */
    @Override
    public void autonomousPeriodic() {
    CommandScheduler.getInstance().run();
    }

@Override
public void teleopInit() {
if (autonomousCommand != null) {
autonomousCommand.cancel();
}
CommandScheduler.getInstance().run();
}

/**

  • This function is called periodically during operator control.
    */
    @Override
    public void teleopPeriodic() {
    CommandScheduler.getInstance().run();
    }

/**

  • This function is called periodically during test mode.
    */
    @Override
    public void testPeriodic() {
    }

public static double getCurrentAngle() {
return currentAngle;
}

private void configButtonControls() {
//Main buttons
mainController.rightPadBottom3.whenPressed(() -> drivetrain.toggleDriveDirection());
mainController.rightPadBottom2.whenPressed(() -> lawnmower.resetCounter());

//Aux buttons
auxController.a.whenPressed(() -> wheeloffortunecontestant.spinPC(1)).whenReleased(() -> wheeloffortunecontestant.spinPC(0));
auxController.b.whenPressed(() -> lawnmower.moveConveyor(-0.2)).whenReleased(() -> lawnmower.moveConveyor(0));
auxController.x.whenPressed(() -> wheeloffortunecontestant.spinRC(1)).whenReleased(() -> wheeloffortunecontestant.spinRC(0));
auxController.y.whenPressed(() -> lawnmower.ballDump(0.6)).whenReleased(() -> lawnmower.ballDump(0));
auxController.back.whenPressed(() -> wheeloffortunecontestant.extendContestant());
auxController.back.whenPressed(() -> changeSecondaryCamera(4));
auxController.start.whenPressed(() -> wheeloffortunecontestant.retractContestant());
Robot.auxController.leftBumper.whenPressed(() -> climber.extendHook());
Robot.auxController.leftBumper.whenPressed(() -> changeSecondaryCamera(3));
Robot.auxController.rightBumper.whenPressed(() -> climber.retractHook());

}

public void changePrimaryCamera() //toggle between intake and shooter cameras with button
{
int camCounter = 0;
if(mainController.headLeft.get()){
if(camCounter == 0)
camPrimary = camserv.startAutomaticCapture(“cam1”, 0); //intake
//camera.setResolution(160, 90);
camPrimary.setFPS(14);
camPrimary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
camCounter = 1;
}
if(camCounter == 1){
camPrimary = camserv.startAutomaticCapture(“cam2”, 2); //shooter
//camera.setResolution(160, 90);
camPrimary.setFPS(14);
camPrimary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
camCounter = 0;
}
}

public void changeSecondaryCamera(int cam) //toggle between colorsensor and climber cameras automatically
{
if(cam == 4) {
camSecondary = camserv.startAutomaticCapture(“cam4”, 4); //colorSensor
//camera.setResolution(160, 90);
camSecondary.setFPS(14);
camSecondary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
}
if(cam == 3) {
camSecondary = camserv.startAutomaticCapture(“cam3”, 3); //climber
//camera.setResolution(160, 90);
camSecondary.setFPS(14);
camSecondary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
}
}

public void allCameraChange() //switches between all cameras manually
{
int camCounter = 0;
if(mainController.headRight.get()) {
if(camCounter == 0) {
camSecondary = camserv.startAutomaticCapture(“cam1”, 0); //intake
//camera.setResolution(160, 90);
camSecondary.setFPS(14);
camSecondary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
camCounter = 1;
}
if(camCounter == 1){
camSecondary = camserv.startAutomaticCapture(“cam2”, 2); //shooter
//camera.setResolution(160, 90);
camSecondary.setFPS(14);
camSecondary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
camCounter = 0;
}
if(camCounter == 2) {
camSecondary = camserv.startAutomaticCapture(“cam3”, 3); //climber
//camera.setResolution(160, 90);
camSecondary.setFPS(14);
camSecondary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
}
if(camCounter == 3) {
camSecondary = camserv.startAutomaticCapture(“cam4”, 4); //colorSensor
//camera.setResolution(160, 90);
camSecondary.setFPS(14);
camSecondary.setPixelFormat(PixelFormat.kYUYV); //formats video specifications for cameras
}
}
}
}

I’m sorry there is likely an easier to read way to post this, but this is our Robot class.

Yeah someone on our team spotted that, we turned off the safety feature in the constructor of DriveTrain and it still didn’t work. We were in such a rush (under lots of pressure to give the robot over to our drive team for their practice) that we may not have tested it properly; I’ll give it another shot tomorrow with that in mind.

package frc.robot.subsystems;

import java.util.function.Supplier;

import com.ctre.phoenix.motorcontrol.ControlMode;
import com.ctre.phoenix.motorcontrol.FeedbackDevice;
import com.ctre.phoenix.motorcontrol.InvertType;
import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX;
import com.ctre.phoenix.motorcontrol.can.WPI_VictorSPX;

import edu.wpi.first.wpilibj.ADXRS450_Gyro;
import edu.wpi.first.wpilibj.SPI;
import edu.wpi.first.wpilibj.SpeedControllerGroup;
import edu.wpi.first.wpilibj.controller.PIDController;
import edu.wpi.first.wpilibj.controller.SimpleMotorFeedforward;
import edu.wpi.first.wpilibj.geometry.Pose2d;
import edu.wpi.first.wpilibj.geometry.Rotation2d;
import edu.wpi.first.wpilibj.interfaces.Gyro;
import edu.wpi.first.wpilibj.kinematics.DifferentialDriveKinematics;
import edu.wpi.first.wpilibj.kinematics.DifferentialDriveOdometry;
import edu.wpi.first.wpilibj.kinematics.DifferentialDriveWheelSpeeds;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import frc.robot.Robot;
import frc.robot.Constants.*;

public class DriveTrain extends SubsystemBase {

//Motor controllers
private static WPI_TalonSRX leftMaster;
private static WPI_VictorSPX leftSlave;
private static WPI_TalonSRX rightMaster;
private static WPI_VictorSPX rightSlave;

private static SpeedControllerGroup leftMotors;
private static SpeedControllerGroup rightMotors;

//Gyro
private final Gyro gyro = new ADXRS450_Gyro(SPI.Port.kOnboardCS0);

//Pathplanning
private static DifferentialDriveKinematics kinematics;
private static DifferentialDriveOdometry odometry;
private static SimpleMotorFeedforward feedforward;

private static PIDController leftPIDController;
private static PIDController rightPIDController;

private static double yVal;
private static double twistVal;
private static double yReduction;
private static double twistReduction;

//Encoder methods
public Supplier leftPosition;
public Supplier rightPosition;
public Supplier leftRate;
public Supplier rightRate;

//Gyro mehtods
public Supplier headingDegrees;
public Supplier headingRotation2d;

//Misc
private DriveDirection currentDirection = DriveDirection.FORWARD;

public DriveTrain() {
leftMaster = new WPI_TalonSRX(RobotMap.DMLeftMaster);
leftSlave = new WPI_VictorSPX(RobotMap.DMLeftSlave);
rightMaster = new WPI_TalonSRX(RobotMap.DMRightMaster);
rightSlave = new WPI_VictorSPX(RobotMap.DMRightSlave);

leftMaster.configSelectedFeedbackSensor(FeedbackDevice.CTRE_MagEncoder_Absolute, 0, 10);
rightMaster.configSelectedFeedbackSensor(FeedbackDevice.CTRE_MagEncoder_Absolute, 0, 10);

leftMaster.setSensorPhase(false);
rightMaster.setSensorPhase(false);

leftPosition = () -> leftMaster.getSelectedSensorPosition(0) * PathConstants.kEncoderDPP; //r
leftRate = () -> leftMaster.getSelectedSensorVelocity(0) * PathConstants.kEncoderDPP * 10; //r
rightPosition = () -> rightMaster.getSelectedSensorPosition(0) * PathConstants.kEncoderDPP; //l
rightRate = () -> rightMaster.getSelectedSensorVelocity(0) * PathConstants.kEncoderDPP * 10; //l

headingDegrees = () -> -gyro.getAngle();
headingRotation2d = () -> Rotation2d.fromDegrees(-gyro.getAngle());

leftSlave.follow(leftMaster);
rightSlave.follow(rightMaster);

leftMotors = new SpeedControllerGroup(leftMaster, leftSlave);
rightMotors = new SpeedControllerGroup(leftMaster, leftSlave);

setDriveDirection(DriveDirection.FORWARD);

kinematics = new DifferentialDriveKinematics(PathConstants.kTrackWidthMeters);
odometry = new DifferentialDriveOdometry(getAngle());
feedforward = new SimpleMotorFeedforward(PathConstants.kS, PathConstants.kV, PathConstants.kA);

leftPIDController = new PIDController(PathConstants.kDriveP, 0, 0);
leftPIDController = new PIDController(PathConstants.kDriveP, 0, 0);

leftMaster.setSafetyEnabled(false);
rightMaster.setSafetyEnabled(false);

}

public void drive(double leftPower, double rightPower) {
leftMaster.set(ControlMode.PercentOutput, leftPower);
rightMaster.set(ControlMode.PercentOutput, rightPower);
}

public void driveVolts(double leftVolts, double rightVolts) {
leftMotors.setVoltage(leftVolts);
rightMotors.setVoltage(rightVolts);
}

public void setDriveDirection(DriveDirection driveDirection) {
if (driveDirection == DriveDirection.FORWARD) {
leftMaster.setInverted(false);
rightMaster.setInverted(true);
} else {
leftMaster.setInverted(true);
rightMaster.setInverted(false);
}
leftSlave.setInverted(InvertType.FollowMaster);
rightSlave.setInverted(InvertType.FollowMaster);
}

public void toggleDriveDirection() {
if (currentDirection == DriveDirection.FORWARD) {
leftMaster.setInverted(false);
rightMaster.setInverted(true);
} else {
leftMaster.setInverted(true);
rightMaster.setInverted(false);
}
leftSlave.setInverted(InvertType.FollowMaster);
rightSlave.setInverted(InvertType.FollowMaster);
}

public void resetEncoders() {
leftMaster.setSelectedSensorPosition(0);
rightMaster.setSelectedSensorPosition(0);
}

public DifferentialDriveWheelSpeeds getWheelSpeeds() {
return new DifferentialDriveWheelSpeeds(
leftRate.get(),
rightRate.get()
);
}

/*

  • gyro methods
    */
    public Rotation2d getAngle() {
    return Rotation2d.fromDegrees(-gyro.getAngle());
    }

public void calibrateGyro() {
gyro.calibrate();
}

public void resetGyro() {
gyro.reset();
}

/*

  • odometry methods
    */
    public Pose2d getPoseMeters() {
    return odometry.getPoseMeters();
    }

public void resetOdometry(Pose2d pose) {
odometry.resetPosition(pose, getAngle());
}

@Override
public void periodic() {
//Joystick drive
yReduction = Robot.mainController.trigger.get() ? 0.5 : 1;
twistReduction = Robot.mainController.trigger.get() ? 0.4 : 0.5;

yVal = Robot.mainController.getY() * yReduction;
twistVal = Robot.mainController.getTwist() * twistReduction;

if (!Robot.mainController.trigger.get()) {
  drive(yVal+twistVal, yVal-twistVal);
} else {
  drive(-(yVal+twistVal), -(yVal-twistVal));
}

//Path planning
odometry.update(getAngle(), leftPosition.get(), rightPosition.get());

}

public double getGyroReading() {
return gyro.getAngle();
}

/*

  • path planning accessors
    */
    public DifferentialDriveKinematics getKinematics() {
    return kinematics;
    }

public DifferentialDriveOdometry getOdometry() {
return odometry;
}

public SimpleMotorFeedforward getFeedforward() {
return feedforward;
}

public PIDController getLeftPIDController() {
return leftPIDController;
}

public PIDController getRightPIDController() {
return rightPIDController;
}

enum DriveDirection {
FORWARD,
BACKWARD
}
}

Our DriveTrain class
I apologize, I understand if you don’t want to read through all of this in the way it is formatted.

Finally, the Command we are running

package frc.robot.commands;

import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj2.command.CommandBase;
import frc.robot.Robot;
import frc.robot.Constants.PathConstants;
import frc.robot.subsystems.DriveTrain;

public class AutoDrive extends CommandBase {

private DriveTrain driveTrain;
private double speed;
private double distance;

public AutoDrive(double speed, double distance) {
addRequirements(Robot.drivetrain);
this.speed = speed;
this.distance = distance;
}

// Called when the command is initially scheduled.
@Override
public void initialize() {
driveTrain = Robot.drivetrain;
// startTime = Timer.getFPGATimestamp();
}

// Called every time the scheduler runs while the command is scheduled.
@Override
public void execute() {
driveTrain.drive(speed, speed);
}

// Called once the command ends or is interrupted.
@Override
public void end(boolean interrupted) {
driveTrain.drive(0, 0);
}

// Returns true when the command should end.
@Override
public boolean isFinished() {
return Math.abs(distance - driveTrain.rightPosition.get()) < PathConstants.kDriveTolerance;
}
}

It’s way easier if you just post a link to the GitHub repo.

I believe it’s your periodic function in DriveTrain: https://github.com/team178/2020RobotCode/blob/7de4faef9f50023dea5bd65eff39b73f4781d8c0/src/main/java/frc/robot/subsystems/DriveTrain.java#L185. In auto, periodic still runs, which pulls data from the controllers. However, the data from the controllers are always 0, which causes periodic to command the drive train to stop. Your actual auto command then tries to set it to a certain speed. In the end, this happens every loop which would explain the behaviours you are seeing.

A solution would be to put teleop driving in a new command.

1 Like

We had similar issues… what we found was we had made an invalid assumption and our autonomous code was fighting with our teleop code. Of course since the teleop code uses the Joystick and the Josticks return zeros for axis input the teleop code was constantly telling the robot to stop while the auton code was telling it to go.

1 Like

I’m sure this will be the solution! Is there any way we can do it without creating a new command? We’ve been straying away from wrapper commands this year (using the periodic method, lambda expressions for lots of our controls). It’s fine if there isn’t, we can create a new wrapper command, I’m just curious.

Yes, I’m sure this is it. Thank you for the assistance!

Our student hacked it by putting a flag on the subsystem “setAutoMode” which then skipped the teleop code… I cringed but it worked and we scored a lot of auton points.

2 Likes

You can use RobotState.isOperatorControl() in your periodic method to check if you are in teleop. https://first.wpi.edu/FRC/roborio/release/docs/java/edu/wpi/first/wpilibj/RobotState.html#isOperatorControl()

1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.