- 1 Robots: Personal or Otherwise
- 1.1 The Scribbler Robot: Movements
- 1.2 And now for something completely different
- 1.3 Defining New Commands
- 1.4 Adding Parameters to Commands
- 1.5 Saving New Commands in Modules
- 1.6 Functions as Building Blocks
- 1.7 Calibration: Making Your Robot Go Straight
- 1.8 Summary
- 1.9 Exercises
Robots: Personal or Otherwise
Error creating thumbnail: /bin/bash: /usr/bin/convert: No such file or directory
Error code: 127
Error creating thumbnail: /bin/bash: /usr/bin/convert: No such file or directory
Error code: 127
In the previous chapter, you were introduced to a few robots. Robots these days are being used in a variety of situations to perform a diverse range of tasks. They have been used in industrial manufacturing for several decades now with applications ranging from electronic circuit assembly to automobile assembly. Most assembly robots are not rovers. They stay in one place but have movable arms that do the assembly.
Error code: 127
More recently, robots have been put to use in a variety of everyday situations: like mowing a lawn (see above); vacuuming or scrubbing a floor; entertainment; as companions for elders; etc. The range of applications for robots today is limited only by our imagination! As an example, scientists in Japan developed a baby seal robot (shown here on the left) that is being used for therapeutic purposes for nursing home patients.
In this course, we will mostly concern ourselves with robots that can move about in their environments. Such robots have become more prevalent in the last few years and represent a new dimension of robot applications. Roaming robots have been used for mail delivery in large offices and, as we saw in the last chapter, as vacuum cleaners in homes. Robots vary in the ways in which they move about: they can roll about like small vehicles (like the lawn mower, Roomba, etc.), or even ambulate on two, three, or more legs (see AIBO and Genghis above). The Scribbler robot you have is also a rover. It moves on three wheels, two of which are powered. In this chapter, we will get to know the Scribbler in some more detail and also learn about how to use its commands to control its behavior.
The Scribbler Robot: Movements
In the last chapter you were able to use the Scribbler robot through Myro to carry out simple movements. You were able to start the Myro software, connect to the robot, and then were able to make it beep, give it a name, and move it around using a joystick. By inserting a pen in the pen port, the scribbler is able to trace its path of movements on a piece of paper placed on the ground. It would be a good idea to review all of these tasks to refresh your memory before proceeding to look at some more details about controlling the Scribbler.
If you hold the Scribbler in your hand and take a look at it, you will notice that it has three wheels. Two of its wheels (the big ones on either side) are powered by motors. Go ahead turn the wheels and you will feel the resistance of the motors. The third wheel (in the back) is a free wheel that is there for support only. All the movements the Scribbler performs are controlled through the two motor-driven wheels. In Myro, there are several commands to control the movements of the robot. The command that directly controls the two motors is the motors command:
where LEFT and RIGHT can be any value in the range -1.0..1.0 and these values control the left and right motors, respectively. Specifying a negative value moves the motors/wheels backwards and positive values move it forward. Thus, the command:
will cause the robot to move forward at full speed, and the command:
will cause the left motor to stop and the right motor to move forward at full speed resulting in the robot turning left. Thus by giving a combination of left and right motor values, you can control the robot's movements. Myro has also provided a set of often used movement commands that are easier to remember and use. Some of them are listed below:
forward(SPEED) backward(SPEED) turnLeft(SPEED) turnRight(SPEED) stop()
In addition, you can also use the following movement commands to translate (i.e. move forward or backward), or rotate (turn right or left):
or you can specify, in a single command, the amount of translation and rotation you wish use:
In all of these commands, SPEED can be a value between -1.0..1.0.
You can probably tell from the above list that there are a number of redundant commands (i.e. several commands can be specified to result in the same movement). This is by design. You can pick and choose the set of movment commands that appear most convenient to you. It would be a good idea at this point to try out these commands on your robot.
Exercise 0: Start Myro, connect to the robot, and try out the following movement commands on your Scribbler:
First make sure you have sufficient room in front of the robot (place it on the floor with a few feet of open space in front of it).
>>> motors(1, 1) >>> motors(0, 0)
Observe the behavior of robot. Specifically, notice if it does (or doesn't) move in a straight line after issuing the first command. You can make the robot carry out the same behavior by issuing the following commands:
>>> move(1.0, 0.0) >>> stop()
Go ahead and try these. The behavior should be exactly the same. next, try making the robot go backwards using any of the following commands:
>>> motors(-1, -1) or move(-1, 0) or backwards(1) >>> stop()
Again, notice the behavior closely. In rovers precise movement, like moving in a straight line, is difficult to achieve. This is because two independent motors control the robot's movements. In order to move the robot forward or backward in a straight line, the two motors would have to issue the exact same amount of power to both wheels. While this technically feasible, there are several other factors than can contribute to a mismatch of wheel rotation. For example, slight differences in the mounting of the wheels, different resistance from the floor on either side, etc. Even something as light as the bluetooth dongle mounted on one side of the robot will result in a variable movement. This is not necessarily a bad or undesirable thing in these kinds of robots. Under similar circumstances even people are unable to move in a precise straight line. To illustrate this point, you can try the following simple experiment:
Find a long empty hallway and make sure you have a friend with you to help with this. Stand in the center of the hallway and mark your spot. Looking straight ahead, walk about 10-15 paces without looking at the floor. Stop, mark your spot and see if you walked in a straight line. Next, go back to the original starting spot and do the same exercise with your eyes closed. Make sure your friend is there to warn you in case you are about to run into an object or a wall. Again, note your spot and see if you walked in a straight line.
For most people, the above experiment will result in a variable movement. Unless you really concentrate hard on walking in a straight line, you are most likely to display the same variability as your Scribbler. Besides, roving does not require such precise moments anyway.
Review all of the other movement commands listed above and try them out on your Scribbler. Again, note the behavior of the robot from each of these commands. In doing this exercise, you may find yourself repeatedly entering the same commands (or simple variations).
And now for something completely different
Error code: 127
IDLE is the name of the editing and Python shell program. When you double-click Start Python you are really starting up IDLE. Python is the name of the language that we will be using, and gets its name from Monty Python's Flying Circus. IDLE supposedly stands for Interactive DeveLopment Environment, but do you know to whom else it might be an homage?
In any event, IDLE provides a convenient way to repeat previous commands.
IDLE Tip: ALT-p retrieves previous command ALT-n retrieves next (On MACs these are CTRL-p and CTRL-n) You can repeat a previous command by using IDLE's command history feature. Press the ALT key (next to the SPACE bar) and the p-key simultaneously and IDLE will display the previous command at the prompt. Pressing ALT-p again will give the previous command from that one and so on. You can also move forward in the command history by pressing ALT-n. You can also click your cursor on any previous command and press ALT-ENTER to repeat that command.
Defining New Commands
Trying out simple commands interactively in IDLE is a nice way to get to know your robot's basic features. We will continue to use this each time we want to try out something new. However, making a robot carry out more complex behaviors requires several series of commands. Having to type these over and over interactively while the robot is operating is not quite viable. Python provides a convenient way to package a series of commands into a brand new command called a function. For example, if we wanted the Scribbler to move forward and then move backward (like a yoyo), we can define a new command (function) called yoyo as follows:
>>> def yoyo(): forward(1) backward(1) stop()
The first line defines the name of the new command/function to be yoyo. The lines that follow are slightly indented and contain the commands that make up the yoyo behavior. That is, to act like a yoyo, move forward and then backward and then stop. The indentation is important and is part of the Python syntax. It ensures that all indented commands are part of the definition of the new command. More on this later. If you have your Scribbler ready, go ahead and try out the new definition above by first connecting to the robot, and then entering the definition above. You will notice that as soon as you type the first line, IDLE automatically indents the next line(s). After entering the last line hit an extra RETURN to end the definition. This defines the new command in Python.
Once the new command has been defined, you can try it by entering the command as shown into IDLE:
Observe the robot's behavior when you give it this command. You may need to repeat the command several times. The robot momentarily moves and then stops. If you look closely, you will notice that it does move forward and backwards.
In Python, you can define new functions by using the def syntax as shown above. Note also that defining a new function doesn't mean that the commands that make up the function get carried out. You have to explicitly issue the command to do this. This is useful because it gives you the ability to use the function over and over again (as you did above). Issuing the new function like this in Python is called, invocation. Upon invocation, all the commands that make up the function's definition are executed in the sequence in which they are listed in the definition.
How can we make the robot's yoyo behavior more pronounced? That is, make it move forward for, say 1 second, and then backwards for 1 second, and then stop? This can be accomplished by using the command, wait which is used as shown below:
where SECONDS specifies the amount of time the robot waits before moving on to the next command. In effect, the robot continues to do whatever it had been asked to do just prior to the wait command for the amount of time specified in the wait command. That is, if the robot was asked to move forward and then asked to wait for 1 second, it will move forward for 1 second before applying the command that follows the wait. Using this, you can modify the behavior of the yoyo command as follows:
>>> def yoyo(): forward(1) wait(1) backward(1) wait(1) stop()
Go ahead and enter the definition exactly as above and issue the command to the scribbler. What do you observe? This time you should see the robot move forward for 1 second followed by a backward movement for 1 second and then stop.
Scribbler Tip: Remember that your Scribbler runs on batteries and with time they will get drained. When the batteries start to run low, the Scribbler may exhibit erratic movements. eventually it stops responding. When the batteries start to run low, the Scribbler's red LED light starts to blink. This is your signal to replace the batteries.
Adding Parameters to Commands
Take a look at the definition ot the yoyo function above and you will notice the use of parentheses, (), both when defining the function as well as when using it. You have also used other functions earlier with parentheses in them and probably can guess their purpose. Commands or functions can specify certain parameters by placing them within parentheses. For example, all of the movement commands, with the exception of stop have one or more numbers that you specify to indicate the speed of the movement. The number of seconds you want the robot to wait can be specified as a parameter in the invocation of the wait command. Similarly, you could have chosen to specify the speed of the forward and backward movement in the yoyo command, or the amount of time to wait. Below, we show three definitions of the yoyo command that make use of parameters:
>>> def yoyo1(speed): forward(speed) wait(1) backward(speed) wait(1) stop()
>>> def yoyo2(waitTime): forward(1) wait(waitTime) backward(1) wait(waitTime) stop()
>>> def yoyo3(speed, waitTime): forward(speed) wait(waitTime) backward(speed) wait(waitTime) stop()
In the first definition, yoyo1, we specify the speed of the forward or backward movement as a parameter. Using this definition, you can control the speed of movement with each invocation. For example, if you wanted to move at half speed, you can issue the command:
Similarly, in the definition of yoyo2 we have parameterized the wait time. And, in the last example, we have parameterized both speed and wait time. This way, we can customize the individual commands with different values resulting in different variations on the yoyo behavior.
Saving New Commands in Modules
As you can imagine, while working with different behaviors for the robot, you are likely to end up with a large collection of new functions. It would make sense then that you do not have to type in the definitions over and over again. Python enables you to define new functions and store them in files in a folder on your computer. Each such file is called a module and can then be easily used over and over again. Let us illustrate this by defining two behaviors: a parameterized yoyo behavior and a wiggle behavior that makes the robot wiggle left and right. The two definitions are given below:
# File: moves.py # Purpose: A couple of useful robot command to try out as a module # First import myro and connect to the robot [these two lines may not be necessary] 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): rotate(-speed) wait(waitTime) rotate(speed) wait(waitTime) stop()
All lines beginning with a '#' sign are called comments. These are simply annotations that help us understand and document the programs in Python. You can place these comments anywhere, including right after a command. The # sign clearly marks the beginning of the comment and anything following it on that line is not interpreted as a command by the computer. This is quite useful and we will make liberal use of comments in all our programs.
Notice that we have added the import and the initialize commands at the top. This may or may not be necessary, check with your instructor.
To store these two behaviors as a module in a file, you can ask IDLE for a New Window (from the File menu, then enter the text above containing the two definitions, and then save them in a file (lets call it moves.py) in your Myro folder (same place you have the Start Python icon). All Python modules end with the filename extension .py and you should make sure they are always saved in the same folder as the Start Python.pyw file. This will make it easy for you as well as IDLE to locate your modules when you use them.
Once you have created the file, there are two ways you can use it. In IDLE, just enter the command:
>>> from moves import *
and then try out any of the two commands. For example, the following shows how to use the yoyo function after importing the moves module:
As you can see from above, accessing the new commands defined in a module is similar to accessing the capabilities of the myro module. This is a nice feature of Python. In Python, you are encouraged to extend the capabilities of any system by defining your own functions, storing them in modules and then using them by importing them. Thus importing from the moves module is no different that importing from the myro module. In general, the Python import command has two features that it specifies: the module name; and what is being imported from it. The precise syntax is described below:
from <MODULE NAME> import <SOMETHING>
where <MODULE NAME> is the name of the module you are importing from, and <SOMETHING> specifies the commands/capabilities you are importing. By specifying a * for <SOMETHING> you are importing everything defined in the module. We will return to this a little later in the course. But at the moment, realize that by saying:
from myro import *
you are importing everything defined in the myro module. Everything defined in this module is listed and documented in the Myro Reference Manual. The nice thing that this facility provides is that you can now define your own set of commands that extend the basic commands available in Myro to customize the behavior of your robot. We will be making use of this over and over again in this course.
Functions as Building Blocks
Now that you have learned how to define new commands using existing ones, it is time to discuss a little more Python. The basic syntax for defining a Python function takes the form:
def <FUNCTION NAME>(<PARAMETERS>): <SOMETHING> ... <SOMETHING>
That is, to define a new function, start by using the word def followed by the name of the function (<FUCTION NAME>) followed by <PARAMETERS> enclosed in parenthesis followed by a colon (:). This line is followed by the commands that make up the function definition (<SOMETHING>...<SOMETHING>). Each command is to be placed on a separate line, and all lines that make up the definition should be indented (aligned) the same amount. The number of spaces that make up the indentation is not that important as long as they are all the same. This may seem a bit awkward and too restricting at first, but you will soon see the value of it. First, it makes the definition(s) more readable. For example, look at the following defintions for the yoyo function:
def yoyo(speed, waitTime): forward(speed) wait(waitTime) backward(speed) wait(waitTime) stop() def yoyo(speed, waitTime): forward(speed); wait(waitTime) backward(speed); wait(waitTime) stop()
The first definition will not be accepted by Python, as shown below:
It reports that there is a syntax error and it highlights the error location by placing the thick red cursor (see line 3 of the definition). This is because Python strictly enforces the indentation rule described above. The second definition, however, is acceptable. For two reasons: indentation is consistent; and commands on the same line can be entered separated by a semi-colon (;). We would recommend that you continue to enter each command on a separate line and defer from using the semi-colon as a separator until you are more comfortable with Python. More importantly, you will notice that IDLE helps you in making your indentations consistent by automatically indenting the next line, if needed.
Another feature built into IDLE that enables readability of Python programs is the use of color highlighting. Notice in the above examples (where we use screen shots from IDLE) that pieces of your program appear in different colors. For example, the word def in a function definitiion appears in red, the name of your function, yoyo appears in blue. Other colors are also used in different situations, look out for them. IDLE displays all Python words (like def) in red and all names defined by you (like yoyo) in blue.
The idea of defining new functions by using existing functions is very powerful and central to computing. By defining the function yoyo as a new function using the existing functions (forward, backward, wait, stop)) you have abstracted a new behavior for your robot. You can define further higher-level functions that use yoyo if you want. Thus, functions serve as basic building blocks in defining various robot behaviors, much like the idea of using building blocks to build bigger structures. As an example, consider defining a new behavior for your robot: one that makes it behave like a yoyo twice, followed by wiggling twice. You can do this by defining a new function as follows:
>>> def dance(): yoyo(0.5, 0.5) yoyo(0.5, 0.5) wiggle(0.5, 1) wiggle(0.5, 1) >>> dance()
Go ahead and try it. Now you have a very simple behavior that makes the robot do a little shuffle dance.
Calibration: Making Your Robot Go Straight
Now that you’ve experimented with your robot’s motors a little, you’ve probably noticed that your robot doesn’t move very precisely; it doesn’t go straight. Then again, can any human move perfectly straight? When you swim, don’t you sometimes bump into the sideline buoys? Could you stand in place and turn a perfect 90 degrees? Probably not. So you can see how the robot’s imperfection resembles human imperfection.
On the other hand, it can get somewhat frustrating trying to have the robot draw a square or cross to the opposite side of a room only to end up with a lovely sketch of a square- triangle hybrid or with a robot that has crashed into a wall perpendicular to the one it started against. While the robot’s never going to be perfect, it turns out there’s a way to make your robot go straighter. It’s called ‘’calibrate’’.
There’s a function with this name in the Myro library – calibrate() – which helps you help the robot find how ‘off’ it is from going straight. Then it automatically sends information to the robot on how to adapt its motor values to make it drive straighter in the future. After you’ve calibrated it once, you technically don’t need to do it again; the motor values will be permanently adapted. However, many factors cause the robot to not go straight, so after a while the robot may start veering off in non-straight lines again. Therefore, it’s a good idea to calibrate your robot every couple of weeks.
The function calibrate() works as follows. When you type in the command, the following interface will appear.
The basic idea in using this calibrate program is that you will just try to drive your robot in a straight line; the computer will automatically set up “tweaked” motor values for the robot, which you can view on the interface. You’ll use the calibrate interface, which is similar to the joyStick interface, to drive the robot. If you can’t look at both your computer and your robot at the same time (which is often the case if you don’t have a laptop), the process will require a little more finesse.
The function is set up to calibrate your robot at four speeds: 1.0, 0.5, -0.5, and -1.0. On the interface, you should see four horizontal bars corresponding to these four speeds, and a “Turn Left” on the left side of the screen and a “Turn Right” analogously placed. When you click inside one of the bars, the robot will move at the given speed, but with a higher left or right component depending on where in the bar you click. If you click in the center of the bar, the robot will move in what it thinks is a straight direction, but which may tend towards either the left or the right (if it goes perfectly straight, there’s no need to calibrate for that speed!). If you click on the left part of the bar, the robot will still move at the given speed, but with a higher left component. The further left from the center you click, the higher the left component will be. The same idea follows for the right side of the bar.
Now you have all the knowledge you need to calibrate your robot. Choose a speed, say 1.0, to calibrate first. Drive the robot for a little while (maybe 20-30 seconds, more if needed) at that speed, moving the cursor left or right along that speed’s horizontal bar until the robot begins to consistently move in a straight line. To check if you’ve correctly calibrated the robot for that speed, you can click on the center square in the horizontal bar and see if the robot moves straight (or, once out of the program, just try forward(1, 1) and make sure if the robot moves straight); if it doesn’t, continue adapting the left or right component until the robot drives straight. Go through the same process for all four speeds. Note that intermediate speeds (e.g. 0.3, -0.7) will be adjusted accordingly by the computer. When you’re done, close the calibrate interface window. The computer will send the calibration information directly to the robot, so now you’re all set to control a straighter-moving robot.
You can re-calibrate if you want to at any time – and as mentioned above, you should do so every couple of weeks – by simply typing calibrate() and going through the process described above.
In this chapter, you have learned several commands that make the robot move in different ways. You also learned how to define new commands by defining new Python functions. Functions serve as basic building blocks in computing and defining new and more complex robot behaviors. Python has specific syntax rules for writing definitions. You also learned how to save all your function definitions in a file and then using them as a module by importing from it. While you have learned some very simple robot commands, you have also learned some important concepts in computing that enable the building of more complex behaviors. While the concepts themselves are simple enough, they represent a very powerful and fundamental mechanism employed in almost all software development. In later chapters, we will provide more details about writing functions and also how to structure parameters that customize individual function invocations. Make sure you do some or all of the exercises in this chapter to review these concepts.
||Move backwards at SPEED (value in the range -1.0..1.0).|
||Move forward at SPEED (value in the range -1.0..1.0).|
||Move at the TRANSLATE and ROTATE speeds (value in the range -1.0..1.0).|
||Turn the left motor at LEFT speed and right motor at RIGHT speed (value in the range -1.0..1.0).|
||Rotates at SPEED (value in the range -1.0..1.0). negative value make it rotate right (clockwise) and positive values rotate left (counter-clockwise).|
||Stops the robot from moving.|
||Move in a straight line at SPEED (value in the range -1.0..1.0). Negative values specify backward movement and positive values specify forward movement.|
||Turn left at SPEED (value in the range -1.0..1.0)|
||Turn right at SPEED (value in the range -1.0..1.0)|
||Pause for the given amount of TIME seconds. TIME can be a decimal number.|
Exercise 1: Compare the robot's movements in the commands turnLeft(1), turnRight(1) and rotate(1) and rotate(-1). Closely observe the robot's behavior and then also try the motor commands:
>>> motors(-0.5, 0.5) >>> motors(0.5, -0.5) >>> motors(0, 0.5) >>> motors(0.5, 0)
Do you notice any difference in the turning behaviors? The rotate commands make the robot turn with a radius equivalent to the width of the robot (distance between the two left and right wheels). Where as the turn commands the robot spin in the same place.
Exercsie 2: Insert a pen in the scribbler's pen port and then issue it command sto go forward for 1 or more seconds and then backwards for the same amount. Does the robot travel the same distance? same trajectory? Record your observations.
Exercise 3: Suppose you wanted to turn/spin your robot a given amount, say 90 degrees. Before you try this on your robot, do it yourself. That is, stand in one spot, draw a line dividing your two feet, and then turn 90 degrees. If you have no way of measuring, your turns will only be approximate. You can study the behavior of your robot similarly by issuing it turn/spin commands and making them wait a certain amount. Try and estimate the wait time required to turn 90 degrees (you will have to fix the speed) and write a fuction to turn that amount. Using this function, write a behavior for your robot to transcribe a square on the floor (you can insert a pen to see how the square turns out).
Exercise 4: Choreograph a simple dance routine for your robot and define functions to carry it out. Make sure you divide the tasks into re-usable moves and as much as possible parameterize the moves so they can be used in customized ways in different steps. Use the building block idea to build more and more complex series of dance moves. Make sure the routine lasts for at least several seconds and it includes at least two repetitions of the entire sequence. You may also make use of the beep command you learned from the last section to incorporate some sounds in your choreography.
Exercise 5: Lawn mower robots and even vacuuming robots can use specific choreographed movements to ensure that they provide full coverage of the area to be serviced. Assuming that the area to be mowed/cleaned is rectangular and without any obstructions, can you design a behavior for your Scribbler to provide full coverage of the area? Describe it in writing. [Hint: Think about how you would mow/vacuum yourself.]