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:
|
jnilinie.zip -- Alle nachfolgend aufgeführten Quelltexte.
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
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:
73_COACH3/09_Algorithmen/03_Evoopt
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.