Shop OBEX P1 Docs P2 Docs Learn Events
Programming a servo in SPIN — Parallax Forums

Programming a servo in SPIN

rlmjdimerlmjdime Posts: 2
edited 2013-10-07 05:22 in Propeller 1
Hello all. I am very new to programming and seem to hit a wall every time I try and write a program. I'm playing around with a servo, and trying to get it to stop at 0 and 180 degrees. I used the example programs in the propeller tool, and was able to get it right. I don't really understand everything that the object files were doing, so I'm trying to recreate using my own code. Maybe my problems stem from not fully understanding the pulse widths, but my own code runs smooth to 0 degrees and then begins to step to 180.
{{Servomotor driver}}


CON


      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000


VAR


   long stack[30]
   long count            'variable to establish start angle
   long count1          'variable to establish end angle
  
PUB Main

  cognew(Moveservo(5), @stack[0])                  'cog to move the servo
  cognew(LED, @stack[20])                             'cog to flash the led


PUB Moveservo (pin)
  dira[5] := 1                                                   'pin 5 set to ouput
  repeat                                                          'repeat the cycle

      
     count1 := (18 * 1111 + 50000)/1000            'set the variable to 18 degrees
    outa[pin]~~                                                'set pin to high 
    waitcnt(clkfreq/100000*count1 + cnt)            'use count 1 and create pulse for 18 degrees
    outa[pin]~                                                  'set pin to low
    waitcnt(clkfreq/200*2 + cnt)                         'wait 20 ms
    
     count := (162 * 1111 + 50000)/1000            'set the count variable to 162 degrees
    outa[pin]~~                                                'set pin high
    waitcnt(clkfreq/100000*count + cnt)             'use count and create pulse for 162 degrees
    outa[pin]~                                                 'pin low
    waitcnt(clkfreq/200*2 + cnt)                        'wait 20 ms
    
    
    


PUB LED 
  dira[0] := 1                  'pin 0 set to output
  repeat                         'repeat cycle
    if outa[5]~                 'if pin 5 low
      outa[0] := 1              ' led on
    else                           
      outa[0] := 0             'else led off

I'm trying to gain an understanding of using multiple cogs, so that is why I implemented the PUB LED. But after adding this my program does nothing. The aim of the code was to have the servo to and fro the extremes, and light the led when it gets there. I actually got the idea for the program from one of the exercises in the propeller education kit.

I've been bouncing around with this for a bit, so any direction and insight is most appreciated.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2013-10-06 20:32
    Your code sends a pulse of one width, then a pulse of another width without giving the servo time to act. It turns out that there really is no good way to tell that the servo has reached the desired position since R/C servos provide no position feedback. You just have to allow them enough time to reach the desired position, sending them pulses every 20ms all the while. Really the only way to tell what position they're at is to either use an encoder to give you direct feedback on movement or to put a current sensor in the power lead to the servo and detect when the current drawn falls below the minimum current drawn by the motor when it's moving. That tells you that the motor has reached the position commanded by the control pulses sent to the motor.

    Here's one example of code that would move the motor from one position to another with a pause after each movement.
    con totalRotationDegrees = 180   ' limit to limit movement in degrees
        usMinPulseWidth = 500   ' minimum pulse width in us at one end of rotation
        usMaxPulseWidth = 2500   ' maximum pulse width in us at other end of rotation
        lowLimit = 18 * (usMaxPulseWidth-usMinPulseWidth) / totalRotationDegrees + usMinPulseWidth
        highLimit = 162 * (usMaxPulseWidth-usMinPulseWidth) / totalRotationDegrees + usMinPulseWidth
        pulses = 100   ' 20 ms cycles
    
    var long stackMove[20]
    
    pub main
       coginit(moveServo(5,lowLimit,highLimit,pauseTime),@stackMove)
       ' this program could continue on here with something else
    
    pub waitms(ms)
       waitcnt((clkfreq/1000)*ms + cnt)
    
    pub servoPulse(pin, usTime)
       ' Generate a positive-going pulse on I/O pin whose width is given in us
       outa[pin]~~
       waitcnt((clkfreq/1000000)*usTime + cnt)
       outa[pin]~
    
    pub moveServo(pin,fromWidth,toWidth,pulseCnt)
       dira[pin]~~   ' Initialize I/O pin
       outa[pin]~
       repeat
          repeat pulseCnt
             servoPulse(pin,fromWidth,toWidth)
             waitms(20)
          repeat pulseCnt
             servoPulse(pin,toWidth,fromWidth)
             waitms(20)
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-06 20:54
    If you want to take another shot at using a servo object to control the servo, there's a really simple demo in post #15 of my QuickStart servo tester thread.

    I because I like to show off, whenever I see mention of using a Propeller to control a servo, I feel the need to remind people of my 32 servo demo. I had seen it mentioned many times that the Propeller could drive up to 32 servos but I hadn't see it done (probably because it's kind of a lot of work without a real useful purpose (other than to show off the fact I have 32 servos)).
  • rlmjdimerlmjdime Posts: 2
    edited 2013-10-06 21:07
    Duane, thanks for the response. I actually found your file first, and it has been the only way I've been able to get the servo functioning correctly! Great code and it has served as a great benchmark for using objects. Let's say that I wanted to add code to control and LED to on/off at a certain point, would adding another cog program cause this one not to function correctly. When I first used your code, I tried to add a separate PUB for led control and the whole program stopped working. Would you say that this was possible? I'm sure it was an error on coding on my part, but just want to make sure I'm not losing it any more than I already feel I am :lol:.
  • Mike GreenMike Green Posts: 23,101
    edited 2013-10-06 21:18
    Your LED routine isn't going to work well since it attempts to light the LED when there's a pulse on the I/O pin used for the servo. That's a pulse from 0.5ms to 2.5ms in width in a pulseless interval of 20ms. The LED would be lit maybe from 5% to 10% of the time ... not very visible.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-10-06 21:21
    rlmjdime wrote: »
    Let's say that I wanted to add code to control and LED to on/off at a certain point, would adding another cog program cause this one not to function correctly. When I first used your code, I tried to add a separate PUB for led control and the whole program stopped working. Would you say that this was possible?

    It's very possible to add a LED to the servo code. There are many ways to do it. If you want to use another cog, you need to keep a few rules in mind. One rule is don't set pin states from more than one cog. Another is to make sure you have enough stack space.

    The easiest way to see what went wrong is to post the code.

    BTW, are you using a Propeller board or a DIP chip on a breadboard? If you are using a board, which one?
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-10-07 05:22
    When working with servos the counters are your friends -- they can be setup to generate very accurate pulses with very little fuss. I've written several programs for a buddy where we embed servo control right into the main object, like you're doing with your experiment. Have a look; you may find this useful.

    Note: this is great for very simple control of one or two servos. When you want to control multiple servos and add features like ramping, it's best to use a servo object -- many of us have written them so you have a lot of good choices.
Sign In or Register to comment.