Simple autonomous encoder program

We are trying to use encoders is year for the first time. For auto we need multiple programs which we have written but not tested. Could some one please check our code to see if it should work how we have witten it? Do we need to use a PID subsystem? If so how do we write it?

P.S: we are trying to avoid a complete rrewrite of the code

 Anything helps
    ~Walker Ward~

Our github: https://github.com/Phred7/SentinelSteamworks/tree/master/src/org/usfirst/frc2906/SentinelSteamworks

You are using while loops in some of the methods in your DriveTrain subsystem that run for an unknown amount of time. While those loops are running, nothing else will respond.

For a command based robot, you don’t really want to be doing any while loops or sleeps. Try to keep your subsystems very simple, move the smarts to your commands and avoid loops and sleeps/delays. I would suggest the following as a starting point on refactoring:

  • After constructing your Encoders, use the setDistancePerPulse() method so you can use the getDistance() method to retrieve a value in inches.
  • Add methods to your drive system so you can read the distance in inches on each encoder.
  • Refactor your DriveEncoders command so that it: reads the current encoder starting position in the initialize() method, applies power to the motors in the execute() method and checks to see if the robot has gone far enough in the isFinished() method.

This won’t be an ideal way to drive autonomously (it won’t stop on a dime and will likely veer some), but it should be enough that you should be able to cross a line.

Example of setting distance per pulse on encoders (in your RobotMap.java):


        // This looks like the value you provided that converts inches to counts
        // on your encoder, use it in the setDistancePerPulse() invocation
        int tinch = 76;
        
        encoderRight = new Encoder(0, 1, true, Encoder.EncodingType.k4X);
        encoderRight.setPIDSourceType(PIDSourceType.kDisplacement);
        encoderRight.setDistancePerPulse(1.0 / tinch);
       // encoderRight.reset();
        
        encoderLeft = new Encoder(2, 3, false, Encoder.EncodingType.k4X);
        encoderLeft.setPIDSourceType(PIDSourceType.kDisplacement);
        encoderLeft.setDistancePerPulse(1.0 / tinch);

Here is an example of two methods to add to your DriveTrain subsystem that return the distance values from the encoders:


    
    /**
     * Returns distance traveled by left side of drive train since reset.
     *
     * @return Distance traveled in inches.
     */
    public double getLeftDistance() {
      // NOTE: Assumes that when you constructed your encoder, you
      // used the setDistancePerPulse() so that it returns the distance
      // in inches.
      return RobotMap.encoderLeft.getDistance();
    }
     
    /**
     * Returns distance traveled by right side of drive train since reset.
     *
     * @return Distance traveled in inches.
     */
    public double getRightDistance() {
      // NOTE: Assumes that when you constructed your encoder, you
      // used the setDistancePerPulse() so that it returns the distance
      // in inches.
      return RobotMap.encoderRight.getDistance();
    }

Here is a refactored version of your DriveEncoders class that applies power to both motors until the distance driven by the left side exceeds a specified amount (NOTE: This is a fairly crude way to do it, but it will probably do what you want and can at least serve as a starting point).


public class DriveEncoders extends Command {
    private int driveDistance;
    private double botSpeed;
    private double endDistance;

    public DriveEncoders(double speed, int userFeet, int userInches) {
        // Use requires() here to declare subsystem dependencies
        // eg. requires(chassis);
        requires(Robot.driveTrain);
        driveDistance = userInches + (12 * userFeet);
        botSpeed = speed;
    }

    // Called just before this Command runs the first time
    protected void initialize() {
      // When this command is started, determine how far we want to drive
      endDistance = Robot.driveTrain.getLeftDistance() + driveDistance;
    }

    // Called repeatedly when this Command is scheduled to run
    protected void execute() {
      // Apply power to drive straight
      Robot.driveTrain.arcadeDrive(botSpeed, 0);
    }

    // Make this return true when this Command no longer needs to run execute()
    protected boolean isFinished() {
      // Stop once we've moved to or past the end distance
      return (Robot.driveTrain.getLeftDistance() >= endDistance);
    }

    // Called once after isFinished returns true
    protected void end() {
        Robot.driveTrain.stop();
    }

    // Called when another command which requires one or more of the same
    // subsystems is scheduled to run
    protected void interrupted() {
      // We will be paranoid and do the same clean up if we are interrupted
      end();
    }
}

Thank you!

I have now updated all our commands. Could you,please double check to see if anything else stands out to you.

 THANK YOU,
     ~Walker Ward
         Team 2906~

Just noticed that our code failed to upload should be fixxed by: 10am pst

Alright so now we have another problem. So after testing it our sendable chooser only ever runs the default command. On the smart dashboard we are seeing the list and are able to see which is selected. When we remove the default all of the commands appear to do nothing. Any ideas?

dashboard:

Let’s try to isolate whether or not the issue is with the sendable chooser or the auton code first.

First, add the following line at the bottom or your robotInit() method in Robot.java:


SmartDashboard.putData("Test GearAhead", new AutoGearStrait());

Deploy the code to your robot.

Bring up the Java SmartDashboard (either change your driver station settings temporarily to Java mode or from Eclipse, select WPILib -> Run SmartDashboard.

You should find a new button on the smart dashboard labeled “Test GearAhead”.

Put the driver station in teleop mode and try running your auton code directly (press the “Test GearAhead” button).

If the robot does what you expect, it sounds like there may be a problem with how you are using the sendable chooser or how the sendable chooser works with the LabView dashboard (our team doesn’t use the LabView dashboard, so I’m not certain how that works with Java code).

So after some testing with the java dashboard it appears to be functioning propperly although it just drives in a circle. Can we still use cameras with this or do we need to just get the labview dashboard to work?

You can try adding your camera to the Java SmartDashboard. Click, View -> Add and then choose “CameraSever Stream Viewer”. After it is added to the Java SmartDashboard, you can use the View -> Editable option to adjust its settings (put the dashboard in edit mode and then size/position the camera view). Also, a right click on the camera view should allow you to adjust some other properties.

so I tested the teleop command like you said and it works, so does the chooser now but our turn commands for the encoders do nothing, literally nothing.

also when we have pistons fire, they don’t for some reason

As far as your driving with encoders, you have a couple of issues in your code:

  • The use of integer values and the order of operations is causing your pivotDriveDistance to be 0 in your DriveTurnEncoderLeft and DriveTurnEncoderRight classes.
  • Your initialize/isFinished methods are out of sync in your DriveLeftEncodersLeft class (isFinished will return true immediately). You will need to refactor your logic.

Here is an example of where integer math is getting you (from DriveTurnEncoderLeft.initialize()):


pivotDriveDistance = (1/2)*(distancePerDegree)*userDegrees;

The way that statement is written, Java will evaluate the expression (1/2) as the integer value of 1 divided by the integer value of two and this comes out to 0. Since (1/2) is zero, your pivotDriveDistance will always be zero.

You can either change it to (0.5), or use double constants like the following to clean this up:


pivotDriveDistance = (1.0/2.0)*(distancePerDegree)*userDegrees;

Here is a stand alone Java program you can use to test the evaluation of expressions (I’m originally from Missouri and need to see these things):



public class Example {
  
  public static void main(String] args) {
    // Following prints out 0.0, not PI/2!
    System.out.println("Integer math: " + ((1/2) * Math.PI));
  }

}

You will need to check all of your code for the use of integer expressions like these as they often produce interesting results.

As far as your solenoids (pistons) not working, here are some things to try:

  • The PCM has LEDs that should light up and turn off as you change the state of a solenoid, this can be useful to verify that your code is sending commands to the PCM and changing its state.
  • Try using Test mode instead of Teleop mode at the driver station. See if you can locate your solenoids in the controls that pop up on the dashboard and fire them by hand.
  • Try adding a couple of smart dashboard buttons to test your piston commands.

Here is an example of adding some test buttons to your robotInit():


SmartDashboard.putData("GearMechIn", new GearMechIn());
SmartDashboard.putData("GearMechOut", new GearMechOut());

Good luck.

Alright, thank you. We got it to work, mostly. The pistons still wont fire in auto though. Unfortunately we had a bot fire after our encoders started working and now the code doesnt stop wone they exceed the set value. We made no code changes. The encoder value still reads on the dashboard. What do you rhink it could be

What did you use to extinguish the fire?

I checked out your code today to take a look.

You have several autonomous command groups. As an example, you have one called AutoGearOnLeft:


public class AutoGearOnLeft extends CommandGroup {

    public AutoGearOnLeft() {
    	addSequential(new GearHold());
    	addSequential(new GearMechIn());
    	addSequential(new WaitCommand(1.5));
    	addSequential(new DriveTurnEncodersRight(.65, 0, 14));
    }
}

The above command group will do the following:

  • It will start the GearHold command and then wait for it to finish.
  • It will wait for the GearMechIn command and then wait for it to finish.
  • It will start the WaitCommand and wait for it to finish (do nothing for 1.5 seconds).
  • It will then start and wait on your DriveTurnEncodersRight command.

The important part of the above steps is that the command group will wait for each command to finish before moving to the next command in the sequence.

Unfortunately, when I look at your GearHold command, it never appears to finish (the isFinished() method always returns false).


public class GearHold extends Command {

    public GearHold() {

    	requires(Robot.gearMech);
    }

    protected void initialize() {
    }

    protected void execute() {
    	Robot.gearMech.GearHold();
    }

    protected boolean isFinished() {
        return false;
    }

    protected void end() {
    }

    protected void interrupted() {
    }
}

To fix this, you will need to refactor the commands you use in autonomous sequences so they can finish. This may involving checking for a condition, setting a time out or simply have isFinished() return true right away.

HOWEVER, this might have ramifications in how the commands behave in other situations. It is possible that changing the behavior of a command for autonomous will cause undesirable behaviors in teleop. It is also possible that changing isFinished() to return true immediately may require you to add additional wait commands between your sequential steps in your autonomous code. So, be a bit careful and make sure to test as your refactor.

Check this: Twitch

Thank you again I will see what we can do