Shop OBEX P1 Docs P2 Docs Learn Events
String buffer problem — Parallax Forums

String buffer problem

Ole Man EarlOle Man Earl Posts: 262
edited 2009-04-30 22:48 in Propeller 1
I have some code here that is driving me nuts !
I have a 6DOF board that outputs acceleration xyz and gyro xyz serially at 115200 baud. The board works fine. I have another program that writes to the TV.text the correct data.
The problem here is the data RunningCount,ax,ay,az,gx,gy,gz do not produce the result I expect. They are always 0 and not the actual values.
I call 'Get6DOF' from a part of my autopilot program expecting the data to be printed via tv.text. Only prints '0'.
Any clues ??

I have some code here that is driving me nuts !
I have a 6DOF board that outputs acceleration xyz and gyro xyz serially at 115200 baud. The board works fine. I have another program that writes to the TV.text the correct data.
The problem here is the data RunningCount,ax,ay,az,gx,gy,gz do not produce the result I expect. They are always 0 and not the actual values.
I call 'Get6DOF' from a part of my autopilot program expecting the data to be printed via tv.text. Only prints '0'.
Any clues ??




PUB readDOF
 
   repeat while Rx <> "A"                ' wait for the "A" to insure we are starting with
    Rx := uart.rxcheck                   ' a complete 6dof sentence
        cptr := 0                        ' zero the buffer pointer to start

      repeat while Rx <> "Z" and cptr < 16 ' continue to collect data until the end of sentence ("Z")
      
           Rx := uart.rxtime(3)          ' get character from uart Rx
                  buffer[noparse][[/noparse] cptr++] := Rx   ' save the character in the buff
        buffer[noparse][[/noparse] cptr] :=0                 ' make sure the buffer ends with a 0

         tv.str(string($A,1,$B,12)) 'set tv position to col 1 line 12       
       tv.str(string("                        "))
        x := buffer[noparse][[/noparse] 0]
        y := buffer[noparse][[/noparse] 1]
        z := (x * 255) + y
      tv.str(string($A,1,$B,11,8)) 'set tv position to col 1 line 12
        tv.dec(z)
        tv.str(string(" Count# #of buffer bytes "))
        tv.dec(cptr)
        tv.out(32)
      tv.str(string($A,1,$B,12,8)) 'set tv position to col 1 line 12
    ' tv.str(buffer)
         return                  ' return to calling routine
'-------------------------------------------------------------------------------------------------------------------------------
PUB Get6DOF                          ' primary entry point

read6DOF                               ' Put the data in a buffer from 6DOF and print on tv

x := buffer[noparse][[/noparse] 1]                         'Now put buffer data into variables 'buffer[noparse][[/noparse]0] contains the letter 'A' we don't need
y := buffer[noparse][[/noparse] 2]
z := (x * 255) + y
RunningCount := z

x := buffer[noparse][[/noparse] 3]
y := buffer[noparse][[/noparse] 4]
z := (x * 255) + y
ax := z
  
x := buffer[noparse][[/noparse] 5]
y := buffer[noparse][[/noparse] 6]
z := (x * 255) + y
ay := z
 
x := buffer[noparse][[/noparse] 7]
y := buffer[noparse][[/noparse] 8]
z := (x * 255) + y
az := z

x := buffer[noparse][[/noparse] 9]
y := buffer [noparse][[/noparse]10]
z := (x * 255) + y
gx := z

x := buffer[noparse][[/noparse] 11]
y := buffer[noparse][[/noparse] 12]
z := (x * 255) + y
gy := z

x := buffer[noparse][[/noparse] 13]
y := buffer[noparse][[/noparse] 14]
z := (x * 255) + y
gz := z

                                            'buffer[noparse][[/noparse]15] contains the letter 'Z' that we don't need
return                                   'return to caller
'------------------------------------------------------------------------------------------------------------------------
PUB read6DOF

 uartDOF.start (22,23,0,115200)        ' start uart on pins 22,23 at 115200 baud for 6DOF Atomic board

 repeat while Rx <> "A"       ' wait for the "A" to insure we are starting with
    Rx := uartdof.rxcheck                ' a complete 6dof sentence
        cptr := 0                        ' zero the buffer pointer to start

    repeat while Rx <> "Z" and cptr < 16 ' continue to collect data until the end of sentence ("Z")
      
           Rx := uartdof.rxtime(1)       ' get character from uart Rx
                  buffer[noparse][[/noparse] cptr ++] := Rx   ' save the character in the buff
        buffer[noparse][[/noparse] cptr] :=0                 ' make sure the buffer ends with a 0

    return                               ' return to calling routine
'------------------------------------------------------------------------------------------------------------------------


Post Edited (Ole Man Earl) : 4/29/2009 9:46:46 PM GMT

Comments

  • Ole Man EarlOle Man Earl Posts: 262
    edited 2009-04-29 17:41
    Guys...I have no idea why the text format changed half way thru the posting..............sorry
  • mparkmpark Posts: 1,305
    edited 2009-04-29 18:19
    Please edit your post and make the following changes:
    • Insert a space after every "[noparse][[/noparse]" that's followed by a number.
    • Add "[noparse][[/noparse] c o d e ]" at the top of your code (but remove the spaces)
    • Add "[noparse][[/noparse] / c o d e ]" at the bottom of your code (remove spaces)
    These changes will fix the font issue and preserve indentation.

    It's always a good idea to use the "Preview before posting" feature too.
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-29 19:12
    Hi Earl,

    as long as you don't correct your post you will at best get guesses but no help. And you should post the whole code - if it's to long attach it. And you should describe a bit more in detail what you want to do! And what does the data you receive look like. What about the definition of the variables and the buffer?
    The part with x*255+y very much looks like making a word out of two bytes with a bug and potential for improovement. The bug is that you have to multiply with 256 instead of 255 and the improvement would be to use a shift instead. That's much faster than the mulitplication.

    dx:=x<<8 + y
  • John AbshierJohn Abshier Posts: 1,116
    edited 2009-04-29 19:49
    I am assuming that buffer contains an ASCII (human readable) string. If so, change (using just one set for example)

    x := buffer[noparse][[/noparse]7]
    y := buffer[noparse][[/noparse]8]
    z := (x * 255) + y
    az := z

    x := buffer[noparse][[/noparse]7] - "0"
    y := buffer[noparse][[/noparse]8] - "0"
    z := x * 10 + y
    az := z

    John Abshier
  • Ole Man EarlOle Man Earl Posts: 262
    edited 2009-04-29 21:11
    Thanks John...Part of the problem is the data comes in low byte then high byte. Also I had my definitions for byte word and long for the variables incorrect.
    The x and y variable are byte and z variable is a word. ahh.....I think I see it...x needs to be a word variable also because it gets multiplied by 256 because it is the hi byte part of the data !
    No, the data is not ASCII readable, except for a leading 65 "A" and a trailing 5B "Z". I have corrected most and now I get data BUT some of it is not right.
    the buffer is like this:

    A ll hh ll hh ll hh ll hh ll hh ll hh ll hh ll hh Z

    The 'll' are 8 bit low byte data and the 'hh' are 8 bit high byte data.
    The A and Z characters are to delineate the data coming in at 115K baud from the 6DOF module.
    So the first 2 bytes of data are the Accelerometer x axis data which is ~ 500. this means the high byte should be 5 and the low byte 0 OR..the hi byte low byte combo should be 500 when combined ?

    Thanks for your help on this.

    BTW How do I edit my post to correct my lack of [noparse][[/noparse] c o d e ] no code in the post ?
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-29 21:28
    Klick the pencil in the upper right corner of you post.

    Are you sure that your buffer starts with an 'A'? I don't see the A written to the buffer somewhere. So, conversion should start with buffer[noparse][[/noparse] 0 ].

    When you use rxcheck, you should make sure that you really got a value and not the value that shows you that the buffer is currently empty. (Just want to mention that because it makes no difference in your code as you wait for an 'A' ;o)

    I suppose your buffer is byte? Is the 6DOF sending positive and negative data?
    The sign extend is very likely wrong as well. If Y is bigger than 127 and you convert it to a word, then all the bits 8-15 are set to 1. So you have to convert that without sign extension:
    z:=x<<8 + ($00ff & y )

    Post Edited (MagIO2) : 4/29/2009 9:36:11 PM GMT
  • John AbshierJohn Abshier Posts: 1,116
    edited 2009-04-29 21:45
    If the data is = 500 then the high byte would be $01 and the low byte $f4 or in decimal high would b 1 and low 244
    z := high * 256 + low or 1 * 256 + 244
    of course a shift could be used in place of multiplying by 256

    All of this is for positive numbers only. Looking at the data sheet, it says that the data is positive and that it is MSB then LSB. So the data is
    A countHi CountLow AXHigh AXLow etc. I think an AX=500 string would be $41 $nn $nn $01 $F4 where $nn is the count variable

    John Abshier
  • Ole Man EarlOle Man Earl Posts: 262
    edited 2009-04-29 21:46
    I didn't see the pencil because the screen needed scrolling to the right ! Duhh....
    Sorry. problem of code on post fixed.
  • Ole Man EarlOle Man Earl Posts: 262
    edited 2009-04-29 22:01
    This finally worked !! Thanks a zillion !
    buffer[noparse][[/noparse] 0] is the 65 or letter A and buffer[noparse][[/noparse] 15] is the letter Z or 5B
    you are right. It is sent MSB then LSB

    
    PUB Get6DOF                            ' primary entry point
    
    read6DOF                               ' Put the data in a buffer from 6DOF
    
    x :=0
    y :=0
    z :=0
    x := buffer                          'Put buffer data into variables
    y := buffer
    z := x * 256 + y
    RunningCount := z
    
    x :=0
    y :=0
    z :=0
    x := buffer
    y := buffer
    z := x * 256 + y
    ax := z
      
    x :=0
    y :=0
    z :=0
    x := buffer
    y := buffer[noparse][[/noparse]6]
    z := x * 256 + y
    ay := z
     
    x :=0
    y :=0
    z :=0
    x := buffer[noparse][[/noparse]7]
    y := buffer[noparse][[/noparse]8]
    z := x * 256 + y
    az := z
    
    x :=0
    y :=0
    z :=0
    x := buffer[noparse][[/noparse]9]
    y := buffer[noparse][[/noparse]10]
    z := x * 256 + y
    gx := z
    
    x :=0
    y :=0
    z :=0
    x := buffer[noparse][[/noparse]11]
    y := buffer[noparse][[/noparse]12]
    z := x * 256 + y
    gy := z
    
    x :=0
    y :=0
    z :=0
    x := buffer[noparse][[/noparse]13]
    y := buffer[noparse][[/noparse]14]
    z := x * 256 + y
    gz := z
    
    return                                   'return to caller
    PUB read6DOF
    
    ' uartDOF.start (22,23,0,115200)        ' start uart on pins 22,23 for 6DOF Atomic board
    
     repeat while Rxdof <>= "A"                  ' wait for the "A" to insure we are starting with
        Rxdof := uartdof.rxcheck                ' a complete 6dof sentence
            cptr := 0                        ' zero the buffer pointer to start
    
        repeat while Rxdof <>= "Z" and cptr < 16 ' continue to collect data until the end of sentence ("Z")
          
               Rxdof := uartdof.rx       ' get character from uart Rx
                      buffer[noparse][[/noparse]cptr++] := Rxdof   ' save the character in the buff
            buffer[noparse][[/noparse]cptr] :=0                 ' make sure the buffer ends with a 0
    
        return                               ' return to calling routine
    
    
  • SSteveSSteve Posts: 808
    edited 2009-04-29 22:50
    You can make read6DOF quite a bit shorter:

    read6DOF
      RunningCount := buffer[noparse][[/noparse] 1]<<8 + buffer[noparse][[/noparse] 2]  'Put buffer data into variables
      ax := buffer[noparse][[/noparse] 3]<<8 + buffer[noparse][[/noparse] 4]
      ay := buffer[noparse][[/noparse] 5]<<8 + buffer[noparse][[/noparse] 6]
      az := buffer[noparse][[/noparse] 7]<<8 + buffer[noparse][[/noparse] 8]
      gx := buffer[noparse][[/noparse] 9]<<8 + buffer[noparse][[/noparse] 10]
      gy := buffer[noparse][[/noparse] 11]<<8 + buffer[noparse][[/noparse] 12]
      gz := buffer[noparse][[/noparse] 13]<<8 + buffer[noparse][[/noparse] 14]
    return
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    OS-X: because making Unix user-friendly was easier than debugging Windows

    links:
    My band's website
    Our album on the iTunes Music Store
  • Ole Man EarlOle Man Earl Posts: 262
    edited 2009-04-29 22:52
    Here is a couple of pics...one the 6DOF and the other a prop tv screen. Notice the 6DOF readout ! Now to USE the data !
    1600 x 1200 - 436K
    1600 x 1200 - 343K
  • Ole Man EarlOle Man Earl Posts: 262
    edited 2009-04-29 22:57
    Thanks again...works like a charm !
    Here is my whole project.

    Post Edited (Ole Man Earl) : 4/29/2009 11:40:46 PM GMT
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-04-30 06:56
    Attention, Attention .... please read carefully .... Attention, Attention .... please read carefully ....
    as you already did not listen to me in my previous post ;o)

    Well, ole man, I'm afraid that I have to say: I don't believe you
    Your progam only looks like it works, but you have serveral bugs in it (And currently I only concentrate on the topic of this thread and not the whole AutoPilot).

    Let me explain something:
    You defined the buffer as bytes and you do some calculations with the result being a word. It's very important to know that numbers in SPIN are signed numbers. For a byte the value range is from -128 to 127.
    As I read in another post your 6DOF will send you the numbers as unsigned. This means that you currently treat unsigned numbers as being signed which will give you wrong results. Example:
    byte $08 - used as unsigned means 8, used as signed means 8
    byte $FE - used as unsigned means 254, used as signed means -2
    If you extend these bytes to a word in SPIN you get:
    byte $08 = word $0008
    byte $FE = word $FFFE
    For the high byte it's no difference, because you shift it by 8 bits. So, in the end you have $FE00. But for your low byte it makes a difference!!! Instead of adding 254 you are adding -2.
    OK ... guess I was a little·bit wrong.·In·SPIN you can use values from·-128 to 127 or from 0 to 255 and it does not do a signed extension if you assign a byte to a word.·Hmm ... I think I·now remember that there's a different assignment operator for that. So, conversion itself is fine.

    That's why I said, you have to "and" the low byte with $00FF. This removes the sign again and you really have the value 254 in your add.
    But still there might be an issue with the conversion. Because you have the interpretation problem with the high byte as well. According to the specs of the 6DOF $FFFE would mean 65534, but SPIN treats it as -2. I don't know what numbers you can expect, but if something bigger than $7fff is valid, you should switch to use LONG instead of WORD for ax, ay .... Then the conversion looks like:
    ax:= ($0000_ff00 & byte[noparse][[/noparse] high ]<<8) + ($0000_00ff & byte[noparse][[/noparse]low])

    Another thing:
    I raised an question about the 'A'. You expect it being in the buffer and I doubted it. Let's have a look at your read6DOF (which I took from the last ZIP posted):

    PUB read6DOF
     repeat while Rxdof [color=red]<>=[/color] "A"                  ' wait for the "A" to insure we are starting with
        [color=red]' you assign Rxdof a value here - this loop simply would repeat forever if you wouldn't have the return
    [/color]    Rxdof := uartdof.rxcheck                ' a complete 6dof sentence
        [color=orange]' here you might read a byte - or not, but you don't know because you don't check the Rxdof to see if rxcheck maybe returned a $100 which means no data[/color]
    [color=orange]    ' received. AND you Rxdof would not be able to store this return value as it's only byte-size. AND YOU DON'T STORE IT ANYWHERE!
    [/color]        cptr := 0                        ' zero the buffer pointer to start
     
        [color=red]' why do you repeat the whole stuff?? Isn't your intention to wait for the A and then start with receiving?[/color]
        repeat while Rxdof <>= "Z" and cptr < 16 ' continue to collect data until the end of sentence ("Z")
          
               Rxdof := uartdof.rx       ' get character from uart Rx
                      buffer[noparse][[/noparse]cptr++] := Rxdof   ' save the character in the buff
            buffer[noparse][[/noparse]cptr] :=0                 ' make sure the buffer ends with a 0
    [color=orange]        ' if you really received 16 bytes, then this would be wrong! You would write the 0 to byte[noparse][[/noparse]16]. But the size of the byte array is 16, so the index[/color]
    [color=orange]        ' range is from 0 to [b]15[/b][/color]
        return                               ' return to calling routine
            
    

    Now let's correct this function:
    PUB read6DOF
     Rxdof:=0                                 'initialize, so we know definitely what's in before checking content in the while
     repeat while Rxdof [color=red]<>[/color] "A"                ' wait for the "A" to insure we are starting with
        Rxdof := uartdof.rxcheck
     cptr := 0                                ' zero the buffer pointer to start
     byte[noparse][[/noparse] cptr++ ]:=Rxdof                    ' NOW the A is really in the buffer
     
     repeat while Rxdof <> "Z" and cptr < 16  ' continue to collect data until the end of sentence ("Z")
         Rxdof := uartdof.rx                  ' get character from uart Rx
         buffer[noparse][[/noparse] cptr++ ] := Rxdof            ' save the character in the buff
    
    
    

    And here is one more bug:
    You expected "A ll hh ll hh ll hh ll hh ll hh ll hh ll hh ll hh Z", but according to John Abshier's post the spec says the 6DOF sends data in hh ll order.


    A ll hh ll hh ll hh ll hh ll hh ll hh ll hh ll hh Z
    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17?? would be the index in the buffer
     
    you say
    byte[noparse][[/noparse] 1 ]<<8 + byte[noparse][[/noparse] 2 ]  ... but byte 1 would be a low byte according to your expectations
     
    so, why does it calculate some good looking numbers? Because as I said: you don't put the A in the buffer
     
    ll hh ll hh ll hh ll hh ll hh ll hh ll hh ll hh Z
     0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 
     
    When using byte 1 you really get a high byte and byte 2 will really be a low byte. But the result is still wrong, because you mix up
    count high with ax low, ax high with ay low ... and the last one will use Z as low ;o)
     
    With the corrected read6dof you now get
     
    A hh ll hh ll hh ll hh ll hh ll hh ll hh ll Z
    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
     
    

    One tip in general:
    You should develop those kind of functions·in a test program·first·and not inside of your main program. Using the real data for a function like that is a very bad idea as variation is not to big. You simply don't find this kind of number conversion bug if you only feed your function with nearly the same data all the time.
    In an test environment you can manually set up different content for the buffer and run the function to see if it produces the right output for the whole range of numbers.

    (Hope this post saves your aircraft ;o)

    Post Edited (MagIO2) : 4/30/2009 9:04:47 PM GMT
  • Ole Man EarlOle Man Earl Posts: 262
    edited 2009-04-30 22:48
    Thanks MagIO2

    This program is working as far as the buffer full of data. I think its working because the numbers I print out on tv appear correct and when I move the 6DOF it responds like I think it should..... Ahh... I did use the code @SSteve provided ! I think I will try your read6DOF part tho.....

    I tried your read6dof and it now ALWAYS gets the "A" first. My program would sometimes miss it. Thanks a bunch also...

    That's what I really like about this forum...help is only a few keystrokes away !

    When your 63...must go back to school !! Got the time now !
Sign In or Register to comment.