3

I am currently building a remote controlled car with the RPi model A+. I am using pygame to run a continuous loop to check the states of the desired keys on the keyboard(w,a,s,d) and based on that run different functions. That cause the RC car to move in the respective direction. The problem I am having is that, the cpu reaches 100% load, and then it freezes(this happened while at stock, and with a medium overclock). I am running both an ssh server and an x11vnc server to control the RPi. Soon after it freezes, it closes both the vnc connection and the ssh connection to the client(the computer I'm using to control the pi). Is all this too much for the Pi to handle? This is my code for the car:

import pygame
import RCcarFunctions
RCcarFunctions.init()
global forward, reverse, left, right
forward, reverse, left, right = False, False, False, False
pygame.init()
pygame.display.init()
size = (640,480)
pygame.display.set_mode((size))
pygame.key.set_repeat(500,10)
print ("Succesfully initialized")
try:
  while True:
    keypressed = pygame.key.get_pressed()
    for event in pygame.event.get():
      if event.type == pygame.KEYDOWN:
        if keypressed[pygame.K_w]:
          forward = True
        if keypressed[pygame.K_a]:
          left = True
        if keypressed[pygame.K_s]:
          reverse = True
        if keypressed[pygame.K_d]:
          right = True
      elif event.type == pygame.KEYUP:
        if event.key == pygame.K_w:
          forward = False
        elif event.key == pygame.K_a:
          left = False
        elif event.key == pygame.K_s:
          reverse = False
        elif event.key == pygame.K_d:
          right = False
      elif event.type == pygame.QUIT:
        RCcarFunctions.cleanup()
        pygame.quit()
    if forward & right:
      RCcarFunctions.right()
    elif forward & left:
      RCcarFunctions.left()
    elif left:
      RCcarFunctions.left()
    elif right:
      RCcarFunctions.right()
    elif forward:
      RCcarFunctions.forward()
      RCcarFunctions.straight()
    elif reverse:
      RCcarFunctions.reverse()
      RCcarFunctions.straight()
    else:
      RCcarFunctions.brake()
except KeyboardInterrupt:
  print ("\ncleaning up")
  RCcarFunctions.cleanup()
  pygame.quit()

If needed the RCcarFunctions library can be found here.

1
  • Just a quick look at this and it is telling me that you would be a lot better off with a faster processor. Like a Raspberry Pi 3. Also, it never seems to give the CPU a rest. If you could let it sleep and only run routines on an interrupt basis you would find your CPU load drop dramatically. Of course, that assumes you would get proper responsiveness. I can't think of a reason why you wouldn't, especially with a faster system. Looks like a fun project.
    – SDsolar
    May 20, 2017 at 10:04

3 Answers 3

3

What CPU utilisation do you expect when the code is in a continuous loop? I expect 100%, anything less and there is something wrong.

Is there any reason

    if keypressed[pygame.K_w]:
      forward = True
    if keypressed[pygame.K_a]:
      left = True
    if keypressed[pygame.K_s]:
      reverse = True
    if keypressed[pygame.K_d]:
      right = True

can't be changed to

    if keypressed[pygame.K_w]:
      forward = True
    elif keypressed[pygame.K_a]:
      left = True
    elif keypressed[pygame.K_s]:
      reverse = True
    elif keypressed[pygame.K_d]:
      right = True

The crash is probably because Python never gets a chance to garbage collect and runs out of memory.

Add a time.sleep(0.05) or similar in your while True loop so that garbage collection gets a chance to run.

7
  • 1
    I'm not really sure what cpu utilization to expect as long as it doesn't crash. I can't make the suggested change because he user might be pressing both forward /reverse and one of the directions. Eg w and a.
    – Fazer
    Jun 10, 2015 at 9:28
  • I realized that the event loop in pygame is only checking one event at a time, so I made the suggested change. But it didn't make a difference.
    – Fazer
    Jun 10, 2015 at 19:14
  • After adding the second power source(as stated in my answer), my cpu utilization dropped to around 65%. You said anything less than 100% and something is wrong..... Were you just throwing that around, or were you serious? EDIT: This is after adding the 0.5s delay and changing the 4 if statements into one if-elif ladder.
    – Fazer
    Jun 10, 2015 at 19:15
  • @Fazer: He was serious, you're now getting less than 100% because you added a significant delay.
    – Jacobm001
    Jun 10, 2015 at 19:35
  • 1
    We only have what we are told to go on. For instance if you said you were powering two servos and the Pi from a microUSB we could guess the power supply as a problem.
    – joan
    Jun 10, 2015 at 19:55
6

I'm assuming you have an RPi 1 (single core processor). Your code is far too intensive for any single core machine, and is terribly inefficient (but may sorta work) on a multicore machine. The problem lies in the logic of your code. You are using what's called "polling". Essentially, you're the kid that's constantly asking, "Are we there yet? Are we there yet, Are we there yet!?".

Polling isn't necessarily a bad thing; it's how USB keyboards work. Most usb keyboards poll at 100MHz (iirc). So if you add a short sleep to the loop, you can use this idea and consume far less resources.

Pygame supports an event based solution which essentially allows your program to "block" (sit and do nothing) until an event (like a keypress) is raised. If you're interested in that method, I would suggest you start with their tutorial on how to handle that.

10
  • Would a 10 millisecond delay be good enough? And also could you point out how my code is innefficient and where, and also solutions to the inefficiency if possible.
    – Fazer
    Jun 9, 2015 at 19:23
  • @Fazer: Well, there are a 1,000 ms in 1 second. 10 ms delay seems like it might be a good place to start. Do you need it to be that fast? How quickly are you going to be issuing commands?
    – Jacobm001
    Jun 9, 2015 at 19:25
  • 1
    @Fazer: I have already pointed out the inefficiency. You're using a nondelayed polling sequence. The solutions are also listed: either add a delay, or preferably, use a state/interrupt system.
    – Jacobm001
    Jun 9, 2015 at 19:25
  • I want it to be able to react to the command ASAP, because it's possible that those commands are to steer it back on course or to prevent it from hitting something etc.
    – Fazer
    Jun 9, 2015 at 19:52
  • 4
    I'll ditto the recommendation to use an event based solution; then your code should go from using 100% to < 1%. I'm not a python or pygame user so don't know the specifics, but the general idea is you'd set the car to do one thing and keep doing it until your callback fires because the keyboard state changed.
    – goldilocks
    Jun 9, 2015 at 21:22
1

I have tried various different delay, all of which still cause my RPi to crash. So, I connected a different battery source to the RPi(earlier I had one for the motors and the pi now I have one each), and I have come to the conclusion that the RPi wasn't getting enough power. Could this be due to the greater potential difference than supplied? Or is it just lack of current?

2
  • I think the Motor will need short bursts of energy everytime you change the Direktion or increase the speed. If the Rpi got off in these cases this might be the cause.
    – S.Spieker
    Jun 13, 2015 at 11:06
  • All RPis are very sensitive to power supply. It should always be kept separate from high-current or any other changing loads. Make darn sure that it always has 2 amps of clean 5V, or 2.5 Amps with a Rpi3. Keep that Pi happy or nothing else is going to work. If it is crashing you should consider that a wake-up call that it is crying out for help.
    – SDsolar
    May 20, 2017 at 10:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.