Optimierung der Linienverfolgung mittells evolutionärem Algorithmus
(EN google-translate)
(PL google-translate)
Die zuletzt diskutierte Möglichkeit Wegmarken zu verwenden, soll zunächst zugunsten des nachfolgenden vielversprechenderen Ansatzes für ein selbst lernendes System zurückgestellt werden:
Auf der Grundlage der zuletzt verbesserten Schaltgeschwindigkeit der GPIO, wurde ein weiteres verbessertes Processing-Skript entwickelt, das nun Linienverfolgung ermöglicht.
Deshalb wird hier die komplette Software in modifizierter Version erneut gezeigt:
Graduell verbesserte Version zur Erzeugung von PWM-Signalen mit Kamera-basiertem Beispiel für Linienverfolgung
Besondere Tricks:
|
cd jetson_linienverfolgung/04_jnineu javac jetson/JetsonMotor.java javah -jni -o ./jetson/jetsonmotor.h jetson.JetsonMotor cd jetson gcc -o jetsonmotor.so -shared -Wl,-soname,jetsonmotor.so -I/usr/lib/jvm/java-8-openjdk-arm64/include/ -I/usr/lib/jvm/java-8-openjdk-arm64/include/linux/ jetsonmotor.c -lc sudo cp ./jetsonmotor.so /opt sudo chmod +x /opt/jetsonmotor.so neu anlegen: fuer_jar_datei/jetson/JetsonMotor.class cd .. cd fuer_jar_datei jar cvf jetson.jar * ..in vorhandener library die neue .jar Datei ersetzen. Jetzt Testprogramm zur Motoransteuerung schreiben: cd ~ ./processing-4.0b6-linux-arm64/processing-4.0b6/processing Die Abarbeitung eines Motorbefehls dauert JETZT knapp etwas unter 10ms
Code 0-1: Ablauf zu Herstellung, Ersetzung und Test der JNI-Library
package jetson; public class JetsonMotor { static { System.load("/opt/jetsonmotor.so"); } public static native void init(); //NEU public static native void enablelinks(); //NEU public static native void disablelinks(); //NEU public static native void enablerechts(); //NEU public static native void disablerechts(); //NEU public static native void linksstop(); public static native void linksvor(); public static native void linksrueck(); public static native void rechtsstop(); public static native void rechtsvor(); public static native void rechtsrueck(); }
Code 0-2: jetson/JetsonMotor.java -- Neue Java-Klasse zur Ansteuerung der GPIO
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class jetson_JetsonMotor */ #ifndef _Included_jetson_JetsonMotor #define _Included_jetson_JetsonMotor #ifdef __cplusplus extern "C" { #endif /* * Class: jetson_JetsonMotor * Method: init * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_init (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: enablelinks * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_enablelinks (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: disablelinks * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_disablelinks (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: enablerechts * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_enablerechts (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: disablerechts * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_disablerechts (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: linksstop * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_linksstop (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: linksvor * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_linksvor (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: linksrueck * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_linksrueck (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: rechtsstop * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_rechtsstop (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: rechtsvor * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_rechtsvor (JNIEnv *, jclass); /* * Class: jetson_JetsonMotor * Method: rechtsrueck * Signature: ()V */ JNIEXPORT void JNICALL Java_jetson_JetsonMotor_rechtsrueck (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif
Code 0-3: jetsonmotor.h -- Automatisch erstelltes Header-File
#include <jni.h> #include <stdio.h> #include <stdlib.h> //NEU JNIEXPORT void JNICALL Java_jetson_JetsonMotor_init(JNIEnv *env, jclass clazz) { system("echo 77 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio77/direction"); system("echo 78 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio78/direction"); system("echo 13 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio13/direction"); system("echo 19 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio19/direction"); system("echo 20 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio20/direction"); system("echo 51 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio51/direction"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_enablelinks(JNIEnv *env, jclass clazz) { system("echo 1 > /sys/class/gpio/gpio77/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_disablelinks(JNIEnv *env, jclass clazz) { system("echo 0 > /sys/class/gpio/gpio77/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_enablerechts(JNIEnv *env, jclass clazz) { system("echo 1 > /sys/class/gpio/gpio19/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_disablerechts(JNIEnv *env, jclass clazz) { system("echo 0 > /sys/class/gpio/gpio19/value"); } //ALT JNIEXPORT void JNICALL Java_jetson_JetsonMotor_linksstop(JNIEnv *env, jclass clazz) { system("echo 0 > /sys/class/gpio/gpio77/value"); system("echo 0 > /sys/class/gpio/gpio78/value"); system("echo 0 > /sys/class/gpio/gpio13/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_linksvor(JNIEnv *env, jclass clazz) { system("echo 1 > /sys/class/gpio/gpio77/value"); system("echo 1 > /sys/class/gpio/gpio78/value"); system("echo 0 > /sys/class/gpio/gpio13/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_linksrueck(JNIEnv *env, jclass clazz) { system("echo 1 > /sys/class/gpio/gpio77/value"); system("echo 0 > /sys/class/gpio/gpio78/value"); system("echo 1 > /sys/class/gpio/gpio13/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_rechtsstop(JNIEnv *env, jclass clazz) { system("echo 0 > /sys/class/gpio/gpio19/value"); system("echo 0 > /sys/class/gpio/gpio20/value"); system("echo 0 > /sys/class/gpio/gpio51/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_rechtsvor(JNIEnv *env, jclass clazz) { system("echo 1 > /sys/class/gpio/gpio19/value"); system("echo 0 > /sys/class/gpio/gpio20/value"); system("echo 1 > /sys/class/gpio/gpio51/value"); } JNIEXPORT void JNICALL Java_jetson_JetsonMotor_rechtsrueck(JNIEnv *env, jclass clazz) { system("echo 1 > /sys/class/gpio/gpio19/value"); system("echo 1 > /sys/class/gpio/gpio20/value"); system("echo 0 > /sys/class/gpio/gpio51/value"); }
Code 0-4: jetsonmotor.c -- unter Verwendung des Header-Files implementierte C-Funktionen. init() muß zuerst einmal aufgerufen werden!
PWM-Erzeugung in den Test-Sketchen in Processing und Linienverfolgung
import processing.video.*; public class Kamera { Capture cam; public int VGABREITE = 640; int VGAHOEHE = 480; Kamera(Capture cam) { this.cam = cam; cam.start(); } public void frischeBildAuf() { if (cam!=null && cam.available() == true) { cam.read(); cam.updatePixels(); } } public int berechneSchwerpunkt() { if(cam==null) { return width/2; } int[] pix = cam.pixels; double zaehler = 0.0; double nenner = 0.0; for(int y=0;y<VGAHOEHE;y++) { for(int x =0; x<VGABREITE;x++) { int index = y*VGABREITE + x; int farbe = pix[index]; int rot = (int)red(farbe); int gruen = (int)green(farbe); int blau = (int)blue(farbe); int echtesrot = rot - gruen - blau; if(echtesrot<0) echtesrot = 0; nenner += (double)echtesrot; zaehler += (double)x*(double)echtesrot; } } double xsp = zaehler / nenner; return (int)xsp; } public void zeichneKamerabild(int xoff, int yoff) { if(cam!=null) image(cam, xoff, yoff); } public void zeichneSchwerpunkt(int xoff, int yoff, int xsp) { if(cam==null) return; stroke(255); strokeWeight(4); line(xsp+xoff,yoff,xsp+xoff,yoff+VGAHOEHE); } }//ende Klasse Kamera
Code 0-5: Klasse Kamera
public class PWM { int plinks; int prechts; int plinksabs; int prechtsabs; int STUFEN; PWMlinks pwmlinks; PWMrechts pwmrechts; public PWM(int STUFEN) { this.STUFEN = STUFEN; plinks=0; prechts=0; //NEU: (nicht vergessen!) JetsonMotor.init(); JetsonMotor.linksvor(); JetsonMotor.rechtsvor(); JetsonMotor.disablelinks(); JetsonMotor.disablerechts(); pwmlinks = new PWMlinks(this); pwmrechts = new PWMrechts(this); } public void pwmLinks(int x) { if(x>=0 && plinks<0) JetsonMotor.linksvor(); else if(x<0 && plinks>=0) JetsonMotor.linksrueck(); plinks = x; if(x>=0) plinksabs = x; else plinksabs = -x; } public void pwmRechts(int x) { if(x>=0 && prechts<0) JetsonMotor.rechtsvor(); else if(x<0 && prechts>=0) JetsonMotor.rechtsrueck(); prechts = x; if(x>=0) prechtsabs = x; else prechtsabs = -x; } }
Code 0-6: Klasse PWM
public class PWMlinks implements Runnable { PWM pwm; public PWMlinks(PWM pwm) { this.pwm = pwm; (new Thread(this)).start(); } //12 Millisekunden Zyklus. //5 Geschwindigkeitsstufen => PWM-Periode ist 60 Millisekunden lang public void run() { while(true) { if(pwm.plinksabs>0) JetsonMotor.enablelinks(); try { Thread.sleep(pwm.plinksabs); } catch(Exception e) { } JetsonMotor.disablelinks(); try { Thread.sleep(pwm.STUFEN - pwm.plinksabs); } catch(Exception e) { } } } }
Code 0-7: Klasse PWMlinks (von PWM benutzt.)
public class PWMrechts implements Runnable { PWM pwm; public PWMrechts(PWM pwm) { this.pwm = pwm; (new Thread(this)).start(); } //12 Millisekunden Zyklus. //5 Geschwindigkeitsstufen => PWM-Periode ist 60 Millisekunden lang public void run() { while(true) { if(pwm.prechtsabs>0) JetsonMotor.enablerechts(); try { Thread.sleep(pwm.prechtsabs); } catch(Exception e) { } JetsonMotor.disablerechts(); try { Thread.sleep(pwm.STUFEN - pwm.prechtsabs); } catch(Exception e) { } } } }
Code 0-8: Klasse PWMrechts (von PWM benutzt)
import processing.video.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import jetson.*; Capture cam; Kamera kamera; PWM pwm; int STUFEN = 50; float anteilvorz=0.0f; public void setup() { cam = new Capture(this, 640, 480); kamera = new Kamera(cam); pwm = new PWM(STUFEN); size(640,480); frameRate(30); } int x=0; float aalt=0.0f; public void draw() { background(0); //kamera.drawTestpixel(); kamera.frischeBildAuf(); int xsp = kamera.berechneSchwerpunkt(); kamera.zeichneKamerabild(0,0); kamera.zeichneSchwerpunkt(0,0,xsp); stroke(0,0,255); line(width/2,0,width/2,height); //Aktivität der Motoren und Regelabweichung anzeigen: textSize(24.0f); fill(255); text("Regeldifferenz = "+anteilvorz,30,30); fill(255,0,0); text("PWM links = "+pwm.plinks,30,90); fill(0,255,0); text("PWM rechts = "+pwm.prechts,width-160,90); //Motoren über Lage des Schwerpunkts ansteuern: float RAND = 10.0; if(xsp>width/RAND && xsp<width-RAND) { float anteil = (xsp-width/RAND)/(width-RAND); // 0..1 anteilvorz = (anteil-0.5)*2.0; // -1..+1 if(anteilvorz==0.0) { pwm.pwmLinks(STUFEN); pwm.pwmRechts(STUFEN); } else if(anteilvorz>0.0) { float u = (float)STUFEN/2 - 0.4f*(float)STUFEN*anteilvorz; pwm.pwmLinks(STUFEN/2); pwm.pwmRechts((int)round(u)); aalt = anteilvorz; } else //if(anteilvorz<0.0) { float u = (float)STUFEN/2 - 0.4f*(float)STUFEN*(-anteilvorz); pwm.pwmLinks((int)round(u)); pwm.pwmRechts(STUFEN/2); aalt = anteilvorz; } } else if(aalt>0.0f) { pwm.pwmLinks(STUFEN/2); pwm.pwmRechts(STUFEN/4); } else if(aalt<0.0f) { pwm.pwmLinks(STUFEN/4); pwm.pwmRechts(STUFEN/2); } else { pwm.pwmLinks(0); pwm.pwmRechts(0); } x++; }
Code 0-9: Hauptprogramm von TestneuJetsonMotor_Kamera_NEU
Testergebnisse
Probefahrt als Video.Bild 0-1: Jetson-Nano bei Linienverfolgung mittels USB-Kamera.
ÜBUNG: "Mehr Rot bitte" -- Verbesserung des Verhaltens bei der Linienverfolgung mittels eines evolutionären Algorithmus'
|
Hier ist noch einmal das Konzept für einen evolutionären Algorithmus:
In Hardware-Form mit einzelnen Versuchen, soll hier also ungefähr das passieren, was hier mit den Rennwagen dargestellt ist:
Hilfestellung 1: Laden / Speichern
public void setup() { double x = 3.0; double y = 4.0; saveStrings("param.txt",new String[] {x+"",y+""}); String[] param = loadStrings("param.txt"); double xx = Double.parseDouble(param[0]); double yy = Double.parseDouble(param[1]); println("xx="+xx); println("yy="+yy); }
Code 0-10: Processing-Sketch zum Speichern und Laden von Parametern.