Shop OBEX P1 Docs P2 Docs Learn Events
Simple, Yet Accurate, Dual Servo Driver (No Assembly Required) — Parallax Forums

Simple, Yet Accurate, Dual Servo Driver (No Assembly Required)

JonnyMacJonnyMac Posts: 9,208
edited 2010-06-25 13:51 in Propeller 1
From time-to-time I see new Spin programmers struggling with driving servos, usually trying to adopt methods learned from their BASIC Stamp (or other micro) experience. For those that want to control a few servos without using a PASM object, this little demo shows how. It does in fact launch a method (called servos) into its own cog so that the servos are properly refreshed every 20ms.

The code is in Spin and I did some analysis to account for the instruction overhead so that the output, expressed in microseconds, is as intended -- I have verified with a 'scope. The demo has two servos, but this can easily be modified (copy, pasted, edit) to up to eight -- don't go beyond eight else you might overrun the 20ms refresh window.

This may seem a little advanced to Spin newcomers, but it's really not that bad. Take a few minutes to study it and you'll find that it's quite straightforward.

[noparse][[/noparse]Edit] Fixed my own copy-paste error as identified by Tim (see below).

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon McPhalen
Hollywood, CA

Post Edited (JonnyMac) : 6/23/2010 8:42:07 PM GMT

Comments

  • TimmooreTimmoore Posts: 1,031
    edited 2010-06-23 19:49
    Jon, I was looking at your code, I think you have a copy/paste error, shouldn't the 2nd set of code use SVO2

    Tim
        pos := (SVO_MIN #> servo1 <# SVO_MAX) * US_001 - 989        ' to ticks, adjust for overhead
        outa[noparse][[/noparse]SVO1] := 1                                             ' create servo 1 pulse
        waitcnt(pos + cnt)
        outa[noparse][[/noparse]SVO1] := 0
        
        pos := (SVO_MIN #> servo2 <# SVO_MAX) * US_001 - 989
        outa[noparse][[/noparse]SVO1] := 1                '???????SVO2                                      
        waitcnt(pos + cnt)
        outa[noparse][[/noparse]SVO1] := 0
    
    
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-06-23 20:38
    Whoops... thanks, Tim. I did that so I could measure the timing between the falling edge of one servo and the leading edge of the next (34us). Thanks for the catch; the file has been corrected.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • Sal AmmoniacSal Ammoniac Posts: 213
    edited 2010-06-23 21:51
    I'd strongly suggest using constants for magic numbers like 989 rather than hard coding them.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-06-23 21:59
    You'll see that constants that could logically change are in fact defined as named constants (e.g., pin numbers, servo position values). In this code the overhead cycles for setting a pin and getting into waitcnt, as well as the timing for the servo refresh window will never change, hence do not need to be defined as named constants. In fact, doing so might cause an uninitiated newcomer to make a change that would upset the behavior of this code. I deliberately didn't call these values out as named constants to prevent such changes.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • Sal AmmoniacSal Ammoniac Posts: 213
    edited 2010-06-24 16:12
    Even so, I'd make these magic numbers constants anyway and note in a comment associated with them that they should not casually be changed by users. Failure to do this makes it likely at some point that you or someone else will change some, but not all, instances of the '989' and wind up scratching your head wondering why things don't work.

    In my opinion, every numeric constant, with the exception of 0 and 1 and a few other rare exceptions, should be declared as a named constant. This is just good programming practice.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-06-24 17:16
    I respectfully disagree, Sal. In my opinion, what's now being called "good programming practice" by so many (not suggesting you), is over-wrought, theoretical showing off (e.g., "Look how clever my code is...."). Those of us [noparse][[/noparse]practical programmers] that write code that gets deployed in products (versus text books) find a balance between the use of named constants (that are actually useful) and "magic numbers" (that never change). In this particular case the cycles count is not going to change, even with a clock change and, therefore, does not need to be "newbie friendly."

    This "magic numbers" rule is a silly rule in my mind, and not one that adds value to an embedded program. For example, I have a pause() method that creates a delay in milliseconds. Personally, I don't find pause(1000) any less useful than pause(ONE_SECOND). But then, I take for granted that anyone using my code knows what they're doing. I refuse to write for those that don't -- maybe this is my problem.

    Again, this is just my opinion. I did comment that the 989 accounts for overhead in the code; that should be quite enough, espeically for code that has been tuned and required no additional modification.

    What makes me smile is that I've been accused of overwriting code; of being too verbose -- you're suggesting I'm not verbose enough. [noparse];)[/noparse] And let's be honest... there are far more egregious violations of "good programming practice" is posted code than a couple magic numbers from time-to-time.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • Sal AmmoniacSal Ammoniac Posts: 213
    edited 2010-06-24 19:36
    I guess we'll just agree to disagree then. wink.gif

    You do contradict yourself in your posts, however. In your initial post you say "I see new Spin programmers struggling with driving servos", which is the audience you seem to be addressing with your code. Then later you say "In this particular case the cycles count is not going to change, even with a clock change and, therefore, does not need to be "newbie friendly."

    It seems to me that your code is directed at new Spin programmers who are struggling to understand things, yet you then say that it doesn't need to be newbie friendly. Your code comment says "adjust for overhead", and I know what you mean, but will a struggling newbie?
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-06-24 20:08
    Agreed -- to disagree, that is. I guess my point is that I can drive my car quite well without being a mechanic. tongue.gif In my opinion many Propeller newcomers take this approach to programming.

    I wrote the code in Spin because many newcomers are afraid of PASM, and I've seen a lot of mis-steps generating proper servo pulses in Spin. The initiated (i.e., not lazy) programmer will find more than enough information to learn from; the lazy can use it as is. I mean, really, how many of us in this forum would take the time to measure cycle count by specific instructions to make the code accurate (as I did)? Five, tops; others don't want to be bothered with this level of detail, they just wanted to be handed code that works. I did that.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-06-24 20:17
    BTW... I created a looped, eight-servo version, too.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • John AbshierJohn Abshier Posts: 1,116
    edited 2010-06-25 00:36
    I just used the servo object in the Propeller library. It is pure Spin for the end user.

    John Abshier
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-06-25 01:09
    Which object? -- the only one I have in my library folder is "servo32_v5" which has a Spin interface, but does the work in PASM.

    BTW, lest anyone think otherwise, I am not proclaiming this a *better* way to do anything, just *another* way, and perhaps something for others to expand on if they choose.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2010-06-25 03:45
    Jon,

    There is a version 7 now which address a few minor fixes that are different than version 5:

    Version 6 - (07-18-2009) - Fixed slight timing skew in ZoneLoop and fixed overhead timing latency in ZoneCore
    Version 7 - (08-18-2009) - Fixed servo jitter in ramping function when servo reached it's target position.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-06-25 13:51
    Thanks, Beau, will have a look.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
Sign In or Register to comment.