methods for Switchable Autonomous Modes

Hello,

I have looked through much of the forums before Stop Build Date for the best and easiest switchable autonomous mode, but none seemed to work.

I use the Simple Robot Template for my code. (my entire cpp file code is posted below)

I noticed methods that are solely through the driver station (IO, Position, etc), and using something through that interface is preferred. I was unable to get any to work in the code (and was uncertain about the position selector).

My second choice would be a dip switch option on the robot itself. (Just I have never programmed inputs like those on the robot, and I still prefer the DS method).

Thanks,
Davis

Robot Code:


#include "WPILib.h"
#include "Math.h"
#include "stdlib.h"
#include "DriverStation.h"

class RobotDemo : public SimpleRobot
{
	RobotDrive R_myRobot;
	
	Joystick J_stick1;
	Joystick J_stick2;
	Joystick J_stick3;
	Joystick J_stick4;
	
	Relay M_standLeft;
	Relay M_standCenter;
	Relay M_standRight;
	
	Victor M_arm;
	
	Relay M_frisbeePusher;
	Relay M_frisbeeReleaser;

public:
	RobotDemo(void):
		R_myRobot(1, 2),
		
		J_stick1(1),
		J_stick2(2),
		J_stick3(3),
		J_stick4(4),
		
		M_standLeft(1),
		M_standCenter(3),
		M_standRight(2),
		
		M_arm(3),
		
		M_frisbeePusher(4),
		M_frisbeeReleaser(5)
	
	{	
		R_myRobot.SetExpiration(0.1);
	}

	void Autonomous(void)
	{		
		R_myRobot.SetSafetyEnabled(false);		
	}

	void OperatorControl(void)
	{
		R_myRobot.SetSafetyEnabled(true);
		
		// inverts the left motor
		R_myRobot.SetInvertedMotor(R_myRobot.kRearLeftMotor, true);
		// inverts the right motor
		R_myRobot.SetInvertedMotor(R_myRobot.kRearRightMotor, true);
		

		R_myRobot.Drive(0.0, 0.0);
		
		
		while (IsOperatorControl())
		{			
			
			// Drive
			R_myRobot.TankDrive(J_stick1, J_stick2);

			// Arm
			if(J_stick4.GetRawButton(1))
				M_arm.Set(J_stick4.GetY());
			else
				if(J_stick4.GetRawButton(2))
					M_arm.Set(J_stick4.GetY()*3/4);	
				else
					M_arm.Set(0.0);
			
			// frisbee pusher
			if(J_stick1.GetRawButton(1))
				M_frisbeePusher.Set(Relay::kForward);
			else
				if(J_stick1.GetRawButton(2))
					M_frisbeePusher.Set(Relay::kReverse);
				else
					M_frisbeePusher.Set(Relay::kOff);
			
			// frisbee Releaser
			if(J_stick2.GetRawButton(1))
				M_frisbeePusher.Set(Relay::kForward);
			else
				if(J_stick2.GetRawButton(2))
					M_frisbeePusher.Set(Relay::kReverse);
				else
					M_frisbeePusher.Set(Relay::kOff);
			
			// stand center
			if(J_stick4.GetRawButton(4))
				M_standCenter.Set(Relay::kForward);
			else
				if(J_stick4.GetRawButton(5))
					M_standCenter.Set(Relay::kReverse);
				else
					if(J_stick4.GetRawButton(3))
						M_standCenter.Set(Relay::kOff);
									
			// stand left + right
			if(J_stick3.GetRawButton(4))
			{
				M_standLeft.Set(Relay::kForward);
				M_standRight.Set(Relay::kForward);
			}
			else
			{
				if(J_stick3.GetRawButton(5))
				{
					M_standLeft.Set(Relay::kReverse);
					M_standRight.Set(Relay::kReverse);
				}
				else
				{
					if(J_stick3.GetRawButton(3))
					{
						M_standLeft.Set(Relay::kOff);
						M_standRight.Set(Relay::kOff);
					}
					else	
					{
						
						// stand left
						if(J_stick3.GetRawButton(6))
							M_standLeft.Set(Relay::kForward);
						else
						{
							if(J_stick3.GetRawButton(7))
								M_standLeft.Set(Relay::kReverse);
							else
							{
								if(J_stick3.GetRawButton(8))
									M_standLeft.Set(Relay::kOff);
							}
						}
						
						// stand right
						if(J_stick3.GetRawButton(11))
							M_standRight.Set(Relay::kForward);
						else
						{
							if(J_stick3.GetRawButton(10))
								M_standRight.Set(Relay::kReverse);
							else
							{
								if(J_stick3.GetRawButton(9))
									M_standRight.Set(Relay::kOff);
							}
						}
					}
				}
			}
			
			Wait(0.005);
		}
	}
};

START_ROBOT_CLASS(RobotDemo);

Why not use a SendableChooser with SmartDashboard?

How would I do that? (I have only ever worked with the default dashboard, and I only used the camera feed from that)

-Davis

Here’s my code, in Java

public void robotInit() {
        // Create a switching autonomous mode
        autoSwitcher = new SendableChooser();
        autoSwitcher.addDefault("Auto 0", new Auton0());
        autoSwitcher.addObject("Auto 1", new Auton1());
        autoSwitcher.addObject("Auto 2", new Auton2());
        SmartDashboard.putData("Auto Switcher", autoSwitcher);
    }

    public void autonomousInit() {
        autonomousCommand = autoSwitcher.getSelected();    
        autonomousCommand.start();
    }

Yes! I can share my experience! In my opinion, you should go with putting a toggle switch or rotary switch on the robot itself. It’s extremely easy to do (just analog). We tried using


switch(variable) //switch variable
{ 
    case ??:    //if variable == something
    case ???:  //if variable == something else
}

but we had some weird problems where we needed to restart the robot to acquire the new position of the switch (we placed something like x=ToggleSwitch->Get() right above while isOperatorControl. I never got around to asking why, because we restart the robot after every match anyways). Ultimately, it worked really well.

If you are looking for an on-robot switch like ekapalka is saying, you could use this:

https://www.estoprobotics.com/estore/index.php?_a=viewProd&productId=63

Which would give you the ability to choose between 8 different autonomous modes using the same logic he used. I still prefer SendableChooser, but if you aren’t looking to mess around with new dashboards and such it’s definitely an option.

(note: it does take up 3 DIO ports on the sidecar, and I know my team is sitting around 12-13 out of 14 atm…)

I like using the DIO’s on the I/O tab of the drivers station. You had mentioned that and yes it’s easily doable. Something like this:


//declare the driver station - perhaps globally in the robot
DriverStation* driverStation;

//...  then in your init code grab the instance
driverStation = DriverStation::GetInstance();

// then in autonomous mode read the inputs to decide
// Start with just 1 through 8 because you can actually label them on
//the driver station what they are
		if (driverStation->GetDigitalIn(1)) {
			AutoRoutine1();
		} else if (driverStation->GetDigitalIn(2)) {
			AutoRoutine2();
		} else if (driverStation->GetDigitalIn(3)) {
			AutoRoutine3();
		}

If you get beyond 8 needed modes, you’ll have to keep a list of how to set the IO’s and you can check for combinations of Inputs you could do this straight binary and use 4 lights to get you 16 or in our case we just had a couple more, so we just added on a couple of 2 light scenarios at the top: use Digital IO’s to choose autonomous Scenarios


		if (driverStation->GetDigitalIn(1) && driverStation->GetDigitalIn(2)) {
			AutoRoutine9();
		} else if (driverStation->GetDigitalIn(1) && driverStation->GetDigitalIn(3)) {
			AutoRoutine10();
		} else if (driverStation->GetDigitalIn(1)) {
			AutoRoutine1();
		} else if (driverStation->GetDigitalIn(2)) {
			AutoRoutine2();
		} else if (driverStation->GetDigitalIn(3)) {
			AutoRoutine3();
		}


Our team came up with a pretty easy method using GPIO and a switch that toggles on and off. Off would be the left side, and on would be the right side. Coding it is incredibly easy because all you need to do is set the two autonomous modes for true and false on the readout of the GPIO. This was a method we came up with right before packaging our bot, and if you are looking for a quick and easy solution I would definitely recommend keeping it simple.

To add one more alternative method to the mix, I typically monitor the joystick buttons during disabled mode, if a pair of buttons gets held for 2 seconds, I change the autonomous mode variable.

When the robot goes into autonomous, I have a switch case that calls the different routines based on the autonomous mode variable.

It has the disadvantage that it doesn’t persist through reset, so if you restart the match or reboot the robot it needs to be set back to the mode you want. It works well if you use the same mode 90% of the time, and have other modes for flexibility. The advantage is that you don’t need any hardware, the implementation is entirely in the robot code.

Really folks - providing you use Smartdashboard, the simplest and most intuitive way to do autonomous is SendableChooser. You don’t even have to have real ‘Commands’ as shown above. The pointer given to AddObject is just a pointer – point it back to the string itself and compare at autonomous time to decide what the user has chosen. It’s super elegant and flexible over time. No need for switches, documenting said switches, holding down buttons, etc.

bob