The world of robots and computers, as you have seen so far is intricately connected. You have been using a computer to connect to your robot and then controlling it by giving it commands. Most of the commands you have used so far come from the Myro library which is specially written for easily controlling robots. The programming language we are using to do the robot programming is Python. Python is a general purpose programming language. By that we mean that one can use Python to write software to control the computer or another device, like a robot, through that computer. Thus, by learning to write robot programs you are also learning how to program computers. Our journey into the world of robots is therefore intricately tied up with the world of computers and computing. We will continue to interweave concepts related to robots and computers throught this journey. In this chapter, we will learn more about robot and computer programs and their structure.
If you think of your robot as a creature that acts in the world, then by programming it, you are essentially building the creature's brain. The power of computers lies in the fact that the same computer or the robot can be supplied a different program or brain to make it behave like a different creature. For example, a program like Firefox makes your computer behave like a web browser. But switching to your Media Player, the computer behaves as a DVD or a CD player. Similarly, your robot will behave differently depending upon the intstructions in the program that you have requested to run on it. In this chapter we will learn about the structure of Python programs and how you can organize different robot behaviors as programs.
Basic Program Structure
The basic structure of a Python program is shown below:
def main(): <do something> <do something> ...
This is essentially the same as defining a new function. In fact, here, we are adopting a convention that all our programs that represent robot brains will be called main. In general, the structure of your robot programs will be as shown below (we have provided line numbers so we can refer to them):
Line 1: from myro import * Line 2: initialize("comX") Line 3: <any other imports> Line 4: <function defintions> Line 5: def main(): Line 6: <do something> Line 7: <do something> Line 8: ... Line 9: main()
Every robot brain program will begin with the first two lines (Line 1 and Line 2). These, as you have already seen, import the Myro library and establish a connection with the robot. In case you are using any other libraries, you will then import them (this is shown in Line 3). This is followed by the definitions of any other functions (Line 4), and then the defnition of the function, main. Finally, the last line (Line 9) is an invocation of the function main. This is placed so that when you load this program into the Python Shell, the program will start executing. In order to illustrate this, let us write a robot program that makes it do a short dance using the yoyo and wiggle movements defined in the last chapter.
# File: dance.py # Purpose: A simple dance routine # First import myro and connect to the robot from myro import * initialize("com5") # Define the new functions... def yoyo(speed, waitTime): forward(speed) wait(waitTime) backward(speed) wait(waitTime) stop() def wiggle(speed, waitTime): motors(-speed, speed) wait(waitTime) motors(speed, -speed) wait(waitTime) stop() # The main dance program def main(): print "Running the dance routine..." yoyo(0.5, 0.5) wiggle(0.5, 0.5) yoyo(1, 1) wiggle(1, 1) print "...Done" main()
We have used a new Python command in the definition of the main function: the print command. This command will print out the text enclosed in double quotes (") when you run the program. Go ahead and try this program on your robot. In a way, this program is not much different from the dance function defined in the previous chapter (except we are using a spin motion to wiggle). However, instead of calling the function dance we are calling it main. As we mentioned earlier, this is just a naming convention that we are adopting that makes it easy to identify the main program in a program file.
In order to run this program on the robot, you can start IDLE, create a new window, enter the program in it, save it as a file (dance.py) and then select the Run Module feature in the window's Run menu. Alternately, to run this program, you can ener the follwoing command in the Python Shell:
>>> from dance import *
This is essentially equivalent to the Run Module option described above. When you run the program you will notice that the robot carries out the dance routine specified in the main program. Also notice the two messages printed in the IDLE window:
These are the result of the print command. This is a very useful command in Python and can be used to output essentially anything you ask it to.
We have launched you into the world of computers and robots without really giving you a formal introduction to the Python language. In this section, we provide more details about the language. What you know about Python so far is that it is needed to control the robot. The robot commands you type are integrated into Python by way of the Myro library. Python comes with several other useful libraries or modules that we will try and learn during this semester. If you need to access the commands provided by a library, all you have to do is import them.
The libraries themselves are largely made up of sets of functions (they can contain other entities but more on that later). Functions provide the basic building blocks for any program. Typically, a programming language (and Python is no exception) includes a set of pre-defined functions and a mecahnism for defining additional functions. In the case of Python, it is the def construct. You have already seen several examples of function definitions and indeed have written some of your own by now. In the def construct, when defining a new function, you have to give the new function a name. Names are a critical component of programming and Python has rules about what forms a name.
Whats in a name?
A name in Python must begin with either an alphabetic letter (a-z or A-Z) or the underscore (i.e. _) and can be followed by any sequence of letters, digits, or underscore letters. For example,
iRobot myRobot jitterBug jitterBug2 my2cents my_2_cents
are all examples of valid Python names. Additionally, another important part of the syntax of names is that Python is case sensitive. That is the names myRobot and MyRobot and myrobot are distinct names as far as Python is concerned. Once you name something a particular way, you have to consistently use that exact case and spelling from then on. Well, so much about the syntax of names, the bigger question you may be asking is what kinds of things can (or should) be named?'
So far, you have see that names can be used to represent functions. That is, what a robot does each time you use a function name (like yoyo) is specified in the definition of that function. Thus, by giving functions a name you have a way of defining new functions. names can also be used to represent other things in a program. For instance, you may want to represent a quantity, like speed or time by a name. In fact, you did so in defining the function yoyo which is also shown below:
def yoyo(speed, waitTime): forward(speed) wait(waitTime) backward(speed) wait(waitTime) stop()
Functions can take parameters that help customize what they do. In the above example, you can issue the following two commands:
>>> yoyo(0.8, 2.5) >>> yoyo(0.3, 1.5)
The first command is asking to perform the yoyo behavior at speed 0.8 with a wait of 2.5 seconds where as the second one is specifying 0.3 and 1.5 for speed and wait, respectively. Thus, by parameterizing the function with those two values, you are able to produce similar but varying outcomes. This idea is similar to the idea of mathematical functions: sine(x) for example, computes the sine of whatever value you supply for x. However, there has to be a way of defining the function in the first place that makes it independent of specific parameter values. That is where names come in. In the definition of the function yoyo you have named two parameters (the order you list them is important): speed and waitTime. Then you have used those names to specify the behavior that makes up that function. That is the commands forward, wait, and backward use the names speed and waitTime to specify whatever the speed and wait times are included in the function invocation. Thus, the names speed and waitTime represent or designate specific values in this Python program. Names in Python can represent functions as well as values. What names you use is entirely up to you. It is a good idea to pick names that are easy to read, type, and also appropriately designate the entity they represent. What name you pick to designate a function or value in your program is very important, for you. For example, it would make sense if you named a function turnRight so that when invoked, the robot turned right. It would not make any sense if the robot actually turned left instead, or worse yet, did the equivalent of the yoyo dance. But maintaining this kind of semantic consistency is entirely up to you.
In the last section we saw that names can designate functions as well as values. While the importance of naming functions may be obvious to you by now, designating values by names is an even more important feature of programming. By naming values, we can create names that represent specific values, like the speed of a robot, or the average high temperature in the month of December on top of the Materhorn in Switzerland, or the current value of the Dow Jones Stock Index, or the name of your robot, etc. Names that designate values are also called variables. Python provides a simple mechanism for designating values with names:
speed = 0.75 aveHighTemp = 37 DowIndex = 12548.30 myFavoriteRobot = "C3PO"
Values can be numbers or strings (anything enclosed in double-quotes, "). The above are examples of assignment statements in Python. The exact syntax of an assignment statement is given below:
<variable name> = <expression>
You should read the above statement as: Let the variable named by <variable name> be assigned the value that is the result of calculating the expression <expression>. So what is an <expression>? Here are some examples:
>>> 5 5 >>> 5 + 3 8 >>> 3 * 4 12 >>> 3.2 + 4.7 7.9 >>> 10 / 2 5
What you actually type at the Python prompt (>>>) is actually called an expression. The simplest expression you can type is a number (as shown above). A number evaluates to itself. That is, a 5 is a 5, as it should be! And 5 + 3 is 8. As you can see when you enter an expression, Python evaluates it and then outputs the result. Also, addition (+), subtraction (-), multiplication (*), and division (/) can be used on numbers to form expressions that involve numbers. You may have also noticed that numbers can be written as whole numbers (3, 5, 10, 1655673, etc) or with decimal points (3.2, 0.5, etc) in them. Python (and most computer languages) distinguish between them. Whole numbers are called integers and those with decimal points in them are called floating point numbers. While the arithmetic operations are defined on both kinds of numbers, there are some differences you should be aware of. Look at the examples below:
>>> 10.0/3.0 3.3333333333333335 >>> 10/3 3 >>> 1/2 0 >>> 1.0/2 0.5
When you divide a floating point number by another floating point number, you get a floating point result. However, when you divide an integer by another integer, you get an integer result. Thus, in the examples above, you get the result 3.3333333333333335 when you divide 10.0 by 3.0, but you get 3 when you divide 10 by 3. Knowing this, the result of dividing 1 by 2 (see above) is zero (0) should not be surprising. That is, while the division operation looks the same (/), it treats integers differently than floating point values. However, if at least one of the numbers in an arithmetic operation is a floating point number, Python will give you a floating point result (see last example above). You should keep this in mind. More on numbers later, before we get back to robots, let us quickly introduce you to strings.
Computers came to be called so because they excelled in doing calculations. However, these days, computers are capable of manipulating any kind of entity: text, images, sounds, etc. Text is made of letters or characters and strings are simply sequences of characters. Python requires that strings be written enclosed in quotes: which could be single ('I am a string'), double ("Me too!"), or even triple quotes ('''I'm a string as well!'''). Treating a string as a value is a powerful feature of Python. Python also provides some operations on strings using which you can write some useful string expressions. Here are some examples:
>>> mySchool = "Bryn Mawr College" >>> yourSchool = "Georgia Institute of Technology" >>> print mySchool Bryn Mawr College >>> print yourSchool Georgia Institute of Technology >>> print mySchool, yourSchool Bryn Mawr College Georgia Institute of Technology >>> yourSchool+mySchool 'Georgia Institute of TechnologyBryn Mawr College' >>> print yourSchool+mySchool Georgia Institute of TechnologyBryn Mawr College
Pay special attention to the last two examples. The operation + is defined on strings and it results in concatenating the two strings. The print command is followed by zero or more Python expressions, separated by commas. print evaluates all the expressions and prints out the results on the screen. As you have also seen before, this is a convenient way to print out results or messages from your program.
A Calculating Program
Ok, set your robot aside for just a few more minutes.
You have now also learned enough Python to write programs that perform simple calculations. Here is a simple problem:
Problem: If the text in a book is 478 pages long and each page has an average of 50 lines of text with an average of 6 words per line, how many words are in the entire text?
In order to answer the question, all you have to do is multiply 6 by 50 to get 300 words per page and then multiply 300 by 478 to get the estimated number of words in the text. You can just use a calculator to this simple calculation. You can also use Python to do this in two ways. You can use it as a calculator as shown below:
>>> 6 * 50 * 478 143400
So now you know the answer!
Also, let us try and write a program to do the above calculation. A program to do the calculation is obviously going to be a bit of overkill. Why do all the extra work when we already know the answer? Small steps are needed to get to higher places. So lets indulge and see how you would write a Python program to do this. below, we give you one version:
The program follows the same structure and conventions we discussed above. In this program, we are not using any libraries (we do not need any). We have defined variables with names wordsPerLine, linesPerPage, and numberOfPages to designate the values given in the problem description. We also defined the variable totalWords and use it to designate the result of the calculation. First, in the main program we assign the values given, followed by performing the calculation. Finally, we use the print command to print out the result of the computation.
You should go ahead, start Python, enter the program, and run it (just as you would run your robot programs) and observe the results. Voila! You are now well on your way to also learning the basic techniques in computing! In this simple program, we did not import anything, nor did we feel the need to define any functions. But this was a trivial program. However, it should serve to convince you that writing programs to do computation is essentially the same as controlling a robot.
The program we wrote above uses specific values of the number of lines per page, average number of words per line, and the number of pages in the text. Thus, this program solves only one specific problem for the given values. What if we wanted to calculate the number of words in a different text with varying numbers of lines of text per page, words per line, etc.? Such a program would be much more useful and could be used over and over again to do the calculation for different texts. Notice that the program begins by assigning sepcific values to the three variables:
wordsPerLine = 6 linesPerPage = 50 numberOfPages = 478
One thing you could do is simply modify those three lines to reflect the values from another text. However, typical programs are much more complicated than this one and it may require a number of different values for solving the problem. When programs get larger, it is a good idea to try and not modify them for every specific problem instance and yet, make them more useful for all problem instances. One way you can achieve this is by using the input facilities of Python. All computer programs typically take some input, do some computation (or something), and then produce some output. Python has a simple input command that can be used to rewrite the program above as follows:
Read the program above carefully. Notice that we have added additional comments as well as print statements. This improves the overall readability as well as the interaction of this program. Notice the use of the input statements above. The basic syntax of input is shown below:
<variable name> = input(<some prompt string>)
That is, the input is just a function whose parameter is a string and the value it returns is the value of the expression that will be entered by the user. That is, when executed, the computer will print out the prompt and wait for the user to enter a Python expression. Whe user can enter whatever expression in response to the prompt and then hit the RETURN or ENTER key. The expression is then evaluated by Python and the resulting value is returned by the input function. That value is then asigned to the variable <variable name>. The statement above uses the same syntax as the assignment statement described above. Python has made obtaining input from a user easy by defining input as a function. Now, look at the use of the input function in the program above. With this modification, we now have a more general program which can be run again and again. Below, we show two sample runs:
Notice how you can re-run the program by just typing the name of the main()function.
There are other ways of obtaining input in Python. We will see those a little later.
Writing programs to control your robot is therefore no different from writing a program to perform a computation. They both follow the same basic structure. The only difference is that all robot programs you will write in this course will make use of the Myro library. In fact, there will be robot programs that will require you to obtain input from the user (see exercises below). You can then make use of the input function as described above.
One characteristic that will distinguish robot programs from those that just do computations is in the amount of time it will take to run a program. Typically, a program that only performs some computation will terminate as soon as the computation is completed. However, it will be the case that most of the time, your robot program will require the robot to perform some task over and over again. here then, is an interesting question to ask:
Question How much time would it take for a vacuuming robot to vacuum a 16ft X 12ft room?
Seemingly trivial question but if you think about it a little more, you may reveal some deeper issues. If the room does not have any obstacles in it (i.e. an empty room), the robot may plan to vacuum the room by starting from one corner and then going along the entire length of the long wall, then turning around slightly away from the wall, and traveling to the other end. In this manner, it will ultimately reach the other side of the room in a systematic way and then it could stop when it reaches the last corner. This is similar to the way one would mow a flat oblong lawn, or even harvest a field of crop, or re-ice an ice hockey rink using a Zamboni machine. To answer the question posed above all you have to do is calculate the total distance travelled and the average speed of the vacuum robot and use the two to compute the estimated time it would take. However what if, as is typically the case, the room has furniture and other objects in it?
You might try and modify the approach for vacuuming outlined above but then there would be no guarantee that the floor would be completely vacuumed. You might be tempted to redesign the vacuuming strategy to allow for random movements and then estimate (based on average speed of the robot) that after some generous amount of time, you can be assured that the room would be completely cleaned. It is well known (and we will see this more formally in a later chapter) that random movements over a long period of time do end up providing uniform and almost complete coverage. Inherently this also implies that the same spot may very well end up being vacuumed several times (which is not necessarily a bad thing!). This is similar to the thinking that a herd of sheep, if left grazing on a hill, will result, after a period of time, in a nearly uniform grass height (think of the beautiful hills in Wales).
On the more practical side, IRobot's Roomba robot uses a more advanced strategy (though it is time based) to ensure that it provides complete coverage. To see the strategy in action, you can visit iRobot's web site () and then select the "Cleans your whole floor" option.
A more interesting (and important) question one could ask would be:
Question: How does a vacuuming robot know that it is done cleaning the room?
Most robots are programmed to either detect certain terminating situations or are run based on time. For example, run around for 60 minutes and then stop. Detecting situations is a little difficult and we will return to that in the next chapter.
So far, you have programmed very simple robot behaviors. Each behavior which is defined by a function, when invoked, makes the robot do something for a fixed amount of time. For example, the yoyo behavior from the last chapter when invoked as:
>>> yoyo(0.5, 1)
would cause the robot to do something for about 2 seconds (1 second to go forward and then 1 second to move backward). In general, the time spent carrying out the yoyo behavior will depend upon the value of the second parameter supplied to the function. Thus if the invocation was:
>>> yoyo(0.5, 5.5)
the robot would move for a total of 11 seconds. Similarly, the dance behavior defined in the previous chapter will last a total of six seconds. Thus, the total behavior of a robot is directly dependent upon the time it would take to execute all the commands that make up the behavior. Knowing how long a behavior will take can help in pre-programming the total amount of time the overall behavior could last. For example, if you wanted the robot to perform the dance moves for 60 seconds, you can repeat the dance behavior ten times. You can do this by simply issuing the dance command 10 times. But that gets tedious for us to have to repeat the same commands so many times. Computers are designed to to repetitious tasks. In fact, repetition is one of the key conpets in computing and all programming languages, including Python, provide simple ways to specify repetitions of all kinds.
Doing Repetition in Python
If you wanted to repeat the dance behavior 10 times, all you have to do is:
for i in range(10): dance()
This is a new statement in Python: the for-statement. It is also called a loop statement or simply a loop. It is a way of repeating something a fixed number of times. The basic syntax of a for-loop in Python is:
for <variable> in <sequence>: <do something> <do something> ...
The loop specification begins with the keyword for which is followed by a <variable> and then the keyword in and a sequence forllowed by a colon (:). This line sets up the number of times the repetition will be repeated. What follows is a set of statements, indented (again, indentation is important), that are called a block that forms the body of the loop (stuff that is repeated).
When executed, the <variable> (which is called a loop index variable) is assigned successive values in the <sequence> and for each of those values, the statements in the body of the loop are executed. A <sequence> in Python is a list of values. Lists are central to Python and we will see several examples of it later. For now, look at the dance example above and notice that we have used the function range(10) to specify the sequence. Since it looks like a function, you should go straight to IDLE and enter it as an expression:
>>> range(10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
The result of entering the range(10) is a sequence (a list) of ten numbers 0..9. Thus, the variable i in the loop:
for i in range(10): dance()
will take on the values 0 through 9 and for each of those values it will execute the dance() command. Let us try this out on the robot. Modify the robot program from the start of this chapter to include the dance function and then write a main program to use the loop above.
# File: dance.py # Purpose: A simple dance routine # First import myro and connect to the robot from myro import * initialize("com5") # Define the new functions... def yoyo(speed, waitTime): forward(speed) wait(waitTime) backward(speed) wait(waitTime) stop() def wiggle(speed, waitTime): motors(-speed, speed) wait(waitTime) motors(speed, -speed) wait(waitTime) stop() def dance(): yoyo(0.5, 0.5) yoyo(0.5, 0.5) wiggle(0.5, 1) wiggle(0.5, 1) # The main dance program def main(): print "Running the dance routine..." for danceStep in range(10): dance() print "...Done" main()
Notice that we have used danceStep (a more meaningful name than i) to represent the loop index variable. When you run this program, the robot should perform the dance routine ten times. Modify the value speficied in the range command to try out some more steps. if you end up specifying a really large value, remember that for each value of danceStep the robot will do something for 6 seconds. Thus, if you specified 100 repetitions, the robot will run for 10 minutes.
IDLE Tip: You can stop a program at any time by hitting the CONTROL-C keys. That is, pressing the CONTROL-key and then at the same time pressing the c-key. In the case of a robot program this will also stop the robot.
In writing robot programs there will also be times when you just want the robot to keep doing its behaviors forever! While technically by forever we do mean eternity in reality what is likely to happen is either it runs out of batteries, or you decide to stop it (by hitting CONTROL-C). The Python command to specify this uses a different loop statement, called a while-loop that can be written as:
while True: <do something> <do something> ...
True is also a value in Python (along with False) about which we will learn more later. For now, it would suffice for us to say that the above loop is specifying that the body of the loop be executed forever! Go ahead, try this out. Modify the previous program to use the while-loop instead of the for-loop. Remember to use the CONTROL-C to stop the loop (and the robot).
This chapter introduced the basic structure of Python (and robot) programs. We also learned about names and values in Python. Names can be used to designate functions and values. The latter are also called variables. Python provides several different types of values: integers, floating point numbers, strings, and also boolean values (True and False). Most values have built-in operations (like addition, subtration, etc.) that perform calculations on them. Also, one can form sequences of values using lists. Python provides simple built-in facilities for obtaining input from the user. All of these enable us to write not only robot programs but also program that perform any kind of computation. Repetition is a central and perhaps the most useful concept in computing. In Python you can specify repetition using either a for-loop or a while-loop. The latter are useful in writing general robot brain programs. In later chapters, we will learn more about all of these Python features and also learn how to write more sophisticated robot behaviors.
There was nothing new introduced in this chapter other than the structure of typical robot programs. However, that is similar to the structure of most Python programs.
A number of new Python features were introduced in this chapter (see Summary above). Review this chapter and make sure you understand them completely before proceeding. Try and do all exercises for this chapter.
Exercise 1: Write a Python program to convert a temperature from degrees Celsius to degreen Fahrenheit. Here is a sample interaction with such a program:
Enter a temperature in degrees Celsius: 5.0 That is equivalent to 41.0 degrees Fahrenheit.
The formula to convert a temperature from Celsius to fahrenheit is: C/5=(F-32)/9, where C is the temperature in degrees Celsius and F is the temperature in degrees Fahrenheit.
Exercise 2: Write a Python program to convert a temperature from degrees Fahrenheit to degreen Celsius.
Exercise 3: Write a program to convert a given amount of money in US dollars to an equivalent amount in Euros. Look up the current exchange rate on the web (see xe.com, for example).
Exercise 4: Modify the version of the dance program above that uses a for loop to use the following loop:
for danceStep in [1,2,3]: dance()
That is, you can actually use a list itself to specify the repetition (and successive values the loop variable will take). We will learn more about lists later.
Exercise 5: Run the word calculation program and when it prompts for input, try entering the following and observe the behavior of the program:
1. Use 8, 63, and 356 as input values as above. Except, when it asks for various values, enter them in any order.
2. Suing the same values as above, instead of entering the value, say 8, instead enter 4 + 4, or 4 * 2, etc.
3. For any of the values to be input, replace them with a string, for instance enter "Bryn Mawr College" when it prompts you for a number.
Observe the behavior of the program after each of the above inputs and write them down. Also, given what you have learned in this chapter, try and explain the resulting behavior.
Exercise 6: Rewrite your solution to Exercise 4 from the previous chapter to use the program structure described above.
Exercise 7: You were introduced to the rules of naming in Python. You may have noticed that we have made extensive use of mixed case in naming some entities. For example, waitTime. There are several naming conventions used by programmers and that has led to an interesting culture in of itself. Look up the phrase CamelCase controversy in your favourite search engine to learn about naming conventions. For an interesting article on this, see The Semicolon Wars.