toggle switch

We were setting up a toggle switch so that when you press a button (p1_sw_trig) it activates a spike (relay1_fwd) and when you press the button again it deactivates it. I will also use this for other things in the programming code, such as a manual overide for the auto tracking.

int switch1, switch2, initVar, printCount, switch1Count, switch2Count;

switch1 = SWITCH1; // port1 trig
switch2 = SWITCH2; // port1 top

if(initVar !=1) // initialize variables
{
printCount = 0;
}

printf(“switch1 = %d”, switch1);
printf(“switch2 = %d”, switch2);

if(switch1 == 1) // if switch1 pressed
{
if(switch1Count != 1) // not forward, so set forward
{
switch1Count = 1;
}
else // forward, so set back
{
switch1Count = 0;
}
}

printCount++;
if(printCount > 100)                      // decreases amount of printfs
{
	printf("switch1 = %d", switch1);
	printf("switch1Count = %d", switch1Count);
	printCount = 0;
}
if(switch1Count == 1)
{
	relay1_fwd = 1;
	switch1Count = 1;
	if1 = 1;
}
if(switch1Count == 0)
{
	relay1_rev = 1;
	switch1Count = 2;
}

Remember KISS.


char activated = 0;

if(switch == 1) // If we told it to change states
{
	if(activated == 0)
	{
		relay1_fwd = 1;
		relay1_rev = 0;
		activated = 1;
	}
	else
	{
		relay1_fwd = 0;
		relay1_rev = 1;
		activated = 0;
	}
}

Voila.

Not quite… that code requires a very fast trigger finger… :slight_smile:

Basically:


char oldstate;

if (p1_sw_top && !oldstate) {
 relay1_fwd = !relay1_fwd;
 relay1_rev = !relay1_rev;
}
if (p1_sw_top != oldstate) oldstate = p1_sw_top;

Should work. It requires you to release the button and press it again to re-activate the change.

Thanks,
do you mean “int activated?”
Thanks again.

Nope, char will work fine. In that case he’s referring to the size of the data, char uses up less memory then an int. unsigned chars range from 0-255, while ints have a lot bigger range. Since theres no bool or a 0-1 value, char is the smallest

Err, my code wasn’t exactly perfect. You would have to hit the button very fast or else it would execute multiple times. I didn’t test Devicenull’s code, but I’d go with that. I’m sure it works better than mine.

Devicenull’s code? Is that on the forums?

He is referring to the gentleman that posted a few posts above you, specifilcally post number 3.

oops. My bad. All this work is already starting to take a toll on me (especially since my only experienced programming peer is on a 8 day trip to the other coast.)

Would you put the toggle switch code after the initialization of the default relay switches? If not where? Would you want to comment out the default relay switch setup?

I am editing the default camera files for the toggle switch. I think it is possible that the camera files won’t let the toggle switch work (until I change something at least) because it won’t printfs won’t print (the camera ones do though)

all of the code listed so far has missed something: switch bounce

when you open or close a simple switch the contacts do not immediately change state and then stay there, they ‘bounce’.

If you looked at the switch on a scope it would look like a squarewave for up to 100mS.

There are two ways basic ways to debounce a switch: HW and SW.

In HW you would need to put a cap across the switch, so that the cap will charge or discharge when the switch is closed or open, and the RC time constant will absorb the bouncing. Instead of a squarewave signal you will see an exponential ramp that (with the right cap) will not cross the On and Off levels more than once. To do this correctly you really need an oscilloscope to see the waveform coming off the switch.

To debounce a switch in SW you use a SW timer. The easy way is, when you see a switch close you immediately accept that as a user input (state = closed) and do whatever you need to do (turn a motor on, turn a motor off… whatever)

but you then set a ‘debounce’ flag. You will not accept another switch closure until that debounce flag is cleared.

When you see the switch open again you decrement a debounce counter (one that will add up to 100mS or more) and you keep reading the switch on each loop. If you see the switch closed again while the debounce flag is still set, you restart the counter to its initial value (still bouncing, start the countdown over).

Once you have polled the switch for 100mS, and it stayed open each time, your debounce counter will reach 0, and you can clear the debounce flag.

This SW method gives you an instant response when you push the button, and it debounces when you take your finger off.

BTW, if you dont want to debounce your switches, the other way is to use two switches, one for ON and one for OFF. That way your outputs dont toggle while the switch is bouncing.

Edited to add: The really annoying thing about switch bounce is it happens so fast that you may not see it. If the switch bounce is toggling your output, then sometimes your system will end up in the correct state (on when you wanted on…) and randomly it will end up in the wrong state. It will act flakey, and if you dont immediately say to yourself “Ah! SwitchBounce!” it will drive you crazy trying to debug your code.

I have some experience with programming, but I’m completely lost. What is HW and SW? Also I kinda have to use a toggle swich because our electrician is completely obsessed with it and it would be inconvenient to have switches everywhere at the competition (like we did last year somewhat).

For HW are you physically putting a cap over the switch? Seems a little impractical.

So is SW basically it switches the state of the switch when you take your finger off it (sort of)? Or is it when you press a switch, it doesn’t accept that switch being pressed for a certain amount of time?

HW =Hardware solution (using a capacitor). the cap could be wired right across the switch, but the value of the cap depends on several factors in your system, and is best determined by testing the results with an oscilloscope (digital scope preferrably).

SW= Software (programming). The method I described accepts the button push immediately (as long as the ‘debounce’ flag has not been previously set), and it starts a timer when the button is released. The SW switches state immediately when the button is pushed (because that is when the driver wants something to happen: …NOW!) Then it watches the button to see when it is released, and makes sure it stays released for the debounce time (100mS) until it will accept another NOW! from the driver.

The best way to visualize a bouncing switch is when someone pushes the button slowly, very slowly till it just makes contact, and they hold it there. What will the code see on the input? ( a mess!) With a one-button solution your drivers will have to be trained to push the button cleanly, not holding their finger on the button and sort-of pressing it. But even when you push it quickly and cleanly, a pushbutton or toggle switch will still bounce.

Two buttons makes everything easier for the SW to handle the inputs, but if you are stuck with one button for ON and OFF, you gotta take what the HW guys gave you and make it work in the code.

Thanks so much. This will help a lot.

I’ve never found contact bounce to be a problem on any joystick button, or on most separate pushbuttons we use. However, we did have to add debounce code for one of our foot pedals a couple of years ago.

usually push buttons are used to turn something on while you hold it, and off when you let it go. In that case, if it goes OnOffOnOffOn for a 100mS when you push it, you probably wont notice (unless you put a scope on the output signal).

The case in this thread, where he wants a single button to act as a toggle, I dont know if Ive seen a team do this before?

People ask about it every year, and they receive pretty much the same programming advice every time. I assume they use it and implement what they asked about.

The TechnoKats have used a toggle function for shifting the drive train between high and low gear for the past few years.

We did last year, and a couple years before that. We had “feet” on our robot that were pneumatically activated to make the robot unmoveable. The button on the control panel toggled their state. Pressing it while they were down would raise them, or lower them if they were up.

I’ve never come across the problem where the signal would bounce. I’m not sure if thats something IFI compensated for, or if it just hasn’t been a problem yet.

Windward: If you use the code that I gave you, the “char oldstate” has to be defined either globally or staticly. Either put it at the top of the code, above any function, or use “static char oldstate;” instead of “char oldstate”. That code should go below the default relay stuff, otherwise they will override it.

I did a little searching on threads from previous years. In the past people have monitored input switches on the operator interface, and seen switch-bounce.

I was thinking perhaps IFI filters the switch inputs, but from what I have been able to find so far, they dont. Unless someone does further testing, or IFI comes up and says they have debounced the switches in the interface, I would design your systems to debounce the switch inputs (user interface and on the robot) if your application requires knowledge of single-push button actions.

from a thread in 2004:

Originally Posted by maxlobovsky
This may or may not be related, but i have found that lots of joystick buttons seem to flicker IE not giving a constant stream of 1’s when they are being pressed. Our code now checks the button over the period of 3 or 4 frames to make sure its really pressed. This is probably a good idea for a winch button anyway, you wouldnt want it accidentally pressed.

Originally Posted by KenWittlief
wow! im impressed that you discovered that by yourself!

Its called ‘switch bounce’ - when you close a switch or pushbutton it takes about a 1/10th of a second for it to make solid contact - the surfaces actually do bounce a tiny bit - so if a fast microprocessor is polling the switch it will see it go 00001101010011110111111011111111111

and your timing is right - 3 frames is about a 100 mS

nice catch!

If you are having problems with the OI reading multiple clicks with one click due to your reaction time being slower then one loop on the processor you can do this:


static unsigned int loops = 30;

if (p1_sw_trig && loops >= 30)
{
  relay1_fwd = !relay1_fwd;
  relay1_rev = !relay1_fwd;
  loops = 0;
}

if (loops < 30)
loops++;

Basically what this does is checks if the button is pushed every 30 processor cycles which with the default code is 786 ms (26.2 ms/Cycle * 30 Cycles). You can change the number from 30 to whatever you want!

Edit: Fixed a small bug