En selvlærende robot

Jeg har leget med forskellige små robotter af skrot (Brushrobot, Beambots, Insect robots, Walkers m.m.). Bl.a. denne lille Walker af en Arduino Nano, et 9V batteri og to servo-motorer:
wp_20161021_005
Kredsløb og kode ses nederst.

Den er ret svært at få til at gå, da det er næsten umuligt at forudsige hvilke vinkler servoerne skal dreje til.

Som regel står den stille (forkerte eller for små udsving i benene) eller den vælter (for store bensving). Det tager nogle minutter, at prøve hvert sæt indstillinger, så det bliver jeg hurtigt træt af.

Jeg har derfor lavet en lille ret enkel kode, så den selv kan lære at gå. Det kaldes vist Robot Learning: Robotten har den tid og tålmodighed, som jeg ikke har.

For at kunne lære, skal den have et mål, som bruges som belønning/straf. Da jeg gerne vil have den til at gå fremad, skal den belønnes, når det sker. Her har jeg givet den en lyskilde, som den kan gå imod. Og en lyssensor (LDR) måler, hvor meget robotten kommer nærmere lyskilden.

Robotten får et sæt tilfælde parametre, som bruges til at tage tre “skridt”, hvorefter den vurderer, om den er kommet nærmere lyset. Derefter nye tilfælde parametre, tre skridt og ny vurdering. Det gentages 10 gange. Hver gang vurderer den desuden, om den har lavet en ny rekord i at komme nærmere lyset, så bedste resultat gemmes.

Rødt lys = der er strøm på.
Rødt blink = et nyt sæt tilfældige parametre er valgt.
Grønt blink = Rekorden er slået. Bedste resultat gemmes.
Grønt lys (blivende) = “Fri fra skole”. Bedste resultat af de 10 forsøg bruges til at gå(!) videre.

Der er desuden nogle præmisser, som jeg har valgt: Rækkefølgen og max antal grader servoerne skal bevæge sig. Den vej på robotten som jeg forventer er fremad. Dem kunne den også blive sat til at optimere. Eller den kunne få servomotorerne sat sammen på en anden måde.

Eksemplet her er tumpe-måden at lære på. Også kaldet Brute Force metoden. Skal der læres mere komplicerede ting, løber vi hurtigt tør for regnekraft. Så kan kunstig intelligens måske hjælpe med at forudsige parametrene, og pludselig er vi alle uden job. Mon ikke SIRI-kommissionen skal kigge på min skabning?

Kredsløb:
robot-walker-m-lyssensor_bb
Ups. Mangler grøn LED fra pin 2 til GND.

Kode:
Koden er delvist skrevet i mBlock, hvorfor nogle biblioteker og linjer måske er overflødige.

#include "Arduino.h"
#include "Wire.h"
#include "SoftwareSerial.h"
#include "Servo.h"

double angle_rad = PI/180.0;
double angle_deg = 180.0/PI;
Servo servo_10;
Servo servo_9;
double lys=0; //måles på pin A5.
int vinkel1;
int vinkel2;
int vinkel3;
int vinkel4;
int delta = 15;
int score;
int bestScore = 0;
int bestVinkel1;
int bestVinkel2;
int bestVinkel3;
int bestVinkel4;

void setup(){
  Serial.begin(9600);
  pinMode(2,OUTPUT); //LED grøn
   pinMode(13,OUTPUT); //LED rød
  servo_10.attach(10);
  servo_9.attach(9);

  //nulstille benene:
       servo_10.write(100); // den ene servo sidder lidt skævt
        delay(1000*0.5);
        servo_9.write(90);
        delay(1000*0.5);

  // nulstille bedste vinkel:
      bestVinkel1=0;
      bestVinkel2=0;
      bestVinkel3=0;
      bestVinkel4=0;
      
  for(int j=0;j<10;j++)
  {
    vinkel1 = (random(-delta,delta));
    vinkel2 = (random(-delta,delta));
    vinkel3 = (random(-delta,delta));
    vinkel4 = (random(-delta,delta));
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    lys = analogRead(A5);
    Serial.print("før: ");
    Serial.println(lys);
    for(int i=0;i<3;i++)
    {
        servo_10.write(100+vinkel1);
        delay(1000*0.5);
        servo_9.write(90+vinkel2);
        delay(1000*0.5);
        servo_10.write(100+vinkel3);
        delay(1000*0.5);
        servo_9.write(90+vinkel4);
        delay(1000*0.5);
    } // slut på lille for 

    score = lys - analogRead(A5); //bliver mere negativ jo nærmere den kommer på lyskilden.
    Serial.print("efter: ");
    Serial.println(score);
    
    if (score < bestScore) { // bliver der sat ny rekord?
      digitalWrite(2, HIGH);
      delay(500);
      digitalWrite(2, LOW);
      bestScore = score;
      bestVinkel1=vinkel1;
      bestVinkel2=vinkel2;
      bestVinkel3=vinkel3;
      bestVinkel4=vinkel4;
    }
    //nulstille benene:
       servo_10.write(100);
        delay(1000*0.5);
        servo_9.write(90);
        delay(1000*0.5);
        servo_10.write(100);
        delay(1000*0.5);
        servo_9.write(90);
        delay(1000*0.5);    
  } //slut på store for
}

void loop()
{
          digitalWrite(2, HIGH);
        servo_10.write(100+bestVinkel1);
        delay(1000*0.5);
        servo_9.write(90+bestVinkel2);
        delay(1000*0.5);
        servo_10.write(100+bestVinkel3);
        delay(1000*0.5);
        servo_9.write(90+bestVinkel4);
        delay(1000*0.5);

        
  
}

Dette indlæg blev udgivet i Arduino. Bogmærk permalinket.