Threading?

I am running into the issue that I can not do other robot things while my kickBall method is running. I am using this way currently for threading, but it crashes as is. I have also tried using the kickBall method to call just kickThread.run(); but that doesn’t let me do anything else while the servo is moving.

Thread kickThread = new Thread() {
		public void run() {
			int i = 0;
			for (; i < 20; i++) {
				if (i == 1) {
					setKickAngle(RobotMap.kickDefaultAngle);
					doneKicking = false;
				} else if (i == 4) {
					setKickAngle(RobotMap.kickHitAngle);
					doneKicking = false;
				} else if (i == 15) {
					setKickAngle(RobotMap.kickDefaultAngle);
					doneKicking = true;
				}
				Timer.delay(0.05);

			}
			doneKicking = true;

			kickThread.interrupt();
		}
	};

	public void autoKick() {
		if (!kickThread.isAlive() && kickThread.isInterrupted()) {
			kickThread.start();
		} else {
			kickThread.run();
		}
	}

Full code at my github
Thanks for any input you guys have!

When you create a Thread in Java, you only need to use the start() method to start the thread running in the background (you do not need to call the Thread’s run() method directly). Try the following changes:


         Thread kickThread = new Thread() {
		public void run() {
			int i = 0;
			for (; i < 20; i++) {
				if (i == 1) {
					setKickAngle(RobotMap.kickDefaultAngle);
					doneKicking = false;
				} else if (i == 4) {
					setKickAngle(RobotMap.kickHitAngle);
					doneKicking = false;
				} else if (i == 15) {
					setKickAngle(RobotMap.kickDefaultAngle);
					doneKicking = true;
				}
				Timer.delay(0.05);

			}
			doneKicking = true;

                        // CHANGE 1: Thread will terminate here, you don't need to try and have your thread interrupt itself
			// kickThread.interrupt();
		}
	};

	public void autoKick() {
                // CHANGE 2: You only need to start your thread once per kick,
                // its run() method will be done in the background
		if (!kickThread.isAlive()) {
			kickThread.start();
		}
	}

Okay, I understand that we can leave the thread just running in the background, and the servo will move the first time we press the button, but I want to be able to press the button more than once per run of the robot. The way it is setup with your changed code I still run into the issue of only being able to kick the ball one time per power cycle. What can I do to fix that?

EDIT: Actually I pushed the code, and the second time I run the autoKick() method the code crashes with Illegal thread state errors.

It looks like you forgot to remove the interrupt() invocation and check that the thread was not running before attempting to start it again.

However, it looks like you are now using the Command based framework in your robot project. In this case you should not need any threading to accomplish the automated task.

As a rough guess, it appears that you are automating the task of kicking the boulder and this task involves spinning up some shooter motors and using a servo to feed the boulder into the shooter. My guess is that you are trying to:

  • Move the servo back to keep the ball out of the “spinners”.
  • Spin up your motors.
  • Move the servo into a “kick” position to push the boulder through the spinners.
  • Let the boulder pass through the spinners (wait a bit).
  • Stop the spinners
  • Return the servo to its default position

Using your existing Shooter subsystem, you should be able to create two new simple commands and one command group to accomplish this.

SetShooterSpeed - Simply sets the power on your shooter spinners and then quits (leaves the motors running).
SetKickerPosition - Sets the position of the shooter servo.
AutonKickCommand - Uses the two above commands and the built in WaitCommand to automate the entire sequence.

Here is a start of SetShooterSpeed.java:


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

import org.usfirst.frc.team2847.robot.Robot;

import edu.wpi.first.wpilibj.command.Command;

/**
 * Command that sets power to shooter wheels and leaves them running.
 */
public class SetShooterSpeed extends Command {
	double speed;

	public SetShooterSpeed(double speed) {
		requires(Robot.shooter);
		this.speed = speed;
	}

	// Called just before this Command runs the first time
	protected void initialize() {
		Robot.shooter.spinShooters(speed);
	}

	// Called repeatedly when this Command is scheduled to run
	protected void execute() {
	}

	// Make this return true when this Command no longer needs to run execute()
	protected boolean isFinished() {
		return true;
	}

	// Called once after isFinished returns true
	protected void end() {
		// Leave shooters running
		// Robot.shooter.spinShooters(0);
	}

	// Called when another command which requires one or more of the same
	// subsystems is scheduled to run
	protected void interrupted() {
		end();
	}
}

Here is SetKickerPosition:


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

import org.usfirst.frc.team2847.robot.Robot;

import edu.wpi.first.wpilibj.command.Command;

/**
 * Command that sets power to shooter wheels and leaves them running.
 */
public class SetKickerPosition extends Command {
	double angle;

	public SetKickerPosition(double angle) {
		requires(Robot.shooter);
		this.angle = angle;
	}

	// Called just before this Command runs the first time
	protected void initialize() {
		Robot.shooter.setKickAngle(angle);
	}

	// Called repeatedly when this Command is scheduled to run
	protected void execute() {
	}

	// Make this return true when this Command no longer needs to run execute()
	protected boolean isFinished() {
		return true;
	}

	// Called once after isFinished returns true
	protected void end() {
	}

	// Called when another command which requires one or more of the same
	// subsystems is scheduled to run
	protected void interrupted() {
		end();
	}
}

Finally, here is the command group that ties it all together:


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

import org.usfirst.frc.team2847.robot.RobotMap;

import edu.wpi.first.wpilibj.command.CommandGroup;
import edu.wpi.first.wpilibj.command.WaitCommand;

public class AutonKick extends CommandGroup {

	public AutonKick(double speed) {
		super("AutonKick " + speed);
		
		// Get .25 seconds for kicker to get into default position
		addSequential(new SetKickerPosition(RobotMap.kickDefaultAngle));
		addSequential(new WaitCommand(0.25));
		
		// Start spinning up shooters and give them 2 seconds to reach speed
		addSequential(new SetShooterSpeed(speed));
		addSequential(new WaitCommand(2.0));
		
		// Move kicker into kick position and give .5 second for boulder
		// to pass through
		addSequential(new SetKickerPosition(RobotMap.kickHitAngle));
		addSequential(new WaitCommand(0.5));
		
		// Stop shooter and return kicker to default position
		addSequential(new SetShooterSpeed(0));
		addSequential(new SetKickerPosition(RobotMap.kickDefaultAngle));
	}
}

NOTE: All of this is a “best guess”, make sure you refactor it to how your robot is actually designed. Also, thanks for providing the github link. It made it much easier to review your code by being able to pull down a copy in Eclipse.

Hope that helps.

Thank you! I was thinking quite narrow minded by thinking the only way I could do it was with threading! Thanks for showing me the way! One question, what does the super() thing do in the commandgroup? I use it in my PIDSubsystem to pass PID info, but what does it do in this case?

EDIT: I ended up doing this, the second parameter of the command can be used as a timeout ex. (addSequential(),1.5). I needed to do this so that the list doesn’t get stuck in the SetShooterSpeedCommand as I don’t have it exit unless its interrupted. This works as desired. Thanks for the help pblankenbaker!

	public KickNShootCommandGroup() {
		// super("KickNShootCommandGroup " + RobotMap.shootSpeed);

		// to get into default position
		addSequential(new SetKickerPositionCommand(RobotMap.kickDefaultAngle));

		// Start spinning up shooters and give them 2 seconds to reach speed
		addSequential(new SetShooterSpeedCommand(RobotMap.shootSpeed), 1.5);

		// Move kicker into kick position and give .5 second for boulder
		// to pass through
		addSequential(new SetKickerPositionCommand(RobotMap.kickHitAngle));
		addSequential(new WaitCommand(0.7));

		// Stop shooter and return kicker to default position

		addSequential(new SetKickerPositionCommand(RobotMap.kickDefaultAngle));
		addParallel(new SetShooterSpeedCommand(0), 0.5);
	}

The super(String) invocation just calls the CommandGroup’s constructor (which is a Command object itself) that takes a string parameter. This parameter sets the name to associate with the command. It is not required (the default constructor will) work.

Setting the name on the Command objects can sometimes be useful when debugging. For example, if you add the line after your shooter subsystem is created, the smart dashboard will display the command that is currently active on it:


SmartDashboard.putData("Shooter", Robot.shooter);

I have tried that and it works quite well! Thanks for the idea. I think in the past I used a thing that would just print the current subsystem but with no useful info like speed or angle. Thanks! I think you helped me also in 2014 with another post. You are a helpful dude.