Shop OBEX P1 Docs P2 Docs Learn Events
One byte at a time? — Parallax Forums

One byte at a time?

stelath_shadow9stelath_shadow9 Posts: 23
edited 2013-10-17 23:22 in Propeller 1
Project: To send single byte commands to prop via bluetooth to control whatever (servo in this case)

Problem: In the code below the commands are "a" for forward then back ward rotation of servo. "u" for temporary clockwise rotation of servo. and "d" for temporary counter clockwise rotation. However, when sending these characters I must send multiple characters to turn the servo i.e. "aa", "uuu", and "dddd" respectively.

The weird part is, every "command" byte I put in to the code must be typed one more time than the last programmed command. for example I must always type "aa" in order to get back and forth motion, and that is the first command programmed into the code. The 2nd command "u" must always be entered "uuu" in order for CW rotation and the command "d" must always be typed in "dddd" for ccw rotation.
As you can see, for every command added to the code I must add an extra one of those characters in order to execute the command, when Ideally what I would like is to only type the character once.

Im not sure what the issue is. I am using the parallax serial terminal code in order to bring the character in.

Any ideas?
p.s. Some of the code is very ugly. I am still attempting to learn spin code a little at a time, so I rely a lot on other crutches like the BS2.spin code or pst.spin. I am mainly shooting for functionality though.
{{ . }}
obj
bs2: "bs2"
pst: "parallax serial terminal"
VAR

 
CON
_clkmode = xtal1 + pll16x                ' System clock → 80 MHz                      
_xinfreq = 5_000_000                     ' Using 5 MHz external crystal oscillator      
servoPin = 17                            ' Servo signal to this I/O pin-change if needed


PUB starting
  pst.start(9600)
  centerservo
 cogstop (0)
Pub centerservo
 pst.rxflush
 
     pst.charin 
 
    


                                        
          
   if pst.charin=="a"
                                                        
    
       pst.str(string("Moving",13))
    
      
                                                                                             
       here
      
   elseif pst.charin=="u"
     up
   elseif pst.charin=="d"
     down
   else
        centerservo
    
   centerservo
pri up
  bs2.Freqout_set(17,50)
  waitcnt(89_000_000+cnt)
  bs2.freqout_set(17,0)
  centerservo
  
Pri Down
   bs2.Freqout_set(17,1900)


waitcnt(75_000_000+cnt)


 bs2.freqout_set(17,0)
   centerservo
Pri here
bs2.Freqout_set(17,50)


waitcnt(89_000_000+cnt)


 bs2.freqout_set(17,0)
 
              


waitcnt(82_000_000+cnt)


 
  bs2.Freqout_set(17,1900)


waitcnt(75_000_000+cnt)


 bs2.freqout_set(17,0)
  centerservo

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-13 11:56
    When you use charin save the character to compare it latter.
    character := Pst.charin
      if character == "a"
        'do stuff when a
      elseif character == "b"
      ' do b stuff
    

    Or better yet
    character := Pst.charin
      case character
        "a":
          'do stuff when a
        "b":
          ' do b stuff
    

    Another thing, use a servo control object.

    In post #15) of my QuickStart servo tester thread is a super simple servo demo. Use the demo as a guide on how to use the servo object. There's also a servo demo in the _demo folder of the Prop Tool's library.

    The servo control object will take care of pulsing the servo at 50 Hz so you don't have to worry about refreshing the servo.

    I'm not sure why you use the cog stop command but I doubt you need it.

    What Propeller board are you using?

    Post #3 of my index has links to Propeller tutorials.
  • Heater.Heater. Posts: 21,230
    edited 2013-10-13 12:15
    stealth_shadow9.

    Your method "centerservo" is calling itself:
    Pub centerservo
       'bla
       'bla
       centerservo
    
    Worse still it is being called by some routines that it calls. This is not good and I am surprised it works for very long at all as that will eat up all the stack and crash. Where you have written "centerservo" it is not just jumping to centerservo like a GOTO in BASIC, it is doing a subrotine call to cenerservo which will use stack space each time-

    You need to put this stuff into a loop using "repeat"

    Also you should only read the command byte once into a variable and the test it's value to decide what to do. something like:
    Pub doCommands | c
        repeat
            c := pst.charin 
        elseif c == "u"
            up 
        elseif c == "d"
            down
    

    Those "up" and "down" commands should just return not call back to "doCommands" or whatever.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-13 12:16
    One downside to PST is the RxCheck method is private. The RxCheck is nice since it doesn't block the program the way CharIn does.

    To get around the this you can either change the method to public or use the RxCount method to see if a character has been received.

    I often use the RxCount like this:
    character := Pst.RxCount
      if character ' same as if character <> 0
        character := Pst.charin
    
        case character
           "a":
             'do stuff when a
           "b":
             ' do b stuff
    

    The above code doesn't block the program. I doubt you need this in your present program but I think it can be a very useful tool.

    The code:
    character := Pst.RxCount
    

    could have used a different variable than "character" I generally just use the same variable for the count as I do for the received byte so I don't need to make a new variable.
  • stelath_shadow9stelath_shadow9 Posts: 23
    edited 2013-10-13 12:29
    Some of the code is from earlier trials when I was attempting to use a prop servo_demo.spin code. It worked but was causing my servo to twitch intermittently while sitting. I used the cog stop command to see if it would remedy the issue, but it didn't, so I decided to try to work around that entire code with the above.

    The code you posted works...kind of. I just tested it out. BUT It still requires 2 bytes i.e. "aa" rather than just "a" to execute the command and when I try to use another command such as "u" for up it I still have to type "uu" and it merely mimics the "a" command

        pst.charin 
        char:= pst.charin
         case char      
            "a",here:
               here
            "u",up:
    
             up
    

    So in this code Im not sure what is supposed to go before the ":" but if i leave it blank it says "expected an expression term"
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-13 12:42
    You're using charin twice. Get rid of the one where you don't capture the character.

    Put you "here" or "up" calls where I typed "' do b stuff".

    I left out a colon after the "b" earlier. I'm fixing this typo.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-13 12:51
    Try this:
         'pst.charin note this has been commented out. You can just delete this line.
        char:= pst.charin
        case char   ' this line should be indented the same as line above   
          "a": ' indent two extra spaces than line above
            here  ' indent two extra spaces than line above      
          "u":  ' indent same as "a":
            up ' indent two extra spaces than line above (same as "here")
    

    Indentation is really important in Spin. Don't indent when it's not needed. It helps a lot if you follow the convention changing your indentations two spaces at a time.
  • stelath_shadow9stelath_shadow9 Posts: 23
    edited 2013-10-13 23:25
    Thank you Duane. This code works perfectly. I suppose I didn't indent with spaces with the first code you sent me. But this works exactly. Why is the indentation so important?
    At any rate thank you a million for your help. I didnt realize that by trying to reference to pst.charin I was actually executing the command again. here is the updated code.
    {{ ServoContinuousRotation.spinTurn Parallax Continuous Rotation Servo clockwise full speed for 21 sec.
    hold still 2 sec, and then counterclockwise full speed for 2 sec. }}
    obj
    bs2: "bs2"
    pst: "parallax serial terminal"
    VAR
     byte char  [1]
     
    CON
    _clkmode = xtal1 + pll16x                ' System clock &#8594; 80 MHz                      
    _xinfreq = 5_000_000                     ' Using 5 MHz external crystal oscillator      
    servoPin = 17                            ' Servo signal to this I/O pin-change if needed
    
    
    PUB starting
      pst.start(9600)
      centerservo
     
    Pub centerservo
     pst.rxflush
       repeat
           'pst.charin note this has been commented out. You can just delete this line.
        char:= pst.charin
        case char   ' this line should be indented the same as line above   
          "a": ' indent two extra spaces than line above
            here  ' indent two extra spaces than line above      
          "u":  ' indent same as "a":
            up ' indent two extra spaces than line above (same as "here")
          "d":
            down
          "s":
            stop
        
            
     
    pri up
      bs2.Freqout_set(17,300)
    pri stop
       
      bs2.freqout_set(17,0)
    
    
      
    Pri Down
       bs2.Freqout_set(17,400)
    
    
    
    
    Pri here
    bs2.Freqout_set(17,300)
    
    
    waitcnt(89_000_000+cnt)
    
    
     bs2.freqout_set(17,0)
     
                  
    
    
    waitcnt(89_000_000+cnt)
    
    
     
      bs2.Freqout_set(17,400)
    
    
    waitcnt(89_000_000+cnt)
    
    
     bs2.freqout_set(17,0)
      centerservo
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-14 15:22
    Indenting is used to indicate blocks of code.

    For example:
    repeat
    x += 1 ' same as x := x + 1
    

    The above code will repeat forever but will not add anything to x. To get the code adding one to x to be repeated, it needs to be indented.
    repeat
      x += 1
    

    The above code will continually add one to x.

    I don't understand how your servo code works at all. I don't understand why you're setting frequencies to control the servo. Depending on what servos you're using, you may be damaging them.

    Do you know how servos work? (This isn't meant to rude, you've stated you're just beginning and I'm wondering if you understand about how to use pulses to control servos.)

    The servo code I linked to earlier is pretty basic. If there's a part of the code you don't understand let us know. You really really should use a servo driver to control your servo.
    Duane Degn wrote: »
    What Propeller board are you using?

    BTW, While I agree BS2_Functions is a crutch (it's useful to see how some things are done on the Prop), I don't think Pst.Spin is a crutch. It's a tool. You certainly don't want to have to write your own serial driver to send debug messages.
  • stelath_shadow9stelath_shadow9 Posts: 23
    edited 2013-10-16 03:27
    I understand how servos work. and it works fine because instead of a reoccurring pulse i am sending a frequency. Frequency works all the same at rotating the servo, but instead of turning it just a little bit one time as a pulse would do, a frequency sends a pulse over and over and over again. Thus rotating the servo continuously. Try it, it works. The servo Im using is a parallax continuous rotation servo http://parallax.com/product/900-00008. The reason I've done this is because I was getting fed up with trying to get the pwm part of the Bs2spin code to work. It turns the servo but only in one direction. So I said to hell with it. Ill just send a continuous pulse with the freq out function.
    Im using the prop activity board.

    The next step I need to figure out is why this code will not work with a normal stand alone prop1
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-16 10:03
    I understand how servos work. and it works fine because instead of a reoccurring pulse i am sending a frequency. Frequency works all the same at rotating the servo, but instead of turning it just a little bit one time as a pulse would do, a frequency sends a pulse over and over and over again. Thus rotating the servo continuously. Try it, it works. The servo Im using is a parallax continuous rotation servo http://parallax.com/product/900-00008. The reason I've done this is because I was getting fed up with trying to get the pwm part of the Bs2spin code to work. It turns the servo but only in one direction. So I said to hell with it. Ill just send a continuous pulse with the freq out function.
    Im using the prop activity board.

    The next step I need to figure out is why this code will not work with a normal stand alone prop1

    After looking at BS2_Functions a bit more, I see it uses the cog's counters to send a continuous frequency out on a pin. This technique apparently works with analog servos, but it won't work with digital servos or ESCs.

    I'll suggest again that you take a look at a proper servo driving object. It will end up saving you a lot of trouble particularly if you want to drive more than two servos per cog.

    Does you stand alone Prop have a crystal?
  • stelath_shadow9stelath_shadow9 Posts: 23
    edited 2013-10-16 11:55
    no but i removed the constants for timing like the xin freq and clkmode. similar to other projects that have worked on the standalone prop
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-16 12:01
    no but i removed the constants for timing like the xin freq and clkmode. similar to other projects that have worked on the standalone prop

    I'd suggest replacing the constants.
  • stelath_shadow9stelath_shadow9 Posts: 23
    edited 2013-10-16 19:25
    Whats odd is that it doesnt work with them there either. I removed them thinking that "oh this must be the issue, since Im not using a crystal, these constants are messing everything up.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-16 19:48
    Whats odd is that it doesnt work with them there either. I removed them thinking that "oh this must be the issue, since Im not using a crystal, these constants are messing everything up.
    Sorry, I missed the no crystal part of the reply.

    The Freqout_set method isn't going to produce an accurate frequency without a crystal. The servo object I've been suggesting also won't work correctly without a crystal.

    You were correct to remove the xin and clkmode settings. There are a couple of clock settings which can be used without a crystal. Take a look at RCSLOW and RCFAST in the Propeller manual. I personally always use a crystal since it makes serial communicating (and a lot of other things) easier.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2013-10-16 20:01
    Why is the indentation so important?
    I am not sure why myself but I found out the hard way that it is a MUST. I spent several hours debugging a simple Servo command and then figured out it was my lack of indenting correctly that was the issue.
  • stelath_shadow9stelath_shadow9 Posts: 23
    edited 2013-10-17 23:22
    Duane Degn wrote: »
    Sorry, I missed the no crystal part of the reply.

    The Freqout_set method isn't going to produce an accurate frequency without a crystal. The servo object I've been suggesting also won't work correctly without a crystal.

    You were correct to remove the xin and clkmode settings. There are a couple of clock settings which can be used without a crystal. Take a look at RCSLOW and RCFAST in the Propeller manual. I personally always use a crystal since it makes serial communicating (and a lot of other things) easier.

    Whats odd is Instead of using the servo portion of the code I decided to try and make an LED blink. Something simple. I paste that code in But I couldn't get it to work . BUT, if i loaded the code to blink an LED or something all on its own, it worked fine.
    CON   
    VAR
    
    
       
    OBJ
     
      
    PUB this
        dira[1]~~
        repeat
        
           
          !outa[1]
          waitcnt(8_000_000+cnt)
        
    
    
       
    
Sign In or Register to comment.