Shop OBEX P1 Docs P2 Docs Learn Events
Can someone show me how to consolidate this code? — Parallax Forums

Can someone show me how to consolidate this code?

moomoomoomoo Posts: 27
edited 2008-08-28 02:45 in Propeller 1
I need a little help trying to consolidate my code. I have built a full size humanoid with 25 servos hooked up to a servo controller and I need a cleaner code.
I'm not the greatest coder in the world and any help would greatly be appreciated.

Second purpose for this is to cut the amount of memory being used. I've got an IR detector for remote control, which works great, but I can't get all my routines on the chip so I can select the routine I want for example : "walk_forward", "turn_to_right", etc.

Also, what's a simple way to add more memory to the propeller?

Comments

  • Erik FriesenErik Friesen Posts: 1,071
    edited 2008-08-28 01:27
    It looks to me like all the strings are the same. So do like this.

    In the dat section, place your string like,

    dat

    doit byte "your string here",0

    then, simply call the string like

    ssc.str(@doit)
  • Mike GreenMike Green Posts: 23,101
    edited 2008-08-28 01:31
    You can't "add more memory" to the Propeller the way you're thinking of it. There are all sorts of ways to add different kinds of memory like EEPROM or static RAM like the Hydra expansion card, but it's 2nd class memory. It works like an I/O device. It's not usable like the Propeller's hub or cog memory.

    You do need to code "smarter". First of all, you need to define what you want your robot to do, how you want the Propeller and the servo controller to work together. For example, having string constants is a very inefficient way to define movements, particularly if only a couple of servos change position at a time. You could have a table of movement changes where each entry is 3 bytes long. If the first byte is 128, the next two bytes is a 16-bit pause time in 10ms units. If the first byte is 129, the next two bytes is a "T" value. If the first byte is 0 to 127, it's a servo number and the next two bytes is a 16-bit servo position. You need a routine that takes a starting byte index into the table and processes all the entries up to the first pause and returns the byte index to the next set of entries. Your routine would go through these entries, transmitting a command or series of commands to the servo controller, then do the pause (WAITCNT) and return the index to the next place to start. If the pause time is zero, this marks the end of a sequence of movements.

    Your first "attention" set would be written (in a DAT section) as:
    Item1  byte  0, 1500 & $FF, 1500 >> 8
               byte  1, 1500 & $FF, 1500 >> 8
               byte  2, 650 & $FF, 650 >> 8
               byte  3, 1500 & $FF, 1500 >> 8
    ' and so on ...
               byte  27, 1500 & $FF, 1500 >> 8
               byte 129, 900 & $FF, 900 >> 8
               byte 128, 20_000 & $FF, 20_000 >> 8
    ' more sequences ...
               byte 128, 0, 0
    
  • Mike GreenMike Green Posts: 23,101
    edited 2008-08-28 01:44
    You might code your routine like
    pub interpret(tableAddress, startUp) | first, second
       repeat
          first := byte[noparse][[/noparse]tableAddress][noparse][[/noparse]startUp++]   ' Get the first byte
          second := byte[noparse][[/noparse]tableAddress][noparse][[/noparse]startUp++]   ' Get the next byte (LSB of 16 bit value)
          second += byte[noparse][[/noparse]tableAddress][noparse][[/noparse]startUp++] << 8   ' Get the last byte (MSB of 16 bit value)
          case first
             0..127:
                SSC.TX("#")
                SSC.DEC(first)
                SSC.STR(STRING(" P"))
                SSC.DEC(second)
                SSC.TX(" ")
             128:
                if second == 0
                   RETURN -1
                else
                   WAITCNT(second * 10_000 + CNT)
                   RETURN startUp
             129:
                SSC.TX("T")
                SSC.DEC(second)
                SSC.TX(" ")
                SSC.TX(13)
    


    If your table was like in the previous post, you'd call it like
    nextStart := interpret(@Item1,0)
    


    This would start at Item1 and return the index after the "byte 128, 20_000 & FF, 20_000 >> 8" which you'd use to call it again instead of the "0". It would return -1 after the end of a sequence of movements.
  • moomoomoomoo Posts: 27
    edited 2008-08-28 01:58
    OK, first off, I've never coded a DAT section, which explains my inefficient code.

    Erik, your explaination is simple but not enough info for me, but it makes sense.

    Mike, I know you live on this forum and I've read your replies. You definitely know your stuff, but you went over my head.
    Can you rewrite my code the way you would do it so I can see what your talking about. I can then rewrite all the other ones (there's about ten routines).
    Or just explain what each number is doing.
  • moomoomoomoo Posts: 27
    edited 2008-08-28 02:17
    byte 1, 1500 & $FF, 1500 >> 8
    Can you explain this part a little better.

    The "byte 1" is just a reference to the first row of commands, right? Then byte 2 to the next row, and so on.

    The "1500 & $FF", I don't understand.

    The "1500>>8", I don't understand either.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-08-28 02:29
    What I wrote is a really simple interpreter. I noticed that your servo controller strings all had a similar format. There was one item which was a servo number and a position ("#<servo> P<position> "). There was another item that was some kind of timing (ramping) information ("T<time> "). Lastly, there was the wait information for the WAITCNT. Everything seemed to be in terms of these three types of items and the timing information ended the transmitted string (and text line).

    The routine I wrote just goes through the table picking up a byte value and a 16-bit word value (as two bytes) that immediately follows the byte. The byte value is either a servo number (0-127) which is followed by a servo position (the 16-bit value) or the value 129 which is followed byte a time (ramp?) value or the value 128 which is followed by a value used for the WAITCNT. Since this value is only 16 bits and the WAITCNT values are pretty big, I scale it by 10_000 clock cycles. If this WAITCNT value is zero (otherwise invalid), it marks the end of a sequence.

    The interpreter is written to process one line of text ended by the WAITCNT value. It's also written so it can be called again immediately as shown to continue with the next line of text.

    The best way to understand what I've written is to hand execute it. Get a big piece of paper and start with the "nextStart := interpret(@Item1,0)". Pretend you're the Propeller and write down that statement. Do what the statement says and write down any changed variables and anything that's transmitted to the servo controller, then do the next statement and write down any more changes. Keep going until it's done. It sounds like a lot of work, but you'll learn a lot.

    Post Edited (Mike Green) : 8/28/2008 2:38:42 AM GMT
  • Mike GreenMike Green Posts: 23,101
    edited 2008-08-28 02:34
    "byte 1" simply compiles to a byte containing the value 1.

    The comma separates successive bytes

    "1500 & $FF" compiles to a byte computed by taking the value 1500 and stripping out the lower 8 bits (using "& $FF") (the value 220).

    "1500 >> 8" compiles to a byte computed by taking the value 1500 and shifting it right 8 bits to extract the upper 8 bits (the value 5).
  • moomoomoomoo Posts: 27
    edited 2008-08-28 02:45
    Mike, thank you so much!

    "1500 & $FF, 1500 >> 8" your taking the lsb and the msb out of the 1500 or whatever the position number will be.

    Now things are making sense.

    You have expanded my understanding, thanks for you patients!
Sign In or Register to comment.