PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Asuro programmieren ohne Asuro lib



ElchiMtr
26.08.2009, 21:38
Hallo ASURO-freunde,

ich würde euch gerne mal was fragen,
kann ich meinen "kleinen" Freund eigentlich auch anders programmieren
und zwar würde ich die die Funktionen des ATMEGA direkt nutzen.
z.b. würde ich sowas wie die MotorSpeed-Funktion durch sowas wie: PWM ausgang soll die PWM frequenz xHz und die Pulselänge y ms oder
der Ausgang xy soll auf HIGH gesetzt werden oder der AD-Wandler soll eingelesen werden.

Versteht ihr was ich meine?
gibt es vlt ne Lib die alle ATMEGA funktionen enthällt ? wenn ja gibts für jeden AVR ne eigene ? ach ja es soll natürlich für c/c++ sein.

danke für eure Hilfe

PS seit bitte etwas nachsichtig hab den ASURO gerade erst wieder raus gekramt.

radbruch
26.08.2009, 21:53
Versteht ihr was ich meine?Nicht wirklich. Verstehst du eigentlich wie die asuro-Library funktioniert?

Ich sehe zwei Wege wie man sich dem Mega8 im asuro nähern kann: Man ersetzt ein paar Funktionen der asuro-Lib durch eigene Funktionen oder man verwendet die Lib gar nicht und betrachtet den asuro-Mega8 als normalen Mega8. Beidesmal ist das Datenblatt des Mega8 und der Schaltplan des asuro die Grundlage auf dem alles weitere aufbaut.

Bitte entschuldige die knapp gehaltene Antwort. Das Thema ist umfangreich, deine Frage sehr allgemein. Es ist mir deshalb nicht möglich detailierter zu antworten.

Gruß

mic

Ceos
26.08.2009, 22:06
der einfach rat heisst "datasheet atmega8" googeln ... ist aber englisch und n guter brocken arbeit, zumal du noch den schaltplan des asuro verstehen lernen müsstest um die "hardware" vernünftig ansteuern zu können

ich rate dir erstmal dazu im wiki nach der seite "AVR einstieg" zu schauen und dir ein wenig bastelwerkzeug zu beschaffen, so ohne weiteres den controller des asuro zu benutzen kann auch mal schnell nach hinten losgehen, lieber durch die grundlagen langsam hocharbeiten! denn so "befehle" verwendet der atmega nicht in C, da muss man schon mit den registern des controllers rumjonglieren.

bascom wäre eine alternative, da ist schon fast alles irgendwie in makros gepackt, aber ist halt ein basic derivat


falls jemand doch widererwartens eine bibliothek für nen M8 mit allen features haben sollte, würde mich das auch interessieren (ich schreib im moment daran einzelne funktionen mit structs und callback pointern zu kapseln, scheitere aber am mangel von zeit)

EDIT: zu langsam ^^

ElchiMtr
26.08.2009, 23:07
Versteht ihr was ich meine?Nicht wirklich. Verstehst du eigentlich wie die asuro-Library funktioniert?

Also wenn ich die Antworten lese denke ich gerade das ich das missverstehe. Ich nähere mich gerade "sehr" langsam den AVRs

Ich kenne C/C++ eigentlich eher von der Programmierung unter Windows, so blöd das klingt aber da is es ja so das die eigentliche Arbeit bereit vorhandene Funktionen machen. Nun dachte ich das Atmel zu seinen AVRs soetwas auch besitzt oder besser zur Verfügung stellt.

@radbruch vlt kannst du mir die Funktionsweise der Asuro Lib kurz erklären oder hast ne Ahnung wo ich dazu etwas das ich auch verstehe nachlesen kann.

vielen Dank Elchi

radbruch
26.08.2009, 23:28
vlt kannst du mir die Funktionsweise der Asuro Lib kurz erklärenNe, das kann ich wirklich nicht. Ich könnte dir Teile daraus erklären, manches habe ich aber leider auch noch nicht kapiert:)

Ein guter Einstieg wäre wohl das A VR-G CC-Tutorial (http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial) vom mikrocontroller.net. Vieles davon findest du in der asuro-Lib (asuro.c) wieder. Die Lib entlastet den Programmierer indem sie Standaufgaben erledigt. Das kann man natürlich auch alles selbst machen. Muss man aber nicht;)

Gruß

mic

oberallgeier
26.08.2009, 23:43
... Also wenn ich die Antworten lese denke ich gerade das ich das missverstehe ...Manchmal kommts vor, dass jeder jeden missversteht - oder so.

1) Der asuro wird von einem AVR-Controller, einem ATmega8L, gesteuert.
2) Damit man nicht gaaaanz in das Datenblatt runtertauchen muss, wurde eine Bibliothek von Routinen für den asuro bzw. seinen mega8 geschrieben.
3) Wer, wie Du, den direkten Weg gehen will, muss sich die Routinen selbst schreiben. Das geht natürlich, ceos hat das mit seinem ersten Satz sauber kommentiert: s..schwer *gggg*, besonders als Einstieg. Aber es ist ohne Einschränkung möglich. Einziges Limit: die Möglichkeiten des Controllers und der angesteuerten Hardware (ach ja, und der Ladezustand der Akkus *gggg*).
4) Hier (klicken) (http://www.arexx.com/downloads/asuro/asuro_manual_de.pdf) ist die asuro BAU- UND BEDIENUNGSANLEITUNG verfügbar. Darin sind einige der Bibliotheksfunktionen beschrieben usw usf. Darin ist auch der Schaltplan als Grundlage eigener Funktionen - die kann man in C, in Assembler und was weiß ich noch für Sprachen schreiben.
5) Hier ist das aktuelle Datenblatt zum ATmega8. (http://www.atmel.com/dyn/resources/prod_documents/doc8159.pdf) Da muss man durch, wenn man sich die asuro-Funktionen selber schreiben will.

Du wirst Dich zurechtfinden, das bisschen Konfusion ist am Anfang üblich. Da muss man durch *gggg*. Viel Erfolg. Mic, bitte nicht böse sein, wenn ich mich einmische.

radbruch
27.08.2009, 00:06
:)

ElchiMtr
27.08.2009, 01:07
Mic, bitte nicht böse sein, wenn ich mich einmische.[/i][/size]

Meine Frage sollte sich natürlich an alle richten nicht nur an Radbruch !!!

Ich hatte das mit der Lib wohl vollkommen falsch verstanden.

Aba da wirft sich mir die frage auf wie machen das die tüfftler welche eigene Bot's bauen schreiben die / schreibt ihr euch dann ähnliche Libs ?

oder nutzen die dann Alle kein C ?

meine Fragen erscheinen vlt etwas merkwürdig und wurden vlt auch schon mal gestellt aber ich würde das echt gern verstehn.


gruß Elchi

oberallgeier
27.08.2009, 09:09
... wie machen das die tüfftler welche eigene Bot's bauen schreiben die / schreibt ihr euch dann ähnliche Libs ...Ich bin kein Tüftler, baue aber meine eigenen Fahrzeuge (https://www.roboternetz.de/phpBB2/viewtopic.php?p=390196&sid=864e69c02732fb615b235e97b12bbe6b#390196) mit einfachen Autonomiefunktionen. Ein Beispiel dazu ist die Regelung. Dazu kann man, muss aber nicht, Bibliotheken bauen, die immer wieder verwendet werden. Dies ist ja einer der hübschen Grundgedanken von C - vermutlich auch bei Anwendungen für Windows.


... oder nutzen die dann Alle kein C ...Hmmm, ich hatte sowohl in Urzeiten unter FORTRAN, als auch bei meinem selbstgeschriebenen Offset für AutoCAD in Lisp die Software in Bibliotheksform entworfen, wenn das irgendwie möglich war.

Nur als Beispiel dafür, wie maches Arbeiten (hier Optimierung) bei selbstgeschriebenen Programmen aussehen kann, hier meine derzeitigen Aktivitäten (https://www.roboternetz.de/phpBB2/viewtopic.php?p=457587&sid=864e69c02732fb615b235e97b12bbe6b#457587) zur Regelung . . . . Ähnliches hat der eine oder andere Autor der asuro-Bibliotheken sicher auch gemacht. Und MEIN Regelungscode für R3D01/MiniD0 steht - zu Anschauungszwecken - gleich dabei.


... meine Fragen ... wurden vlt auch schon mal gestellt ...Sollen wir jetzt für Dich die Suchfunktion anwerfen? Um Antworten auf Deine Fragen zu finden?

Ceos
27.08.2009, 10:34
ich habs ja oben auch schon geschrieben, man kann sich für jede peripherie am controller libs(eigentlich nur header und c files mit methoden) schreiben oder einfach nur in einer einzgen main schreiben und die register manipulieren, der berühmte spaghetticode ^^

radbruch
27.08.2009, 11:05
Hallo

Am Beispiel eines LCDs kann ich mal zeigen wie ich eine Lib zusammenbastle:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=41805

Hier versuche ich ein Display im 4-Bit-Mode mit 6 Pins am RP6(Mega32) anzuschliesen. Der Code ist ziemlich verwirrend, weil LCD-Ansteuerung und eigentliches Programm vermischt sind. Mit ausgelagerten LCD-Funktionen wird es dann wieder übersichtlicher:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=390124#390124

Hier kann ich nun das LCD ansprechen ohne darüber nachdenken zu müssen wie die Ausgabedaten zum Display geschaufelt werden. Wie für viele andere Aufgaben findet man auch für LCDs vorgefertigte LIBs die man an eigenen Bedürfnisse anpassen kann. So sind z. B. die Libs von Peter Fleury (http://jump.to/fleury) weit verbreitet und quasi ein Standart:
http://homepage.hispeed.ch/peterfleury/avr-software.html#libs

Allerdings muss man beim Anpassen schon C-geübt sein. Ich mache solche Dinge gerne selber, der Lerneffekt scheint mir dabei größer zu sein.

Ach ja, bei meinem aktuellen asuro-probot-Projekt (https://www.roboternetz.de/phpBB2/viewtopic.php?p=457172#457172) ändere ich die orginale asuro-Lib um mit "normalen" asuro-Befehlen die Hardware des probot ansprechen zu können:

PWM mit 4 Leitungen:

// Selbsttest für den asuro-ProBot 22.8.09 mic

#include "selftest.h"

uint16_t i;

void Init(void);
void Sleep(unsigned char time36kHz);
void Msleep(int dauer);
void SerWrite(unsigned char *data,unsigned char length);
void PrintInt(int wert);
inline void StatusLED(unsigned char color);
inline void FrontLED(unsigned char status);
void BackLED(unsigned char left, unsigned char right);
inline void MotorSpeed(unsigned char left_speed, unsigned char right_speed);
inline void MotorDir(unsigned char left_dir, unsigned char right_dir);

int main(void) {

Init();
SerWrite("\n\rasuro-ProBot-Selbsttest\n\r", 27);
SerWrite("22.8.09 mic \n\r", 14);
DDRD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6); // D12-15 und FrontLED
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6); // high bedeutet LEDs aus

while(1)
{
MotorDir(RWD,FWD);
PORTD &= ~((1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6));
MotorSpeed(200,200);
Msleep(2000);
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6);
MotorSpeed(255,255);
Msleep(1000);
PORTD &= ~((1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6));
MotorSpeed(150,150);
Msleep(2000);
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6);
MotorSpeed(0,0);
Msleep(100);

MotorDir(FWD,RWD);
PORTD &= ~((1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6));
MotorSpeed(200,200);
Msleep(2000);
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6);
MotorSpeed(255,255);
Msleep(1000);
PORTD &= ~((1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6));
MotorSpeed(150,150);
Msleep(2000);
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6);
MotorSpeed(0,0);
Msleep(100);

PORTD &= ~((1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6));
Msleep(500);
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6);
Msleep(500);
PORTD &= ~((1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6));
Msleep(500);
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD6);
Msleep(500);
}
return(0); // wird nie erreicht!
}

volatile unsigned char count36kHz;
volatile unsigned long timebase;

/* uses timer2 (36kHz for IR communication */
SIGNAL (SIG_OVERFLOW2)
{
TCNT2 += 0x25;
count36kHz ++;
if (!count36kHz) timebase ++;
}

void Init (void)
{
//-------- seriell interface programmed in boot routine and already running -------
// prepare 36kHz for IR - Communication
TCCR2 = (1 << WGM20) | (1 << WGM21) | (1 << COM20) | (1 << COM21) | (1 << CS20);
OCR2 = 0x91; // duty cycle for 36kHz
TIMSK |= (1 << TOIE2); // 36kHz counter for sleep

// prepare RS232
UCSRA = 0x00;
UCSRB = 0x00;
UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit
UBRRL = 0xCF; // 2400bps @ 8.00MHz

// I/O Ports
DDRB = IRTX | LEFT_DIR | PWM | GREEN_LED;
DDRD = RIGHT_DIR | FRONT_LED | ODOMETRIE_LED | RED_LED;

// for PWM (8-Bit PWM) on OC1A & OC1B
TCCR1A = (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1);
// tmr1 running on MCU clock/8
TCCR1B = (1 << CS11);

// A/D Conversion
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // clk/64

MotorDir(FWD,FWD);
MotorSpeed(0,0);
sei();
}

void Sleep(unsigned char time36kHz)
{ unsigned char ziel=(time36kHz+count36kHz) & 0x00FF;
while (count36kHz != ziel);
}

void Msleep(int dauer)
{
while(dauer--) Sleep(36);
}

void SerWrite(unsigned char *data,unsigned char length)
{
unsigned char i = 0;
UCSRB = 0x08; // enable transmitter
while (length > 0) {
if (UCSRA & 0x20) { // wait for empty transmit buffer
UDR = data[i++];
length --;
}
}
while (!(UCSRA & 0x40));
for (i = 0; i < 0xFE; i++)
for(length = 0; length < 0xFE; length++);
}

void PrintInt(int wert)
{ char text[6]=" ";
itoa(wert,text,10);
SerWrite(text,5);
}

/* Set motor speed */
inline void MotorSpeed(unsigned char left_speed, unsigned char right_speed)
{
OCR1A = left_speed;
OCR1B = right_speed;
}

/* Set motor direction */
inline void MotorDir(unsigned char left_dir, unsigned char right_dir)
{
if(left_dir) PORTB &= ~(1 << PB5); else PORTB |= (1 << PB5);
if(right_dir) PORTB &= ~(1 << PB4); else PORTB |= (1 << PB4);
}



4 Status-LEDs:

// Selbsttest für den asuro-ProBot 22.8.09 mic

#include "selftest.h"

uint16_t i;

void Init(void);
void Sleep(unsigned char time36kHz);
void Msleep(int dauer);
void SerWrite(unsigned char *data,unsigned char length);
void PrintInt(int wert);
void PrintBin(char wert);
inline void StatusLED(unsigned char color);
inline void FrontLED(unsigned char status);
void BackLED(unsigned char left, unsigned char right);
inline void MotorSpeed(unsigned char left_speed, unsigned char right_speed);
inline void MotorDir(unsigned char left_dir, unsigned char right_dir);
void LineData(unsigned int *data);
inline void StatusLED(unsigned char color);
void SetLEDs(unsigned char status);

int main(void) {

uint8_t i, j;

Init();
SerWrite("\n\rasuro-ProBot-Selbsttest-LEDs\n\r",32);
SerWrite("25.8.09 mic \n\r", 14);
DDRD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6); // D12-15 und FrontLED
PORTD |= (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6); // high bedeutet LEDs aus
//PORTD &= ~((1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5)); // D12-15 an

Msleep(1000);
StatusLED(GREEN);
Msleep(1000);
StatusLED(RED);
Msleep(1000);
StatusLED(YELLOW);
Msleep(1000);
StatusLED(OFF);
Msleep(1000);
SetLEDs(0b11111); // FrontLED, D14(red), D15, D13, D12(green)
Msleep(1000);

while(1)
{
j=5;
while(j--) for(i=0; i<5; i++)
{
SetLEDs(1<<i);
Msleep(400);
}
j=30;
while(j--)for(i=0; i<4; i++)
{
SetLEDs(1<<i);
Msleep(150);
}
}
return(0); // wird nie erreicht!
}

volatile unsigned char count36kHz;
volatile unsigned long timebase;

/* uses timer2 (36kHz for IR communication */
SIGNAL (SIG_OVERFLOW2)
{
TCNT2 += 0x25;
count36kHz ++;
if (!count36kHz) timebase ++;
}

void Init (void)
{
//-------- seriell interface programmed in boot routine and already running -------
// prepare 36kHz for IR - Communication
TCCR2 = (1 << WGM20) | (1 << WGM21) | (1 << COM20) | (1 << COM21) | (1 << CS20);
OCR2 = 0x91; // duty cycle for 36kHz
TIMSK |= (1 << TOIE2); // 36kHz counter for sleep

// prepare RS232
UCSRA = 0x00;
UCSRB = 0x00;
UCSRC = 0x86; // No Parity | 1 Stop Bit | 8 Data Bit
UBRRL = 0xCF; // 2400bps @ 8.00MHz

// I/O Ports
DDRB = IRTX | LEFT_DIR | PWM | GREEN_LED;
//DDRD = RIGHT_DIR | FRONT_LED | ODOMETRIE_LED | RED_LED;

// for PWM (8-Bit PWM) on OC1A & OC1B
TCCR1A = (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1);
// tmr1 running on MCU clock/8
TCCR1B = (1 << CS11);

// A/D Conversion
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // clk/64

MotorDir(FWD,FWD);
MotorSpeed(0,0);
sei();
}

void Sleep(unsigned char time36kHz)
{ unsigned char ziel=(time36kHz+count36kHz) & 0x00FF;
while (count36kHz != ziel);
}

void Msleep(int dauer)
{
while(dauer--) Sleep(36);
}

void SerWrite(unsigned char *data,unsigned char length)
{
unsigned char i = 0;
UCSRB = 0x08; // enable transmitter
while (length > 0) {
if (UCSRA & 0x20) { // wait for empty transmit buffer
UDR = data[i++];
length --;
}
}
while (!(UCSRA & 0x40));
for (i = 0; i < 0xFE; i++)
for(length = 0; length < 0xFE; length++);
}

void PrintInt(int wert)
{ char text[6]=" ";
itoa(wert,text,10);
SerWrite(text,5);
}
void PrintBin(char wert)
{ char text[8]=" ";
itoa(wert,text,2);
SerWrite(text,8);
}

/* Set motor speed */
inline void MotorSpeed(unsigned char left_speed, unsigned char right_speed)
{
OCR1A = left_speed;
OCR1B = right_speed;
}

/* Set motor direction */
inline void MotorDir(unsigned char left_dir, unsigned char right_dir)
{
if(left_dir) PORTB &= ~(1 << PB5); else PORTB |= (1 << PB5);
if(right_dir) PORTB &= ~(1 << PB4); else PORTB |= (1 << PB4);
}
void LineData(unsigned int *data)
{
ADMUX = (1 << REFS0) | IR_LEFT; // AVCC reference with external capacitor
Sleep(10);
ADCSRA |= (1 << ADSC); // Start conversion
while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
data[0] = ADCL + (ADCH << 8);

ADMUX = (1 << REFS0) | IR_RIGHT; // AVCC reference with external capacitor
Sleep(10);
ADCSRA |= (1 << ADSC); // Start conversion
while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete
ADCSRA |= (1 << ADIF); // clear ADCIF
data[1] = ADCL + (ADCH << 8);
}
inline void StatusLED(unsigned char color)
{
if (color == OFF) {GREEN_LED_OFF; RED_LED_OFF;}
if (color == GREEN) {GREEN_LED_ON; RED_LED_OFF;}
if (color == YELLOW) {GREEN_LED_ON; RED_LED_ON;}
if (color == RED) {GREEN_LED_OFF; RED_LED_ON;}
}
void SetLEDs(unsigned char status)
{
status = ~(status<<2); // LEDs sind PD2-7 gegen Vcc schaltend!
PORTD &= status; // nur gesetzte LEDs einschalten
PORTD |= status & ~3; // PD0 und PD1 nicht verändern!
}


Und der aktuelle Header:

// Selbsttest für den asuro-ProBot 22.8.09 mic

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>

#define FALSE 0
#define TRUE 1

#define OFF 0
#define ON 1

#define GREEN 1
#define RED 2
#define YELLOW 3

/* --------------- INTERNAL ------------- */
#define GREEN_LED_OFF PORTD |= GREEN_LED
#define GREEN_LED_ON PORTD &= ~GREEN_LED
#define RED_LED_OFF PORTD |= RED_LED
#define RED_LED_ON PORTD &= ~RED_LED

#define FWD 0
#define RWD 1
#define BREAK 0x00
#define FREE (1 << PB4) | (1 << PB5) /* (1 << PD4) | (1 << PD5)*/

#define IRTX (1 << PB3)
#define GREEN_LED (1 << PD5)
#define RED_LED (1 << PD2)

#define PWM (1 << PB1) | (1 << PB2)
#define RIGHT_DIR (1 << PB4) | (1 << PB5)
#define LEFT_DIR (1 << PD4) | (1 << PD5)

#define BATTERIE (1 << MUX0) | (1 << MUX2) //ADC5
#define SWITCH (1 << MUX2) //ADC4
#define IR_LEFT (1 << MUX0) | (1 << MUX1) //ADC3
#define IR_RIGHT (1 << MUX1) //ADC2

#define Speaker (1 << PD5) // speaker an D14
#define Speaker_on PORTD &= ~(1<<PD5)
#define Speaker_off PORTD |= (1<<PD5)

#define FRONT_LED (1 << PD6)
#define FRONT_LED_on PORTD &= ~(1<<PD6)
#define FRONT_LED_off PORTD |= (1<<PD6)

#define ODOMETRIE_LED (1 << PD7)
#define ODOMETRIE_LED_ON PORTD |= ODOMETRIE_LED
#define ODOMETRIE_LED_OFF PORTD &= ~ODOMETRIE_LED

#define WHEEL_LEFT (1 << MUX0) //ADC1
#define WHEEL_RIGHT 0 //ADC0

#define LED12_on PORTD &= ~(1<<PD2)
#define LED13_on PORTD &= ~(1<<PD3)
#define LED14_on PORTD &= ~(1<<PD5) // Achtung Reihenfolge D14/15 getauscht!
#define LED15_on PORTD &= ~(1<<PD4)

#define LED12_off PORTD |= (1<<PD2)
#define LED13_off PORTD |= (1<<PD3)
#define LED14_off PORTD |= (1<<PD5)
#define LED15_off PORTD |= (1<<PD4)


Gruß

mic

ElchiMtr
28.08.2009, 16:33
Danke sehr ich glaube ich habs jetzt verstanden