Two Joysticks co-pilot locking-out pilot

Hey guys,
We’re coding in Java this year and still learning… today’s problem is we can’t use both joysticks at the same time.

Co-pilot controls the elevator and the arm.
Pilot controls the driving and shooting of the power cube.

While we have any button pressed on our co-pilot joystick it locks/interrupts/overrides the pilot command.

For instance; while the pilot is driving (any direction) the co-pilot starts raise elevator, the pilot stopped driving, but the robot stayed in drive while the co-pilot was still pressing raise elevator. While copilot is using rase/lower elevator/arm the driver joystick would not initialize.

thoughts please! :slight_smile:

Can you provide a link to your teams github code if you have one?

Make sure that when you are declaring your joysticks, you are declaring them to have two separate ports. E.g. your driver stick might be port 0, and your manipulator might be port 1.

Joystick stick = new Joystick(0);

The 0 in this statement is the port number.

Sorry, we do not have our code posted…
We are declaring them on separate ports and they work fine independently.

It will be an easy problem to solve if people can see your code. If you can not post all your code online somewhere, can an you at least post the section of code that is reading all your joystick values here?

here is a copy of our code via google drive, hoping someone sees an easy-to-fix problem! :slight_smile:

https://drive.google.com/open?id=1su6ORhz65fR0KiO4guR_a0nY6wk0KJGO

When the co-pilot pushes a button, they grab control of the robot in this loop:


		while(Robot.oi.getCoPilotJoystick().getRawButton(5)==true) {
			Robot.Arm.SwingDown(); //only executes while joystick pressed AND Limit Switch is open (false)
		}
		Robot.Arm.Stop();

You should never have loops like this when writing a basic IterativeRobot.

From this:

It is important not to have any long running code in the periodic methods such as loops or delays.

Your command probably needs to look more like this:


public class SwingDown_Commands extends Command{
		
	public SwingDown_Commands() {
		requires(Robot.Arm);
	}
	
	@Override
	protected void initialize() {	
	}
	
	@Override
	protected void execute() {	
		Robot.Arm.SwingDown();
	}
	
	@Override
	protected boolean isFinished() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	protected void end() {
		Robot.Arm.Stop();
	}
	
	@Override
	protected void interrupted() {
		Robot.Arm.Stop();
	}
}

If you put some debugging in execute() you’ll see that it gets called many times.

All the commands, other than arcade drive that I looked at have this problem. Their execute methods look like this:

protected void execute() {	
	while(Robot.oi.getCoPilotJoystick().getRawButton(5)==true) {
		Robot.Arm.SwingDown(); //only executes while joystick pressed AND Limit Switch is open (false)
	}
	Robot.Arm.Stop();
}

The scheduler will call your execute and isFinished methods 50 times a second while your command is active and you must not have a while loop like this in there. You are keeping the scheduler from calling other active command’s execute and isFinished methods. That is why the driving stops.

Your buttons are running their commands as whileHeld, so if you change your execute to something like the following, it should work. The other methods looked fine in my quick check.

protected void execute() {	
	Robot.Arm.SwingDown();
}

This will not take into account the limit switch but I do not see that being used in any of your current code at this time.

I hope this helps,
Steve

Okay, tried changing our
protected void execute() to everything described above and it did not fix…

  • We still cannot operate both joysticks simultaneously.
  • And it continues the command even after released…

Please provide your updated code. As it will continue to help us to better understand what is wrong.

Robot.java > autonomousPeriodic()


while(BackUS.getAverageVoltage() > RobotMap.Front_JustEnoughForATurn) {
    Robot.DriveTrain.BackwardDrive();
}

This while loop could lock your program in Autonomous. To my knowledge if your auto is stuck in this loop when Autonomous ends, your robot will not force itself out of this, and continuing to drive back. Leading to an Emergency Stop.

DriveTrain_Subsystem.java > All of the Turn methods that use the Gyro


while (gyro.getAngle() < 45) {
    MainDrive.drive(0.8, 1);
}

If your gyro malfunctions (the wire gets broken, or the gyro comes un-mounted. Your code could get stuck in one of these while loops forever and the robot would continue to move as prescribed, leading to a likely Emergency Stop.

All your Command’s execute methods (except ArcadeDrive_Command.java)


protected void execute() {	
    while(Robot.oi.getCoPilotJoystick().getRawButton(4)==true) {
        Robot.Arm.SwingUp(); //only executes while joystick pressed AND Limit Switch is open (false)
    }
    Robot.Arm.Stop();
}

The execute Method is already going to be looped while holding the button you assigned as whileHeld in the OI.

ArmUp.whileHeld(new SwingUp_Commands());

The difference is that the execute method’s loop will be controlled by the robot’s command scheduler, while your commands will simply stick in that one loop (meaning that Nothing else on the robot will run or function) while in the loop. You do not need to be checking the button state, and the checks on the limit switches should be if statements, not in while loops, because if that switch fails, your robot may be stuck in that loop and the robot may just stop, or may continue in an undesired fashion, leading to an Emergency Stop.

In command-based (or any iterative-base), as stated above by MrRoboSteve,you shouldn’t be using any while loops or delays except where unavoidable, and even then you need to make sure they’re programmed in such a way that if something goes wrong, they won’t hang up the robot during a match.

I hope that analysis helps. If you need help with further code problems, please post your updated code for us. Thanks.

Double-checked everything that we know to do and can’t find the problem yet…

https://drive.google.com/file/d/170sIqZLYdn1H2tpBTnKFOnPaS8v0ISrW/view?usp=sharing

Here’s the new code, please share your thoughts!

Every one of your commands still have while loops in the execute method. Which means that when that one command is running, no other command (or any other robot code) with run. HOWEVER, Motors and other outputs will continue with their last given command.

So if the last thing your drive command did was set the motors to go forward at 0.8, then when the SwingUp command button is pressed, it will get stuck in the while loop in that command and the motors will not get updated further, and so they will continue to run forward at 0.8.

I repeat yet again, you SHOULD NOT be using any sort of while loop in your robot code. Especially not in your commands on a Command-Based robot.

Sorry, wrong link! We have removed all the while loops so that we are only calling “while held” via the OI, but the issue is still there.

new link:
https://drive.google.com/file/d/12bBe3Z1XsHEqhEMPRtBSsRuRZy5GG2qH/view?usp=sharing

Thank you in advance for any help!

When a whileHeld is released, it cancels the command. Which will call the interrupted method. In some of your commands you have put stops in the interrupted, but in others you only put the stop in the end method. That could cause a motor or other actuator set by the command to continue after the command is done.

You should also probably move all your JoystickButton declarations to outside the OI Constructor (where the Joystick declarations are). I’ve no idea what consequences this will cause leaving them in the constructor.

Thanks for the feedback! Just to clarify…

  • Should we have stops in the interrupted and the end? Or just the interrupted? Or just the end?

  • Uhm, where should we move our Joystick declarations to?

Since you are only using whileHelds, and your isFinished will never return true. end doesn’t really matter, and interrupted does matter. What I would do is set one to be the stop, and then call it with the other, or just put the stop in both.

Joystick stay where they are. JoystickButtons get moved just under Joystick.

ie


	Joystick Driver = new Joystick(0);
	Joystick CoPilot = new Joystick(1);
	
	JoystickButton Igrab = new JoystickButton(Driver, 2);
	JoystickButton Iout = new JoystickButton(Driver, 1);
	
	//JoystickButton Idle = new JoystickButton(Driver, 3);
	JoystickButton ArmUp = new JoystickButton(CoPilot, 4);
	JoystickButton ArmDown = new JoystickButton(CoPilot, 5);		
	JoystickButton ELower = new JoystickButton(CoPilot,2);
	JoystickButton ERaise = new JoystickButton(CoPilot, 3);
	
	public OI() {
		ERaise.whileHeld(new Lift_Commands());
		ELower.whileHeld(new Lower_Commands());
		Igrab.whileHeld(new Grab_Commands());
		Iout.whileHeld(new Out_Commands());
		ArmUp.whileHeld(new SwingUp_Commands());
		ArmDown.whileHeld(new SwingDown_Commands());
	}

You likely want the same code in the end() and interrupted() methods of your commands.

Here’s a sample (C++, but same concept)

Thanks so much! We got it working smoothly - just in time for a little bit of drive practice before we bagged!