Functions

Functions are bits of code that do specific things so you don't have to recreate the wheel every time you have to do something. The idea is that you can hide the inner working of the function, which makes it easier to think about other things you're trying to do.

Functions should make life easier.

Note on Pico vs. Zero:
  1. For the Pico use board.GP0 instead of board.D18 because they are set up to use different input pins by default.

References:

  1. QuickRef: Functions

Why Functions

To turn off all the lights we just need a simple loop:


            for i in range(20):
              pixels[i] = (0,0,0)
            

However, as we write more interesting lighting sequences, we'll find that we need to do this quite often, so we can create a shortcut that we'll call a function.

Assignment 1

Write a program to do the following (you don't have to use functions to do it),
  1. Light up all of the lights (green) (in sequence with a 0.1 second delay),
  2. Turn off the lights
  3. Wait for 1 second,
  4. Light up all the lights again (red)
  5. Turn off the lights
Code ▼

Writing Functions (Turn off the lights)

A function to turn off the lights looks like this:


              def lightsOff():
                for i in range(20):
                  pixels[i] = (0,0,0)
            

Let's redo Assignment 1 but use a function to turn the lights off. The function is defined on lines 7-10, and called twice on lines 20 and 31.


            import board
            import neopixel
            import time

            pixels = neopixel.NeoPixel(board.GP0, 20)

            # FUNCTION: to turn off all the lights
            def lightsOff():
              for i in range(20):
                pixels[i] = (0,0,0)


            # MAIN PROGRAM STARTS HERE
            # make lights blue in sequence
            for i in range(20):
              pixels[i] = (0,0,10)
              time.sleep(0.1)

            # CALL the function to turn off lights
            lightsOff()

            # wait 1 second
            time.sleep(1)

            # make lights red in sequence
            for i in range(20):
              pixels[i] = (10,0,0)
              time.sleep(0.1)

            # CALL the function to turn off lights
            lightsOff()

            

Assignment 2

Write a function called allBlue that turns all of the lights blue (in sequence with a 0.1 second timestep), and use it in a program that:
  1. Light up all of the lights (blue) (in sequence with a 0.1 second delay),
  2. Turn off the lights
  3. Wait for 1 second,
  4. Light up all the lights again (red)
  5. Turn off the lights
  6. Wait for 1 second,
  7. Light up all the lights again (blue)
Code ▼

Passing Parameters

We could make separate functions that light up all the different colors in sequence (you may have already done so for the red lights in Assignment 2). However, this would be easier to handle if we could tell the function which color to use.

So we'll pass a parameter called color to a function, which will use that color.

Let's call the function lightSequence.


              def lightSequence(color):
                for i in range(20):
                  pixels[i] = color
                  time.sleep(0.1)

              lightSequence( (10,0,0) )       # call to make lights red
              lightSequence( (0,0,10) )       # call to make lights blue
            

In the call to the function with lightSequence( (10,0,0) ), we pass the color (e.g. red (10,0,0) in the first call).

The function definition, def lightSequence(color): expects to be passed one parameter called "color", that the function uses to set the led colors on line 3.

Assignment 3

Use the lightSequence function to:
  1. Light up all of the lights (red) (in sequence with a 0.1 second delay),
  2. Turn off the lights then wait for 1 second.
  3. Light up all the lights again (green)
  4. Turn off the lights then wait for 1 second.
  5. Light up all the lights again (blue)
  6. Turn off the lights then wait for 1 second.
  7. Light up all the lights again (yellow)
Code ▼

Assignment 4

Write a function that lights the LEDs backwards and use it to:
  1. Light up all of the lights (red) (in sequence with a 0.1 second delay),
  2. Turn off the lights (no wait)
  3. Light up all the lights backwards (green)
  4. Light up all the lights again (blue)
  5. Light up all the lights backwards (red)
Code ▼

Passing Multiple Parameters

You can pass multiple variables to a function, they just need to be comma separated. For example, a function to make three lights red, blue, and green respectively would look like:


              def lightRGB(a, b, c):
                pixels[a] = (10,0,0)
                pixels[b] = (0,10,0)
                pixels[c] = (0,0,10)

              # function call
              lightRGB(1, 4, 10)
            
Full Program ▼

Assignment 5

Write a function called lightUp that you can pass a number of lights to and it will light up that many lights in sequence (0.1 second delay between lights). For example, if you passed it the number 7, 7 LEDs would light up.
  1. Light up the first 5 lights (red) (in sequence with a 0.1 second delay),
  2. Light up the first 10 lights (green) in sequence
  3. Light up all the lights (blue) in sequence
  4. Light just the first 10 lights (red) in sequence
  5. Light just the first 5 lights (yellow) in sequence
Code ▼

Error Messages: Passing Parameters

What happens when you pass too many, or too few parameters?

Understanding error messages is a lot easier if you've seen them before. So it's useful to make intentional errors and observe the resulting errom messages.

What error message do you get when you forget to pass a variable to a function that needs one?

The lightRGB function below requires 3 parameters (a, b, and c), but if we put in only two paramters in the function call:


                  def lightRGB(a, b, c):  # requires 3 parameters
                    pixels[a] = (10,0,0)
                    pixels[b] = (0,10,0)
                    pixels[c] = (0,0,10)

                  # function call
                  lightRGB(1, 4)  #passing only 2 paramters
                
Error Message ▼

                  Traceback (most recent call last):
                    File "", line 13, in 
                  TypeError: function takes 3 positional arguments but 2 were given
                

Assignment 6: Error Messages when Passing Parameters

What error message do you get when you pass too many variables to the lightRGB function?
Code ▼
Error Message ▼

Default Parameters

The lightUp function can light any given number of leds and sets their color.


              def lightUp(n, color):
                  for i in range(n):
                    pixels[i] = color
                    time.sleep(0.1)
            

However, we might frequently want to light up all the leds. We can set it up so that the function does that by default if you don't pass it a number parameter (n). Because python does not like it if you have non-default parameters after default parameters, we'll also set a default color ("blue").


              def lightUp(n=20, color=(0,0,10)):
                  for i in range(n):
                    pixels[i] = color
                    time.sleep(0.1)
            

Now we can call the function without any argumements and it will still work.


              import board
              import neopixel
              import time

              pixels = neopixel.NeoPixel(board.GP0, 20)

              def lightUp(n=20, color=(0,0,10)):
                for i in range(n):
                  pixels[i] = color
                  time.sleep(0.1)

              # function call
              lightUp()
            

We can pass either parameter if we want, but it can get tricky if we don't name them. The rule is that you still need to pass the parameters in the right positional order. In this case, that means if you called the function with lightUp(5), that would work, but trying to set only the color, lightUp((0,10,0)) would fail (you should try them yourself to see the error messages).

To avoid this issue we can just name the parameters as we pass them. So to make all 20 leds green we can use:


              def lightUp(n=20, color=(0,0,10)):
                for i in range(n):
                  pixels[i] = color
                  time.sleep(0.1)

              lightUp(color=(0,10,0))
            

Assignment 7: Using Default Parameters

Use the lightUp function, while taking maximum advantage of the default parameters to:
  1. Light up all the lights (blue) in sequence,
  2. Light up the first 10 lights (red) in sequence
  3. Light up all the lights (green) in sequence
  4. Light up all the lights (blue) in sequence
  5. Light just the first 10 lights (yellow) in sequence
Code ▼

Assignment 8: Last Lights

Write a function lastLights that:
  1. lights up the last n lights in sequence, given the number of lights (n) and their color.
  2. By default, it should light up all the leds.
  3. Default color: green
For example, if you passed lastLights(n=7) it should do this:
Code ▼

Assignment 9: Step Lights

Write a function stepLights that:
  1. Lights up all the leds that are multiples of the given step
  2. The default step = 1
  3. Default color: green
  4. Default time between steps = 0.1 seconds
For example, if you passed stepLights(step=2, dt=1) it should do this:
Code ▼

Returning Values from Functions

To make interesting color patterns, it can be useful to use complementary colors. These are matched colors that go well together.

A simple way to find a complementary color to a given color is to figure out what color would need to be added to give white.

For example, the RGB color code for blue is (0,0,255) and white is (255,255,255), so if we subtract blue from white we get:


              (255, 255, 255) - (0, 0, 255) = (255, 255, 0)
            

(255, 255, 0) is yellow, which is the complementary color for blue.

Example: Write a function called complementaryColorthat returns the complementary color for any given color.


              def complementaryColor(color):
                r = 255 - color[0]
                g = 255 - color[1]
                b = 255 - color[2]
                return (r, g, b)

              # MAIN PROGRAM: find the complementary color of blue
              blue = (0, 0, 255)
              compColor = complementaryColor(blue)
              print(compColor)
            

In the function:

To see this in practice. Here is a program that lights up the first light with a color (color1) and the last light with its complementary color (compColor), using the complementaryColor function:


              import board
              import neopixel
              import time

              pixels = neopixel.NeoPixel(board.GP0, 20)

              def complementaryColor(color):
                  r = 255 - color[0]
                  g = 255 - color[1]
                  b = 255 - color[2]
                  return (r, g, b)

              # MAIN PROGRAM
              color1 = (0, 0, 255)
              compColor = complementaryColor( color1 )
              print(f'complementary color of {color1} is {compColor}')

              pixels[0] = color1
              pixels[-1] = compColor
            

Assignment 10: Scaling Complementary Colors

Finding the complementary color by subtracting from 255 makes for some very bright lights. We can instead use a different number, call it a scaling value to subtract the rgb values from instead.

Write a function that takes two input parameters (a color and a scaling value) and returns the scaled complementary color.

Inputs:
  1. A color (in the form (r, g, b))
  2. A scaling value that is used instead of 255 to calculate the complementary color.

For example. If the input color is color = (10, 5, 7) and the scaling value = 10, then the complementary color returned should be (0, 5, 3).

Use the function to make the first 10 lights the starting color, and the second 10 the complementary color.

Code ▼

Importing Functions from Other Files

We've made an number of functions that will be useful in designing light patterns. However, keeping them all in the same file adds some clutter we can aleviate by moving our functions into a separate file and importing them when we need them.

This is particularly useful when you're sharing a Pi Pico, because you can save your functions in a separate file that does not get overwritten by other students.

First, let's create a file with the functions, lightsOff, lightUp, lastLights, and complementaryColor (you can put other functions in if you like). I'm going to call my file docFuncs.py , but you should give yours a unique name.

docFuncs.py

              import board
              import neopixel
              import time

              pixels = neopixel.NeoPixel(board.GP0, 20)

              def lightsOff():
                  for i in range(20):
                      pixels[i] = (0,0,0)

              def lightUp(n=20, color=(0,0,10)):
                  for i in range(n):
                      pixels[i] = color
                      time.sleep(0.1)

              def lastLights(n=20, color=(0,10,0)):
                  startLed = 20-n
                  for i in range(startLed, 20):
                    print(i)
                    pixels[i] = color
                    time.sleep(0.1)

              def complementaryColor(color):
                  r = 255 - color[0]
                  g = 255 - color[1]
                  b = 255 - color[2]
                  return (r, g, b)

            

Now, we can write a much shorter program that imports the functions.

code.py

              from docFuncs import *

              lightUp()
              lightsOff()
              lastLights(8)

            

Assignment 11: Importing Functions

Add as many functions as you'd like to your functions file and make an interesting lighting pattern using them.