PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM Frage



Regnator
23.04.2013, 10:33
Hallo Leute,

ich habe ein kleines Problem:

Ich habe ein Gehäuse mit Motoren des CC-RP5, AT89C5131 & einen PCF8591 welchen ich über I²C an den µC angebunden habe(zum auslesen von Analogsensoren). Das wird ein kleiner autonomer Roboter / ist es schon.

Mein derzeitiges Programm :


/*------------------------------------------------------------------+
| File: Roboterfahrzeug |
| Autor: |
| Klasse: E3GS1 |
| Controller: at89c5131 |
| Datum: 27.03.13 |
| Version: 2 |
+--------------------------------------------------------------------+
| Beschreibung: |
| |
+-----------------------------------------------------------------------------*/

#include <at89c5131.h> // fuer Atmel AT89C5131

/* adda_kniel.c ************************************************** *******************************
* Hilfsprogramme für den AD- und DA- Umsetzer mit I2C-Bus ********************************
* An DA-Umsetzer wert ausgeben: void aout (unsigned char wert)
* AD-Umsetzer einlesen, Kanal = 0,1,2,3: unsigned char ain (unsigned char kanal)
************************************************** ****************************************/
// geänderte Version 11/2007: Start und Stop-Bedingungen, funktioniert mit US-Sensoren
// geänderte Version 12/2006: funktioniert endlich aus als Library: adda.obj mit
// Tool -> Library-Manager in die Bibliothek RC51atms.lib einfügen

#include <reg51.h> // Registerdefinitionen
//#include <intrins.h> // für Rotationsfunktion

// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!
//****** verwendete I2C-Leitungen ************************************************** *******
sbit SDA = P4^1; // SDA-Leitung: ED2-Boards P3_5, (USB-Boards P4_1)
sbit SCL = P4^0; // SCL-Leitung: ED2-Boards P3_4, (USB-Boards P4_0)
//************************************************** **************************************
// !-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!-!

//***** verwendete Adressen und Kontrollbyte für den AD- und DA-Umsetzter ****************
#define Motor1 P1
#define Motor2 P2
#define vor 0x50
#define zurueck 0x44
#define stopp 0x40
#define adr_lies 0x91 // 10010001 -> 1001 fest, 000 durch Platine, 1 Wert lesen
#define adr_schreib 0x90 // 10010000 -> 1001 fest, 000 durch Platine, 0 Wert lesen
#define contr_ain 0x40 // 01000000 -> Kontrollbyte 4 einzelne ADU, Kanal= Offset dazu
sbit acc7 = 0xE7; // für Aus- und Eingabe eines Bits des Akkus
//void warte(int z);
// ************************************************** ***************************************
// I2C- Routinen zur Ansteuerung eins I2C-Slaves
// I2C-Bus-Funktionen i2c_init, i2c_start, i2c_stop, i2c_schreiben, i2c_lesen auch für andere
// I2C-Bus-ICs verwendbar
// ************************************************** ***************************************

// **** Zeitverzögerung zur Verlangsamung der Datenübertragungsrate ***********************
// **** i=2 bis i=100 wählen je nach I2C-IC und Pull-Up-Widerstand
void zeit (void) {unsigned char i; for (i=5;i!=0;i--) ;}
void vorwaerts (void);
void rueckwaerts (void);
void drehen (void);
void speaker(void);
void warte(int z);
void stop(void);
// ************************************************** **************************************
// ****** Initialiserung I2C-Bus ************************************************** ********
void i2c_init (void)
{
SDA = 1; // Leitungen in den Grundzustand High
zeit ();
SCL = 1;
zeit ();
}

// ****** Startbedingung I2C-Bus ************************************************** ********
void i2c_start (void)
{
SDA = 1; // Grundzustand
SCL = 1; // neu eingefügt 11/07
zeit();
SDA = 0; // Wechsel SDA von 1 -> 0 während SCL = 1
zeit ();
SCL = 0;
zeit ();
}

//****** Stoppbedingung I2C-Bus ************************************************** *********
void i2c_stop (void)
{
SDA = 0; // neu eingefügt 11/07
SCL = 1;
zeit ();
SDA = 1; // Wechsel von SDA 0 -> 1 während SCL =1
zeit ();
}

//************************************************** ***************************************
// * Byte ausgeben an I2C-Bus , Rückgabewert = Acknoledgebit = 0 wenn erfolgreich
// ************************************************** **************************************
bit i2c_schreiben (unsigned char byte)
{
unsigned char z; // Zähler
bit ack; // Acknoledge-Bit
ACC = byte; // Rotationsregister Akku
for (z = 8; z != 0; z --) // Zähler: serielle Ausgabe von 8 Bit
{
SDA = acc7; // Bit7 des Akku ausgeben
zeit ();
SCL = 1; // Daten sind gültig
asm {0x23}; // Akku links schieben
//ACC = _crol_ (ACC,1); // links rotieren, Funktion von intrins.h
zeit ();
SCL = 0; // Datenausabe beendet
zeit ();
}
SDA = 1; // Leitung freigeben für Acknoledge-Bit
zeit ();
SCL = 1; // Slave kann bestätigen
zeit (); // warten
ack = SDA; // Acknoledge-Bit lesen
zeit ();
SCL = 0; // Slave soll Ackn-Ausgabe beenden
zeit();
return (ack); // Acknoledge-Bit ist Rückgabewert der Funktion
// ack = 0 bedeutet "verstanden" !!!!!!
}


//************************************************** ***************************************
// * Byte einlesen vom I2C-Bus. Bei Ack=1 wird Acknoledgebit gesendet, sonst nicht
// ************************************************** ***************************************
unsigned char i2c_lesen (bit ack)
{
unsigned char z,byte;
SDA = 1; // Leitung freigeben (high) für Daten
for (z = 8; z != 0; z --) // Zähler: serielles Einlesen von 8 Bit
{
SCL = 1; // Daten sind gültig
zeit ();
acc7 = SDA; // Datenbit in den Akku
asm {0x23}; // Akku links schieben
// ACC = _crol_ (ACC,1); // links rotieren, Funktion von intrins.h
//P2_7 = SDA;
zeit();
SCL = 0; // Daten lesen beendet
zeit();
}
byte = ACC; // Eingelesenes Byte
if (ack == 1) {SDA = 0;} // Acknowledge-Bit senden
else {SDA = 1;} // kein Acknowledge-Bit
zeit ();
SCL = 1; // Ackn. gültig
zeit ();

SCL = 0; // Ackn. beendet
zeit ();
SDA = 0; // Leitung SDA vorbereiten für Stoppbed.
zeit ();
return (byte); // eingelesenes Byte = Rückgabewert
}

//************************** ADU und DAU- Funktionen *************************************

//************************************************** ***************************************
// * AD-Umsetzter einlesen, Kanal = Nr des ADU: 0,1,2,3
// ************************************************** ***************************************
unsigned char ain (unsigned char kanal)
{
unsigned char wert;
i2c_init (); // I2C-Bus initialisieren (Grundzustand)
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_schreib); // Adresse des IC und Schreibwunsch (zur Kanalwahl)
i2c_schreiben ( (kanal&0x03) | contr_ain); // Controll-Byte mit Kanalnummer
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_lies); // Adresse des IC und Lesewunsch

i2c_lesen (1); // neue AD-Wandlung Acknoledge = 1
wert = i2c_lesen (0); // Wert abholen Acknoledge =0
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
return (wert);
}

//************************************************** ***************************************
// * An DA-Umsetzer wert ausgeben
// ************************************************** ***************************************
void aout (unsigned char wert)
{
i2c_init (); // I2C-Bus initialisieren (Grundzustand)
i2c_start (); // Startbedingung I2C-Bus ausgeben
i2c_schreiben (adr_schreib); // Adresse ADU
i2c_schreiben (contr_ain); // Control-Byte acu für Analogwert einlesen
i2c_schreiben (wert); // Wert ausgeben
i2c_stop (); // Stoppbedingung I2C-Bus ausgeben
}


void main (void) // Hauptprogramm
{
unsigned char wert; //Definition Variable wert
unsigned char swert; //Definition Variable swert zum abfragen
P0=0x00; // Port0 - Port3 als Ausgang deklarieren
P1=0x00;
P2=0x00;
P3=0x00;
while(1) //While Schleife
{
P3_1=1; //linke weiße LED ausschalten
P3_3=1; //linke rote LED ausschalten
P3_5=1; //rechte rote LED ausschalten
P3_7=1; //rechte linke LED ausschalten
wert = ain(0); //Kanal 0 einlesen und auf wert schreiben
P0 = ~wert; //wert auf P0 schreiben
swert=wert&0x80; //swert = wert mit 80 Hex "und"-Verknüpft
switch(swert) // abfrage von swert
{
case 0x80: rueckwaerts(); //Wenn swert = 80 Hex dann führe das Programm rückwärtsfahren aus
break; // Break um die Abfragen von einander zu trennen
default: vorwaerts(); break; // Wenn swert ungleich 80 Hex dann führe das Programm vorwärtsfahren aus
}
wert = ain(1);
P0 = ~wert;
swert=wert&0x80;
switch(swert)
{
case 0x80: rueckwaerts();
break;
default: vorwaerts(); break;
}
wert = ain(2);
P0 = ~wert;
swert=wert&0x80;
switch(swert)
{
case 0x80: rueckwaerts();
break;
default: vorwaerts(); break;
}
}
}

void vorwaerts (void) //Unterprogramm Vorwärtsfahren
{
Motor1 = vor; // die höherwertige 1 ist der Enable Pin
Motor2 = vor; // die niederwertige 1 ist die Richtung des Motors
}

void rueckwaerts (void) //Unterprogramm Rückwärtsfahren
{
unsigned char hinten_abfrage;
hinten_abfrage = ain(3);
if(hinten_abfrage>=0x40)
{
drehen();
}
else
{
stop(); // Sprung ins Unterprogramm stop
P3_1=0; // LED links weiß an
P3_3=1; // LED links rot aus
P3_5=1; // LED rechts rot aus
P3_7=0; // LED rechts weiß an
Motor1 = zurueck; // Motoren nach hinten fahren lassen
Motor2 = zurueck;
speaker(); // Unterprogramm für den Piepser
drehen(); // Verzweigungs ins Unterprogramm drehen
}
}

void drehen (void) // Unterprogramm drehen
{
double long x; // Variable x mit einem großen Datenbereich adressieren
Motor1 = zurueck; // Motor 1 rückwärts fahren lassen
Motor2 = vor; // Motor 2 vorwärts fahren lassen
for(x=0;x<2100;x++); // Warteschleife in der x hochgezählt wird
}

void stop(void) // Unterprogramm stop & rote LEDS an
{
Motor1=stopp; // Enable pin & Drehrichtungsangabe aus
Motor2=stopp;
P3_3=0; // LED links rot an
P3_5=0; // LED rechts rot an
warte(50); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
}

void speaker (void) // Unterprogamm für die Lautsprecher
{
P3_0=1; // Lautsprecher an
warte(25); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
P3_0=0; // Lautsprecher aus
warte(10); // Sprung ins unterprogramm warte mit Übergabe einer Variablen
P3_0=1;
warte(25);
P3_0=0;
}

void warte(int z) // Unterprogramm fürs Warten
{
int s, x; // definieren von Variablen
for(s=z;s>0;s--) // s nimmt den Wert von z an welche vorher übergeben wurde. s wird runtergezählt
{
for(x=2000;x>0;x--); // for schleife in welcher x runtergezählt wird
}
}


Nun meine Frage : wie bekomme ich eine PWM zur Steuerung der Motoren möglichst einfach hin ? Die Motoren werden über einen L298 geschalten.

Geistesblitz
23.04.2013, 12:11
Am einfachsten wäre wirklich Software-PWM, allerdings weiß ich nicht, wie man die unter C anspricht. Unter Bascom ist es jedenfalls ziemlich easy und ich denk mal, dass es mit C auch ähnlich gehen wird. Welche Timer sind denn noch frei? Wenn kein Timer mehr frei ist sieht es generell schlecht für PWM aus.

Regnator
23.04.2013, 12:15
Bis jetzt wird noch kein Timer verwendet.

Sorry, hätte vielleicht noch erwähnen sollen, dass es in C ist. Als Compiler benutze ich Ride7.

Hättest du mir dann ein Beispiel parat, um mir das mal zu verdeutlichen wie der ungefähre Aufbau aussieht ?

Geistesblitz
23.04.2013, 12:46
Hmm, such da besser mal im Netz, ich kenn mich nämlich noch nicht so mit C aus (oder jemand anders ist so nett, das zu erzählen). Auf jeden Fall geht Hardware-PWM nur mit bestimmten Pins, die man sich mal im Datenblatt raussuchen sollte. Hab auch ganz übersehen, dass du gar keinen AVR verwendest. Keine Ahnung, ob das von mir Geschriebene dann noch gilt.

RoboHolIC
23.04.2013, 13:15
Nun meine Frage : wie bekomme ich eine PWM zur Steuerung der Motoren möglichst einfach hin ? Die Motoren werden über einen L298 geschalten.

Fragst du nach Software, nach Hardware oder bist du ergebnisoffen? Ganz viele Controller können PWM-Signale erzeugen, die man an die Eingänge /INH1 und /INH2 del L298 anschließt. Alternativ gibt es die Möglichkeit von I2C-fähigen PWM-Generatoren, Typen kenne ich nicht auswendig. Wenn der Anspruch an die PWM niedrig ist, z.B. 10 Stufen@100Hz, dann macht das ein evtl. schon laufender 1kHz-Interrupt nebenher mit.

Regnator
23.04.2013, 13:41
Ich suche eine Software-Pwm.

Der Anspruch ist einfach nur, dass ich meine Motoren über ein High - Low getaktes Signal an dem L298 entsprechend langsamer laufen, oder ist das programmtechnisch nicht zu verwirklichen ?

Hab da mitlerweile was zu meinem µC gefunden :
// Initialisierung
TMOD = 0x11; // setzt beide Timer in den 16-Bit Mode
TR0 = 1; // Timer 0 läuft jetzt, mit jedem Maschinenzyklus
// wird jetzt TH0:TL0 um 1 hochgezählt

while(1)
{
// in der Endlosschleife
if (TF0 == 1) // Flag wird beim Überlauf auf 1 gesetzt
{ TF0 = 0; // Flag erstmal löschen, der Timer zählt bereits munter weiter
Tu_Was( ); // für was wolltest Du die Zeit nochmal nutzen??
}
Weitere_Aktionen( );
}

Kann ich wenn TF0 =1 einer Variable einen Wert zuweisen und mit meinem Signal der Motoren per & Verknüpfen ?

Wenn ich einer geringere Zeit möchte kann ich ja einfach TH0 / TL0 schon einem Startwert zuweisen, oder ?

RoboHolIC
24.04.2013, 01:20
Ein Timer genügt. Der wird abwechselnd auf den Startwert für High-Zeit oder Low-Zeit gesetzt. Das Überlaufflag kann doch vermutlich einen Interrupt auslösen, das erspart Polling auf dieses Flag. Je nach Arbeitstakt (High / Low) wird dann beim Überlauf der PWM-Ausgang umgeschaltet. Die Verknüpfung macht der L298 in Hardware via /INHn. Wenn du Ports sparen willst, geht die VerUNDung natürlich auch in Software.

Dein Controller hat aber ein PWM-Modul auf dem Chip. Bist du an Software-PWM gebunden durch vorhandene Elektronik?

Regnator
24.04.2013, 07:01
Ja, da meine Schaltung sozusagen schon fertig ist und ich die Software PWM als kleines Extra noch hinzufügen wollte, da ich noch ein paar Schalter frei habe und somit meine Frequenz veränderbar machen wollte.
Mit deinem INHn meinst du den enable pin, oder ?
Die PWM wollte ich schon über Polling laufen lassen, da mir der µC meinen Roboter ja nicht auf einmal im rückwärtsfahren stehen bleiben soll, weil er in den Interrupt springt.
Leider sind meine Bilder zu groß, sonst hätte ich sie hochgeladen um mal zu veranschaulichen wie mein Stand der Dinge ist.

lorcan
24.04.2013, 07:57
Im Datenblatt (http://www.atmel.com/Images/doc4136.pdf) wird auf das Programmable Counter Array (PCA) verwiesen, das kann die PWM in Hardware erzeugen. Du must nur das Tastverhältnis der PWM ändern und die Zähler starten / stoppen. Danach läuft das ganze im Hintergrund und frisst keine Resourcen.

RoboHolIC
24.04.2013, 16:58
. . . meine Schaltung sozusagen schon fertig ist . . . Software PWM als kleines Extra noch hinzufügen . . . ein paar Schalter frei habe und somit meine Frequenz veränderbar machen wollte.
Da will sich mir der Sinnzusammenhang einfach nicht erschließen! PWM ist kein kleines Extra sondern eine wichtige Funktionalität zur Begrenzung der Anlaufströmer der Motoren und zur Regelung des Geradeauslaufs. Frequenz und PWM (wohl eher Duty Cycle der PWM) sind zwei verschiedene Dinge. Wenn du noch in der Entwicklung bist, dann kümmere dich um dein Verständnis der OnChip-PWM-Erzeugung und lege die Schaltung dafür aus. Dafür sind die Peripheriemodule ja da. Kein Polling für Dinge, die eigentlich selbständig im Hintergrund laufen können. Anders gesagt: Es ist nicht die Aufgabe des Chefs (Hauptprogramm), stündlich (jede Millisekunde) zu kontrollieren, ob noch Klopapier auf der Rolle ist. Derartiges wird delegiert. Wenn du das jetzt nicht verbesserst, wirst du dich später bestimmt ärgern, weil du dir damit die Karten gelegt hast.

Mit deinem INHn meinst du den enable pin, oder ? Ja. Das n steht für die Ziffern 1 bzw. 2 der beiden quasi gleichartig wirkenden Inhibit-Eingänge des L298.

Die PWM wollte ich schon über Polling laufen lassen, da mir der µC meinen Roboter ja nicht auf einmal im rückwärtsfahren stehen bleiben soll, weil er in den Interrupt springt. Nein, nein, nein; sorry, aber das ist Unfug. Jedes Bit, jeder Pin behält seinen Zustand bei, solange, bis er vom Programm, von der Hardware oder der nächsten Stromunterbrechung verändert wird. Und das ist alles genauestens geordnet und im Datenblatt beschrieben. Ein Interrupt stört da entweder überhaupt nicht, oder man hat ihn falsch programmiert; aber das lässt sich ja korrigieren. Ganz im Gegenteil: Man _kann_ einen Interrupt als SW-Treiber für die Hardware konzipieren, sodass das Hauptprogramm letztlich unabhängig von der Hardware und Chip-individuellen Registerstruktur nur noch über Statusflags, Messwertvariablen und Steuervariablen im SRAM mit der Hardware Verbindung hat. Der Interrupt wirkt dann als "dienstbarer Geist" oder Haushalter unbemerkt im Hintergrund und managt die ganze Chose.

Regnator
25.04.2013, 08:03
25234

Aktuelles Aussehen:25235

Die grünen Platinen sind vorgegeben und dürfen nicht verändert werden. Desweiteren muss der AT89C5131 verwendet werden.

Meine Frage zu dem ganzen Thema ist eigentlich wie ich eine Pwm einbaue die noch freie Schalter auf der Platine abfragt und den Motor dann entsprechende langsamer fahren lässt.

Mein Programm sieht vereinfacht so aus :

1. Frag die Sensoren ab
2. Wenn vorne frei ist, dann fahr nach vorne.
2a. Wenn nicht frei ist dann überprüfe ob hinten frei ist
3.Wenn frei ist dann fahr zurück und drehe.
3a. Wenn nicht frei ist, dann drehe so lange bis frei wird.

Ich habe hier auch schon das PDF für eine PWM für diesen µC gefunden, allerdings würde ich gerne wissen wie ich eben bei den Unterprogrammen den Wert der PWM sozusagen auf den Motorenpins ausgebe / auf dem Inhibit.

http://www.atmel.com/Images/doc4345.pdf

RoboHolIC
25.04.2013, 14:40
Die grünen Platinen sind vorgegeben und dürfen nicht verändert werden. . . .
Meine Frage zu dem ganzen Thema ist eigentlich wie ich eine Pwm einbaue die noch freie Schalter auf der Platine abfragt und den Motor dann entsprechende langsamer fahren lässt.
1) Option Software-PWM wurde bereits diskutiert; ist für jeden beliebigen Pin des Controllers realisierbar.
2) Option Hardware-PWM des Controllers: klappt ohne Änderung der Platine oder der Verdrahtung nur, wenn der Motor-steuernde Pin (zufällig) der PWM-Ausgangs-Pin des Controllers ist.
3) Bestimmt dürfen die Flachbandkabel verändert werden, das ist ja reversibel, bzw. man knipst sich einen neuen Satz von Kabeln, die man dann modifiziert
4) Punkt 3 schließt die Option mit ein, einen externen PWM-Erzeuger in die Flachbandkabel einzuschleifen: nicht benötigte Signale werden 1:1 weitergereicht; PWM aus I2C-Chip, UND-verknüpft mit dem bisherigen MOTOR_EIN, werden zum L298 verdrahtet


allerdings würde ich gerne wissen wie ich eben bei den Unterprogrammen den Wert der PWM sozusagen auf den Motorenpins ausgebe / auf dem Inhibit.
Ach, kommst du doch an den /INH des L298 ran? Dann braucht es weder in SW noch in HW eine UND-Verknüpfung.

Deine Informationen kommen leider ziemlich spärlich und nur tröpfchenweise hier an; was den /INH des L298 angeht, sind sie sogar konträr, denn im Beitrag #6 hast du explizit nach SW-PWM und der Möglichkeit einer SW-UND-Verknüpfung gefragt und nun fragst du wieder nach der HW-Lösung! Vielleicht zeigst du uns jetzt einfach mal die Schaltpläne; daran entscheidet sich die Machbarkeit im status quo (ausgenommen SW-PWM, denn die ist in jedem Fall irgendwie realisierbar). Und kläre, ob eine Lösung mit zwischengeschalteter Platine erlaubt/gewünscht ist. Erst wenn die Karten auf dem Tisch liegen, kann man dich sinnvoll beraten.

Regnator
25.04.2013, 15:41
2523725238

Ich wäre definitiv an einer Softwäre PWM interessiert, eine Hardware PWM würde bedeuten, dass ich eine neue Platine fräsen/bestücken müsste ;)
Ja ich darf so viele Platinen zwischenschalten wie ich will, allerdings ist der I²C port durch meinen ADC belegt. (Kleinere grüne Platine)

Punkt eins wäre für mich am besten.
Und ja ich kann den Enable meines L298 über meinen µC schalten

RoboHolIC
25.04.2013, 22:10
Hi Regnator,

ein letzter Überzeugungsversuch von mir, dann hör' ich mit dem Predigen auf, versprochen!

Der Verdrahtungsaufwand für einen I2C-Chip ist vergleichsweise minimal, das geht auch sehr gut von Hand verdrahtet.

Mag sein, dass dein I2C-Port derzeit nur den ADC bedient; belegt im Sinne von "mehr geht nicht" ist er damit aber nicht.
I2C ist ein Bus, es sind mehrere I2C-Slaves an einem Bus möglich. Zur Not kann die fixe PWM duty cycle ja beim Programmstart via I2C initialisiert werden, der restliche Code bleibt unverändert und man fährt weiterhin mit Standgas durch die Gegend. Man kann aber auch mit beiden I2C-Bausteinen im Wechsel kommunizieren, ohne dass die Verzögerungen bei der Analogerfassung die Reaktionsfähigkeit des Gefährts spürbar beeinflussen und deine von mir vermutete praktische Studienleistung kriegt mehr Niveau. Nix für ungut.

Gruß
RoboHolIC

Regnator
29.04.2013, 14:26
Naja ich lass das dann mal mit der PWM, da Abgabe bereits am Donnerstags ist und ich bis dahin nicht alle Platinen wieder bestückt/ gelötet bekomme.
Aber Danke für Euren Einsatz!
Es war "nur" ein Projekt für meine Berufsschule und meine eigenen Vorgaben, die erfüllt werden mussten sind, dass es Gegenständen selbstständig ausweicht.
Trotzdem nochmal Danke für Eure Bemühungen.
Vielleicht werde ich es nochmal nach der Benotung verändern, die Möglichkeiten dafür sind gegeben.