UltraBorg PBR BattBorg and pygame robot. Help request for Python code.
Forums:
Hello PiBorg community,
Firstly I'd like to thank everyone at PiBorg for creating such brilliant boards.
The PBR gives plenty of power to control motors and the BattBorg does an excellent job of powering the Pi from batteries. The UltraBorg is a great bit of kit, offering control over servos and distance sensors. I love them all and have brought them together to create a robot with an onboard pan/tilt camera.
However, I am having some trouble with some Python code that I have cobbled together. I am sure this is a classic case of "operator error" and hopefully, can be easily resolved by someone with more knowledge than myself.
The code is designed to take inputs from a keyboard (wireless) and either move motors controlled by the PBR forwards, backwards, left and right; or move two servos controlled by the UltraBorg up, down, left and right.
The motors work perfectly with the code, but whenever I press a key to operate the servos I receive the following error:-
Traceback (most recent call last): File "/home/pi/picoborgrev/1.2-servo_motorcontrol_PBR_pygame .py", line 118, in servo_up() File "/home/pi/picoborgrev/1.2-servo_motorcontrol_PBR_pygame .py", line 47, in servo_up servo2 += rateServo2 UnboundLocalError: local variable 'servo2' referenced before assignment
I have moved bits of code around trying to resolve the issue, but to no avail.
I have tried to comment the code methodically to show what I am trying to achieve with each section of the program. Hopefully this will help diagnose the source of the problem.
Thank you in advance for your time and any assistance you are able to offer.
Kind regards,
TankMan
PS The code is as follows:-
#!/usr/bin/env python import time import PicoBorgRev import pygame import os import UltraBorg # Settings servoMin = -1.0 # Smallest servo position to use servoMax = +1.0 # Largest servo position to use startupDelay = 0.5 # Delay before making the initial move stepDelay = 0.1 # Delay between steps rateStart = 0.05 # Step distance for all servos during initial move rateServo1 = 0.01 # Step distance for servo #1 rateServo2 = 0.01 # Step distance for servo #2 # Start the UltraBorg UB = UltraBorg.UltraBorg() # Create a new UltraBorg object UB.Init() # Set the board up (checks the board is connected) # Start the PicoBorg Reverse PBR = PicoBorgRev.PicoBorgRev() PBR.Init() PBR.ResetEpo() # Start pygame & define pygame screen size pygame.init() screen = pygame.display.set_mode ((480,480)) print 'Move to central' # Initial settings servo1 = 0.0 servo2 = 0.0 # Set our initial servo positions UB.SetServoPosition1(servo1) UB.SetServoPosition2(servo2) # Wait a while to be sure the servos have caught up time.sleep(startupDelay) # Define servo variables def servo_left(): servo1 += rateServo1 def servo_right(): servo1 -= rateServo1 def servo_up(): servo2 += rateServo2 def servo_down(): servo2 -= rateServo2 # Check if any servos exceed limits and constrain to limit if servo1 > servoMax: servo1 = servoMax if servo1 < servoMax: servo1 = servoMax if servo2 > servoMax: servo2 = servoMax if servo2 < servoMin: servo2 = servoMin # Set our new servo positions UB.SetServoPosition1(servo1) UB.SetServoPosition2(servo2) # Define motor variables def forwards(): PBR.SetMotor1(+0.8) PBR.SetMotor2(+0.7) def back(): PBR.SetMotor1(-0.8) PBR.SetMotor2(-0.7) def left(): PBR.SetMotor1(-0.6) PBR.SetMotor2(+0.6) def right(): PBR.SetMotor1(+0.6) PBR.SetMotor2(-0.6) def stop(): PBR.MotorsOff() def shutdown(): os.system("sudo shutdown -P now") while True: pygame.display.flip() keystate=pygame.key.get_pressed() if keystate[pygame.K_DOWN]: print 'backwards' back() elif keystate[pygame.K_UP]: print 'forwards' forwards() elif keystate[pygame.K_RIGHT]: print 'right' right() elif keystate[pygame.K_LEFT]: print 'left' left() elif keystate[pygame.K_a]: print 'servo left' servo_left() elif keystate[pygame.K_d]: print 'servo right' servo_right() elif keystate[pygame.K_w]: print 'servo up' servo_up() elif keystate[pygame.K_x]: print 'servo down' servo_down() elif keystate[pygame.K_SPACE]: print 'shutdown' shutdown() else: stop() for event in pygame.event.get(): if event.type == pygame.QUIT: stop() exit(0) time.sleep(0.01)
piborg
Mon, 04/11/2016 - 11:29
Permalink
Global vs local values
I think your problem is due to how Python uses variables.
Put simply if you are trying to read a value then Python will use anything it can find.
If you are trying to change a value it expects it to exist locally.
The simplest way to fix this would be to make the
servo1
andservo2
variables global.First change the initial settings to be global:
Then any function which needs them should also make them global, for example:
now these functions will change the global version instead.
TankMan
Wed, 04/20/2016 - 20:31
Permalink
IT LIVES! Thank you very much.
Hi piborg,
IT LIVES!
Thank you very much for your superbly swift and very helpful reply.
It has been a pretty busy week, so please accept my apology for not replying sooner.
I have managed to implement your code correctly and the pan/tilt mechanism is finally working.
I will tweak the code that limits the up/down and left/right limits and add a key-press that centres the mechanism, but, right now it works and I'm smiling from ear to ear.
I may be re-inventing the wheel a bit with this code, as I know that you have a web GUI. I will find time to explore it.
This code runs without wifi, controlled by a bluetooth keyboard and there are merits to that.
It has been a superb learning experience and your help has been the icing on the cake.
I wish you all the very best of fortune.
Kind regards,
TankMan
TankMan
Tue, 08/06/2024 - 17:07
Permalink
Update to Python3
Hi all,
I am trying to revive the robot using a RaspberryPi 3 running Bullseye and Python3.
I think the problem I am experiencing is caused by Python3.
I have downloaded the PicoBorgRev3.py and UltraBorg3.py files and have saved them in the same folder as the code I want to run. I have amended the code to import PicoBorgRev3 as PicoBorgRev and import UltraBorg3 as UltraBorg.
The Demo GUI files for the PicoBorgReverse and UltraBorg are both working, so I am confident everything is wired-up correctly.
I am receiving an error when I run my code.
I run the code from terminal using this line:-
pi@raspberrypi:~/Python $ sudo python 1.4-servo_motorcontrol_PBR_pygame.py
and receive this error:-
I am guessing this is caused by the new RaspberryPi using Python3.
The code is:-
I have also attached the code as a .txt file.
I would greatly appreciate any help/advice you have, as I love PiBorg products and really want to get this back up and running.
Thank you in advance.
piborg
Mon, 08/05/2024 - 17:52
Permalink
Python 3 global
You are correct, this is a difference between Python 2 and 3 :)
Basically Python 3 is a bit more strict about the use of
global
to help prevent accidental mix-ups between local and global values. In this case the error is thatservo1
is used on the line aboveglobal servo1
.Normally you would fix this by moving
global servo1
above theif
block, but it this case we already have it up on line 33, so it can simply be removed. The same issue applies toglobal servo2
.In other words remove the
global ...
lines in theif
block like so:Don't remove the ones in the
def servo_...
functions above. Since they are functions they do need their ownglobal ...
lines.TankMan
Tue, 08/06/2024 - 16:42
Permalink
Global variable fix worked, but new error regarding PyGame
Hi all,
Thank you very much for your swift response and for confirming that the error was due to Python3 handling global variables differently.
I made your recommended changes and that has moved me past the original error.
iI am getting a new error now, which appears to be regarding PyGame.
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "/home/pi/Python/./1.5-servo_motorcontrol_PBR_pygame.py", line 19, in
UB = UltraBorg.UltraBorg() # Create a new UltraBorg object
NameError: name 'UltraBorg' is not defined
I have seen elsewhere in the forum that PyGame can cause problems, and have seen that you created your own library -- GamePad.
I will download the code for GamePad, which is Python3 compatible, and will let you know how I get on.
I did anticipate that the migration to Python3 would require some updating of the code, but the only other option was to install Python2. My personal feeling is that, in the long term, the additional effort is worth while to give me up-to-date working code.
Once I have the robot working correctly over Bluetooth from a keypad, the next step will be to investigate your Web UI to stream video and offer control from the IP (which will mean my current code will be redundant, but I would like to get it working before I take the leap into Web Interfacing).
Thanks again for your help.
TankMan
Tue, 08/06/2024 - 16:43
Permalink
GamePad doesn't appear to be the solution for me
Ooops. After further investigation, I now see that GamePad is for using PlayStation-style controllers, not keyboards.
Is the error I am getting another global variable glitch from Python3? Are you able to offer a suggestion?
Thank you very much for your super-human patience.
TankMan
Tue, 08/06/2024 - 16:52
Permalink
Possible solution
Hi all,
Please ignore the previous two posts. I think I have the solution.
Line 7 reads:
I think it should be:
I will test and let you know the result.
TankMan
Tue, 08/06/2024 - 17:16
Permalink
PicoBorgReverse, UltraBorg and BattBorg via Bluetooth keyboard
Hello again,
As I suspected, this time the error was created by myself with the lower-case "b" being the culprit.
The capital "B" in UltraBorg in line 7 was the solution.
The working code is as follows:-
Thank you again for your help with the global variable discrepancy from Python3, and for making such excellent hardware, and most of all for your superb software support.
I wish you all the very best. :)
piborg
Tue, 08/06/2024 - 20:57
Permalink
Great news :)
Glad to hear you got it working.
TankMan
Tue, 08/27/2024 - 16:49
Permalink
Updated working code with new features
Hi piborg,
I have been delving deeper into the convoluted intricacies of global variables in Python 3, and although I stated the last code I posted was working, it turns out that there was a glitch.
The keyboard inputs were being registered (and printed on-screen for feedback) for the motors and servos, but only the motors were actually responding.
I finally tracked the problem down to the lines of code that set the servo positions. I have now moved that code inside the functions that define the up, down, left and right movement of the servos.
I have also added a key-press that re-centres the servos and some code that drops the 12V input voltage to the PBR to a 6V output voltage that matches the requirement of the motors I'm currently using.
I'm so glad to have revived this project. It has been on the shelf for eight years and really deserved the effort to update it. I'm now excited to explore your web GUI and the additional connection opportunities that will offer.
Thanks again for your help, you are great and I wish you all the very best for the future.
The new code is as follows:-