Shop OBEX P1 Docs P2 Docs Learn Events
Too many variables??? — Parallax Forums

Too many variables???

GhiamonsterGhiamonster Posts: 8
edited 2010-05-11 23:42 in BASIC Stamp
Using PBasic 2.5 with a BS2 (Boe Bot kit). Trying to run the following program and get 'Out of Variable Space' message!
From what I understand of the chipset's specs, there's 128 bytes of variable space? Not counting the CON definitions
(and not knowing how much space the PINs take up, there's only 58 bytes taken up by the WORD and WORD Arrays (2 bytes per WORD, correct?).

What am I missing??

' Servo Choreography - Test4Choro2.bs2
' Move 4 servos at the same time, different directions
'
' {$STAMP BS2}
' {$PBASIC 2.5}
S1················ PIN············ 12················· ' First Servo
S2················ PIN············ 13················· ' Second Servo
S3················ PIN············ 14················· ' Third Servo
S4················ PIN············ 15················· ' Fourth Servo
ServCenters······· VAR·········· Word(4)
ServLeftOff········ VAR·········· Word(4)
ServRightOff······· VAR·········· Word(4)
CurrPos············· VAR·········· Word(4)
ServTarget········ VAR·········· Word(4)
Srvs················· VAR·········· Word(4)
ServSpeed·········VAR·········· Byte(4)
BtwnPulses········ CON·········· 20·················· ' ms between servo pulses
counter··········· VAR·········· Word·················· ' Loop index

ServCenters(1)=750
ServCenters(2)=750
ServCenters(3)=750
ServCenters(4)=750
ServRightOff(1)=550
ServRightOff(2)=350
ServRightOff(3)=550
ServRightOff(4)=350
ServLeftOff(1)=450
ServLeftOff(2)=300
ServLeftOff(3)=450
ServLeftOff(4)=300

DEBUG "Centering Servos", CR
GOSUB CenterServos

Srvs(1)=CurrPos(1): Srvs(2)=CurrPos(2): Srvs(3)=CurrPos(3): Srvs(4)=CurrPos(4)

ServTarget(1)=CurrPos(1)-ServRightOff(1)
ServSpeed(1)=5

ServTarget(2)=CurrPos(2)+ServLeftOff(2)
ServSpeed(2)=5

ServTarget(3)=CurrPos(3)-ServRightOff(3)
ServSpeed(3)=5

ServTarget(4)=CurrPos(4)-ServLeftOff(4)
ServSpeed(4)=5

FOR Srvs(1)=Currpos(1) TO ServTarget(1) STEP ServSpeed(1)
·· PULSOUT S1, Srvs(1)
·· Currpos(1)=Srvs(1)
·· IF Srvs(2)<ServTarget(2) THEN
····· PULSOUT S2, Srvs(2)
····· Srvs(2)=Srvs(2)+ServSpeed(2)
····· Currpos(2)=Srvs(2)
·· ENDIF
·· IF Srvs(3)<ServTarget(3) THEN
····· PULSOUT S3, Srvs(3)
····· Srvs(3)=Srvs(3)+ServSpeed(3)
····· Currpos(3)=Srvs(3)
·· ENDIF
·· IF Srvs(4)<ServTarget(4) THEN
····· PULSOUT S4, Srvs(4)
····· Srvs(4)=Srvs(4)+ServSpeed(4)
····· Currpos(4)=Srvs(4)
·· ENDIF
·· PAUSE BtwnPulses
NEXT
END

CenterServos:
·· FOR counter = 1 TO 100
····· PULSOUT S1, ServCenters(1)
····· PULSOUT S2, ServCenters(2)
····· PULSOUT S3, ServCenters(3)
····· PULSOUT S4, ServCenters(4)
····· PAUSE BtwnPulses
·· NEXT
·· CurrPos(1)=ServCenters(1)
·· CurrPos(2)=ServCenters(2)
·· CurrPos(3)=ServCenters(3)
·· CurrPos(4)=ServCenters(4)
·· RETURN

Thanks,
Mike

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2010-05-07 23:48
    There are 26 bytes of variables (13 words) available (VAR). Constants don't count (CON). Some Stamp models have an additional memory space (scratchpad RAM) that's treated differently. The BS2 doesn't have scratchpad RAM.

    The I/O pins are separate. They're accessible as three additional words (and bytes and bits) called INS / OUTS / DIRS.
    You will have to find some way to get by with fewer variables.
  • GhiamonsterGhiamonster Posts: 8
    edited 2010-05-08 01:47
    Looks like time to graduate to a Propeller and a servo controller. Even the BS2px is rather limited.

    Anyone know when the servo·controller board will be available for the Propeller? It looks like there USED to be one for the BS2
    but it's discontinued...
  • MoskogMoskog Posts: 554
    edited 2010-05-08 07:46
    I think that a propeller would be overkill here.

    Why do you use Words on static things like Servcenters?

    Why use Word on a counter that counts only to 100?

    Go through your program and you will find several examples of wasting variable spaces.
  • metron9metron9 Posts: 1,100
    edited 2010-05-08 14:27
    If you used Byte instead of word your numbers would be 0-255, in your routine that calculates could multiply by 3 those values,
    so 250 would be 750, 249 would be 747 so you would lose some resolution but in just the 4 arrays you would save 12 bytes.

    Not sure if 747 to 750 on a servo would be close enough though.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!
  • Mike GreenMike Green Posts: 23,101
    edited 2010-05-08 14:45
    As Moskog noted, some of your variables are static values. They never change. These could be stored in the EEPROM using DATA statements and retrieved with READ statements. The Stamp Manual chapters on these statements will show you how to use them.
  • GhiamonsterGhiamonster Posts: 8
    edited 2010-05-08 14:50
    Originally I DID have byte for the counter...don't know what happened with the WORD buisness but you're right.
    At the time I wasn't sure if the CON wasn't taking up more space than a WORD would. Now that I understand that CON
    doesn't take up Register space, I can change those back.

    The Propeller would be for more complex tasks that I know are coming up. Given the limitations I've already run into here
    with the BS2, I think it may be wise to consider it.

    Metron, that's a good idea (at least to get me through this exercise)! I don't need precision as much as trying out logic.

    I've made a 4 servo "arm" that I'm trying to articulate off the BOE. The code I posted is testing moving all the servos at
    different rates and directions all at the same time. I'm using 4 simply because that's all the servo ports I've got (without
    tearing apart cables and breadboarding. That's the reasoning behind the query for the servo controller.

    Hover1 - that Propeller Servo Controller can be driven off the BS2, correct?
  • Mike GreenMike Green Posts: 23,101
    edited 2010-05-08 15:04
    The Propeller Servo Controller was designed as a replacement for the older servo controller partly because the microprocessor used in the older unit won't be available in the future. It also provides new features and, because it uses a Propeller, could even be used as a stand-alone servo controller. So yes, it can be used with a BS2.
  • GhiamonsterGhiamonster Posts: 8
    edited 2010-05-08 15:25
    Yeah that's the way I'll probably go, but I also see going to the Propeller chip in the near future just for the extra power/capabilities.

    Thanks for all your replies! Although the original intent was to make this all variable driven so I can set variables, call the routine,
    set them to different values, call the same routine, etc., since that's not happening, I DID get the concept to work with the CONs.
    It's possible that using the servo controller will alleviate the necessity for this many variables.

    Here's the code - it drives 4 servos, alternating right/left/right/left 90/45/90/45 degrees at about 1/2 speed:

    ' Servo Choreography - Test4Choro2.bs2
    ' Move 4 servos at the same time, different directions/rates
    '
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    S1················ PIN············ 12················· ' First Servo
    S2················ PIN············ 13················· ' Second Servo
    S3················ PIN············ 14················· ' Third Servo
    S4················ PIN············ 15················· ' Fourth Servo
    ServCenter1······· CON·········· 750
    ServCenter2······· CON·········· 750
    ServCenter3······· CON·········· 750
    ServCenter4······· CON·········· 750
    ServRightOff1····· CON·········· 550
    ServRightOff2····· CON·········· 350
    ServRightOff3····· CON·········· 550
    ServRightOff4····· CON·········· 350
    ServLeftOff1······ CON·········· 450
    ServLeftOff2······ CON·········· 300
    ServLeftOff3······ CON·········· 450
    ServLeftOff4······ CON·········· 300

    CurrPos··········· VAR·········· Word(4)
    ServTarget········ VAR·········· Word(4)
    Srvs·············· VAR·········· Word(4)
    ServSpeed········· CON·········· 5
    BtwnPulses········ CON·········· 20·················· ' ms between servo pulses
    counter··········· VAR·········· Byte·················· ' Loop index
    DEBUG "Centering Servos", CR
    GOSUB CenterServos
    Srvs(1)=CurrPos(1): Srvs(2)=CurrPos(2): Srvs(3)=CurrPos(3): Srvs(4)=CurrPos(4)
    ServTarget(1)=CurrPos(1)-ServRightOff1
    'ServSpeed(1)=5
    ServTarget(2)=CurrPos(2)+ServLeftOff2
    'ServSpeed(2)=5
    ServTarget(3)=CurrPos(3)-ServRightOff3
    'ServSpeed(3)=5
    ServTarget(4)=CurrPos(4)+ServLeftOff4
    'ServSpeed(4)=5
    FOR Srvs(1)=Currpos(1) TO ServTarget(1) STEP ServSpeed
    ·· PULSOUT S1, Srvs(1)
    ·· Currpos(1)=Srvs(1)
    ·· IF Srvs(2)<ServTarget(2) THEN
    ····· PULSOUT S2, Srvs(2)
    ····· Srvs(2)=Srvs(2)+ServSpeed
    ····· Currpos(2)=Srvs(2)
    ·· ENDIF
    ·· IF Srvs(3)>ServTarget(3) THEN
    ····· PULSOUT S3, Srvs(3)
    ····· Srvs(3)=Srvs(3)-ServSpeed
    ····· Currpos(3)=Srvs(3)
    ·· ENDIF
    ·· IF Srvs(4)<ServTarget(4) THEN
    ····· PULSOUT S4, Srvs(4)
    ····· Srvs(4)=Srvs(4)+ServSpeed
    ····· Currpos(4)=Srvs(4)
    ·· ENDIF
    ·· PAUSE BtwnPulses
    NEXT
    END
    CenterServos:
    ·· FOR counter = 1 TO 100
    ····· PULSOUT S1, ServCenter1
    ····· PULSOUT S2, ServCenter2
    ····· PULSOUT S3, ServCenter3
    ····· PULSOUT S4, ServCenter4
    ····· PAUSE BtwnPulses
    ·· NEXT
    ·· CurrPos(1)=ServCenter1
    ·· CurrPos(2)=ServCenter2
    ·· CurrPos(3)=ServCenter3
    ·· CurrPos(4)=ServCenter4
    ·· RETURN
  • metron9metron9 Posts: 1,100
    edited 2010-05-08 15:32
    Another way to get more out of less.

    Assume you have a number you need 0 to 1500 (Is that the full rotation of a servo with 750 as the center?)

    anyway lets say you need 4 servos and words would be 8 bytes to get full resolution using 0-1500 as your minimum and maximum

    If you used 4 bytes so 0-255 range and then define one additional nibble as control bits. Bits 0..3 would represent Plus or minus

    You would use if then logic to add or subtract the number or some other logic in the calculation.

    Taking the center value of 750, servo1s variable (0-255) could represent adding 250 to 750 or subtracting 250 from 750 by setting or resetting bit 0 in the control mask nibble.

    That gives you a range of 750-255 = 495 to 750+255= 1005. Giving you full resolution but a reduced range.

    Increasing the range you could multiply the servos Byte (0-255 by a factor of 2 and get 750-(255*2) = 750-510 = 240 minimum up to 750 +510 = 1260 maximum, larger range at 1/2 resolution

    Multiply by 3 and you have the same resolution as the original idea but you have added just one bit in a control mask to your overhead. Full range lower resolution.

    Think of it this way, you are waisting 5 bits per variable if your range is 0-1500 and you use a word because they are not being used.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!

    Post Edited (metron9) : 5/8/2010 3:37:50 PM GMT
  • MoskogMoskog Posts: 554
    edited 2010-05-08 18:44
    And to make your program more readable you could use one singel name for all CONs with same value.

    instead of

    ServCenter1······· CON·········· 750
    ServCenter2······· CON·········· 750
    ServCenter3······· CON·········· 750
    ServCenter4······· CON·········· 750

    ..you can use:

    ServCenter CON 750


    And change the subroutine to

    ····· PULSOUT S1, ServCenter
    ····· PULSOUT S2, ServCenter
    ····· PULSOUT S3, ServCenter
    ····· PULSOUT S4, ServCenter

    ·
  • GhiamonsterGhiamonster Posts: 8
    edited 2010-05-11 18:46
    I've thought about the DATA/READ and fully intend to take advantage of this in a later version (once I get past this variable thing).

    The program is just a first pass/concept. My ultimate goal is to have a variable driven compact routine that will
    allow me to "choreograph" a homemade "arm" consisting of 4 servos with all servos able to move at the same time with different
    rates/directions. So far, the concept looks good.

    I'm now running into a POSSIBLE bug that doesn't seem directly related to the program. From all I see, no matter what I do, it
    LOOKS like one of the variables is getting corrupted.

    I'm using metron9's idea of using numbers below 255 and multiplying to get the servo values I need (thanks!). In this way I
    can get the variables I need within the 26 byte limitation.

    Here's a code snippet, (first the variable definition):

    S1················ PIN·············· 12················· ' First Servo
    S2················ PIN·············· 13················· ' Second Servo
    S3················ PIN·············· 14················· ' Third Servo
    S4················ PIN·············· 15················· ' Fourth Servo

    ServCenter········ CON············· 150·················· ' Servo centering constant

    OffsetBit········· VAR········· Byte(4)·················· ' Will contain a 0 or 1 for each servo indicating which direction to move

    ServOffset········ VAR········· Byte(4)·················· ' Will contain 1-500 to determine how far to move the servo

    CurrPos··········· VAR········· Byte(4)·················· ' Servo's current position
    ServTarget········ VAR········· Byte(4)·················· ' (Calculated CurrPos(n)+/-ServOffset(n) - plus or minus depending on OffsetBit(n)) Target position of the servo
    Srvs·············· VAR········· Byte(4)·················· ' Contains the WORKING version of CurrPos - may be able to remove this and just use CurrPos...
    ServSpeed········· VAR········· Byte(4)·················· ' Step factor to use in moving from CurrPos to ServTarget

    BtwnPulses········ CON·············· 20·················· ' ms between servo pulses
    AddData··········· VAR············ Word·················· ' Used to index through EEPROM

    And the code pertaining to my problem:

    ' The DATA statements below describe the movements of the servos. There are groups of 12, subdivided
    ' into groups of 3 for each servo, in order from 1-4.
    'Positions of the data statements are:
    '·· 1··· Direction - 0 or 1, 0=Right, 1=Left
    '·· 2··· Pulses - (divided by 5) How far to move the servo from it's CURRENT position
    '·· 3··· Speed - How fast to move the servo - 1=slowest
    '
    Datain_1 DATA 1,100,3,0,100,3,1,100,3,0,100,2,
    ············· 0,100,1,1,100,2,0,100,5,1,100,1,
    ············· 0,0,0,0,0,0,0,0,0,0,0,0,0

    FREQOUT 4,2000,2000

    GOSUB CenterServos

    AddData=0
    DO
    ·· Srvs(2)=CurrPos(2)
    ·· Srvs(3)=CurrPos(3)
    ·· Srvs(4)=CurrPos(4)
    ·· 'READ Datain_1 + AddData, OffsetBit(1),ServOffset(1),ServSpeed(1),
    ·· '························ OffsetBit(2),ServOffset(2),ServSpeed(2),
    ·· '························ OffsetBit(3),ServOffset(3),ServSpeed(3),
    ·· '························ OffsetBit(4),ServOffset(4),ServSpeed(4)
    ·· READ Datain_1 + (AddData· + 0), OffsetBit(1)
    ·· READ Datain_1 + (AddData· + 1), ServOffset(1)
    ·· READ Datain_1 + (AddData· + 2), ServSpeed(1)
    ·· READ Datain_1 + (AddData· + 3), OffsetBit(2)
    ·· READ Datain_1 + (AddData· + 4), ServOffset(2)
    ·· READ Datain_1 + (AddData· + 5), ServSpeed(2)
    ·· READ Datain_1 + (AddData· + 6), OffsetBit(3)
    ·· READ Datain_1 + (AddData· + 7), ServOffset(3)
    ·· READ Datain_1 + (AddData· + 8), ServSpeed(3)
    ·· READ Datain_1 + (AddData· + 9), OffsetBit(4)
    ·· READ Datain_1 + (AddData· + 10), ServOffset(4)
    ·· READ Datain_1 + (AddData· + 11), ServSpeed(4)
    ·· IF ServOffset(1)=0 THEN GOTO Endit

    When I run this (see screenshot) and the first READ occurs, it's looking like ServSpeed(4) - the last read - always gets 16. No matter what number is in
    the data statement AND no matter where I put the read - I even swapped ServSpeed2 (along with the appropriate index) and ServSpeed(4) STILL
    corrupted to 16. It's almost like when I use ALL available variable slots the 26th gets whacky.
    590 x 581 - 124K
  • metron9metron9 Posts: 1,100
    edited 2010-05-11 19:04
    ServOffset VAR Byte(4) ' Will contain 1-500 to determine how far to move the servo

    Byte is 0-255

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!
  • GhiamonsterGhiamonster Posts: 8
    edited 2010-05-11 19:44
    Sorry - typo in the comment. Notice that all the offset values are 100. I was thinking that the FINAL value would be 500 and is calculated at PULSOUT time...
    I don't even get to any calculations. The data (in the case of the first DATA line) for ServSpeed(4) should be 2, reading as 16. All other numbers look good.
    Driving me nuts.
  • metron9metron9 Posts: 1,100
    edited 2010-05-11 20:53
    Hmm, I will load it up and see what I get, i can't see anything wrong in the program unless the word declaration is messing with some kind of an offset, you could try defining the word variable as the first declaration and see if that could be causing the problem. Maby remove it and use a constant for testing the theory.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Think Inside the box first and if that doesn't work..
    Re-arrange what's inside the box then...
    Think outside the BOX!
  • GhiamonsterGhiamonster Posts: 8
    edited 2010-05-11 23:04
    Oh! Oh! (waving his hand from the back of the class)

    I'll try getting rid of the Word (AddData) and using SRV(1) - it's used only in the DO loop below the READ loop...that'll free up 2 bytes.
    BRB
  • GhiamonsterGhiamonster Posts: 8
    edited 2010-05-11 23:42
    Alrighty then...curiouser and curiouser.

    Got it to work, but in a most weird way. Started out to multi-task a variable, but that didn't work out logically. Used Srv(1)
    in place of AddDATA thinking it only got used in 1 DO (which it did)...but zeroed it out at the beginning of each READ loop..
    then wondered why it kept looping and looping (duh).

    So then added AddData back in (my READ Address offset), changing from Word to Byte just to get back 1 byte. I had it this way before and
    was getting strange corruption (a different one). It should start with zero, usually would start with some random number. Each
    time through the loop it would ALWAYS be somewhere between 12 and 15! Changed it to Word and all was good. I mention this because I thought
    it was weird that a variable defined as Byte would do this with a number WELL BELOW 255.

    Now, back to the original problem (that pesky 16 in the ServSpeed(4) variable). In the course of scratching my head on all this, I decided to
    regroup a couple things in the variable section (being the good little programmer I am) and move the ServSpeed array from under Srvs
    to under the ServOffset array (so the group would match the data coming from the READs).

    Whan Bam! It works!

    I'll have to put a bunch more DEBUG statements in to see what's being corrupted now because I'm sure SOMETHING's still corrupting.
    Just don't know what...yet

    I've attached the full program along with a screenshot of the memory map in case you want to take a look.

    Thanks for your assistance!!!
Sign In or Register to comment.