View Full Version : Solution to Timing Loops
Steven Carmain
26-01-2003, 12:43
I have found out how to time. Based of the information from Innovation First, a loop is every 26.2 ms, assuming your code does't lengthen it. Based off of that, there are 38.167938931297709923664122137405 loops per sec. So to do close timing without overloading the stamp, you do:
Time VAR byte
RealTime VAR byte
Time = Time + delta_t + 1
if Time > 38 then
Time = Time - 38
RealTime = RealTime + 1
EndIf
This way only uses 2 bytes insted of a byte and a word. I tryed the delta_t * 262 / 10 but it overloaded the stamp and was very inaccurate.
Based of of this formula, then the basic stamp will be 0.530431579 seconds fast at end of match.
You can check this information on this xls I inclosed.
Anthony Kesich
26-01-2003, 15:31
:D i must applaud you for your idea. I myself, being a rookie programmer on a rookie team, am just getting the hang of the language, but after reading the forum got this idea yesterday, but then flushed it out, on one basis. doesn't delta_t count the total number of packets missed since starting the program? :confused:
-Anthony
Originally posted by Anthony Kesich
total number of packets missed since starting the program? [/B]
No, delta_t counts the number of missed packets since your last serin. it gets reset to 0 with each serin.
Anthony Kesich
26-01-2003, 16:07
thats good to hear, you always want to check your bases. you know, play it safe.
-Anthony
Steven Carmain
26-01-2003, 21:19
Did you get the xls. If you guys didn't, then can I have a email address if you want a copy or to post it in the internet
You can attach it to your post as a file. That would probably be best. That way everyone can download it straight from here.
Greg McCoy
27-01-2003, 08:08
Originally posted by Steven Carmain
I have found out how to time. Based of the information from Innovation First, a loop is every 26.2 ms, assuming your code does't lengthen it.
How is this possible? Unless you use only the default code, this number will change, and you have to change the code if you are going to do anything automated.
It's really not that hard to just figure out the numbers by guess and check.
You can do a timer with 2 bytes too, only difference is that you can only count to 255, and when you reach this number you simply start a new step, as documented in my programming sample in the white papers.
Steven Carmain
27-01-2003, 08:17
If you do the research like I did, then you would see that a loop is 26.2 ms a loop. If your code is shorter then you wait at serin until you get the information and start the loop over. If you take too long in your code, then the delta_t comes in. It count the number of loops you missed as long as it is in the serin. If you miss 5 serins then you have the basic run error. So in theory, this should be accurate.
Anthony Kesich
27-01-2003, 22:32
all i know is this code works. I played with basic autonomous mode today (this isn't that sad, seeing as i am the only real programmer at my school, this is a rookie team, and i have taught myself almost all of the code) and this works like a charm. Since most people only use timing in auton mode, you will only be off by about .066 seconds, and that is extremely insignificant. (It was so little that i didn't notice at all)
-Anthony
one question. why the timing loops? why not just a counter?
i made a little program a few days ago, all it does is use a byte and a nibble, and based on the counter and nibble advances through a select case. all you do to control it is adjust the byte to how high to count, and always advance the nibble by one. you can get up to 18 operations in this way, actually more if you don't use the full 255 loops from one byte at a time.
if this doesn't make sense, i'll post the code tomorrow afternoon when i find it. it's very simple when you see it, and it works fine. no need to worry about time, because if the loop gets longer, even a timer would get screwed up.
Greg McCoy
28-01-2003, 19:33
Yeah, that's pretty much what I did. It seems to me that it does the exact same thing with less complexity and the exact same efficiency if done correctly.
First, this thread starter knows what he's talking about. Second, a counter counts loops. The number of loops you get in one second changes. Don't believe me:
copy a simple statement 100 times, or use some calc in your program and see how slow the counter goes.
I can forsee that this years coding is that complex when compared to last years (all we needed were a few if statements). The delta_t is the only TRUE thing in your code, so it is imperative that you do the auton mode the way suggested, and do NOT use counters.
GUESS AND CHECK IS NOT HELPING US LEARN ANYTHING
uh, i can control how long it does something based on counting with cycles AND delta_t. it's the same as a timing loop, minus the extra memory and added difficulty. and i've seen no problems so far with my code. sure, it aint pretty, but it's dead reckoning, it's not supposed to be!
There is no advantage to converting Stamp loops to "real" time. It is a 1-to-1 conversion, meaning that each "real" time value corresponds to some fixed number of loops and vice-versa. For example, the following code would do exactly the same thing:
loopCnt VAR byte
loopCntHigh VAR nib
loopCnt=0
loopCntHigh=0
SERIN...
if (loopCnt + 1 + delta_t > 255) then loopCntHigh=loopCntHigh + 1 : loopCnt=loopCnt+1+delta_t-255 else loopCnt=loopCnt+1+delta_t
SELECT (loopCntHigh<<8 + loopCnt)
CASE range1Low TO range2High
'do stuff
CASE range2Low TO range2High
'do other stuff
CASE ELSE
'do even more stuff
ENDSELECT
SEROUT...
This will let you count up to 4096 loops, which is approx 1min 45s worth of autonomous time. Plus, it only uses 1.5 bytes!
Questions about the above stuff? Email or PM me and I'd be more than happy to explain.
Once again you correct me!!! Oh, I'm lazy anyway but thanks for the free code. Only one question have I:
where'd you get the 8 from in SELECT(loopCntHigh<<8 + loopcnt)
i think you and i are on the same page (only i'm on a different plane) , and its great learning from you!!!
Greg McCoy
29-01-2003, 21:08
Yes! He explained it better than I did. One thing that I would add is if you are really strained for RAM is that you could keep the counter a byte and if you need numbers bigger than the byte will supply, just add steps until you get the length you need.
Originally posted by mjt902
Once again you correct me!!! Oh, I'm lazy anyway but thanks for the free code. Only one question have I:
where'd you get the 8 from in SELECT(loopCntHigh<<8 + loopcnt)
i think you and i are on the same page (only i'm on a different plane) , and its great learning from you!!!
The 8 will shift it left by 8 bits, leaving enough space for the byte (8-bits) to fill in the newly created free space.
Here's an example:
Assume loopCntHigh is 3 (0011 in binary), meaning we've looped through 256 values of loopCnt 3 times.
Assume loopCnt is 199 (11000111).
Then: loopCntHigh<<8=001100000000
Add loopCnt: 001111000111, which is 967. This makes sense as 256*3+199=967.
Does that make any sense? Bit shifting operations are always messy, but sometimes they are the easiest solution to problems like this (a single number spanning multiple variables).
Caleb Fulton
30-01-2003, 08:46
Rob: Is there a place online that documents the mathematical limits of PBasic?
I ask because I like your bytevariable<<8+nibblevariable trick :)
Originally posted by Caleb Fulton
Rob: Is there a place online that documents the mathematical limits of PBasic?
I ask because I like your bytevariable<<8+nibblevariable trick :)
Depends on what limits you are talking about. The Stamp manual from Parallax contains all the math operators, etc that the Stamp supports, but it doesn't give many good examples of how you would use most of it.
For me, I've picked most of it up doing a LOT of C/C++ stuff, much of which includes bit-operations such as this. Randall Hyde's assembly language tutorial (http://webster.cs.ucr.edu/Page_asm/ArtofAssembly/0_ArtofAsm.html) has some really good info on binary math and logic, but it isn't exactly and easy read. Like always, I'm available to answer any questions anybody comes up with, so feel free to drop me a PM or email.
--Rob
Mike537Strategy
01-02-2003, 15:29
I'm trying to use the original timer code from the first thread in a simple dead reckoning pattern. My code has the time calculator directly after the SERIN, has 2 lines of code changing the wheel numbers for the SEROUT, then the SEROUT. It loops this until realtime = whatever time I want. It goes forward, turns right, forward, right, forward, right, then forward. The problem is that after the first forward (Which works perfectly), it just turns right until I turn off the robot. Any ideas why? The variables are the same as the default, delta_t is declared and set to 1 in intilization. The forums aren't being nice and the SERINs are all on one line in the actual code.
do
Serin COMA\COMB, INBAUD, [oi_swA,oi_swB,rc_swA,rc_swB,p2_x,p1_x,p4_x,p3_x,PB _mode,packet_num,p2_y,p1_y,p4_y,p3_y,p2_wheel,p1_w heel,p4_wheel,p3_wheel]
time = time + delta_t + 1
if time > 38 then
time = time - 38
realtime = realtime + 1
endif
p1_y = 254
p2_y = 254
Serout USERCPU, OUTBAUD, [255,255,p1_y,0,p2_y,0,127,127,127,127,127,127,
127,127,127,127]
loop until realtime = 2
do
Serin COMA\COMB, INBAUD, [oi_swA,oi_swB,rc_swA,rc_swB,p2_x,p1_x,p4_x,p3_x,PB _mode,packet_num,p2_y,p1_y,p4_y,p3_y,p2_wheel,p1_w heel,p4_wheel,p3_wheel]
p1_y = 254
p2_y = 0
time = time + delta_t + 1
if time > 38 then
time = time - 38
realtime = realtime + 1
endif
Serout USERCPU, OUTBAUD, [255,255,p1_y,0,p2_y,0,127,127,127,127,127,127,
127,127,127,127]
loop until realtime = 1
do
Serin COMA\COMB, INBAUD, [oi_swA,oi_swB,rc_swA,rc_swB,p2_x,p1_x,p4_x,p3_x,PB _mode,packet_num,p2_y,p1_y,p4_y,p3_y,p2_wheel,p1_w heel,p4_wheel,p3_wheel]
time = time + delta_t + 1
if time > 38 then
time = time - 38
realtime = realtime + 1
endif
p1_y = 254
p2_y = 254
Serout USERCPU, OUTBAUD, [255,255,p1_y,0,p2_y,0,127,127,127,127,127,127,
127,127,127,127]
loop until realtime = 2
do
Serin COMA\COMB, INBAUD, [oi_swA,oi_swB,rc_swA,rc_swB,p2_x,p1_x,p4_x,p3_x,PB _mode,packet_num,p2_y,p1_y,p4_y,p3_y,p2_wheel,p1_w heel,p4_wheel,p3_wheel]
p1_y = 254
p2_y = 0
time = time + delta_t + 1
if time > 38 then
time = time - 38
realtime = realtime + 1
endif
Serout USERCPU, OUTBAUD, [255,255,p1_y,0,p2_y,0,127,127,127,127,127,127,
127,127,127,127]
loop until realtime = 1
do
Serin COMA\COMB, INBAUD, [oi_swA,oi_swB,rc_swA,rc_swB,p2_x,p1_x,p4_x,p3_x,PB _mode,packet_num,p2_y,p1_y,p4_y,p3_y,p2_wheel,p1_w heel,p4_wheel,p3_wheel]
time = time + delta_t + 1
if time > 38 then
time = time - 38
realtime = realtime + 1
endif
p1_y = 254
p2_y = 254
Serout USERCPU, OUTBAUD, [255,255,p1_y,0,p2_y,0,127,127,127,127,127,127,
127,127,127,127]
loop until realtime = 2
do
Serin COMA\COMB, INBAUD, [oi_swA,oi_swB,rc_swA,rc_swB,p2_x,p1_x,p4_x,p3_x,PB _mode,packet_num,p2_y,p1_y,p4_y,p3_y,p2_wheel,p1_w heel,p4_wheel,p3_wheel]
p1_y = 254
p2_y = 0
time = time + delta_t + 1
if time > 38 then
time = time - 38
realtime = realtime + 1
endif
Serout USERCPU, OUTBAUD, [255,255,p1_y,0,p2_y,0,127,127,127,127,127,127,
127,127,127,127]
loop until realtime = 1
do
Serin COMA\COMB, INBAUD, [oi_swA,oi_swB,rc_swA,rc_swB,p2_x,p1_x,p4_x,p3_x,PB _mode,packet_num,p2_y,p1_y,p4_y,p3_y,p2_wheel,p1_w heel,p4_wheel,p3_wheel]
time = time + delta_t + 1
if time > 38 then
time = time - 38
realtime = realtime + 1
endif
p1_y = 254
p2_y = 254
Serout USERCPU, OUTBAUD, [255,255,p1_y,0,p2_y,0,127,127,127,127,127,127,
127,127,127,127]
loop until realtime = 2
Don't forget to reset realtime to 0 between your sections. Or, you could change the "loop until realtime=1" to "loop until realtime=3". From quickly looking over your code, I'd guess that this is the problem.
--Rob
Anthony Kesich
02-02-2003, 20:40
why are all of you making it so hard on yourselves?
just put the time counting loop at the beginning of your autonomous mode, then use if/then statements relating realtime and time. Why repeat it 7 times throughout your code along with serin again and again? plus, why worry about counting for 1 min 45 sec? unless i am extremely mistaken, the auton mode is only 15 seconds long, and i doubt you want to run your robot autonomously after that because no matter how godly of a programmer you are, human senses, adaptability, and recognization will always outdo straight computer logic.
-Anthony
Mike, what is up with all the identical code, don't you think you could go with the flow of the main loop and just do something like this:
':::Timer variables
cntr_cycles VAR byte
seconds VAR nib '15 sec timer,make byte for more time
seconds = 0 'same as your realtime variable
cntr_cycles = 0 'same as your time variable
...
if auton_mode = 1 then do_auton
'non autonomous code
goto skip_auton
do_auton:
':::15 second TIMER::
if cntr_cycles >= 38 then update_timer
goto skip_update_timer
update_timer:
seconds = seconds + 1
cntr_cycles = 0
skip_update_timer:
select seconds
case <6 'until seconds = 5
drive_R = 180 'put drive commands accordingly
drive_L = 180
case <11
drive_R = 127
drive_L = 127
case <16
drive_R = 64
drive_L = 190
endselect
cntr_cycles = cntr_cycles + 1 + delta_t
'debug ?cntr_cycles, tab, ?delta_t, tab, ?cntr_cycles, cr
':::15 second TIMER::
Questions/comments, pm me
Steven Carmain
05-02-2003, 13:12
A problem is your mixing syntaxes. The goto in the beginning is 2.0, but select case is 2.5
Originally posted by Steven Carmain
A problem is your mixing syntaxes. The goto in the beginning is 2.0, but select case is 2.5
There is no problem with his code. You can mix 2.0 syntax into the 2.5 without any problems. It would be better from a style perspective to have said:
if auton_mode=1 then
'auto code goes here
else
'normal here
endif
but it isn't wrong to do it the other way.
You don't need to worry abou the timing, just take your "cue" for the fifteen seconds from when auton_mode changes to zero and comp_mode (or something like that) changes to 1.
Originally posted by Morgoth
You don't need to worry abou the timing, just take your "cue" for the fifteen seconds from when auton_mode changes to zero and comp_mode (or something like that) changes to 1.
But if you're doing dead-reckoning, you need to know how many seconds have passed so far so that you know what you should be doing.
Ahhhh, now I understand. Thanks for the insight. We are going to follow the line so I didn't think of that.
Greg McCoy
08-02-2003, 10:32
There are many ways to skin the cat, but some ways are better than others :D
Nate Smith
08-02-2003, 15:00
Originally posted by rbayer
But if you're doing dead-reckoning, you need to know how many seconds have passed so far so that you know what you should be doing.
Not necessarily the number of seconds, but rather the amount of time(program cycles work here) your program has been running...and it's easy enough to have a program you can "train"...i'm going to be putting together a white paper sometime later in the season about the autonomous training system I came up with for a team that I got asked to help...
Rickertsen2
08-02-2003, 19:27
prolly a dumb question, but why do you add in delta_t?
[edit]
o wait nevermind.
but how often does the other processor send packets to the stamp?
what about packetnum? what does that do?
Greg McCoy
08-02-2003, 19:41
Originally posted by Rickertsen2
prolly a dumb question, but why do you add in delta_t?
This is what I've been wondering the whole time. "Solution to timing loops"? I didn't know there was a problem, lol...
Originally posted by Greg McCoy
This is what I've been wondering the whole time. "Solution to timing loops"? I didn't know there was a problem, lol...
Using delta_t gives you a more accurate reading of how much time has passed. The problem revolves around the fact that loop speed on the IFI controller is quantized and is always a multiple of 26ms. Therefore, if your code takes 27ms to get through a loop, you're actually going to run as 52ms per loop because you have to wait for the next one.
Using delta_t, you can determine if you missed any 26ms intervals between serins, so you would actually know that 52ms has passed in the previous example instead of "one loop" which could be either 26 or 52ms.
--Rob
Greg McCoy
08-02-2003, 21:15
Ok, that makes sense, but does 26 some milliseconds in drive time really affect the robot as it drives? I ran automated code without this and had almost perfect position accuracy. It seems like an awfully tiny difference to me.
Steven Carmain
09-02-2003, 06:05
Greg, quit screwing up my posts and work on wiring our second drive base, our anti-gravity one. I need the electrical done so I can do the program.
Joe Ross
09-02-2003, 10:17
Originally posted by Greg McCoy
Ok, that makes sense, but does 26 some milliseconds in drive time really affect the robot as it drives? I ran automated code without this and had almost perfect position accuracy. It seems like an awfully tiny difference to me.
It will make no absolutely no difference if the time through the longest set of branches in your code is less then 26 ms. It will make a slight difference if the the occasional loop is more then 26 ms. If each loop takes 120ms, and you assume 26ms per loop and don't use delta_t, you are in big trouble.
Greg McCoy
09-02-2003, 12:39
Originally posted by Steven Carmain
Greg, quit screwing up my posts and work on wiring our second drive base, our anti-gravity one. I need the electrical done so I can do the program.
My intention is not to "screw up posts" or anything of the like, but only to help everyone make better code and solve robot problems. We ALL can learn something new. Discussing topics like this is most certainly helpful to countless teams, both those with a lot of programming experience and those that don't quite have so much skill or knowledge. Sorry if I offended anyone or their ideas...
Rickertsen2
09-02-2003, 17:28
adding delta_t won't make any difference in your code unless your loop takes more than 26ms.
does anybody know what packet_num does?
randomperson
09-02-2003, 23:19
Blah...
I keep seeing posts on timer this, timer that.. why use software timers? So inaccurate if you have lots of code.. I mean, the loop isn't always a set period of time if you mod the code a lot (yeah, we aren't really using anything in the default code except the declarations.. and most of those are gone too.. lol). Using a hardware pulse generator (555 anyone?) allows you to have multiple software timers without worrying too much about loop periods and other useless complex crapola. I mean, you only need a resolution of around 1/4 second at most anyways..
Steven Carmain
10-02-2003, 13:33
Originally posted by randomperson
So inaccurate if you have lots of code.. I mean, the loop isn't always a set period of time if you mod the code a lot (yeah, we aren't really using anything in the default code except the declarations.. and most of those are gone too.. lol).
That is the purpose of delta_t. It always runs and sees how many loops you missed, if any. And I found out it can be a nib insted of a byte to save on variables. Now, if D.J. and Greg finish wiring the drive base...
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.