Hello RVR+/RVR - LED Control
Now that you've written your first python program, let's bring RVR+/RVR into the picture! We're going to use the observer
interface of the RVR+/RVR SDK, since it's the simplest option.
Let's walk through writing a script to control RVR's LEDs in a new file that we'll name rvr_leds.py
.
Basic Version
note
Before starting this step is is important to have the exact file path for the sphero-sdk-raspberrypi-python
folder. An easy way to verify this is to use the cd
and ls
commands until you are in this folder. Once you are there you can use the command pwd
, which stands for print working directory, and take note of the file path. You will need in in Step 2.
Open a new file in the text editor you chose the last step. We'll need to start by importing some standard python modules.
import sys # Allows us to use sys.path.append below import time # Allows us to insert delays in our script
Next we can import some RVR+/RVR SDK modules. We'll need these to interact with RVR+/RVR and control the LEDs
# sys.path tells the interpreter where to look for modules. # Tell it to look in the SDK directory as well. #Remember that this path may be different depending on where your folder is sys.path.append('/home/pi/sphero-sdk-raspberrypi-python') # Now that it can find the SDK, we can import some useful SDK modules from sphero_sdk import SpheroRvrObserver from sphero_sdk import Colors
Now that we have access to the SDK, we need an instance of the
SpheroRvrObserver
object, which we'll namervr
.# Instantiate (create) a SpheroRvrObserver object rvr = SpheroRvrObserver()
At this point, we can already interact with RVR+/RVR. But we need to make sure that RVR is not in "soft sleep", a low-power standby mode. If RVR+/RVR is already awake, this command will simply be ignored by RVR+/RVR, so it's always safe to send it at the start of your script.
# Make sure RVR is awake and ready to receive commands rvr.wake()
The wakeup process will involve a brief LED animation sequence, so we'll want to make sure there's time for that to complete. We can pause execution of our script for 2 seconds like this:
# Wait for RVR to wake up time.sleep(2)
Now we can take control of RVR's LEDs. Let's try out a couple of different ways to use them.
# Set all of RVR's LEDs to a named color rvr.led_control.set_all_leds_color(color=Colors.yellow) # Wait a second so we get to see the color change time.sleep(1) # Now try using RGB (Red Green Blue) values. # This allows us to pick any color in the RGB colorspace. rvr.led_control.set_all_leds_rgb(red=255, green=0, blue=0)
Before we run our program, we should end with closing the serial port.
# Call this at the end of your program to close the serial port rvr.close()
Now let's try it out! The full script should look like this:
import sys # Allows us to use sys.path.append below import time # Allows us to insert delays in our script # sys.path tells the interpreter where to look for modules. # Tell it to look in the SDK directory as well. sys.path.append('/home/pi/sphero-sdk-raspberrypi-python') # Now that it can find the SDK, we can import some useful SDK modules from sphero_sdk import SpheroRvrObserver from sphero_sdk import Colors # Instantiate (create) a SpheroRvrObserver object rvr = SpheroRvrObserver() # Make sure RVR is awake and ready to receive commands rvr.wake() # Wait for RVR to wake up time.sleep(2) # Set all of RVR's LEDs to a named color rvr.led_control.set_all_leds_color(color=Colors.yellow) # Wait a second so we get to see the color change time.sleep(1) # Now try using RGB (Red Green Blue) values. # This allows us to pick any color in the RGB colorspace. rvr.led_control.set_all_leds_rgb(red=255, green=0, blue=0) # Call this at the end of your program to close the serial port rvr.close()
tip
Remember comments? Text following a
#
character will be ignored by the interpreter. If you have different comments or no comments, your program will work the same way as ours.# I am a comment. Python ignores me, but programmers read me.
Are you in
~/rvr-projects/
in your terminal? Remember it should look like this:pi@raspberrypi:~/rvr-projects $
If it doesn't, then use the
cd
command to navigate your terminal to that directorycd ~/rvr-projects
And then run the script!
python3 rvr_leds.py
Did you see RVRs LEDs turn yellow, then red? Great! You just wrote your first program controlling RVR!
If you didn't see the LEDs change color, make sure you've carefully followed our setup instructions. You can also check out our troubleshooting section, or hit the community forum if you really get stuck.
"Fancy" Version
There are some issues with the script we just wrote:
Everything happens sequentially, with no functions used to organize and reuse code. This is okay for a really simple script, but we can do better.
If the script exits early, due to an error or a keyboard interrupt (pressing Ctrl+C on the keyboard), then the serial port won't be closed. This could cause issues later, so we should avoid it.
Exiting the script early actually takes two keyboard interrupts, and generates a bunch of extra terminal output:
pi@raspberrypi:~/rvr-projects $ python3 led_rvr.py
^CTraceback (most recent call last): File "led_rvr.py", line 27, in <module> time.sleep(1) KeyboardInterrupt ^CException ignored in: <module 'threading' from '/usr/lib/python3.7/threading.py'> Traceback (most recent call last): File "/usr/lib/python3.7/threading.py", line 1281, in _shutdown t.join() File "/usr/lib/python3.7/threading.py", line 1032, in join self._wait_for_tstate_lock() File "/usr/lib/python3.7/threading.py", line 1048, in _wait_for_tstate_lock elif lock.acquire(block, timeout): KeyboardInterrupt
We can solve both of the problems above with just a little more effort.
We can place code in functions to organize it, or to reuse it in multiple places. We're going to move much of what we just wrote into a function called
main
. We start defining a function like this:# This tells the Python interpreter that we are defining # a function named main that takes no arguments def main(): # Our code inside the function gets indented like this. # In the RVR SDK code you'll see a standard indentation of 4 spaces.
Now, we can copy and paste everything between the instantiation of
rvr
and thervr.close()
line into ourmain
function, which will get us almost there. Here's our newmain()
:def main(): # Make sure RVR is awake and ready to receive commands rvr.wake() # Wait for RVR to wake up time.sleep(2) # Set all of RVR's LEDs to a named color rvr.led_control.set_all_leds_color(color=Colors.yellow) # Wait a second so we get to see the color change time.sleep(1) # Now try using RGB (Red Green Blue) values. # This allows us to pick any color in the RGB colorspace. rvr.led_control.set_all_leds_rgb(red=255, green=0, blue=0)
So far we've defined our main function, but we need to actually call the function for the interpreter to execute it. We do this by adding the following code block, which calls
main()
as long as this file was the one directly called by the interpreter:# This tells the interpreter to run our main() function if it is running this script # directly (and not importing it as a module from elsewhere) if __name__ == '__main__': main()
Now the interpreter will run
main()
, but we still haven't dealt with the not-so-graceful manual exit. We can fix that with atry..except..finally
block. Notice thatrvr.close()
got moved into thefinally
section. This ensures that it will be called at the end of the program whether it completes normally or hits an exception.# This tells the interpreter to run our main() function if it is running this script # directly (and not importing it as a module from elsewhere) if __name__ == '__main__': try: # Stuff to try doing (which might generate an exception) main() except KeyboardInterrupt: # What to do if there's a keyboard interrupt (ctrl+c) exception # In this case, we're just going to print a message print('\nProgram terminated with keyboard interrupt.') finally: # What to do before we exit the block rvr.close()
The final product should look like this:
import sys # Allows us to use sys.path.append below import time # Allows us to insert delays in our script # sys.path tells the interpreter where to look for modules. # Tell it to look in the SDK directory as well. sys.path.append('/home/pi/sphero-sdk-raspberrypi-python') # Now that it can find the SDK, we can import some useful SDK modules from sphero_sdk import SpheroRvrObserver from sphero_sdk import Colors # Instantiate (create) a SpheroRvrObserver object rvr = SpheroRvrObserver() # This tells the Python interpreter that we are defining # a function named main that takes no arguments def main(): # Make sure RVR is awake and ready to receive commands rvr.wake() # Wait for RVR to wake up time.sleep(2) # Set all of RVR's LEDs to a named color rvr.led_control.set_all_leds_color(color=Colors.yellow) # Wait a second so we get to see the color change time.sleep(1) # Now try using RGB (Red Green Blue) values. # This allows us to pick any color in the RGB colorspace. rvr.led_control.set_all_leds_rgb(red=255, green=0, blue=0) # This tells the interpreter to run our main() function if it is running this script # directly (and not importing it as a module from elsewhere) if __name__ == '__main__': try: # Stuff to try doing (which might generate an exception) main() except KeyboardInterrupt: # What to do if there's a keyboard interrupt (ctrl+c) exception # In this case, we're just going to print a message print('\nProgram terminated with keyboard interrupt.') finally: # What to do before we exit the block rvr.close()
Let's try it out! Run your program as we did before
pi@raspberrypi:~/rvr-projects $ python3 rvr_leds.py
If we try pressing
ctrl+c
while the script is running, we should see our message print out like this:pi@raspberrypi:~/rvr-projects $ python3 rvr_leds.py ^C Program terminated with keyboard interrupt.
Next up!
In the next tutorial, we'll get your RVR+/RVR driving!