Chapter 6 Insect-Like Behaviors
-------------------------------

Braitenberg Vehicles
--------------------

1984 book - Vehicles: Experiments in Synthetic Psychology
simple machines - complex behaviors
(simple machines withe a few sensors; sensor values are
 sampled and provided as input to the motors of the machine!)

Law of uphill analysis and downhill invention - 
  much more difficult to guess the internal structure of an object
  simply by observing its behavior; relatively easy to create the
  internal structure for a particular behavior.

Braitenberg vehicles:
---------------------

Vehicle 1: Alive
----------------

One sensor and one motor - value of sensor directly fed into
the motor (see Figure on Page 131).

###############################################################
def normalize(v):
  # write code here to normalize value v to range 0.0 to 1.0

def main():
  # Braitenberg Vehicle 1: Alive
  while True:
    L = getLight("center")
    forward(normalize(L))

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

How do we normalize the light sensor?
We need to convert the value to a proportional value between
0.0 and 1.0 with 0.0 indicating darkness and 1.0 indicating brightness.
Also, since the light sensor reports high values (5000 max) for
darkness and low values (closer to 0) for brightness, we may use the
following normalize function:

def normalize(v):
  # Normalize v (in range 0..5000) to range 0.0..1.0 inversely
  return 1.0 - v/5000.0

for v=3000 (when you place a finger on the middle sensor), 
normalize(v) would be 0.4 - approx half-speed

But we will be operating the robot in a normal room with ambient light
(whose values are reported in the range 150-250). So, for v=200
normalize(v) = 0.9599 - close to full speed!

So, this version of normalize is not good! It does not consider 
ambient light conditions.

def normalize(v):
  if v > Ambient:
    v = Ambient
  return 1.0 - v/Ambient

Light:  v = 0; normalize(v) = 1.0
Ambient: normalize(v) = 0.0
v > Ambient: normalize(v) = 0.0

Full program:

##########################################
from myro import *
init("com"+ask("what port?"))

Ambient = getLight("center")

def normalize(v):
    if v > Ambient:
        v = Ambient
    return 1.0 - v/Ambient

def main():
    setForwardness("scribbler-forward")
    while True:
        L = getLight("center")
        forward(normalize(L))

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

Vehicle 2: Coward and Aggressive
--------------------------------

2a: Coward (See figure on page 135)

2 sensors; each sensor drives a different motor
left sensor drives left motor
right sensor drives right motor

Full program for Coward:

##########################################
from myro import *
init("com8")

Ambient = sum(getLight())/3.0 # average the three sensor values

def normalize(v):
    if v > Ambient:
        v = Ambient
    return 1.0 - v/Ambient

def main():
    setForwardness("scribbler-forward")
    while True:
        L = getLight("left")
        R = getLight("right")
        motors(normalize(L),normalize(R))

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

Full program for Aggressive:

##########################################
from myro import *
init("com8")

Ambient = sum(getLight())/3.0 # average the three sensor values

def normalize(v):
    if v > Ambient:
        v = Ambient
    return 1.0 - v/Ambient

def main():
    setForwardness("scribbler-forward")
    while True:
        L = getLight("left")
        R = getLight("right")
        motors(normalize(R),normalize(L)) # note change in arguments here

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

Other Normalizations
--------------------

The normalization we have seen produces a value in the range 0 (dark) and 
1 (light) - called excitatory relationship.

other possibility: inverse relationship - 1 = dark, 0 = light
called inhibitory relationship.

###########################
#inhibitory normalization
def normalize(v):
  if v > Ambient:
    v = Ambient
  return v/Ambient
######################

If we use inhibitory normalization with "Coward" and "Aggressive"
connections, we get "Love" and "Explorer" respectively.

Love (Vehicle 3a page 138):
robot will come to rest facing the light source near it.

Explorer (Vehicle 3b page 138): 
robot will come to rest facing away from the light source
  and may wander away towards other light sources, if any

Other normalizations: Use non-monotonic functions.

e.g. f(v) = exp(-(v-mean)**2 / (2*stddev**2))
Bell curve p 139

Robots with "Instincts"!

###########################################
from math import *
def normalize(v):
  mean = Ambient/2.0
  stddev = Ambient/6.0
  if (v > Ambient):
    v = Ambient
  return exp(-(v-mean)**2 / (2*stddev**2))
###########################################

Multiple Sensors
----------------

One could use multiple sensors (e.g. light as well as obstacle) to
design robot behaviors.

More Vehicles:
--------------
See page 141:

Timid
Indecisive
Paranoid

These could be programming assignments!

Simple Reactive Behaviors
-------------------------

Designing Reactive Behaviors

(1) Light Following
Flashlight - light sensors report values around 50

###########################################
# Light follower
# Page 147

from myro import *
init("com8")

thresh = 50
fwdSpeed = 0.8
cruiseSpeed = 0.5
turnSpeed = 0.7

def main():
    setForwardness("scribbler-forward")

    while True:
        L, C, R = getLight()
        
        if C < thresh: # bright light straight forward - go forward
            move(fwdSpeed, 0)
        elif L < thresh: # bright light at left - turn left
            move(cruiseSpeed, turnSpeed)
        elif R < thresh: # bright light at right - turn right
            move(cruiseSpeed, -turnSpeed)
        else: # no bright light - move forward slowly...or stop()?
            move(cruiseSpeed/2, 0)

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

(2) Avoiding Obstacles

if obstacle straight ahead - then turn left or right
if obstacle on left - turn right
if obstacle on right - turn left
otherwise cruise

###########################################
# Avoiding obstacles
# Page 149

from myro import *
init("com8")

cruiseSpeed = 0.6
turnSpeed = 0.5

def main():
    setForwardness("scribbler-forward")
    
    while True:
        L, R = getIR()
        L = 1 - L
        R = 1 - R
        
        if L and R: # obstacle straight ahead - turn left or right..
            move(0, turnSpeed)
        elif L: # obstacle on left - turn right
            move(cruiseSpeed, -turnSpeed)
        elif R: # obstacle on right - turn right
            move(cruiseSpeed, turnSpeed)
        else: # otherwise cruise
            move(cruiseSpeed, 0)

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

Another way to write this program is to use getStall()
i.e. bump and turn left or right... similar to lab 2!
###########################################
# Avoiding obstacles by bumping
# Page 150

from myro import *
init("com8")

cruiseSpeed = 1.0
turnSpeed = 0.5

def main():
    setForwardness("scribbler-forward")

    while True:
        if getStall():
            move(0, turnSpeed)
        else:
            move(cruiseSpeed, 0)

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

(3) Corral Exit

Page 151 - Figure:

Enclosed area with maze like partitions with light at the entrance.
Robot inside.
Program to make the robot exit the maze?

Follow the wall (using left or right obstacle detectors) until
light is seen.