- 1 Lab 4: Sensing the World and Making Decisions
- 1.1 Objectives
- 1.2 Internal Sensing
- 1.3 External Sensing
- 1.4 Obtaining Sensory Information
- 1.5 Making Decisions
- 1.6 Beyond Simple Decisions
- 1.7 Random Walks
- 2 Assignment 04
- 3 Links
Lab 4: Sensing the World and Making Decisions
- Get to know the Scribbler's sensors
- Use the random function to create random behaviors
- Use conditional expressions and loops to make decisions
Robots have a variety of sensors that can sense different external stimuli such as light, temperature, distance from another object etc. Your Scribbler robot has a few sensors that can be used to keep track of its internal state and detect certain environmental conditions. Let's explore how your robot does internal sensing.
Propioception: Sensing from Within
Propioception is a sensing mechanism that a robot uses to sense its internal state. Using this mechanism, your robot can sense time, and its battery level.
Every computer has an internal clock. Your robot can use this clock to sense time. For instance, you can keep track of time or use functions like wait(seconds) to control when certain commands are executed.
Try the following:
>>> time1 = currentTime() >>> wait(3) >>> time2 = currentTime() >>> timeElapsed = time2 - time1 >>> print timeElaped
The function currentTime() returns the time elapsed in seconds since some earlier time. When you print timeElapsed, you should see the time elapsed between time1 and time2 in seconds. You can combine the timing commands and the while loop to do the following:
>>> startTime = currentTime() >>> while (currentTime() - startTime) < 5.0: forward(0.5, 0.5)
The above commands tells the robot to go forward until 5.0 seconds have elapsed. You can also use the timeRemaining function to do the same thing:
>>> while timeRemaining(5.0): forward(0.5, 0.5)
Sensing Battery Power Level
As you may have already checked, your robot uses 6 AA batteries that provide voltages that vary between 0 and 9 volts. This voltage level will decrease as you use your robot to carry out different tasks. As the voltages get lower and lower, your robot will behave more erratically. Voltages below 6.5 Volts are generally considered low. The red LED's on the robot and the fluke are battery level indicators that flash repeatedly when the voltage level of your robot is too low. Your robot can now carry out different tasks based on its battery level. For instance:
while (getBattery() > 6.0): botDance()
In the above code, the robot will only do its dance, defined in the function botDance(), when the battery level is above 6.0 Volts.
In addition to sensing its internal state, your robot also has sensors that senses different aspects of its environment. The image below shows two types of sensors that your robot has - proximity and light sensors. In this section we will learn about the physical quantities they detect.
The following is a list of external stimuli that the robot can sense and a description of how the robot senses them.
- Light: There are three light sensors on your robot. These are located in the three holes on the front of your robot. These sensors can detect the levels of brightness (or darkness). Your robot can use these sensors to detect variations in ambient light in a room.
- Proximity: At the front of the robot you will see two tiny lamps on each side of the robot. These are IR emitters. If the light that is emitted by these sensors get reflected by the presence of an obstacle, then the light will bounce back towards the robot and is captured by the IR sensor that is present in the tiny notch in the middle of the two IR emmiters (see figure above).
Obtaining Sensory Information
In addition to using the joystick operation, you can use various functions in the Myro library to obtain these sensor values. These are listed below:
- getLight(<POSITION>): This returns the current value in the <POSITION> light sensor. Your Scribbler has three light sensors (see picture above). <POSITION> can either be 'left', 'center', 'right' or one of the numbers 0, 1, 2. The positions 0, 1, and 2 correspond to the left, center, and right sensors. For example, keep your robot in the same position and try the following:
>>> getLight('left') >>> getLight(0) >>> getLight('center') >>> getLight(1) >>> getLight('right') >>> getLight(2)
- getIR(<POSITION>): This returns the values of the IR sensors. <POSITION> can be 0 or 'left' and 1 or 'right'. Try the following:
>>> getIR('left') >>> getIR('right') >>> getIR(0) >>> getIR(1)
- Obstacle: Detects using the fluke's infrared sensor. High value indicates an object in front of the robot, whereas a low value indicates open space. Try the following:
>>> getObstacle("left") >>> getObstacle("middle") >>> getObstacle("center") >>> getObstacle("right") >>> getObstacle(0) >>> getObstacle(1) >>> getObstacle(2)
- Bright: Performs an almost identical function to getLight(); however, it takes input from the fluke's camera rather than from the scribbler's sensors. Try the following:
>>> getBright('left') >>> getBright(0) >>> getBright('center') >>> getBright(1) >>> getBright('right') >>> getBright(2)
Now that you are familiar with your robot's sensing capabilities, you can use this knowledge to make different decisions.
Although we have not yet officially addressed the issue of using the 'while loop' or the use of 'if/else', the use of such functions is a handy tool to have in one's arsenal of PYTHON knowledge. In Lab 01, people may recall that there was some information regarding the use of 'true' and 'false' equations. They also referenced output with the use of the askQuestion() function.
Is there light at the end of the tunnel?:
if askQuestion("Is there light at the end of the tunnel")=='Yes': print "Yes! I see it!" else: print "No, better luck next time."
These types of questions that use if and else are called conditional expressions and their answers are either a yes or a no. In Python, a yes is equivalent to the value True and a no to the value False. The operator == is a way of asking if the thing on its left (in this case, the value) is equal to the value on its right (in this case 0). == is a very useful operation and can be used to see if any two entities are equal. For example, try the following:
>>> 200 == 200 >>> 200 == 7 >>> "robot" == "robot" >>> "robot" == "Robot" >>> 3.14 == 3.14 >>> 3.14 == 3.142 >>> a, b, c = 10, 20, 10 >>> a == b >>> a == c >>> a == a
Return to the getLight() problem, we could've also used the while loop in conjunction with the if loop to make the decision as follows.
while True: forward(1) if getLight('left') > 200: stop() break
There are two new commands here: break and if. The break command can be used inside any loop to tell the execution to break out of the loop (or terminate the repetitions specified by the loop). The if statement has the following structure:
if <CONDITION>: <do something> <do something> ...
That is, if the condition specified by <CONDITION> is True then whatever is specified in the body of the if statement is executed. If the condition is False, all the statements under the if command are skipped over. Thus in the while-loop shown above, the robot is being asked to go forward, repeatedly forever. If it has 'breaks' out of the loop (i.e. senses less then 200 with the getLight() function), then it should stop and break out of the loop.
More Conditional Expressions: Relational and Logical Operations
Relational operations are used for comparisons. For example: less than (<), less than or equal to(<=), greater than (>), greater than or equal to (>=), equal to (==) and not equal to (!=). Try the following to a get a sense for how these conditional expressions can be used:
>>> 4 > 5 >>> 5 <= 30 >>> 1 != 1 >>> 4 != 6 >>> 67 > 2 >>> (3+4) >= (2-1) >>> "old bag" != "new bag"
You can create more complex conditional expressions using the logical operations (also called Boolean operations): and, or, and not. Try the following examples:
>>> (20 < 7) and (81 > 31) >>> not ( (20 < 7) and (81 > 31) ) >>> (2 > 3) or (3 > 4) >>> (1 > 7) or (3 > 2)
We can define the meaning of logical operators as follows:
- <expression-1> and <expression-2>: Such an expression will result in a value True only if both <expression-1> and <expression-2> are True. In all other cases (i.e. if either one or both of <expression-1> and <expression-2> are False) it results in a False.
- <expression-1> or <expression-2>: Such an expression will result in a value True if either <expression-1> or <expression-2> are True or if both are True. In all other cases (i.e. if both of <expression-1> and <expression-2> are False) it results in a False.
- not <expression>: Such an expression will result in a value True if <expression> is False or False if <expression> is True). I.e., it flips or complements the value of expression.
Beyond Simple Decisions
You can combine if-statements with the else-statements to make two-way decisions as follows:
if <condition>: <do something> else: <do something else>
That is, if the <condition> is true it will do the commands specified in <do something>. If, however, the <condition> is false, it will <do something else>. You can also extend the if-statement to help specify multiple options using the elif-statement as follows (notice the last else):
if <condition-1>: <command set 1> elif <condition-2>: <command set 2> elif <condition-3>: <command set 3> ... ... else: <last command set>
You can inject some randomness in your robot behaviors by using random numbers. Python, and most programming languages, provides a library for generating random numbers. In order to access the random number generating functions in Python you have to import the random library, using the following command:
from random import *
We will explore the functions random and ranrange for now. These are described below:
Functions for generating random numbers:
- random(): This returns a random number between 0.0 and 1.0.
- randint(A, B): Returns a random number in the range [A,...,B-1]. A and B are numbers.
Try these commands at the prompt!
Using the random generating functions, you can randomize the behavior of your robot. For instance, you can create a program that makes your robot take a random amount of steps for a random amount of time as it moves about the room. Try the following (feel free to edit the program and make your own random movement):
def randomWalk(): forward(random(), 3) turnLeft(0.5, randint(1,5)) backward(random(), randint(2,7))
In reality, you only need the function random() to generate random numbers in any range. For example, you can get a random number between 1 and 6 with randint(1,6) or as shown below:
randomValue = 1 + int(random()*6)
The function int() takes any number as its parameter, truncates it to a whole number and returns an integer. Given that random() returns values between 0.0 (inclusive) and 1.0 (exclusive), the above expression will assign a random value between 1..5 (inclusive) to randomValue. You can try other values besides 6 to test the above command.
Please Note: For the following, print out of a copy of your program and a description of what the robot does.
1. Writing your version of randint: Write a new function called myRandInt() that works just like randint():
def myRandInt(A, B): # generate a random number from A to B-1 (just like as defined for randint)
Hint: use mod (%). i.e. 86%5 use it on a couple different numbers... what does it do?
2. Sensing Light: Write a program that makes your robot detect and orient towards bright light.
3. Wall Following: Imagine your robot in an environment that has a 1.5 ft walled corridor going around a 2 ft by 2 ft square box. Write a program that will enable the robot to go around this box. You can use the blocks in the lab to do this. One strategy you can use is to have the robot go forward in a straight line until it bumps into a block/wall. After a bump it will proceed to make a 90 degree turn (you may need to have it go backwards a little to enable turning room) and then continue again in a straight line.
4. Readings: Read Chapters 5 and 6 of your text (these readings will also help with your assignment).