Servo Issues while using PWM with Raspberry Pi

Question:

My setup is simply the servo JX-PDI-6221MG being directly activated with raspberry pi’s PWM through GPIO library. The servo is brand new, I followed this tutorial and set duty cycle values between 0 and 100. The angles it makes have no pattern, it seems to go one way from 20 to 50 and them from 60 to 90 the other.

I decide to loop through all possible duty cycles (code is below) and I confirm that the variations aren’t smooth and it doesn’t look precise. After trying to set fix values again it suddenly starts to spin in multiple directions, even without I changing anything. Not even GPIO.cleanup() or killing python related processes made it stop.

Is my Raspberry Pi getting jitter and being very imprecise or was I a victim of falsification?

Code:

import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setup(11,GPIO.OUT)
pwm=GPIO.PWM(11,330) #which is the same as shown in datasheet
pwm.start(0)

for i in range(0,100):
     pwm.ChangeDutyCycle(i)
     time.sleep(0.02)

for i in range(0,100):
     i = 100 - i
     pwm.ChangeDutyCycle(i)
     time.sleep(0.02)`
Asked By: atelles3

||

Answers:

AFAIK, only GPIO 18 can be used by GPIO library for hardware PWM. try changing tht GPIO.OUT to that.

Also try using pigpio library which allows ANY GPIO pin to do hardware timed PWM.

Answered By: aquagremlin

Servos generally need precise timing, so on a non-realtime device like the Raspberry Pi that means you need to use the hardware PWM pins. RPi.GPIO only supports software emulated PWM, so you need to use another library, e.g. pigpio.

Answered By: Henrik

This is because that Raspberry Pi is a non-Realtime controller.

For that, try to use pigpio, this library includes a support for hardware PWM.

Quick example:

import sys
import time
import random
import pigpio

NUM_GPIO=32

MIN_WIDTH=1000
MAX_WIDTH=2000

step = [0]*NUM_GPIO
width = [0]*NUM_GPIO
used = [False]*NUM_GPIO

pi = pigpio.pi()

if not pi.connected:
   exit()

if len(sys.argv) == 1:
   G = [4]
else:
   G = []
   for a in sys.argv[1:]:
      G.append(int(a))
   
for g in G:
   used[g] = True
   step[g] = random.randrange(5, 25)
   if step[g] % 2 == 0:
      step[g] = -step[g]
   width[g] = random.randrange(MIN_WIDTH, MAX_WIDTH+1)

print("Sending servos pulses to GPIO {}, control C to stop.".
   format(' '.join(str(g) for g in G)))

while True:

   try:

      for g in G:

         pi.set_servo_pulsewidth(g, width[g])

         # print(g, width[g])

         width[g] += step[g]

         if width[g]<MIN_WIDTH or width[g]>MAX_WIDTH:
            step[g] = -step[g]
            width[g] += step[g]

      time.sleep(0.1)

   except KeyboardInterrupt:
      break

print("nTidying up")

for g in G:
   pi.set_servo_pulsewidth(g, 0)

pi.stop()

You can take a look on Servo Code from Python examples at pigpio website.

Or, check out the support of pigpio in gpiozero.

Answered By: Meqdad Dev
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.