Part 3. Programming with Create

Perhaps most concisely, robotics might be considered the art and science of connecting sensors with actuators to accomplish desired tasks. This section guides you through a couple of ideas for making those connections. First, however, we introduce two ways for structuring these more complex interactions with the Create: via functions or class methods.

The file task1.py contains two top-level functions and one class definition. Here is a copy of the file:
# task1.py
# 
# Example interactions with the Create
#
# you can load this file the first time with
# >>> import task1
# and you can reload it after making changes with
# >>> reload(task1)
# you can import all of the names into the local namespace with
# >>> from task1 import *
#
# Or, you can simply copy this line every time:
# >>> import task1 ; reload(task1) ; from task1 import *

import create
import time

#
# using a function that takes the robot as input...
#
def backup(r):
    """ this function simply backs the robot up
        for two seconds (as an aside, this string is
        printed if you type help(task1.backup)

        the input is the robot, r
    """
    r.go(-10,0)
    time.sleep(2) # go for 2 seconds
    r.stop();


#
# another function example...
#
def testLoop(r):
    """ an example of an sense-plan-action loop
        admittedly, there's not much planning here

        the input is the robot, r
    """
    r.toSafeMode()
    while True:

        # sense
        d = r.sensors()  # get all sensors...

        # "plan"
        left = d[create.LEFT_BUMP]
        right = d[create.RIGHT_BUMP]
        playButton = d[create.PLAY_BUTTON]

        # act
        if right > 0:
            print 'right bump'
            r.go(0,0)
        elif left > 0:
            print 'left bump'
            r.go(0,30)
        elif playButton > 0:
            print 'button press'
            r.go()
            break

        # don't go too fast...
        time.sleep(0.015)

    print 'End of testLoop\'s loop!'

#
# an example of deriving a class...
#
class MyCreate(create.Create):

    def __init__(self):
        """ this constructor has a hard-coded value for
            the serial port to ease typing
        """
        serialportname = '/dev/tty.RooTooth-COM0-1'
        create.Create.__init__(self,serialportname)

    def beethoven(self):
        """ plays four famous notes """
        self.playSong( [(55,16),(55,16),(55,16),(51,64)] )


As indicated at the top of the file, you can initially load it in with

>>> import task1
and you can reload it after changes with

>>> reload(task1)
and you can import its names into the local namespace with

>>> from task1 import *
or you can do all three every time with a single line (I tend to do this...)

>>> import task1 ; reload(task1) ; from task1 import *




Trying out these examples

Once you've loaded the file, you should be able to run

>>> backup(r)
presuming you still have r, the Create object, left over from prior interactions. Similarly, the function

>>> testLoop(r)
will allow the user to tell the robot to rotate or stop by pressing on different sides of the bumper. The "play" button (with a single arrow on it) qill quit the loop.

If you don't have a Create object or want to make a new one, first close the old one's serial port with

>>> r.close()
then, you can try

>>> r = task1.MyCreate()
but you'll have to change the serial port name to suit your computer!



Challenges


The next few tasks guide you to think through some of the capabilities that the Create has to offer... . Try one of the first few tasks, and then consider how you might augment it, as suggested by the second list of behaviors. First list: try one (or more!) of these basic tasks:
  1. Create a program that drives the robot in a square (or regular n-gon, if you prefer)
  2. Create a program that measures the width of a hallway when started near the middle and facing perpendicular to the hallway's direction.
    Extra!: when facing in any direction at all!
    Double secret extra!: even if there is an obstacle in the hallway.
  3. Create a program that drives the robot until it bumps something, and then turns a random amount, and continues. This is perhaps the simplest wandering routine.
  4. Create a program that, when started near a wall, can drive to that wall and then follow it around the room (or out the door, if the door is open!)


Extensions

Once you have one (or more) of these tasks debugged, try extending the physical interface to include a start or stop trigger or auditory or visual feedback, e.g., one or more of the following extensions
  1. Have the robot play notes whose pitch indicates how far it thinks it is from its starting point. This allows an auditory check on the robot's odometric accuracy.
  2. Challenge! Create a program in which a push from the back triggers the robot to jolt forward. (This is what the "wimp" demo programs does. This question is really asking how it does it!)
  3. Have a button press pause the task, and then have another button press resume it.
  4. Use the three LEDs to connect appropriate visual feedback to your task. For example, you might have the lights indicate the state of the behavior.


Depending on the complexity of the task, you may end up building a state-machine to arbitrate among the possible sensor and user inputs.