Help with BS2 code optimization
rotary9k
Posts: 26
Hey guys,
I'm working on a project and only know the basics to PBASIC.· I have recently ran into the problem of "EEPROM" full.··I was wondering if anyone could give suggestions as to how I can condense my code.
Basically I have an infinite loop which takes in three variables via SERIN, then executes a certain command based on what those three variables were. So I have:
SERIN 0,84,[noparse][[/noparse]var1]
SERIN 0,84,[noparse][[/noparse]var2]
SERIN 0,84,[noparse][[/noparse]var3]
Then I have a series of IF...THEN statements checking the variables one by one to see what it should do. So I have:
IF (var1 = "M") THEN
·· IF (var2 = "F") THEN
···· IF (var3 = "3") THEN
······· //code here
···· ELSEIF (var3 = "4") THEN
······ //code here
···· ENDIF
·· ELSEIF (var2 = "B") THEN
·····IF (var3 = "3") THEN
······ //code here
···· ELSEIF (var3 = "4") THEN
······ //code here
···· ENDIF
·· ENDIF
ELSEIF (var1 = "T") THEN
·· IF (var2 =
···//blah blah
ENDIF
So var1 can either be M or T.· var2 can be either F,B,L,R. var3 can be 1-9.· So the program first sees whether var1 is M or T. Then proceeds to see if var2 is F,B,L, or R. Then finally proceeds to see which value 1-9 var3 is, then executes a command. After the command is finished executing, the loop goes back to SERIN.
I can post my .bs2 file later when I have access to it.
I'm working on a project and only know the basics to PBASIC.· I have recently ran into the problem of "EEPROM" full.··I was wondering if anyone could give suggestions as to how I can condense my code.
Basically I have an infinite loop which takes in three variables via SERIN, then executes a certain command based on what those three variables were. So I have:
SERIN 0,84,[noparse][[/noparse]var1]
SERIN 0,84,[noparse][[/noparse]var2]
SERIN 0,84,[noparse][[/noparse]var3]
Then I have a series of IF...THEN statements checking the variables one by one to see what it should do. So I have:
IF (var1 = "M") THEN
·· IF (var2 = "F") THEN
···· IF (var3 = "3") THEN
······· //code here
···· ELSEIF (var3 = "4") THEN
······ //code here
···· ENDIF
·· ELSEIF (var2 = "B") THEN
·····IF (var3 = "3") THEN
······ //code here
···· ELSEIF (var3 = "4") THEN
······ //code here
···· ENDIF
·· ENDIF
ELSEIF (var1 = "T") THEN
·· IF (var2 =
···//blah blah
ENDIF
So var1 can either be M or T.· var2 can be either F,B,L,R. var3 can be 1-9.· So the program first sees whether var1 is M or T. Then proceeds to see if var2 is F,B,L, or R. Then finally proceeds to see which value 1-9 var3 is, then executes a command. After the command is finished executing, the loop goes back to SERIN.
I can post my .bs2 file later when I have access to it.
Comments
If the "//code here" stuff does very similar things, you may be able to simplify that part of the program. It would be helpful if you could list the possible combinations of allowed characters and a description of the kinds of things done for each (or an example of the sort of thing).
This would be more helpful than just a copy of your PBasic program.
One of the biggest consumers of program space is the SERIN/SEROUT statements. Your three lines with SERIN could’ve been shortened down to one by doing the following:
SERIN 0, 84, [noparse][[/noparse]var1, var2, var3]
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chris Savage
Parallax Tech Support
I didn't know I could just condense my 3 SERIN commands to·SERIN 0,84,[noparse][[/noparse]var1, var2, var3]. I'll do that.
As for my code, here is a more detailed explanation:
var1 = either "M" or "T", meaning "Move" or "Turn"
var2 = either "F","B","L","R", meaning "Forward", "Backwards", "Left", "Right".
var3 = any number 1-9, meaning distance in feet or degrees (9 = 90degrees, 6 = 60degrees, etc).
Combinations include:
(M) - (F/B/L/R) - (1:9) which commands the bot to Move Forward [noparse][[/noparse]var3] feet, Move Backwards [noparse][[/noparse]var3] feet, Move Left [noparse][[/noparse]var3] feet, Move Right [noparse][[/noparse]var3] feet.
(T) - (L/R) - (3/6/9) which commands the bot to Turn Left [noparse][[/noparse]var3x10] degrees, Turn Right [noparse][[/noparse]var3x10] degrees.
' {$STAMP BS2}
' {$PBASIC 2.5}
Var1 VAR Byte
Var2 VAR Byte
Var3 VAR Byte
TempVal VAR Byte
SelVal··· VAR Byte
Index··· ·VAR Byte
LeftValue· VAR Word
RightValue VAR Word
I············ ·VAR Word
LeftPin· CON 14
RightPin CON 15
MAIN:
· SERIN 0,84,[noparse][[/noparse]var1]
· SERIN 0,84,[noparse][[/noparse]var2]
· SERIN 0,84,[noparse][[/noparse]var3]
· SelVal = 0
· LOOKDOWN· Var1, [noparse][[/noparse]"M", "T"], TempVal ' TempVal gets zero or one
· SelVal = TempVal * 100
· LOOKDOWN Var2, [noparse][[/noparse]"F", "B", "L", "R"], TempVal ' Tempval gets 0 through 3
· SelVal = TempVal * 10
· 'SelVal = SelVal + Var3
· ' Okay, when here, SelVal can equal:
· ' MFx == 001..009, MBx == 011..019, MLx == 021..029, MRx == 031..039,
· ' TFx == 101..109, TBx == 111..119, TLx == 121..129, TRx == 131..139
· '· This gives you 8 x 9 == 72 possibilities.
· '· That's a LOT of possibilities -- are you sure you use them all?
· '· Can you "parameterize" the 1..9 entries so you only need 8 subroutines
· '· instead of 72 of them?
· LOOKUP SelVal, [noparse][[/noparse]000, 010, 020, 030, 100, 110, 120, 130], Index· ' Index gets 0 through 7
· ON Index GOSUB MF_Hit, MB_Hit, ML_Hit, MR_Hit, TF_Hit, TB_Hit, TL_Hit, TR_Hit
· GOTO MAIN
MF_Hit:
· LeftValue = 650
· RightValue = 850
· FOR I = 0 TO (Var3 * 100)· ' or whatever, experiment for the right values...
··· GOSUB SendValues
··· PAUSE 20
· NEXT
· GOSUB StopWheels· ' Optional
· RETURN
MB_Hit:
· RETURN
ML_Hit:
· RETURN
MR_Hit:
· RETURN
TF_Hit:
· RETURN
TB_Hit:
· RETURN
TL_Hit:
· RETURN
TR_Hit:
· RETURN
SendValues:
· PULSOUT LeftPin, LeftValue
· PULSOUT RightPin, RightValue
· RETURN
StopWheels:
· PULSOUT LeftPin, 750
· PULSOUT RightPin, 750
· RETURN
' So var1 can either be M OR T.· var2 can be either F,B,L,R. var3 can be 1-9.
' So the program first sees whether var1 is M OR T. THEN proceeds TO see
' IF var2 is F,B,L, OR R. THEN finally proceeds TO see which value 1-9 var3 is,
' THEN executes a command. After the command is finished executing, the LOOP goes back TO SERIN.
' *** EDIT ***
' Note I wrote the above before you mentioned that "TB" (Turn Backwards) made no sense.· You can still
' leave the code in as an "empty" "Return" statement.· This shouldn't cause a problem with the code,
' since it will never be commanded, and would be ignored if it was commanded.· It also makes the
' lookup/lookdown code very short and simple if you·leave it in.
' In "Truth Table" coding we call this a "don't care" condition.
Post Edited (allanlane5) : 6/2/2008 9:09:06 PM GMT
By the way, notice how optimization is rarely a matter of how to fiddle with the specific statements of the program and much more about rethinking how you do things in terms of the overall goals and structure of the program.
Post Edited (Mike Green) : 6/2/2008 8:57:19 PM GMT
So, probably the only commands you really have to "populate" will be move forward x, move backward x, turn left x degrees, turn right x degrees. You do have some "commands" left over to do fancy "move forward while turning" moves, though.
SelVal = 0
LOOKDOWN Var1, [noparse][[/noparse]"M", "T"], TempVal ' TempVal gets zero or one
SelVal = TempVal * 100
LOOKDOWN Var2, [noparse][[/noparse]"F", "B", "L", "R"], TempVal ' Tempval gets 0 through 3
SelVal = TempVal * 10
Should that last line of code be SelVal = SelVal + TempVal*10 ? Seems like you need to add the value to the first SelVal value.
And I never thought about calculating the pulse count for distance by including the actually var3 in it. Before I had individual cases for each number 1-9, so you can probably imagine how many lines of code I had. Had a feeling there must've been a better way . I'm going to try to implement this code today and let you know how it goes.
Thanks again you've all been so helpful.
And yeah, when executing Move Left, Move Right commands, I had it turn left/right 90degrees, then forward. That's pretty much the only way right?
Btw, the idea of moving forward while spinning sounded pretty cool. Can you point me somewhere where I can learn how to do that?
Post Edited (rotary9k) : 6/2/2008 10:49:08 PM GMT
IF TempVal = -1 THEN GOTO CommandErr
You can also use statements like ON TempVal GOTO or ON TempVal GOSUB. Look at their description in the PBasic manual.
SEROUT 16, 16468, [noparse][[/noparse]"> ", Var1, ",", Var2, ",", Var3, " == ", DEC SelVal,CR]
just before the ON ... GOSUB, to show you what the stuff is really doing.
And yes, I blew the "* 10" clause, but you got the intent there.
Oh, and why is your "SERIN" on pin zero? Shouldn't it be on Pin 16 (which is the "Programming Port")?
Post Edited (allanlane5) : 6/3/2008 1:48:09 AM GMT
I still can't seem to get the code working quite right. Using the SEROUT command you showed me, It seems that giving commands like MF1 will result in a SelVal of 0 instead of 000, which apparently then causes the robot to move forward indefinitely until i reset.
Whats also strange is the fact that a command like TR6 gives 1030 instead of 130. I looked over the code and can't find where the error is.
And about the bot spinning while moving forward...how do I do that?
Sorry I wasn't able to check everything out on a local BS2, but I'm glad you figured it all out.
The bot "turning while moving forward" is quite difficult (meaning finicky. Meaning not really reliable.) The way you do it is to get one wheel spinning forward slightly faster than the other wheel. The "PULSOUT" numbers between 750 and 850 will give slight differences in speed, depending on how far away from 750 they are.
Oh, and the 1030 probably comes from multiplying the wrong number by 10. SelVal = SelVal + 100 * Var1: SelVal = SelVal + 10 * Var2 ' That should work.
Note BS2 doesn't follow the "multiply before add" rule -- instead it applies the operators strictly left to right (unless you use parens).
I was also trying to implement some kind of "Play a song" feature using the RTTTL format, but it looks like the standard BS2 stamp is definitely not large enough to add that to my existing code. I was thinking about other BS2 modules for additional memory, but had some questions:
Mike, you mentioned: "That won't provide more than 2K, but does provide the capability of several 2K "programs" and you can divide up the functionality maybe with each 2K "slot" handling one or two commands." --regarding other stamp modules.
What exactly does that mean? In my case, would it mean that one 2k"slot" would handle my existing code and another 2k"slot" can handle the RTTTL code I want to implement, but they won't be able to interact with each other?