pythonpygameraspberry-piservo

RaspberryPi pigame servo controll


I hooked up a servo onto my RaspberryPi 3, and i want to control it. I am currently using pygame library. It is installed and is a latest version. This is my code :

# Import libraries
import RPi.GPIO as GPIO
import time
import pygame
from pygame.locals import *

pygame.init()

# Set GPIO numbering mode
GPIO.setmode(GPIO.BOARD)
# Set pin 11 as an output, and define as servo1 as PWM pin
GPIO.setup(11,GPIO.OUT)
servo = GPIO.PWM(11,50) # pin 11 for servo1, pulse 50Hz
# Start PWM running, with value of 0 (pulse off)
servo.start(0)
angle = 90.0
servo.ChangeDutyCycle(2+(angle/18))
time.sleep(0.5)
servo.ChangeDutyCycle(0)
changed = False

while 1:
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                if angle > 10:
                    angle = angle - 5
                    changed = True
            elif event.key == pygame.K_d:
                if angle < 170:
                    angle = angle + 5
                    changed = True
            elif event.key == pygame.K_q:
                break
           
        if changed:
            servo.ChangeDutyCycle(2+(angle/18))
            time.sleep(0.5)
            servo.ChangeDutyCycle(0)
            time.sleep(1.5)
            changed = False

#Clean things up at the end
servoH.stop()
GPIO.cleanup()
pygame.quit()

But it does not detect an event. I keep hitting the keybord keys and the servo just stands still. I debugged it, and it detects no keybord/mouse events what so ever.

Please help.


Solution

  • Your code is ok, but it's not possible to receive window events (like key-presses) without a window.

    Adding a window to your program makes it work OK.

    Here's my test-code:

    # Import libraries
    #import RPi.GPIO as GPIO
    import time
    import pygame
    from pygame.locals import *
    
    SCREEN_WIDTH = 600
    SCREEN_HEIGHT= 400
    
    BLACK  = (   0,   0,   0 )
    YELLOW = ( 255, 255,   0 )
    
    pygame.init()
    screen = pygame.display.set_mode( ( SCREEN_WIDTH, SCREEN_HEIGHT ) )
    
    """
    # Set GPIO numbering mode
    GPIO.setmode(GPIO.BOARD)
    # Set pin 11 as an output, and define as servo1 as PWM pin
    GPIO.setup(11,GPIO.OUT)
    servo = GPIO.PWM(11,50) # pin 11 for servo1, pulse 50Hz
    # Start PWM running, with value of 0 (pulse off)
    servo.start(0)
    servo.ChangeDutyCycle(2+(angle/18))
    time.sleep(0.5)
    servo.ChangeDutyCycle(0)
    """
    angle = 90.0
    changed = False
    running = True
    
    font = pygame.font.SysFont( None, 25 )
    angle_label = font.render( "Angle: %4.2f" % ( angle ), True, YELLOW )
    
    
    while running:
        for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_a:
                if angle > 10:
                    angle = angle - 5
                    changed = True
            elif event.key == pygame.K_d:
                if angle < 170:
                    angle = angle + 5
                    changed = True
            elif event.key == pygame.K_q:
                break
           
        if changed:
            """
            servo.ChangeDutyCycle(2+(angle/18))
            time.sleep(0.5)
            servo.ChangeDutyCycle(0)
            time.sleep(1.5)
            """
            angle_label = font.render( "Angle: %4.2f" % ( angle ), True, YELLOW )
            changed = False
    
        # Update the display
        screen.fill( BLACK )
        screen.blit( angle_label, ( 50, 50 ) )
        pygame.display.update()
    
    #Clean things up at the end
    """
    servoH.stop()
    GPIO.cleanup()
    """
    pygame.quit()
    

    Note that using time.sleep() is not ideal in PyGame code, because it blocks the event-loop. Your OS may consider your application to have locked-up, and prompt the user to terminate it. It would be better to use real-time timestamps to implement this delay manually - only sending updates to the servo when the time-window allows it.