LimitSwitches

Hello I am trying to make a motor run forwards only when im holding a button and stop if I release the button OR if the thing the motor is moving hits a limitswitch

I have it going up and down ONLY when the button is held but the moment I try to add limitswitch code it stops working

lift is the subsystem - liftUp, liftDown, and liftStop are the commands and in the OI the buttons are in a group all with armLiftDown or Up or Stop

Also how do I make the chooser code in Robot.java work. I don’t see the autonomous command I set in the Driver Station

Here is the code on GitHub: https://github.com/FranklinMarquette/Robot2016

Thanks so much for the help!

Your choice of verb “hits” raises a red flag. Just in case, please read this thread.

the moment I try to add limitswitch code it stops working

Are you familiar with NO (normally open) vs NC (normally closed)?

What motor controller are you using??

The following WPIlib document provides a nice example of setting up an autonomous chooser: http://wpilib.screenstepslive.com/s/4485/m/26401/l/255419-choosing-an-autonomous-program-from-smartdashboard

As far as using your limit switch, I only saw the construction of the DigitalInput objects in your Lift subsystem (usage was commented out).

I would suggest the following:

  • Use the LiveWindow methods in your constructor so you can put your driver station in test mode and then press each switch to check if it returns true or false when pressed.
  • In your liftUp() method, set the power to 0 instead of 1 if the limit switch is pressed.
  • Always make sure to stop your lift when a command is not directly controlling it (your limit switches are not hard wired, so you have to stop the motors).
  • If it is possible to go past the limit switch, use the hardware counters (you already had them roughed in) and have your command check to see if the count changes).

Here are some suggested changes to Lift.java


package org.usfirst.frc.team4623.robot.subsystems;

import edu.wpi.first.wpilibj.Counter;
import edu.wpi.first.wpilibj.DigitalInput;
import edu.wpi.first.wpilibj.SpeedController;
import edu.wpi.first.wpilibj.Victor;
import edu.wpi.first.wpilibj.command.Subsystem;
import edu.wpi.first.wpilibj.livewindow.LiveWindow;

public class Lift extends Subsystem {

    Victor liftMotor = new Victor(7);
    DigitalInput topSwitch, botSwitch;
    Counter topCounter, botCounter;
    
    public Lift() {
      topSwitch = new DigitalInput(0);
      botSwitch = new DigitalInput(1);
      topCounter = new Counter(topSwitch);
      botCounter = new Counter(botSwitch);

      LiveWindow.addActuator("Lift", "Motor", liftMotor);
      LiveWindow.addSensor("Lift", "Top Switch", topSwitch);
      LiveWindow.addSensor("Lift", "Top Count", topCounter);
      LiveWindow.addSensor("Lift", "Bot Switch", botSwitch);
      LiveWindow.addSensor("Lift", "Bot Count", botCounter);
    }
    
    /**
     * @return Number of times the top limit switch has been hit.
     */
    public int getTopCount() {
    	return topCounter.get();
    }
    
    /**
     * @return Number of times the bottom limit switch has been hit.
     */
    public int getBotCount() {
    	return botCounter.get();
    }

    public void liftUp() {
    	double power = 1;
        // stop motor if attempt is made to go past the top
    	if (topSwitch.get()) {
    		power = 0;
    	}
    	liftMotor.set(power);
    }

    public void liftDown() {
    	double power = -1;
        // stop motor if attempt made to go past bottom
    	if (botSwitch.get()) {
    		power = 0;
    	}
        liftMotor.set(power);
    }

    public void liftStop() {
        liftMotor.set(0);
    }
    protected void initDefaultCommand() {
    }
}

The following is a suggested change to the LiftUp.java command. It makes use of the count of times the top limit switch has been hit to provide an extra level of safety in case you manage to slip past the limit switch. You would want to do a similar change to the lift down command.


package org.usfirst.frc.team4623.robot.commands;

import org.usfirst.frc.team4623.robot.Robot;
import edu.wpi.first.wpilibj.command.Command;

public class liftUp extends Command {

    // Used to detect the case of going past the limit switch
    private int limitCnt;

    public liftUp() {
    	requires(Robot.lift);
    }

    protected void initialize() {
    	limitCnt = Robot.lift.getTopCount();
    }

    protected void execute() {
    	if (limitCnt == Robot.lift.getTopCount()) {
                // Have not gone past limit switch, OK to try and move up
                // (lift subsystem will stop us if we are on the limit switch)
    		Robot.lift.liftUp();
    	} else {
    		// Somehow we got past the top limit switch, stop motors!
    		Robot.lift.liftStop();
    	}
    }

    protected boolean isFinished() {
        return false;
    }

    protected void end() {
        Robot.lift.liftStop();
    }

    protected void interrupted() {
        end();
    }
}

WARNING: The above changes assume that all of your lift commands will be controlling the lift power in their execute() methods and stopping the lift power when they end or are interrupted (which looks like the approach you are taking).

Also, the counter safety checks will only save you one time using the approach shown. For example, if your lift goes past the top limit switch and you issue the lift up command again, the lift will continue moving up and never stop (expect bad things to happen).

Alternatively, you can do fairly sophisticated software control on your lift such that it knows when it’s approaching the limit switches (via encoder/potentiometer) and applies PID control to slow it down. So eventually, it will gently “hit” the limit switch and stop. In fact with this capability, you don’t even need the upper limit switch, this is called “soft limit”. This is especially useful because while it is generally easy to add a lower limit switch, it is sometimes difficult to add an upper limit switch. For example, if you have an extending arm, it is sometimes impossible to find a place to mount an upper limit switch because it extends into open space. We have a PIDMotor class in our library that implements this capability. There is a method in this class:


public void setPidPower(double power, double minPos, double maxPos, boolean holdTarget)

In this method, you tell it what maximum motor power you want to drive the motor (typically, it receives this value from the joystick). You also provide the range of motion the motor can travel. It will check against this range using the encoder (or potentiometer). A lower limit switch is used to “zero calibrate” the encoder (or potentiometer). An optional upper limit switch can be used as an additional safety for the upper range. Finally, the holdTarget boolean specifies whether it should use active PID to hold the current position when you stop the motor (i.e. power is set to zero). The code for this class can be found here.