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:

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 


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


pi@raspberrypi:~/rvr-projects $


If it doesn't, this will get you there:

cd ~/rvr-projects


# 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.

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.

#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


# Instantiate (create) a SpheroRvrObserver object

rvr = SpheroRvrObserver()


# 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)


# 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()    


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


"Fancy" Version

There are some issues with the script we just wrote:

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.

# 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)

# 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()


# 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()


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()

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.

   # 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

    )


    # 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()


pi@raspberrypi:~/rvr-projects $ python3 drive_rvr.py



ℹ️ 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.

exit


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


Ready for more? Check out our project ideas for how to continue!