Chapter 5 Sensing the World
---------------------------

Scribbler Sensors
-----------------

(1) Camera: can take a still picture of whatever the robot is seeing.

(2) Light: 3 light sensors (3 holes on the front of Scribbler) - 
can detect amount of light;

Also, using information from the camera, Scribbler makes available
an alternative set of brightness sensors (left, center, right) - called bright

(3) Proximity: detects if there are objects nearby; There are 2 sets of
proximity sensors: 
  IR Sensors (left and right) on the lower front of Scribbler
  Obstacle Sensors (left, center, right) on the Fluke

senses()

this command opens up a display window which shows the current
values of ALL sensors (except camera).

they are updated every second.

Camera (located on the Fluke)
-----------------------------

takePicture()
takePicture("color")
takePicture("gray")

no parameter - default is color

To take and display a picture:

p = takePicture()
show(p)

or

show(takePicture())

To save picture on disk:

p = takePicture()
savePicture(p,"scene.jpg")

Do this:

N = 0
while timeRemaining(30)
  show(takePicture())
  turnLeft(0.5,0.2)
  N = N + 1
print N

Change takePicture() to takePicture("gray") in above program.
What is N now?

You will see a larger N for grayscale pictures.
Because there is less information to store grayscale pictures.

Pixels (picture elements):
Each image is made up of several tiny picture elements (pixels).

In a color image, each pixel contains amount of Red, Green, Blue
(RGB) - each value is in the range 0..255 - so, it takes 3 bytes.
For example, (255,0,0) would represent Red color.

In a grayscale (black and white) picture, each pixel contains level
of Gray in the range 0..255 (where 0 denotes Black and 255 denotes
White)

So, a 256x192 color image takes up 256x192x3 = 147,456 bytes
whereas a 256x192 grayscale image takes up only 256x192 = 49,152 bytes.

Animated GIF of images generated by robot:

Pics = []
while timeRemaining(30):
  pic = takePicture()
  show(pic)
  Pics.append(pic)
  turnLeft(0.5,0.2)
savePicture(Pics,"scene2.gif")

Light Sensing
-------------
light sensors on Scribbler: detect ambient light

getLight()
  returns a list of 3 values of all light sensors
getLight(POSITION)
  POSITION  = 0, 1, 2 or "left", "center", "right"
  returns the left, center, or right light sensor value

Values reported by the sensor are in the range 0..5000
low value indicates bright light
high value indicates darkness

L, C, R = getLight()

Camera image also can be used to detect light (bright):
level of brightness on the image

getBright()
  returns a list of 3 brightness values (left, center, right)
getBright(POSITION)
  POSITION  = 0, 1, 2 or "left", "center", "right"
  returns the left, center, or right brightness values

Values in a different range!
Higher values = bright 
Lower values = dark

Do this:

###########################################################
# record average ambient light values
Ambient = sum(getLight())/3.0

# This function normalizes light sensor values to 0.0..1.0
def normalize(v):
    if v > Ambient:
        v = Ambient
    return 1.0 - v/Ambient

def main():
    # Run the robot for 60 seconds
    while timeRemaining(60):
        L, C, R = getLight()
        # motors run proportional to light
        motors(normalize(L), normalize(R))

main()
###########################################################
What does the above program do? Use flash light to show light at
Left or Right sensor. Which insect does therobot resemble?

Proximity Sensing
-----------------

Scribbler has 2 sets of Infra Red (IR) proximity detectors in the front.
There are 3 additional proximity sensors on the Fluke.

The Scribbler Proximity sensors can be accessed via:

getIR()
  returns two values in a list; each value is a 0 or a 1. 
    0 - there is an object right in front
    1 - there is no object right in front
getIR(0)
getIR("left")
getIR(1)
getIR("right")

The two sensors are placed far apart from each other; so they can
detect objects on either side of the robot.

The Fluke proximity sensors can be accessed via:

getObstacle()
  returns a list of 3 values (left, center, right)
getObstacle(0)
getObstacle(1)
getObstacle(2)
getObstacle("left")
getObstacle("center")
getObstacle("right")

values are in the range 0..7000 with 0 indicating nothing in front
and higher number implying presence of an object in front.

Do This:

##############################
def main():
  setForwardness("scribbler-forward")
  while timeRemaining(60):
    L, R = getIR()
    motors(R,L)

main()
##############################
Run the above program and try placing a notebook in the front, left,
and right of the robot. Observe what happens.
What happens when you switch R and L values?


Lists in Python
---------------

List is a sequence of objects (numbers, strings, images, etc.)

empty list

L = []
N = [12, 24, 36]
FamousNumbers = [3.14, 2.718, 42]
Cities = ["Atlanta","New York City", "Detroit"]

Useful functions on lists:

len(N)
  returns length of list
N+FamousNumbers
  produces concatenation of lists
Cities[0]
  first item in list
Cities[1:3]
  returns a sublist from items indexed 1..2
12 in N
  returns True

Cities.sort()
Cities.reverse()
Cities.append("Chicago")

for city in Cities:
  print city

range(5) = [0,1,2,3,4]

Strings are also teated as lists of characters!!

ABC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for letter in ABC:
  speak(letter)

sentence = "Would you have any grey poupon"
sentence.split()
['Would','you', 'have', 'any', 'Grey', 'Poupon']

split() function splits sentence into words.

Inputs to a program
-------------------

From terminal:

nSteps = input("Enter number of steps in staircase: ")
print nSteps

other ways to input:

- from file on disk
- from game pad which is plugged into computer USB port
- from a web page on the internet
- getting sensory data from robot
...

Game Pad Controllers:

Page 114 figure - 8 buttons and one axis (x,y)

buttons: 1 for ON and 0 for OFF
axis: 2 values 
  x-axis -1.0..1.0
  y-axis -1.0..1.0

getGamepad("axis")
  returns a list of 2 values [x-axis, y-axis]
getGamepad("button")
  returns a list of 8 values of 0's and 1's
both wait for user to press a button or axis and then returns the value

getGamepadNow("axis")
getGamepadNow("button")

these commands do not wait - they report value NOW!

Do this:

while timeRemaining(30):
  print getGamepad("button")

repeat above for "axis"

####################################
def main():
  # A simple game pad based robot controller
  while timeRemaining(30):
    X,Y = getGamepad("axis")
    motors(X,Y)

main()
####################################

What happens?
Change motors(X,Y) to move(X,Y) or to move(-X,-Y)
What happens now?

World Wide Web
--------------

Python can be used to access the content on the Web!

Look at http://www.fi.edu/weather/data/jan07.txt
weather data for Philadelphia since 1872!

from urllib import *
Data = urlopen("http://www.fi.edu/weather/data/jan07.txt")
print Data.read()
# urlopen returns a connection!

A little more about Python functions:
-------------------------------------

Some functions do an action: e.g. forward(1,1), speak("Hello")
But others do return a value: e.g. getLight(0), getStall()

In Python ALL functions return a value!

x = speak("foo")
print x

will print string "None"

return statement:

def triple(x):
  return x*3

triple(3)

x = triple(12)
print x

General form of return statement

return <expression>

if-statement:

if <CONDITION>:
  Statement-1
  Statement-2
  ...