When creating a command for our hatch extender which is controlled by a limit switch, I’m following the WPI documentation and putting the method in the initialize() command to make the motor drive. However, the motor only briefly pulses and then stops, even though the isFinished() criteria isn’t being completed. The motor safety is off as well. I’m probably missing something obvious.
This is the command for the mechanism
public class FourBarLinkageCommand extends Command
{
boolean linkageDeployed = false;
public FourBarLinkageCommand()
{
linkageDeployed = false;
requires(Robot.fourBarLinkage);
System.out.println("Four Bar Linkage has been created");
// Use requires() here to declare subsystem dependencies
// eg. requires(chassis);
}
// Called just before this Command runs the first time
@Override
protected void initialize()
{
System.out.println("linkage initialized");
Robot.fourBarLinkage.initializeCounter();
Robot.fourBarLinkage.hatchForward();
System.out.println("Initialized At " + java.lang.System.currentTimeMillis());
}
// Called repeatedly when this Command is scheduled to run
@Override
protected void execute()
{
System.out.println("TIMESTAMP: " + java.lang.System.currentTimeMillis());
}
// Make this return true when this Command no longer needs to run execute()
@Override
protected boolean isFinished()
{
System.out.println(Robot.fourBarLinkage.isFrontSwitchSet() || Robot.fourBarLinkage.isRearSwitchSet());
return Robot.fourBarLinkage.isFrontSwitchSet() || Robot.fourBarLinkage.isRearSwitchSet(); // finishes when the limit switch is activated, shouldn't be an issue due to how slowly it goes
}
// Called once after isFinished returns true
@Override
protected void end()
{
Robot.fourBarLinkage.stopLinkage();
System.out.println("linkage finished at: " + java.lang.System.currentTimeMillis());
}
// Called when another command which requires one or more of the same
// subsystems is scheduled to run
@Override
protected void interrupted()
{
}
}
This is the subsystem for the mechanism
public class FourBarLinkageForHatch extends Subsystem
{
// Put methods for controlling this subsystem
// here. Call these from Commands.
WPI_TalonSRX fourBarLinkageTalon = RobotMap.fourBarLinkageTalon;
DigitalInput hatchArmSwitchFront = new DigitalInput(RobotMap.HATCH_ARM_SWITCH_ID_FRONT);
DigitalInput hatchArmSwitchBack = new DigitalInput(RobotMap.HATCH_ARM_SWITCH_ID_BACK);
Counter counterFront = new Counter(hatchArmSwitchFront);
Counter counterRear = new Counter(hatchArmSwitchBack);
@Override
public void initDefaultCommand()
{
// Set the default command for a subsystem here.
// setDefaultCommand(new MySpecialCommand());
}
public void hatchForward()
{
fourBarLinkageTalon.set(ControlMode.PercentOutput, 0.8);
}
public void hatchBack()
{
fourBarLinkageTalon.set(ControlMode.PercentOutput, -0.8);
}
public void stopLinkage()
{
fourBarLinkageTalon.set(ControlMode.PercentOutput, 0);
}
public boolean isFrontSwitchSet(){
return counterFront.get() > 0; // increments when the limit switch is activated
}
public boolean isRearSwitchSet(){
return counterRear.get() > 0;
}
public void initializeCounter(){
counterFront.reset();
counterRear.reset();
}
}
The command isn’t exiting, the execute timestamp continues to run and the switches continue to return false. The talon status lights flash green briefly so they are running, at least for a pulse, and then stay solid orange. No other code is using the talon either.
Do you have your code on github, so that I can look at the rest of it? By far the most likely scenario is that there is other code that is setting the motor back to zero.
Additionally, you really shouldn’t have your motors be global variables, for precisely this reason. You should also be initializing your subsystem’s fields inside of a constructor.
Okay, I can’t find any place in your code where you’re explicitly using the motor elsewhere, but it worries me that you’ve instantiated your cargomotor with a device ID of 9999999, and in general it’s hard to check every piece of code that could be touching the motor.
Try making the motor a private field in the relevant subsystem, and set the cargomotor to a CAN ID that is actually in the valid range.
It does not; the motor controller should continue at the value it was last set to until it is told to do something else.
For most processors, this would be true. As I understand it, the FRC RIO firmware requires that the motor speed be refreshed every hundred milliseconds or so. This “watchdog” function is also why robots stop when user code has a wait() or a long while loop in it.
MotorSafety does what you describe (stops the motors if they aren’t driven periodically), but it’s only enabled by default in drivetrains (although maybe some of the vendor motor controllers enable it by default)? The watchdog feature added this year is used solely to warn about loop overruns / long delays, it doesn’t actually turn off the motors.
@Oblarg is correct. For example, in position control, we’ll often set the position using the subsystem’s methods in the command’s initialize(). The system runs, and then in isFinished(), we’ll check with the subsystem if we’re onTarget(). If we are, then we stop.
Is anything else using the subsystem at that time?
Is the default command being called?
Make sure isFinished() is returning what you think. I spent way too long chasing down a ! (caused the command to end immediately) in one of our subsystems.
Every FRC-legal motor controller requires regular signals so that the e-stop and end-of-match will shut motors down. The question is whether the controlling computer (RIO) requires a refreshed signal. If you and @oblarg are correct, I’ve been party to a bunch of superfluous code.
So I tried declaring the motor controller private in the subsystem that it’s being used in, and it still didn’t work. As a workaround I’m just using it in execute().