kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Echtzeitanwendungen auf Basis von HDL

(EN google-translate)

(PL google-translate)

  • 1 -- 20|03|2018 -- TUESDAY

Beschreibung eines FPGA und Einführung in VHDL

69_FPGA/01_Einfuehrung/

Umgang mit der Entwicklungsumgebung XSE

69_FPGA/02_Einrichtung/
69_FPGA/04_Getting_Started/
69_FPGA/21_XSE14/
  • 2 -- 27|03|2018 -- TUESDAY
69_FPGA/05_Beispiele
69_FPGA/06_Uebung
  • 3 -- 09|04|2018 -- TUESDAY

Version3: "Modularisierung" des Mustervergleichers

69_FPGA/05_Beispiele/03_Mustervergleich
69_FPGA/08_Synchronisieren
69_FPGA/10_Servo

Einführung zu PWM:

40_Mikrocontroller/04_PWM
Übung

nur Aufgabe 3:

69_FPGA/09_Uebung

... sowie die Aufgabe am Ende des Servo-Kapitels.

  • 4 -- 24|04|2018 -- TUESDAY

VHSL und UNISIM

69_FPGA/11_VHDL
69_FPGA/12_UNISIM
69_FPGA/13_LUT
Übung 0

Analysieren und testen Sie das nachfolgende Programm. Quelle:

Wählen Sie selber sinnvolle Hardware-Pin-Verknüpfungen in der ucf-Datei.

69_FPGA/13_LUT
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity mustervergleich is
    Port ( A1 : in  STD_LOGIC;
           A0 : in  STD_LOGIC;
           B1 : in  STD_LOGIC;
           B0 : in  STD_LOGIC;
           C : out  STD_LOGIC);
end mustervergleich;

architecture Behavioral of mustervergleich is
begin
    LUT4_instanz : LUT4
        generic map ( INIT => "1000010000100001" )
        port map (O => C,I0 => A0,I1 => A1,I2 => B0,I3 => B1);
end Behavioral;

Code 0-1: Code.

Übung 1

Schreiben und testen Sie ein VHDL-Programm, bei dem ein 4-Bit Binärcode in einen 4-Bit-Gray-Code umgewandelt wird. Siehe z.B.

de.wikipedia.org/wiki/Gray-Code

a) Setzen Sie die Lösung ohne UNISIM um.

b) Setzen Sie die Lösung mit UNISIM um (Verwendung eines LUT-Elements).

Wählen Sie geeignete Ein- und Ausgänge.

Verwenden Sie LEDs für die Ausgabe.

c) Verwenden Sie Taster / Kabel für die Eimgabe.

d) Verwenden Sie einen Prozeß, der mit 1Hz "hochzählt" als Eingabe (vergl. 4-Bit-Vergleicher).

Übung 2

Bauen Sie einen 3-Bit-Vergleicher unter Verwendung von LUT-Elementen auf.

Übung 3

Üben Sie mit dem Operator & aus Kapitel:

69_FPGA/11_VHDL

Schreiben Sie dazu ein "rotierendes" Lauflicht.

  • 5 -- 08|05|2018 -- TUESDAY

Als Vorbereitung auf die Semester begleitende Klausur in elektronischer Form wird hier die erste von zwei Klausuren vom letzten Jahr angeboten.

Üben Sie sich darin, die Aufgaben in einfachen Textdateien zu entwerfen, damit es Ihnen beim E-Test dann leichter fällt Quelltext ohne Entwicklungsumgebung hin zu schreiben.

In den zweiten 90 Minuten des Unterrichts können Sie dann die vorgefertigten Projekte verwenden, um Ihren Code zu testen.

69_FPGA/30_day_by_day/material_uebungs_etest.zip
MUSTERLÖSUNG AUFGABE 1, GRUPPE A: 69_FPGA/30_day_by_day/Aufgabe1.zip
69_FPGA/30_day_by_day/Studentische_Musterloesung_Aufg2_Lucas_Riecke.zip
  • 6 -- 15|05|2018 -- TUESDAY

Einführung in Neuronale Netze mit Processing

  • Theorie zu Neuronalen Netzen:
67_Echtzeitsysteme/08_NeuronaleNetze

cognimem

www.cognimem.com/support/application-references/off-shore-fish-sorting/index.html

Einführung in Processing

78_Processing

Processing-Beispiele aus der Vorlesung:

69_FPGA/30_day_by_day/B1.zip
69_FPGA/30_day_by_day/B2.zip
  • 7 -- 29|05|2018 -- TUESDAY

Einfache Modellierung eines Fahrzeugs / Regelung mit N.N. -- nur Kinematik!!!


Cognimem: Neurocar.

Cognimem: Tutorials / Demonstrations

69_FPGA/30_day_by_day/AV.zip -- Processing-Sketche zu einer sehr simplen AV-Simulation
Einfache Regeln, um ein autonomes Vehikel autonom fahren zu lassen ...

Bild 0-1: Einfache Regeln, um ein autonomes Vehikel autonom fahren zu lassen ...

Gruppenarbeit mit dem Ziel ein selbst lernendes Neuronales Netz zu erstellen

Hinweise:

  • Die Sketche AV001..AV006 bauen aufeinander auf.
  • A006 dient als Benchmark: Lenkregelung auf Grundlage einfachster Regeln
  • A004 / A005: Übergang von "prozedural" zu "objektorientiert" -- Soll Anhaltspunkt zur Umsetzung Neuronaler Netze liefern.
  • Gemeinsam in Vorlesung: Ansatz zur Kodierung eines Neurons und eines Neuronenlayers.
  • 8 -- 05|06|2018 -- TUESDAY

Vorbereitung für VA am 5.6. (zum vorher herunterladen und ausdrucken):


69_FPGA/30_day_by_day/AVneuro.zip -- Drei Sketche, die zu einem selbst lernenenden Neuronalen Netz für die Lenkregelung hinführen.
Übergreifende Aufgabe in FPGA UND Microcontroller

... darum unbedingt gemischte Gruppen bilden!

Realisierung einer FPGA-basierten Lenkregelung für das simulierte Vehikel.

Dazu: Datenaustausch zwischen PC und FPGA mittels Arduino über die serielle Schnittstelle.

Und: Übertragung des Neuronalen Netzes in eine Struktur, die mit diskreten Werten auskommt.

Im Unterricht: Gemeinsamer Basisentwurf

Teilaufgaben:

Side-kick1: Alfasteuerung für Optimierer.

Side-kick2: Überführung der Musterlösung in ein sinnvoll parametrisiertes objektorientiertes Programm.

  1. Daten vom PC beim Arduino empfangen (Arduino IDE / Processing)
  2. Daten vom Arduino beim PC empfangen (Arduino IDE / Processing)
  3. Bidierktionale Datenübertragung zwischen PC und Arduino (Arduino IDE / Processing)
  4. Einfache Regeln für die Lenkung vom Arduino abrufen: Zum Arduino Sesnordaten schicken, vom Arduino Lenkbewegung empfangen
  5. Überführung des Neuronalen Netzes in eine mit Integer arbeitende Struktur zunächst als Java-Programm.
  6. Elektrische Anbindung zwischen Arduino (5V) und FPGA (3V) und Austausch digitaler Werte.
  7. Konzept zur Übertragung der in 1. gewonnenen Struktur auf einen FPGA. (z.B. Lookup-Table für sigmoide Funktion)
  8. Für Problemstellung passende Anbindung des Arduino an den FPGA über digitale Ein- und Ausgänge.
  9. Einfache Regeln für die Lenkung vom FPGA via Arduino abrufen.
  10. Konzept des Neuronalen Netzes auf den FPGA übertragen.
Pin-Belegungen Arduino / FPGA:

Sensor   s0   s1   s2   s3 
FPGA     IO25 IO26 IO27 IO28
Arduino   IO5  IO6  IO7  IO8

Lenkung   -1    +1    0
FPGA     IO23  IO24  keiner von beiden
Arduino   IO3  IO4   keiner von beiden

Alles mit inverser Logik, 
um elektrisches Konzept umsetzbar zu machen

WIE SCHICKE ICH DIE SENSORWERTE VOM ARDUINO
AN DEN FPGA?:

//Arduino:
void setup()
{
    //Sensoren: von Arduino nach FPGA
    pinMode(5,INPUT);
    pinMode(6,INPUT);
    pinMode(7,INPUT);
    pinMode(8,INPUT);

    digitalWrite(5,LOW);
    digitalWrite(6,LOW);
    digitalWrite(7,LOW);
    digitalWrite(8,LOW);

    ...

    //Lenkzustand von FPGA nach Arduino
    pinMode(3,INPUT);
    pinMode(4,INPUT);
    digitalWrite(3,LOW); //hier auch kein pullup!
    digitalWrite(4,LOW); //  ... dadurch positive Logik möglich

}

//Pattern senden:  s0=0 s1=1 s2=1 s3=1 

void loop()
{
    ...

    pinMode(5,OUTPUT); //s0 = 0
    pinMode(6,INPUT);  //s1 = 1
    pinMode(7,INPUT);  //s2 = 1
    pinMode(8,INPUT);  //s3 = 1

    ...
}


Code 0-2: Pin-Belegungen Arduino / FPGA:

Teillösungen

Teillösung 1: Lenkregelung erfolgt über Arduino
Teillösung 1

Bild 0-2: Teillösung 1

  • gelbe LED: Sensorwert s3 IO12, grüne: s2 IO11, rote: s1 IO10 und s0 IO9 (empfängt Arduino)
  • Text oben links im Processing-Sketch: empfangene Lenkwerte vom Arduino
Film zu Teillösung 1
//Sendet den Lenkzustand zurück an den PC:
// X==-1 Y==1  Z==0

int sensor=0;
int lenk = 0;

void setup() 
{
    Serial.begin(9600);

    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
    pinMode(12,OUTPUT);

    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
    digitalWrite(12,LOW);
}

void loop() 
{
    while(Serial.available())
    {
        sensor = Serial.read();
    }

    if(sensor>='A' && sensor<='A'+15)
    {
        sensor-='A';

        //Regeln wie in regel() ... einfache Version im Processing Sketch
//Processing:        
//      public float regeln(int[] sensorwerte) //liefert omega
//     {
//         if(sensorwerte[2]==0)
//            return -1;
//         else if(sensorwerte[3]==0)
//            return 1;
//         else
//            return 0.0;
//      }

//Hier:
        if((sensor/4)%2==0)  //s2
            lenk = -1;
        else if((sensor/8)%2==0) //s3
            lenk =  1;
        else
            lenk = 0;    

        //Zurück schicken:
        if(lenk==-1)
            Serial.write('X');
        else if(lenk==1)
            Serial.write('Y');
        else
            Serial.write('Z');

        // S0
        if(sensor%2>0) 
            digitalWrite(9,HIGH);
        else  
            digitalWrite(9,LOW);
        sensor/=2;
        // S1
        if(sensor%2>0) 
            digitalWrite(10,HIGH);
        else  
            digitalWrite(10,LOW);
        sensor/=2;
        // S2
        if(sensor%2>0) 
            digitalWrite(11,HIGH);
        else  
            digitalWrite(11,LOW);
        sensor/=2;
        // S3
        if(sensor%2>0) 
            digitalWrite(12,HIGH);
        else  
            digitalWrite(12,LOW);
         
    }
}

Code 0-3: Quelltext Arduino (AV502_sensor_von_PC_Lenk)

    public void zeitschritt(float dt)
    {
        ....
         //Sensorwerte an den Arduino senden:
         myPort.write((int)'A'+  sensorwerte[0]
                              +2*sensorwerte[1]
                              +4*sensorwerte[2]
                              +8*sensorwerte[3]
                              );

         //Lenkwert vom Arduino empfangen:
         while(myPort.available()>0)
         {
             int wert = myPort.read();
             if((char)wert=='X')
                 LENK_VON_ARDUINO = -1;
             if((char)wert=='Y')
                 LENK_VON_ARDUINO =  1;
             if((char)wert=='Z')
                 LENK_VON_ARDUINO =  0;
         }
    }

...

public float regeln(int[] sensorwerte) //liefert omega
{
     //Lenkwerte vom Arduino nehmen:
     return LENK_VON_ARDUINO;
}


public void draw()
{
     background(0);
     textSize(20);
     fill(255);
     text("Lenkwert von Arduino: "+LENK_VON_ARDUINO,10,20);
  
     translate(width/2, height/2);
     scale(1.0,-1.0);
     ....         
}

Code 0-4: Wichtige Code-Teile Processing

Processing-Sketch gezip: AV502_Arduino_Regeln_Lenk.zip
Arduino-Sketch gezipt: AV_502_sensor_von_PC_Lenk.zip
Teillösung 2: Lenkregelung erfolgt über FPGA
Lenksignale vom FPGA.

Bild 0-3: Lenksignale vom FPGA.

69_FPGA/30_day_by_day/fpga1.mp4

Nachweis, dass die Signale wirklich vom FPGA kommen: Lenk0 / Lenk1 - Letungen temporär kappen:


Lenksignale gekappt. Fahrzeug entgleist.

Bild 0-4: Lenksignale gekappt. Fahrzeug entgleist.

Lekregelun erfolgt nach Regeln über den FPGA


Das Processing-Programm aus der ersten Teillösung kann unverändert wiederverwendet werden.


//Leitet Sensorwerte weiter an den FPGA:
//Sensor Arduino(out) FPGA(in)
// s0 == IO5 ==   IO25 
// s1 == IO6 ==   IO26 
// s2 == IO7 ==   IO27 
// s3 == IO8 ==   IO28 

//Lenkwert:
//Wert Arduino(in) FPGA(out)
//-1    IO3     IO23
// 1    IO4     IO24
// 0    IO3==IO4==0

//Sendet den Lenkzustand zurück an den PC:
// X==-1 Y==1  Z==0

int sensor=0;
int lenk = 0;
int i; //Laufvariable für Schleifen
void setup() 
{

    //Verbindung zu FPGA
    //Sensoren: von Arduino nach FPGA
    pinMode(5,INPUT);
    pinMode(6,INPUT);
    pinMode(7,INPUT);
    pinMode(8,INPUT);

    digitalWrite(5,LOW);
    digitalWrite(6,LOW);
    digitalWrite(7,LOW);
    digitalWrite(8,LOW);

    //Lenkzustand von FPGA nach Arduino
    pinMode(3,INPUT);
    pinMode(4,INPUT);
    digitalWrite(3,LOW); //hier auch kein pullup!
    digitalWrite(4,LOW); //  ... dadurch positive Logik möglich        

    //Kontroll-LEDs:
    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
    pinMode(12,OUTPUT);

    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
    digitalWrite(12,LOW);
    
    Serial.begin(9600);
}

void loop() 
{
    while(Serial.available())
    {
        sensor = Serial.read();
    }

    if(sensor>='A' && sensor<='A'+15)
    {
        sensor-='A';

        //Regeln wie in regel() ... einfache Version im Processing Sketch
//Processing:        
//      public float regeln(int[] sensorwerte) //liefert omega
//     {
//         if(sensorwerte[2]==0)
//            return -1;
//         else if(sensorwerte[3]==0)
//            return 1;
//         else
//            return 0.0;
//      }

//Hier: DEAKTIVIERT, soll jetzt von FPGA kommen.
//        if((sensor/4)%2==0)  //s2
//            lenk = -1;
//        else if((sensor/8)%2==0) //s3
//            lenk =  1;
//        else
//            lenk = 0;    

//Dazu zuerst Sensorzustand an FPGA weiterleiten:
        //s0
        if((sensor/1)%2==1)
            pinMode(5,INPUT); //High bei FPGA wird über dessen Pullup-R erreicht!!!            
        else
            pinMode(5,OUTPUT); //Damit wird GROUND übertragen und LOW bei FPGA stellt sich ein

        //s1
        if((sensor/2)%2==1)
            pinMode(6,INPUT); 
        else
            pinMode(6,OUTPUT); 

        //s2
        if((sensor/4)%2==1)
            pinMode(7,INPUT); 
        else
            pinMode(7,OUTPUT); 

        //s3
        if((sensor/8)%2==1)
            pinMode(8,INPUT); 
        else
            pinMode(8,OUTPUT); 

        //Jetzt ein paar Taktzyklen Pause, bis sich der
        //Ausgabezustand beim FPGA stabilisiert hat (ev. unnötig):
        for(i=0;i<100;i++)
            PORTB|=0b00000000;

        //Nun Lenkzustand von FPGA holen:
        if( digitalRead(3)>0 )
            lenk = -1;
        else if( digitalRead(4)>0 )
            lenk = 1;
        else
            lenk = 0;    

        //Zurück schicken:
        if(lenk==-1)
            Serial.write('X');
        else if(lenk==1)
            Serial.write('Y');
        else
            Serial.write('Z');

        // S0
        if(sensor%2>0) 
            digitalWrite(9,HIGH);
        else  
            digitalWrite(9,LOW);
        sensor/=2;
        // S1
        if(sensor%2>0) 
            digitalWrite(10,HIGH);
        else  
            digitalWrite(10,LOW);
        sensor/=2;
        // S2
        if(sensor%2>0) 
            digitalWrite(11,HIGH);
        else  
            digitalWrite(11,LOW);
        sensor/=2;
        // S3
        if(sensor%2>0) 
            digitalWrite(12,HIGH);
        else  
            digitalWrite(12,LOW);
         
    }
}

Code 0-5: Neues Arduino-seitiges Programm

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity neuro1 is
    Port ( MEINECLOCK : in  STD_LOGIC;
           MEINELED : out  STD_LOGIC;
           S0 : in  STD_LOGIC;
           S1 : in  STD_LOGIC;
           S2 : in  STD_LOGIC;
           S3 : in  STD_LOGIC;
           LENK0 : out  STD_LOGIC;
           LENK1 : out  STD_LOGIC);
end neuro1;
-- Clock-In == 6MHz, Toggeln nach 3000000 Schritten ergibt 1Hz Blinkfrequenz.
architecture Behavioral of neuro1 is
    signal zaehler    : integer range 0 to 2999999 := 0;
    signal logikpegel : std_logic := '0';
    signal dummy0 : std_logic := '0';
    signal dummy1 : std_logic := '0';
    signal dummy2 : std_logic := '0';
begin
        process begin
            wait until rising_edge(MEINECLOCK);
            if (zaehler<2999999) then
                zaehler <= zaehler+1;
            else
                zaehler <= 0;
                logikpegel <= not logikpegel;					 
            end if;
        end process;
        MEINELED <= logikpegel or ( dummy0 and dummy1 );
		  LENK0 <= not S2;
		  LENK1 <= not S3;
		  dummy0 <= S0; -- Um Compilerprobleme an dieser Stelle zu vermeiden
		  dummy1 <= S1;
end Behavioral;

Code 0-6: FPGA-Quelltext "neuro1" -- Da bei den einfachen Regeln S0 und S1 nicht benutzt werden, werden Dummy-Signale verwendet.

## GCLK6 ist auf FPGA-Chip Pin 56
NET "MEINECLOCK" LOC = "P56";
## IO_L05P_0 ist auf FPGA-Chip Pin 125
NET "MEINELED"   LOC = "P125";

NET "MEINECLOCK" IOSTANDARD = LVCMOS25;
NET "MEINELED"   IOSTANDARD = LVCMOS33; 

NET "S0"  LOC = "P135" | PULLUP  | IOSTANDARD = LVCMOS33 ; ## IO25
NET "S1"  LOC = "P139" | PULLUP  | IOSTANDARD = LVCMOS33 ; ## IO26
NET "S2"  LOC = "P140" | PULLUP  | IOSTANDARD = LVCMOS33 ; ## IO27
NET "S3"  LOC = "P142" | PULLUP  | IOSTANDARD = LVCMOS33 ; ## IO28

NET "LENK0"   LOC = "P132" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ; ## IO23
NET "LENK1"   LOC = "P134" | IOSTANDARD = LVCMOS33 | SLEW = SLOW ; ## IO24

Code 0-7: ucf-Datei

neuro1.zip -- FPGA-Projekt
AV_503_sensor_von_FPGA.zip -- Arduino-Projekt
Teillösung 3: NN nach Integer überführen und auf Arduino testen

Bevor das Neuronale Netz (NN) auf dem FPGA implementiert wird, wird das NN mit Integer-Werten umgesetzt und auf dem Arduino getestet.

Es wurde -127...+127 (knapp ein Byte / signed char) als Zahlenbereich für die Gewichte festgelegt und 0..127 als Wertebereich bei der sigmoiden Funktion.

Nach der Optimierung gibt das Processing-Programm alle Gewichte aus, um sie im Arduino-Programm verwenden zu können.

Außerdem wird geprüft, ob bei der gewichteten Summenbildung keine Werte außerhalb eines Zahlenbereiches von +/-32000 vorkommen (ca. 4Byte signed Integer):

AV601_integer_Neuro.zip (Processing-Sketch)
AV_601_Neuro_Arduino.zip (Arduino-Sketch, wird zusammen mit Processing-Sketch AV502_Arduino_Regeln_lenk benutzt s.o.)
//Sendet den Lenkzustand zurück an den PC:
// X==-1 Y==1  Z==0

//Verwendet ein Neuronales Netz
//auf Grundlage von:
//   AV601_integer_Neuro

//MAXWERT=16129 MINWERT=-3575  .... deshalb 2-Byte-Integer o.k.

int sensor=0;
int lenk = 0;

char w[] = {-77,-77,127,-23,73,-127,23,-27,73,-27,-23,-127,23,-27,-127,-27,23,-27,127,-73};

//für Input -127..+127, also 255 verschiedene Werte:
char sigmo[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,6,15,34,63,92,111,120,124,126,126,126,126,126,126,126,126,126,126,126,126,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127};
int s0,s1,s2,s3,   out0,out1,out2,out3,out4;
int sens0,sens1,sens2,sens3;
int sigmoid(int x)
{
   if(x<-127) x=-127;
   if(x> 127) x=127;
   x+=127;
   return sigmo[x];
}

int neuro(int s0, int s1,int s2, int s3)
{
    out0=s0*w[0]+s1*w[1]+s2*w[2]+s3*w[3];
    out1=s0*w[4]+s1*w[5]+s2*w[6]+s3*w[7];
    out2=s0*w[8]+s1*w[9]+s2*w[10]+s3*w[11];
    out3=s0*w[12]+s1*w[13]+s2*w[14]+s3*w[15];

//    out0 = sigmoid(out0);
//    out1 = sigmoid(out1);
//    out2 = sigmoid(out2);
//    out3 = sigmoid(out3);

    out4 = out0*w[16]+out1*w[17]+out2*w[18]+out3*w[19];

//    out4 = sigmoid(out4);

    if(out4>32)        
        return 1;
    else if(out4<-32)        
        return -1;
    else
        return 0;    
        

//    out4 = (out4 - 63)/63;

//    return out4;
}

void setup() 
{
    Serial.begin(9600);

    pinMode(9,OUTPUT);
    pinMode(10,OUTPUT);
    pinMode(11,OUTPUT);
    pinMode(12,OUTPUT);

    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
    digitalWrite(12,LOW);
}

void loop() 
{
    while(Serial.available())
    {
        sensor = Serial.read();
    }

    if(sensor>='A' && sensor<='A'+15)
    {
        sensor-='A';

        //Regeln wie in regel() ... einfache Version im Processing Sketch
//Processing:        
//      public float regeln(int[] sensorwerte) //liefert omega
//     {
//         if(sensorwerte[2]==0)
//            return -1;
//         else if(sensorwerte[3]==0)
//            return 1;
//         else
//            return 0.0;
//      }

//Hier: DEAKTIVERT

//        if((sensor/4)%2==0)  //s2
//            lenk = -1;
//        else if((sensor/8)%2==0) //s3
//            lenk =  1;
//        else
//            lenk = 0;    

//Neuronales Netz:
        if((sensor/1)%2==0)
            sens0=0;
        else
            sens0=1;    

        if((sensor/2)%2==0)
            sens1=0;
        else
            sens1=1;    

        if((sensor/4)%2==0)
            sens2=0;
        else
            sens2=1;    

        if((sensor/8)%2==0)
            sens3=0;
        else
            sens3=1;    

        lenk = neuro(sens0,sens1,sens2,sens3);

        //Zurück schicken:
        if(lenk==-1)
            Serial.write('X');
        else if(lenk==1)
            Serial.write('Y');
        else
            Serial.write('Z');

        // S0
        if(sensor%2>0) 
            digitalWrite(9,HIGH);
        else  
            digitalWrite(9,LOW);
        sensor/=2;
        // S1
        if(sensor%2>0) 
            digitalWrite(10,HIGH);
        else  
            digitalWrite(10,LOW);
        sensor/=2;
        // S2
        if(sensor%2>0) 
            digitalWrite(11,HIGH);
        else  
            digitalWrite(11,LOW);
        sensor/=2;
        // S3
        if(sensor%2>0) 
            digitalWrite(12,HIGH);
        else  
            digitalWrite(12,LOW);
         
    }
}

Code 0-8: Arduino-Programm (wahlweise mal mit/mal ohne sigmoide Funktion)

Teillösung 4: NN auf FPGA übertragen
Neuronales Netz auf FPGA steuert (sehr simple) Fahrzeugsimulation auf PC.

Bild 0-5: Neuronales Netz auf FPGA steuert (sehr simple) Fahrzeugsimulation auf PC.

69_FPGA/30_day_by_day/nn1.mp4

Da sinnvollerweise die Umsetzung nicht als Prozeß erfolgt, müssen neue Sprachelemente eingeführt werden, die prozeßhaften Code als "fest verdratete" Konstrukte umsetzen.

Die neuen Sprachelemente, die diese Anforderung erfüllen sind:

  • with ... select ....
  • when ... else ...
w-werte als Konstanten für FPGA:
constant w0: integer := -77;
constant w1: integer := -77;
constant w2: integer := 127;
constant w3: integer := -23;
constant w4: integer := 73;
constant w5: integer := -127;
constant w6: integer := 23;
constant w7: integer := -27;
constant w8: integer := 73;
constant w9: integer := -27;
constant w10: integer := -23;
constant w11: integer := -127;
constant w12: integer := 23;
constant w13: integer := -27;
constant w14: integer := -127;
constant w15: integer := -27;
constant w16: integer := 23;
constant w17: integer := -27;
constant w18: integer := 127;
constant w19: integer := -73;

Sigmoid - Lookup: -127...+127
Bis -5: 0,
Bei -4: 2,
Bei -3: 6,
Bei -2: 15,
Bei -1: 34,
Bei 0: 63,
Bei 1: 92,
Bei 2: 111,
Bei 3: 120,
Bei 4: 124,
ab   5: 126,
ab  17: 127

Code 0-9: Vordefinierte Werte

Machbarkeitsstudie: Neuronales Netz mit fünf Neuronen auf Integer-Basis in FPGA:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;


entity neuro2 is
    Port ( MEINECLOCK : in  STD_LOGIC;
           MEINELED : out  STD_LOGIC;
           S0 : in  STD_LOGIC;
           S1 : in  STD_LOGIC;
           S2 : in  STD_LOGIC;
           S3 : in  STD_LOGIC;
           LENK0 : out  STD_LOGIC;
           LENK1 : out  STD_LOGIC);
end neuro2;
-- Clock-In == 6MHz, Toggeln nach 3000000 Schritten ergibt 1Hz Blinkfrequenz.
architecture Behavioral of neuro2 is
--w-werte als Konstanten für FPGA:
constant w0: integer := -77;
constant w1: integer := -77;
constant w2: integer := 127;
constant w3: integer := -23;
constant w4: integer := 73;
constant w5: integer := -127;
constant w6: integer := 23;
constant w7: integer := -27;
constant w8: integer := 73;
constant w9: integer := -27;
constant w10: integer := -23;
constant w11: integer := -127;
constant w12: integer := 23;
constant w13: integer := -27;
constant w14: integer := -127;
constant w15: integer := -27;
constant w16: integer := 23;
constant w17: integer := -27;
constant w18: integer := 127;
constant w19: integer := -73;
    signal zaehler    : integer range 0 to 2999999 := 0;
    signal logikpegel : std_logic := '0';
	 
	 -- Speichern der gewichteten Summen:
    signal out0    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out1    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out2    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out3    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out4    : integer range -32768 to 32767 := 0; -- 16Bit Variable

    -- Speichern der out-Werte nach Anwendung der sigmoiden Funktion:
    signal out0_sigmo    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out1_sigmo    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out2_sigmo    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out3_sigmo    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal out4_sigmo    : integer range -32768 to 32767 := 0; -- 16Bit Variable
	 
	 -- Sensorzustände als Integer-Werte zur Verfügung stellen:
    signal iS0    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal iS1    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal iS2    : integer range -32768 to 32767 := 0; -- 16Bit Variable
    signal iS3    : integer range -32768 to 32767 := 0; -- 16Bit Variable
begin
        process begin
            wait until rising_edge(MEINECLOCK);
            if (zaehler<2999999) then
                zaehler <= zaehler+1;
            else
                zaehler <= 0;
                logikpegel <= not logikpegel;					 
            end if;
        end process;
        MEINELED <= logikpegel;
		  
		  -- Sensorwerte als Integer-Werte zur Verfügung stellen:
		  iS0 <= 1 when (S0 = '1') else 0;
		  iS1 <= 1 when (S1 = '1') else 0;
		  iS2 <= 1 when (S2 = '1') else 0;
		  iS3 <= 1 when (S3 = '1') else 0;

        -- Gewichtete Summen der ersten Schicht:		  
		  out0 <= w0*iS0 + w1*iS1 + w2*iS2 + w3*iS3;
		  out1 <= w4*iS0 + w5*iS1 + w6*iS2 + w7*iS3;
		  out2 <= w8*iS0 + w9*iS1 + w10*iS2 + w11*iS3;
		  out3 <= w12*iS0 + w13*iS1 + w14*iS2 + w15*iS3;

        -- So kann der Lookup-Table der sigmoiden Funktion umgesetzt werden:
        with out0 select out0_sigmo <=
		      0 when -32768 to -5, 
		      2 when -4, 
		      6 when -3, 
		      15 when -2, 
		      34 when -1, 
		      63 when 0, 
		      92 when 1, 
		      111 when 2, 
		      120 when 3, 
		      124 when 4, 
		      126 when 5 to 17, 
				127 when others;

        with out1 select out1_sigmo <=
		      0 when -32768 to -5, 
		      2 when -4, 
		      6 when -3, 
		      15 when -2, 
		      34 when -1, 
		      63 when 0, 
		      92 when 1, 
		      111 when 2, 
		      120 when 3, 
		      124 when 4, 
		      126 when 5 to 17, 
				127 when others;

        with out2 select out2_sigmo <=
		      0 when -32768 to -5, 
		      2 when -4, 
		      6 when -3, 
		      15 when -2, 
		      34 when -1, 
		      63 when 0, 
		      92 when 1, 
		      111 when 2, 
		      120 when 3, 
		      124 when 4, 
		      126 when 5 to 17, 
				127 when others;

        with out3 select out3_sigmo <=
		      0 when -32768 to -5, 
		      2 when -4, 
		      6 when -3, 
		      15 when -2, 
		      34 when -1, 
		      63 when 0, 
		      92 when 1, 
		      111 when 2, 
		      120 when 3, 
		      124 when 4, 
		      126 when 5 to 17, 
				127 when others;
		  		  
		  out4 <= w16*out0_sigmo + w17*out1_sigmo +w18*out2_sigmo +w19*out3_sigmo;

        with out4 select out4_sigmo <=
		      0 when -32768 to -5, 
		      2 when -4, 
		      6 when -3, 
		      15 when -2, 
		      34 when -1, 
		      63 when 0, 
		      92 when 1, 
		      111 when 2, 
		      120 when 3, 
		      124 when 4, 
		      126 when 5 to 17, 
				127 when others;

        -- Generieren binärer Zustände aus dem Wert des Ausgangsneurons		  
        with out4_sigmo select LENK0 <=
		      '1' when -32768 to -32, 
				'0' when others;
				
        with out4_sigmo select LENK1 <=
		      '1' when 32 to 32767, 
				'0' when others;		  
end Behavioral;

Code 0-10: neuro2.vhd

neuro2.zip -- xilinx-Projekt, arbeitet zusammen mit: AV502_Arduino_Regeln_Lenk (Processing) und AV_502_sensor_von_PC_Lenk (Arduino).
  • 9 -- 12|06|2018 -- TUESDAY

Das Java in Processing

java.zip java.zip -- Im Unterricht entstandenes Java-Programm.
main1.zip main1.zip -- Im Unterricht entstandener Processing-Sketch.
main2.zip main2.zip -- Im Unterricht entstandener Processing-Sketch.
  • main-Methode bei Processing-Sketchen
  • Konzept der inneren Klassen
  • Nutzen von Listen: ArrayList
  • UML-Klasendiagramme
  • Vordefinierte Call-Back-Funktionen
  • Threads: Parallele Prozesse
  • Konzept der Vererbung und der Schnittstellen im Vergleich
  • Eigene Klassen schreiben

main-Methode bei Processing-Sketchen

36_Java/01_GettingStarted

Konzept der inneren Klassen

Exportieren eines Processing-Sketches.

Nutzen von Listen: ArrayList

Beispiel im Unterricht

UML-Klasendiagramme

30_Informatik3/02_UML/02_UML_Klassendiagramm
30_Informatik3/02_UML/04_Statische_Variable
30_Informatik3/02_UML/03_Konstruktor
30_Informatik3/08_Listen_und_Templates/01_Containertypen/01_ListeUML
30_Informatik3/03_Strings/02_stringUML

Vordefinierte Call-Back-Funktionen

Siehe Processing Reference zu mouse und keyboard:

https://processing.org/reference/

Threads: Parallele Prozesse

36_Java/04_Threads
67_Echtzeitsysteme/02_Threads/01_Java
77_Android/04_Threads

Konzept der Vererbung und der Schnittstellen im Vergleich

extends:

36_Java/02_Hybrid
76_Mikroprozessoranwendungen/07_java/01_Fenster

interface:

18_Fuzzy/07_Haengependel/02_Simulation
94_VSI/09_Hybrid/04_Kamera
62_Regelungssysteme/06_Javaanwendung/03_Gradientenverfahren

Eigene Klassen schreiben

Beispiel: Neuronales Netz

75_Echtzeit3/01_NeuronaleNetze/01_Neuron
75_Echtzeit3/01_NeuronaleNetze/02_Backpropagation
67_Echtzeitsysteme/08_NeuronaleNetze/03_Umsetzung
Übungsprojekt
Tic01.zip -- Hilfestellung
Tic02.zip -- Ergänzung (Methoden, die prüfen, ob jemand und ggf. wer gewonnen hat)

Schreiben Sie ein selbst lernendes Tic-Tac-Toe-Spiel mit Processing auf der Basis eines Neuronalen Netzes.


Kleine aufeinander aufbauende Teilprojekte:

  • Programm, dass das Spielfeld darstellt und das Kreuze und Kreise einzeichnet, wo man hinklickt.
  • Programm, bei dem man gegeneinander spielen kann.
  • Programm, bei dem man gegeneinander spielen kann und das ungültige Spielzüge erkennt und nicht ausführt.
  • Programm, das selber gültige zufällige Spielzüge macht.
  • Programm, das selber gültige zufällige Spielzüge macht und auch gegen sich selber spielen kann
  • Klassen/Objektkonzept: Spiel, Spieler
  • Passendes Neuronales Netz zu Tic-Tac-Toe
  • Netz-Optimierung für Tic-Tac-Toe mittels gegen sich selbst antretenden NN-Entitäten
  • NN, das gegen Menschen spielt
  • 11 -- 26|06|2018 -- TUESDAY

Thematisch gemischte Projektarbeiten in "FPGA" und "Mikrocontroller"

Zum Abschluß des Semesters biete ich an, eines aus mehreren thematisch gemischten Projektthemen zu wählen und über die Zeit der FPGA, sowie der Mikrocontroller LV daran zu arbeiten.

Es gibt drei Themen:

  1. Tic-Tac-Toe mit Neuronalem Netz
  2. Einachser mit Arduino Micro und MPU6050
  3. Ansteuerung eines 150-LED-Panels und Realisierung des Spiels Snake

Einige von Ihnen haben bereits angefangen an einem der Themen zu arbeiten.

Damit die anderen noch einsteigen können, werde ich in der LV am Morgen die Themen ausführlich besprechen und Anregungen und Tips zur Umsetzung gegeben.

Letztere könnten auch Anlaß geben, das Projekt (ev. in einem neuen Team) noch einmal neu zu greifen.

Zielsetzung / Sammlung hilfreicher Links und Anregungen zu Thema 1: Tic-Tac-Toe mit Neuronalem Netz

ZIELSETZUNG Konzept und Realisierung für: Zwei Neuronale Netze treten immer wieder in mehreren Runden gegeneinander an und werden dabei immer besser / wachsen aneinander.

Links: Siehe oben alles zu Tic-Tac-Toe und zur Programmierung und Optimierung eines Neuronalen Netzes.

Anregungen:

  • Gute Visualisierung umsetzen, auch für den inneren Zustand der Netze und den Optimierungsstand.
  • Statt einer Java-Repräsention einen Code-Generator in Java schreiben, der ein C/Mikrocontroller-Programm und eine FPGA-Version erzeugt, das nur mit Integern arbeitet.

Dazu:

  • Einen Parser schreiben, der einfache Ersetzungen in Textschnipseln bewerkstelligt.
  • StringBuffer als Grundlage, den Quelltext nach und nach zusammenzubauen.
  • Codeschnipsel aus Dateien laden und verarbeiten.

public class NeuroGenerator
{
    //Beispiel: int[] schichten_staerke = {2,5,5,5,3};
    public NeuroGenerator(int[] schichten_staerke)
    {
       ....
    }

    public String erzeugeCquelltext()
    {
       ....
    }
    public String erzeugeFPGAquelltext()
    {
       ....
    }
}


Code 0-11: Idee für Generator-Klasse


int sigmo(int gewichtete_summe)
{
}

//Referenz auf Ausgabe out , Ref. Eingabe in, Gewichte w
void netz(char[] out, int[] in, char[] w) 
{
    //Schicht 0:
    int z0 = sigmo(w[0]*in[0] + w[1]*in[1] + ...);
    int z1 = sigmo(w[4]*in[0] + w[5]*in[1] + ...);
    int z2 = sigmo(w[8]*in[0] + w[9]*in[1] + ...);
    //Schicht 1:
    ...
    //Schicht n: (Ausgangsschicht)
    out[0] = ...
}


Code 0-12: Vorschlag für die erzeugte C-Funktion

Weitere Ideen:

  • Optimierer in C schreiben (vermutlich 100mal schneller).
  • Alles in eine main-Methode inlinen.
  • sigmo() wie auf FPGA mit Lookup erzeugen, damit es keine Unterschiede zwischen dem Verhalten des FPGA und dem C-Programm gibt.
  • Testfall: Graycode erzeugen
  • Zusatz Analysemethoden: Welche Integerzahl kann im Netz maximal auftauchen, dementsprechend Wertebereich für FPGA festlegen.

Wie kann man Strings laden und speichern?:


String[] text_zeilen = loadStrings("meine_daten.txt");

saveStrings("dateiname.txt",text_zeilen);

ACHTUNG:
Daten in einem Unterordner des Sketch-Folders mit dem Namen "data" ablegen!


Code 0-13: Laden und speichern von Strings mit Processing

Wie kann man einen Parser schreiben?:


String text = "Das ist # ein Beispiel";

StringBuffer sb = new StringBuffer();
for(int i=0;i<text.length();i++)
{
    char c = text.charAt(i);
    if(c=='#')
       sb.add("gutes");
    else
       sb.add(c);
}

// => "Das ist gutes ein Beispieltt"


Code 0-14: Nützliche Elemente, um einen Parser mit Processing zu schreiben.

Zielsetzung / Sammlung hilfreicher Links und Anregungen zu Thema 2: Einachser mit Arduino Micro und MPU6050

ZIELSETZUNG: Statt der Testsoftware auf kramann.info soll eine Library mit Gyro-Korrektur verwendet werden.

Einachser: 15_Einachser
Elektronikplatine zum Einachser: 15_Einachser/02_Bauanleitung/03_Elektronikplatine
Testsoftware als Ausgabgsbasis: 15_Einachser/02_Bauanleitung/09_Testsoftware
"Jeff Rowberg wrote some Arduino libraries to obtain the accelerometer / gyro data and handle all the calculations" ... http://www.instructables.com/id/Arduino-MPU6050-GY521-6-Axis-Accelerometer-Gyro-3D/
https://forum.arduino.cc/index.php?topic=494673.0
http://lessons.julien-drochon.net/arduino-unity-mpu-6050-using-gyoscope-to-control-unity3d/
https://playground.arduino.cc/Main/MPU-6050
tutorial-how-to-use-the-gy-521-module-mpu-6050

Arduino-Uno-Programm für Verwendung des Gyroskops anpassen an Arduino Mikro und hier verwenden.

Zielsetzung / Sammlung hilfreicher Links und Anregungen zu Thema 3: Ansteuerung eines 150-LED-Panels und Realisierung des Spiels Snake

ZIELSETZUNG: Kein Snake, nur eine LED mittels Joystick "wandern lassen". Mit Fire-Button Farbe wechseln.

Anregungen:

  • Dreierketten-Platine für dauerhaften Aufbau verwenden.
  • Buchsenleisten als Fassung für zwei Arduino-Micro
  • Alle Kabel abstöpselbar, aber mit verpolsicheren Buchsen und für jedes Kabel eine andere Anzahl an Litzen: Vermeidung von Verwechslungen.
Fassung für den Arduino-Micro mit Hilfe von zwei Buchsenleisten.

Welche Elemente werden mit der Hauptplatine verbunden?:

  • Zwei Netzteile
  • Ein Joystick
  • Zwei LED-Leisten (100 und 50er)
Lichtkette 1
Lichtkette 2