Shop OBEX P1 Docs P2 Docs Learn Events
Help with BS2 code optimization — Parallax Forums

Help with BS2 code optimization

rotary9krotary9k Posts: 26
edited 2008-06-03 18:05 in BASIC Stamp
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.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2008-06-02 20:23
    There's only 2K bytes available for your program. The IF/THEN statements can take a certain amount of memory, but probably the "//code here" stuff is what's taking most of it. If the different commands are really different, there may not be much you can do other than to use a Stamp with more memory. 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.

    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.
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2008-06-02 20:26
    Hello,

    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
  • rotary9krotary9k Posts: 26
    edited 2008-06-02 20:39
    Thanks Mike and Chris,

    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.
  • allanlane5allanlane5 Posts: 3,815
    edited 2008-06-02 20:43
    This looks like a great place for "lookdown" and "lookup".

    ' {$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
  • Mike GreenMike Green Posts: 23,101
    edited 2008-06-02 20:52
    All of the Move commands are essentially the same. The direction translates into a pair of values to be used to drive the servos. "F" might give 650/650 while "B" would give 850/850. "R" would use 650/850 while "L" would use 850/650. All of the other code is identical for the Move commands. The Turn commands similarly are the same except for the pulse width values used for the servos. A LOOKDOWN statement translates the letters into an index while a couple of LOOKUP statements give you the values for the servo pulses given the index.

    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
  • allanlane5allanlane5 Posts: 3,815
    edited 2008-06-02 21:11
    When thinking about this -- what's a "Move Left x feet" mean? Is that a left turn (in which case, how many degrees?) followed by a forward?

    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.
  • rotary9krotary9k Posts: 26
    edited 2008-06-02 22:41
    Wow, thanks a lot for that sample code. I never knew about the Lookup/Lookdown commands. I went through it and understood it all for the most part, but had a few questions that perhaps you could answer:

    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
  • rotary9krotary9k Posts: 26
    edited 2008-06-02 23:12
    I tried implementing this code, and it seems that no matter what command I give it, it only moves forward, indefinitely. Could you perhaps take a look at this when you have time and let me know if I did something wrong. See attached:
  • Mike GreenMike Green Posts: 23,101
    edited 2008-06-02 23:12
    Do keep in mind that you've got no error checking. Set TempVal to -1 before each LOOKDOWN and check it afterwards like with:

    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.
  • allanlane5allanlane5 Posts: 3,815
    edited 2008-06-03 01:41
    Looks good. I think you need something like:

    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
  • rotary9krotary9k Posts: 26
    edited 2008-06-03 06:11
    SERIN on pin0 is what the examples in the EB500 manual show, and thats what worked for me.

    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.
  • rotary9krotary9k Posts: 26
    edited 2008-06-03 07:06
    Aha! Got it working. LOOKUP doesn't work the way you put it apparently. I changed it to LOOKDOWN and voila. Thanks a lot for your help, this will give me much more space for other implementations.

    And about the bot spinning while moving forward...how do I do that?
  • allanlane5allanlane5 Posts: 3,815
    edited 2008-06-03 12:02
    Ah, you're using an EB500, not a wired connection to the PC. That makes sense, then.

    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).
  • rotary9krotary9k Posts: 26
    edited 2008-06-03 17:47
    Alright, everything is up and running now. I just assumed the BS2 would follow simple arithmetic rules such as Multiply before Add, but paranthesis will do.

    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?
  • Mike GreenMike Green Posts: 23,101
    edited 2008-06-03 18:05
    There's a Nuts and Volts Column on Multi-Bank Programming (www.parallax.com/Portals/0/Downloads/docs/cols/nv/vol3/col/nv87.pdf) which discusses this in detail. You can't call and return from another "slot". There's only a RUN statement, but variables can be shared between "slots". Typically, the main program has several "commands" and one or more of them use the space in another "slot". The main program RUNs a program in another "slot" which then restarts the main program with a variable set to indicate that the main program is continuing from a command that switched to another "slot" rather than starting from scratch.
Sign In or Register to comment.