First Programs
Hello World - Starting Python
Let's make a new directory for our RVR+/RVR projects
If you ever want to pull the latest SDK updates using git, you'll ideally want to keep your own code separate from the SDK. In this tutorial, we'll accomplish that by putting everything in a new directory outside of the SDK. Enter this command in your terminal to create the directory
# Create a new directory called rvr-projects inside of our home directory
mkdir ~/rvr-projects
Before moving to the next step make sure you are in the new directory
cd ~/rvr-projects
ℹ️ NOTE
About Text Editors and IDEs
A text editor is exactly what it sounds like. It's a program that allows you to edit text files. Python scripts are text files that contain Python code.
An IDE, or Integrated Development Environment, is a program that typically includes text editing features, plus some extra features designed to make programming in particular languages easier. An IDE may provide helpful auto-complete suggestions, debugging features, and much more.
Raspberry Pi OS typically has the following programs preinstalled:
Mousepad
A simple graphical text editor, similar to Notepad on Windows.
Found under Accessories->Text Editor in the Applications Menu
Nano
A terminal-based text editor. Since its entire interface is implemented in the terminal, you can use it from another computer over SSH.
To learn more about using Nano, you can check out the previously mentioned Pac-Man treasure hunt on the terminal from the Raspberry Pi Foundation.
Geany
A small lightweight IDE that supports several languages including Python.
Found under Programming in the Applications Menu.
Thonny Python IDE
A more focused IDE specifically for Python development.
Found under Programming in the Applications Menu.
Getting Started with Python - Hello World
It's traditional to start any programming language with a "Hello World" program. It turns out that in Python, this is really easy.
💡 TIP
Nano Text Editor is probably already on your pi, to test this try this commend:
nano --version
If it returns something like this then you are set:
GNU nano, version 3.2
(C) 1999-2011, 2013-2018 Free Software Foundation, Inc.
(C) 2014-2018 the contributors to nano
Email: nano@nano-editor.org Web: https://nano-editor.org/
Now to open Nano you can just type this command:
nano
Open up your text editor or Python IDE of choice, and make a new file. Save it as hello.py in ~/rvr-projects.
Add the line below (and save):
print("Hello World")
If we want to, we can also add comments to our script. Comments are notes to ourselves (or other programmers reading our programs later). They are ignored by the python interpreter, and begin with the # character like this:
# This is a comment. It won't do anything functional.
# We will use comments throughout this tutorial, but you can
# leave them out if you'd like
Now, in your terminal, make sure you are in ~/rvr-projects. You can tell by looking at your prompt, which should look like this:
pi@raspberrypi:~/rvr-projects $
If it doesn't, this will get you there:
cd ~/rvr-projects
In your terminal, enter the following command:
# Invokes the default Python 3.x interpreter to run our script
python3 hello.py
It should look like this:
pi@raspberrypi:~/rvr-projects $ python3 hello.py
hello world!
pi@raspberrypi:~/rvr-projects $
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 name rvr.
# 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 directory
cd ~/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.
"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 the rvr.close() line into our main function, which will get us almost there. Here's our new main():
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 a try..except..finally block. Notice that rvr.close() got moved into the finally 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.
Go Driving
Let's make RVR+ and RVR move!
❗️ IMPORTANT
During this tutorial, your RVR+/RVR will be driving. We strongly recommend that you set up SSH access on your Pi and mount it securely to the RVR+/RVR development plate before continuing.
Start with a standard template
Let's go ahead and make a new script in ~/rvr-projects and name it drive_rvr.py. We'll drop in the following standard boiler-plate code as a starting point. (This will look familiar from the previous tutorial):
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')
# We're
from sphero_sdk import SpheroRvrObserver
# 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)
# Now RVR is ready for action. Add new stuff here.
# This block gets executed if the interpreter is directly running this
# file, not importing it as a module. It's a good general practice
if __name__ == '__main__':
try:
# Stuff we want to do (in this case, just call our main function)
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()
You can now use this template to write driving programs, just by starting with your commands under time.sleep(2).
Add In Driving
For this tutorial, we're going to use the drive_control, which is a helper class within SpheroRvrObserver designed to make basic driving operations simpler.
To start we want to navigate to below time.sleep(2). We'll be driving RVR by specifying a heading (0-359 degrees) and a speed to drive along that heading. When RVR powers on, its initial heading will be 0. By using the following command it won't matter if you don't remember which way it was pointing when you powered it on. We can reset the heading to zero like so:
# Resetting our heading makes the current heading 0
rvr.drive_control.reset_heading()
Next we can go ahead and do some driving! Let's add a few method calls to our program:
# This helper method drives RVR forward on the specified heading
# and returns to our main function when the specified time has
# elapsed. This means it is a "blocking" function.
rvr.drive_control.drive_forward_seconds(
speed=64, # This is out of 255, where 255 corresponds to 2 m/s
heading=0, # Valid heading values are 0-359
time_to_drive=1 # Driving duration in seconds
)
# This version drives RVR in reverse
rvr.drive_control.drive_backward_seconds(
speed=64, # This is out of 255, where 255 corresponds to 2 m/s
heading=0, # Valid heading values are 0-359
time_to_drive=1 # Driving duration in seconds
)
The entire program should now 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
# 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)
# Resetting our heading makes the current heading 0
rvr.drive_control.reset_heading()
# This helper method drives RVR forward on the specified heading
# and returns to our main function when the specified time has
# elapsed. This means it is a "blocking" function.
rvr.drive_control.drive_forward_seconds(
speed=64, # This is out of 255, where 255 corresponds to 2 m/s
heading=0, # Valid heading values are 0-359
time_to_drive=1 # Driving duration in seconds
)
# Now back up.
rvr.drive_control.drive_backward_seconds(
speed=64, # This is out of 255, where 255 corresponds to 2 m/s
heading=0, # Valid heading values are 0-359
time_to_drive=1 # Driving duration in seconds
)
# 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 we want to do (in this case, just call our main function)
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 run our program and see what happens.
pi@raspberrypi:~/rvr-projects $ python3 drive_rvr.py
Your RVR+/RVR should drive forward for 1 second, then reverse for 1 second. Feel free to play around with different heading, speed, and time values, or add extra movements. Make it your own!
ℹ️ NOTE
If RVR+/RVR is stationary and commanded to drive along a new heading, it will first turn in place to face that heading, then drive forward or backward. The turn-in-place operation will be included in the driving time, so the turn angle will affect driving distance.
Driving by distance can be done with far greater precision using the drive to position controller, though the usage is more complex. Check ~/sphero-sdk-raspberrypi-python/getting_started/observer/driving/drive_to_position_si.py for an example.
Optional Steps
Choose Your Python Version
How to find out your Python version
In our instructions, we typically say to run Python scripts with the following command format:
python3 <scriptname.py>
python3 is actually a symbolic link to a specific Python interpreter. Which one? You can find out by entering:
python3 --version
or use the following command to see how the symbolic link points to the a specific interpreter:
ls -l /usr/bin/python3
What if I want to use a different version?
One easy way to accomplish this (and reduce your typing requirements), is to create an alias. You can open the file ~/.bashrc in your favorite text editor and add the following line at the end of the file:
alias py="/usr/bin/python3.7"
Or without a text editor, just enter this command :
echo "\nalias py=\"/usr/bin/python3.7\n\"" > ~/.bashrc
After editing your ~/.bashrc, you'll need to reload it:
source ~/.bashrc
Now, whenever you enter py, your shell will interpret it as a direct call to your python interpreter of choice! And your fingers can rest easy without typing out python3 every time ;)
# Look ma, less typing!
py <scriptname.py>
Using Pipenv
ℹ️ NOTE
In the past, we have recommended that everyone use pipenv for RVR+/RVR Python projects. If you are only using your Raspberry Pi for projects with RVR+/RVR, or you're not worried about impacting your system Python installation, it is generally easier to skip pipenv as shown in our advanced setup instructions.
Using a Python Virtual Environment
Pipenv is a tool used to manage Python virtual environments (also known as VMs). It's considered good practice to run python projects (like our SDK) in a VM in order to keep all dependencies local to a project folder (Pipenv is not the only such tool available - see PEP-405 for more information) . This is done in order to not interfere with the Raspberry Pi's global libraries and tools, including the default version of Python, which other projects might depend on. In the preconfigured Raspbian image, a virtual environment is already set up in the SDK root directory, /home/pi/sphero-sdk-raspberrypi-python, and you can optionally use it.
To launch the virtual environment, enter the following command:
pipenv shell
Installing the RVR+/RVR SDK Dependencies
If you are not starting from the Sphero preconfigured SD card image, you'll need to set up a Python virtual environment yourself before you use it. Once you've cloned the SDK, you can use a helper script that we wrote to make VM setup easier.
🔥 CAUTION
This hasn't been tested yet
To set up a Python virtual environment with all the dependencies needed by the RVR+/RVR SDK, just run the following commands:
# Change this as needed if you decided to put your copy of the SDK in a different location
cd ~/sphero-sdk-raspberrypi-python
# Run the pipenv setup script
./tools/pipenv-setup.sh
ℹ️ NOTE
This will take a while, and may look like it has gotten stuck at times. On Pi Zero W, it may not work.
Starting Programs
Once your RVR+/RVR is connected to your Pi, any time you want to work on RVR+/RVR python programs, be sure to start the VM from within the root SDK folder. Assuming the SDK is located at /home/pi/sphero-sdk-raspberrypi-python, to ensure you are in the right place, use the following command:
cd ~/sphero-sdk-raspberrypi-python
The character ~ represents the /home/pi directory.
Now activate the VM with the following command:
pipenv shell
If you see the name of the SDK folder in parentheses before your command prompt, you are now in a project-specific VM!
If you'll be running the example scripts from the getting_started folder, you can use cd to get to the directory of the example you'd like to execute, and then you can run that code using:
python scriptname.py
Exiting the VM
Once you are finished working with the SDK, you can exit the VM in one of two ways.
by issuing the following command:
exit
by pressing Ctrl + D.
Turning Off Your Raspberry Pi
Once you are finished using your Raspberry Pi and RVR+/RVR, make sure to shut down your Raspberry Pi:
sudo shutdown now