Shop OBEX P1 Docs P2 Docs Learn Events
Servo Speed — Parallax Forums

Servo Speed

jcfergusonjcferguson Posts: 86
edited 2006-10-20 07:18 in BASIC Stamp
Does anyone have any ideas about how to control the turning speed of a servo (the "ramp"?) with code instead of a PSC?

I have a program that controls three servos via RF link between joystick/bs2 and servos/bs2. I was thinking of different scenarios where I would read the values from the joystick/bs2 with SERIN, then have a separate subroutine to drive each servo that would compare the actual position of the servo to the SERIN value and progress towards that value in slower steps?

Any thoughts about this? My current code is below if it helps. I think this has to be done on the receiver side, though maybe there are other possibilities?

Carlos

Comments

  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2006-10-05 17:46
    FOR move=old_pos TO new_pos·· STEP idx
    PULSOUT 0,move
    PAUSE 20
    ·NEXT
    old_pos=move

    Carlos, Its not truly ramp but this snippet of code will move a servo from its old position to a new position at a constant speed the speed can be varied or controlled by the value of idx.

    Jeff T.
  • jcfergusonjcferguson Posts: 86
    edited 2006-10-05 19:54
    Thanks Jeff, this seems like what I am looking for - I wonder how to set the first old-pos value though - the receiver code is in an endless loop and I guess I could just read SERIN before starting that loop - so on power up, old-pos would be set to the joystick position and then head into the loop. I'll plug this into my code and see how it works when the joystick is thrown one way, then the other - I suppose this depends on the speed of the loops.

    Thanks,

    Carlos
  • ZootZoot Posts: 2,227
    edited 2006-10-05 22:50
    How about something along these lines? This is a simpler version of code I cribbed from one of my bot projects.

    step   VAR   Word      'could also be a byte if max step of 255 is OK
                                   'could be a constant if you don't need to change speed during execution
    servopos   VAR   Word
    sevoset   VAR   Word   'equiv of old pos -- the position actually sent
    RC    VAR   servopos    ' make this a unique variable if you need to save RC values for some reason
    servomin   CON    500    'some absolute minimum physical servo pulse value
    servomax  CON    1000   'some absolute minimum physical servo pulse value
    
    Start:
    
       step = 30    'this will be the effective speed of the servo -- change it your program at runtime as you require
    
    
    
    Main:
    
    CheckRC:
       'some code to read receiver values into RC1 plus convert to same scale as used by pulsout for servos
       'now RC1 = some desired initial servo position
       ' remember that servopos = RC1 unless RC1 is unique
       
    AdjustServo:
        IF ( servopos > servoset ) THEN
            servoset = servoset + step MAX servopos
        ELSEIF ( servopos < servoset ) THEN
            servoset = servoset - step MIN servopos
        ENDIF
        GOSUB SendServo
    
    AdjustSpeed:
        'some code here that optionally adjusts step up or down -- i.e., change your speed during execution
    
    GOTO Main       'you could also skip CheckRC if don't you want to always track your joystick 
    
    END
    
    SendServo:
        servoset = servoset MIN servomin MAX servomax  'can save your servo if you have math or coding errors
        PULSOUT Pin, servoset
        PAUSE 20                          'omit this or adjust if you already hitting near 20ms of overhead during each loop
        RETURN
    
    



    You can add in more code for true ramping (acceleration) rather than just speed -- in other words, you could have step increment each time through the loop and the servo will move faster and faster over time. Etc.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    Post Edited (Zoot) : 10/5/2006 10:56:42 PM GMT
  • jcfergusonjcferguson Posts: 86
    edited 2006-10-06 01:59
    Thanks Jeff and Zoot,

    I think the missing part in my thinking was MAX and MIN - I couldn't figure out how to make sure the stepping servo didn't overstep the actual position. My code - adaptation of yours - is below. It works nicely (though my servomax and servomin seem to make things jumpy - is there a reason for this you can see).

    Carlos
  • ZootZoot Posts: 2,227
    edited 2006-10-06 03:00
    Not sure precisely why your servos are jumpy, but I saw a few things in your code that didn't look quite right...

    ServoMin            CON    500            'minimum safe signal for servo
    ServoMax             CON    1000             'maximum safe signal for servo
    
    



    My numbers for above were based on 2us steps for a PSC or a BS2 and would result in 180 degrees of travel min to max. Your servos may not have that physical range. You should adjust these numbers to be safely less than your actual physical limits on the servos.

        PULSOUT S1Pin, S1TimerVal MIN ServoMin MAX ServoMax        'drive servo
    
    



    Someone more expert than me will have to say if the above would really work properly -- I'm not sure about setting max and min in same statement as the pulsout .... you may want to try setting limits on the var before the actual pulsout. In my own implementation of code like this I actually store all the servo limits in EEprom and then read them back by channel so I have single subroutine that a) reads limits for a given servo channel, b) sets limits on that channel's position var, c) sends the resulting corrected position to the proper pin (or PSC servo channel).

    SendServo:
    
        'PAUSE 7
    
    



    Looks like you don't have a pause in your loop at all -- are you possibly overdriving the servos? Given that you are reading your RC info serially, I would think your Stamp would blast through this loop pretty quickly ... maybe too quickly. Most servos seem to handle 20ms-45ms between pulses -- have you tried a straight PAUSE 20 there? You might get less jitter.

    Lastly, you might get jumpiness if your stepped values "rollover" but that seems unlikely with your small step size, the range of max and min, and the word size variable.

    If none of that does the trick, I may be out of ideas [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST
  • jcfergusonjcferguson Posts: 86
    edited 2006-10-06 14:18
    I think the jumpy servos were due to a low 9v battery. I forget each time that when the battery goes low, the servos start behaving badly...

    I wondered about putting the max and min there in the pulsout, but thought maybe it would save a command.

    I mess around with that pause and try to get the servos sounding smooth, beyond that it seems like guesswork.

    Thanks for the tips, my servos are sllllooooooooowwwwwwwwwwww like I want them.


    Carlos
  • ZootZoot Posts: 2,227
    edited 2006-10-07 02:49
    If you have a scope, you can check a servo pin to see how often you really get a pulse. If you don't, and you have a spare stamp, you can use pulsin or count on the spare stamp and pulsout 1ms on another pin each time through your servo loop and see how often you get pulse.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST
  • HU robotHU robot Posts: 2
    edited 2006-10-19 09:42
    Hello;

    Now you know how you can control your servo "sllllooooooooowwwwwwwwwwww", you will maybe help me with my problem?

    I have a servo and·I want to turn it from the middel to the·left and right. Fast and slow. The fast movement works but I don't know how you can control it that it moves slowly.
    I want to control it slowly to a position. If you read my code you wel see that·I give the servo one pulse by "linksbeetje:" and "rechtsbeetje:" the other cases are fine.

    By "linksbeetje:" and "rechtsbeetje:"·I only give one pulsout to the servo and then it turns almost 30 degrees. I want to control it in steps of at most 2 degrees. Is that possible? and does someone nows how you can do this?

    So if I pres the Q button of my keyboard the servo moves 2 degrees to the left

    Greetings

    Ernstjan (Dutch student)
  • jcfergusonjcferguson Posts: 86
    edited 2006-10-19 16:35
    Hi Ernstjan,

    The problem in your code is that when you send pulsout 15, 300 or 15, 1200 you are telling the servo to go all the way to point 1200 (full left) or point 300 (full right). You are sending the same command to your servo if they hit "q" or "a" - pulsout 15, 1200. You just tell it to stay there longer with your for/next loop for "links".

    What you actually want to do is tell the servo to go "a little more left" or "a little more right" from the present position, right?

    You need to set up a variable for your pulsout value so that you can add a little to the value when you hit "q" and subtract a bit when you hit "e".






    In Variables:

    ServoValue VAR Word 'this is the value sent out to the servo with the driveservo subroutine

    In Constants

    DrivePin CON 15 'this is the pin that will drive the servo
    LeftExtremeValue CON 1200 'these numbers can be adjusted to set the limits of motion on the servo
    MiddleValue CON 750
    RightExtremeValue CON 300
    ServoIncrement CON 10 'this is the size of your "beetje" steps, can be changed to change step size


    Then in the main section:

    TakeAction: ' Determines what to do based on result of GetInput
    SELECT Command
    CASE "1","a"
    ServoValue = LeftExtremeValue
    Gosub DriveServo
    RETURN

    CASE "2","s"
    ServoValue = MiddleValue
    Gosub DriveServo
    RETURN

    CASE "3","d"
    ServoValue = RightExtremeValue
    Gosub DriveServo
    RETURN

    CASE "4","q"
    ServoValue = ServoValue + ServoIncrement 'add to the Servovalue, change this for larger or smaller steps
    ServoValue = ServoValue MAX LeftExtremeValue 'this keeps you from overshooting the left limit
    Gosub DriveServo
    RETURN

    CASE "5","e"
    ServoValue = ServoValue - ServoIncrement
    ServoValue = ServoValue MIN RightExtremeValue 'this keeps you from overshooting the right limit
    GOSUB DriveServo
    RETURN

    CASE ELSE
    DEBUG " : Invalid Command Received", CR
    GOSUB DriveServo 'you still need to tell the servo to stay where it is.
    RETURN

    ENDSELECT





    Then your subroutine would just be this:


    DriveServo:
    Pulsout DrivePin, ServoValue
    Pause 10 'this number should be adjusted slightly to make the servo turn smoothly
    Return











    I should say I am a learner too. I am not sure if this is what you want it to do -- If this doesn't work, perhaps someone else will give you more guidance!

    Carlos
  • HU robotHU robot Posts: 2
    edited 2006-10-20 07:18
    Thanks for posting a reply!

    Yes thats what I want to do. I did now that I was sending the servo to it extreem position, and·I tryed it with the feedback you get on yout problem but it didn't work so I have to ask smile.gif !

    Next week·I have a vacation so·I can't test you code, but I think it will be fine.

    If I have questions I will post again.

    Greeting

    Ernstjan
Sign In or Register to comment.