View Full Version : toggle switch
Windward
16-01-2006, 15:02
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.
devicenull
16-01-2006, 15:51
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.. :)
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.
Windward
17-01-2006, 17:47
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.
Thanks,
do you mean "int activated?"
Thanks again.
devicenull
17-01-2006, 17:58
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
Thanks,
do you mean "int activated?"
Thanks again.
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.
Windward
17-01-2006, 18:22
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?
Francis-134
17-01-2006, 18:58
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.
Windward
17-01-2006, 19:08
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.)
Windward
21-01-2006, 13:31
Not quite.. that code requires a very fast trigger finger.. :)
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.
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)
KenWittlief
21-01-2006, 13:50
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.
Windward
21-01-2006, 14:17
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?
KenWittlief
21-01-2006, 15:27
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.
Windward
21-01-2006, 15:32
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.
Alan Anderson
21-01-2006, 17:57
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.
KenWittlief
21-01-2006, 18:00
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?
Alan Anderson
21-01-2006, 18:37
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.
devicenull
21-01-2006, 18:41
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.
KenWittlief
21-01-2006, 20:48
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
KenWittlief
22-01-2006, 00:37
you have the basic idea, but you need a few more lines of code.
the way its written 'loops' will keep incrementing, eventually it will get to zero and your switches will be ignored for almost a second (till it gets to 30 again, 786mS later)
you have the basic idea, but you need a few more lines of code.
the way its written 'loops' will keep incrementing, eventually it will get to zero and your switches will be ignored for almost a second (till it gets to 30 again, 786mS later)
Small mistake ... I fixed it in the code above!
Windward
25-01-2006, 19:15
I am trying to get the code to work with 2 spikes. It works with 1 spike, but I'm still a little confused on how to modify.
if(initVar != 1)
{
relay2_fwd != relay2_rev;
initVar = 1;
}
if (p1_sw_trig && !oldstate)
{
relay1_fwd = !relay1_rev;
relay1_rev = !relay1_fwd;
relay2_fwd = !relay2_rev;
relay2_rev = !relay2_fwd;
}
if (p1_sw_trig != oldstate)
oldstate = p1_sw_trig;
I initialized the relay2 fwd & rev so it was opposite. Otherwise the code was pretty much the same.
I am not sure where to procede from here.
KenWittlief
25-01-2006, 22:12
what do you want the 2nd spike to do? trigger the same as the first one?
trigger the opposite direction?
devicenull
25-01-2006, 22:56
I am trying to get the code to work with 2 spikes. It works with 1 spike, but I'm still a little confused on how to modify.
if(initVar != 1)
{
relay2_fwd != relay2_rev;
initVar = 1;
}
if (p1_sw_trig && !oldstate)
{
relay1_fwd = !relay1_rev;
relay1_rev = !relay1_fwd;
relay2_fwd = !relay2_rev;
relay2_rev = !relay2_fwd;
}
if (p1_sw_trig != oldstate)
oldstate = p1_sw_trig;
I initialized the relay2 fwd & rev so it was opposite. Otherwise the code was pretty much the same.
I am not sure where to procede from here.
While that may work, It's a bit different then what I had..
if(initVar != 1)
{
relay2_fwd != relay2_rev;
initVar = 1;
}
if (p1_sw_trig && !oldstate)
{
relay1_fwd = !relay1_fwd;
relay1_rev = !relay1_rev;
relay2_fwd = !relay2_fwd;
relay2_rev = !relay2_rev;
}
if (p1_sw_trig != oldstate)
oldstate = p1_sw_trig;
The NOT (!) operator basically toggles the state of it. If it was 0, it becomes 1. If it was 1, it becomes 0.
If thats confusing consider this:
char A = 0;
printf("%i",A);
A = !A;
printf("%i",A);
A = !A;
printf("%i",A);
Will result in this output:
0
1
0
I'm not sure if this post will help, or just confuse you more. Let me know if you still don't understand.
Windward
27-01-2006, 17:19
I want to use the 2 spikes to activate and retract a piston.
I understand how you take the opposite of the present state I didn't realize that I switched the forward and reverse. I will try to fix that next.
KenWittlief
27-01-2006, 19:01
check the electrical section of the pneumatics manual. You only need one spike per cylinder. The two valves can be controlled by the FWD and REV outputs off the spike, using battery ground for the return.
or you can use two diodes, so that FWD powers one valve, and REV (reversed voltage) powers the other valve.
remember the spike has three output states: forward, reverse, and off.
Windward
27-01-2006, 20:31
check the electrical section of the pneumatics manual. You only need one spike per cylinder. The two valves can be controlled by the FWD and REV outputs off the spike, using battery ground for the return.
or you can use two diodes, so that FWD powers one valve, and REV (reversed voltage) powers the other valve.
remember the spike has three output states: forward, reverse, and off.
I tried writing some code to get make it so when I press p1 trigger the piston will close, then wait a little then open, then allow it to be "fired" again.
But when the second wait() comes up the computer either crashes, and with it commented it, it doesn't work. What's wrong.
void wait(void)
{
time = 0;
count = 0;
for (count=0; count <10000; count++)
{
for (time=0; time < 50; time++)
{
prev = 1;
}
time = 0;
}
count = 0;
time = 0;
}
void fire(void)
{
printf("Piston Forward\r");
relay1_rev = 0;
relay1_fwd = 1;
wait();
printf("Piston Back\r");
relay1_fwd = 0;
relay1_rev = 1;
// wait();
printf("Firing done!\r");
prev = 0;
}
if (p1_sw_trig == 1 && prev == 0)
{
prev =1;
fire();
}
KenWittlief
27-01-2006, 20:36
you cant do wait loops like that on robot controller code.
you need a counter than increments on each 'pass through' of the code.
your wait loop is making all the code in the RC wait until the loop is done. The other uC in the RC thinks the code has gone out to lunch, so it shuts the controller down.
Windward
27-01-2006, 20:45
you cant do wait loops like that on robot controller code.
you need a counter than increments on each 'pass through' of the code.
your wait loop is making all the code in the RC wait until the loop is done. The other uC in the RC thinks the code has gone out to lunch, so it shuts the controller down.
So, what would that code look like?
half geek
27-01-2006, 21:23
So, what would that code look like?
char fire(void) //Will return 0 until firing is complete
{
static unsigned int counter = 0;
printf("Piston Forwardr");
relay1_rev = 0;
relay1_fwd = 1;
if (counter > MAX_COUNTER) //MAX_COUNTER is defined in .h
{
printf("Piston Backr");
relay1_fwd = 0;
relay1_rev = 1;
printf("Firing done!r");
counter = 0;
return 1;
}
else
{
counter++;
return 0;
}
}
This will push the piston forward for MAX_COUNTER processor loops (26.2ms each), then retract the piston. When it is called, it should continue being called until it returns a 1.
I'm not exactly sure what the original code is trying to do, but this is my best guess.
Also, its probably error-licious for lack of testing and sorta slapping it together.
I hope it helps though.
remember the spike has three output states: forward, reverse, and off.
Actually four:
forward reverse
off off
off on
on off
on on
Although the spike is labeled fwd and rev, it is really two sperate on/off relays. Doesn't make a lot of sense when hooked up to a piston to have both on, but there are other applications...
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.