torsdag den 28. oktober 2010

NXT Programming, Lesson 7

Dato: 28-10-2010
Varighed: 3 +
Deltagere: Nick og JC

Formål med øvelsen
Dagens øvelse går ud på at implementere og få en bedre forståelse
af "Braitenberg's
vehicles" [Brait]. Disse maskiner er interessante at kigge på da de
udforsker uforudsigelighed ved brug af flere sensorer og flere motorer.

Planen for øvelsen
Planen for i dag er følgende:
  • Bygge vehicle 2a og 2b. Vehicle 1 vil ikke blive bygget da vurderingen er at
    denne ikke vil være ligeså udfordrende som vehicle 2a og 2b. Yderligere
    er det langt mere interessant at observere 2a og 2b da disse benytter
    flere sensorer og motorer, og dermed er mere uforudsigelige end vehicle
    1 som kun benytter en sensor og en motor.
  • De to vehicles vil blive bygget med lys sensorer og testet ved hjælp at
    lyset fra en lommelygte.
  • Yderligere vil der blive sat en lampe på toppen af de to forskellige robotter for
    at se hvordan de reagere på hinanden.
  • I Tom Deans [TomDean] noter bygges robotterne med en enkelt tråd, vi vil
    prøve at undersøge hvordan de reagere hvis hver lys sensor på en robot
    har sin egen tråd.
  • Sidst vil der blive eksperimenteret med hvordan robotterne reagere hvis de
    har to værdier, maksimum og minimum. Værdierne sættes i de forrige
    øvelser efter den største og mindste lys værdi set gennem hele
    robottens levetid. Eksperimentet er nu at gøre det over N tid.
Forventede resultater
Det forventes at robotterne vil være uforudsigelige både med en tråd og
endnu mere med to tråde.

vehicle 2a og 2b
Vehicle 2a og 2b er i princippet den samme robot, dog med lys sensorerne
henholdsvis ikke krydsede og krydsede.





Robotterne kører det samme program, så den eneste forskel er om kablerne ikke er
krydsede eller krydsede.
public class Main
{ 
public static void main (String[] aArg) throws Exception {
float maxRight = -1;
float minRight = -1;
float maxLeft = -1;
float minLeft = -1;
float powerR;
float powerL;
LightSensor lsRight;
LightSensor lsLeft;

lsRight = new LightSensor(SensorPort.S1);
lsRight.setFloodlight(false);
lsLeft = new LightSensor(SensorPort.S2);
lsLeft.setFloodlight(false);

int circMax = 300;
CircularBuffer circRight = new CircularBuffer(circMax);
CircularBuffer circLeft = new CircularBuffer(circMax);

while(!Button.ENTER.isPressed()) {
float lsRightValue = lsRight.readValue();
float lsLeftValue = lsLeft.readValue();

circRight.add((int)lsRightValue);
circLeft.add((int)lsLeftValue);

if(maxRight == -1) {
maxRight = lsRightValue;
minRight = lsRightValue;
maxLeft = lsLeftValue;
minLeft = lsLeftValue;
} else {
if(maxRight < maxright =" lsRightValue;" maxleft =" lsLeftValue;"> lsRightValue) minRight = lsRightValue;
if(minLeft > lsLeftValue) minLeft = lsLeftValue;
}
powerR = -1;
powerL = -1;
if(lsRightValue == minRight) powerR = 0;
else if (lsRightValue == maxRight) powerR = 100;

if(lsLeftValue == minLeft) powerL = 0;
else if (lsLeftValue == maxLeft) powerL = 100;

if(powerR == -1) powerR = ((lsRightValue - minRight)/(maxRight-minRight))*100;
if(powerL == -1) powerL = ((lsLeftValue - minLeft)/(maxLeft-minLeft))*100;

Car.forward((int) powerR, (int) powerL);
LCD.drawString("minRight " + minRight, 0, 0);

LCD.drawString("maxRight " + maxRight, 0, 1);

LCD.drawString("powerRight " + (int)powerR, 0, 2);

LCD.drawString("powerLeft " + (int)powerL, 0, 3);

Thread.sleep(300);
}
}
}



Robot 2a forsøger at kigge væk fra lyskilden, som det kan ses i nedenstående
video:




Det bør bemærkes at hvis lyskilden er ligefremme (lys sensorener ser den
samme værdi) vil den nærme sig lyskilden indtil den er så tæt på at de
to lys sensorer registrere forskellige værdier og den dermed kører væk
fra lyskilden.

Robot 2b vil derimod forsøge at nærme sig lyskilden, dvs. den vil hele tiden
forsøge at få de to lys sensorer til registrere den samme værdi.






Uforudsigeligheden ved robotterne ligger i deres sensorers individuelle minimum og maksimum
værdier, som sættes afhængigt af omgivelserne. F.eks. hvis sensor 1
starter med en høj lysværdi og sensor 2 starter med en lav lysværdi vil
robotten køre i ring når en normal lysværdi opfanges efterfølgende.
Dette vil dog kun være tilfældet så længe miljøet er det samme, eller vi
implementere sådan at minimum og maksimum kun baseres på værdier som er
N skridt gamle, dette vil blive uddybet senere.





To robotter mødes
Droppet grundet tidsmangel, selvom det kunne have været et sjovt eksperiment.
Vurderingen er at N skridt gamle værdier eksperimentet er mere
interessant.

To trådet robot
Droppet grundet tidsmangel. Det vurderes at lab 8 vil give et ligeså godt
indblik i hvad flere tråde gør ved en robot.

N skridt gamle værdier
Ved at huske de sidste N skridt undgås at hvis en robot på et tidspunkt får
nogle meget underlige værdier vil den huske disse og dermed agere efter
disse til evig tid. Et eksempel på et sådan problem opstår hvis man når
robot 2a starter sørger for den ene lys sensor er helt sort og den anden
er så lys så mulig, hvilket vil resultere i en robot som køre i cirkler:





I denne video ses det at robotten kører i ring, da den har en meget lav
minimum på den ene sensor og en meget høj værdi på den anden. Dette vil
den blive ved med at gøre, da den aldrig kan ændre på de første værdier.


Med en implementation, hvor den kun husker de sidste N skridt, kan robotten
"glemme" de første målinger efter et stykke tid. I vores lille
eksperiment med høj og lav værdi på de to sensore, vil denne nye
implementation betyde at den efter et stykke tid vil vænne sig til dens
"nye" omgivelser, og begynder at køre mere lige ud. Dette er smart, hvis
vi har en robot der skal agerer i omgivelser hvor lysforholdene kan
ændre sig.

Vi brugte en cirkulær buffer til at gemme de sidste 300 målinger for hver
af sensorerne, og kun i blandt disse finde minimum og maximum. Koden for
vores buffer ser således ud:





class CircularBuffer {
private Integer[] buffer;

private int tail;

private int head;

private int n = 0;
private int cacheMin;
private int cacheMax;
private boolean cacheBool = false;

public CircularBuffer(int n) {
buffer = new Integer[n];
tail = 0;
head = 0;
}

public void add(int toAdd) {
cacheBool = false;

if (head != (tail - 1)) {
buffer[head++] = toAdd;
}
head = head % buffer.length;

if(n < buffer.length-1) n++;
}

public int get() {
int t = 0;
int adjTail = tail > head ? tail - buffer.length : tail;
if (adjTail < head) {
t = buffer[tail++];
tail = tail % buffer.length;
}
return t;
}

public String toString() {
return "CircularBuffer(size=" + buffer.length + ", head=" + head + ", tail=" + tail + ")";
}

public float getMin() {
if(!cacheBool) {
calcMinMax();
}
return cacheMin;
}

public float getMax() {
if(!cacheBool) {
calcMinMax();
}
return cacheMax;
}

private void calcMinMax() {
int min = Integer.MAX_VALUE;
int max = -1;
for(int i=0; i< n; <="" i++)="" if(buffer[i]="" min)="" min="buffer[i];" {="" }=""> max) {
max = buffer[i];
}
}
cacheMin = min;
cacheMax = max;
cacheBool = true;
}
}






Hver gang getMin() eller getMax() bliver kaldt udregner vi en ny, eller
returnerer en cached værdi.


Den cirkulære buffer bruges nu til at beregne nye minimum og maksimum
værdier, således:


maxRight = circRight.getMax();
minRight = circRight.getMin();
maxLeft = circLeft.getMax();
minLeft = circLeft.getMin();


Det er tydeligt på robottens opførsel at disse beregninger tager tid, og den
reagerer derfor ikke så hurtigt som før på skarpt lys eller mørke.

fredag den 15. oktober 2010

NXT Programming, Lesson 6

Robot race


To make the robot go as fast as possible, we decided to do some experiments with gearing. A few examples of the prototypes can be seen below:



After some guidance from Lasse, we realised that chains was not the right way to transfer power. We rebuild the robot to use only gears. Pictures and movie below.



The gear mounted on the motor have 40 teeth, while the gear connected to the wheel have 20 teeth. This should double the speed of the wheel. We also use the biggest wheel to get higher speed.

PID

We have tried to implement the PID-controller from [PID]. We got it to work somewhat, but the parameters need alot of tweaking to make it follow the line to perfection. 

We decided that it would be more useful to make a scripted car, to get the full potential of the gearing.

Scripted car of doom!
Video will follow. Work in progress. But it is awesome.