Forum: Mikrocontroller und Digitale Elektronik Seltsames Verhalten - Arduino


von Joh (Gast)


Lesenswert?

Hallo zusammen,

ich sitze seit fast zwei Stunden hier und finde den Fehler nicht, 
weshalb ich nun die letzte Instanz (nämlich dieses Forum) gewählt habe, 
um meinen Fehler zu finden.

Es geht darum, zwei DC-Motoren anzusteuern (H-Brücke), das Ganze 
funktioniert auch hardcodiert einwandfrei, wenn ich meinen Arduino Nano 
flashe, und mittels H-Brücke die angeschlossenen Motoren ansteuere.

Siehe Code:
1
#define BAUDRATE 9600
2
3
#define BRAKEVCC                  0
4
#define CLOCKWISE                 1                                                                         // Clockwise (im Uhrzeigersinn)
5
#define COUNTERCLOCKWISE          2                                                                         // Counterclockwise (gegen den Uhrzeigersinn)
6
#define BRAKEGND                  3
7
#define CS_THRESHOLD              15                                                                         // Safety current 
8
#define CLOCKWISE_MOTOR_0         9                                                                          // Pin am Arduino, der die Drehrichtung von Motor_0 im Uhrzeigersinn festlegt
9
#define CLOCKWISE_MOTOR_1         7                                                                          // Pin am Arduino, der die Drehrichtung von Motor_1 im Uhrzeigersinn festlegt
10
#define COUNTERCLOCKWISE_MOTOR_0  8                                                                          // Pin am Arduino, der die Drehrichtung von Motor_0 gegen den Uhrzeigersinn festlegt
11
#define COUNTERCLOCKWISE_MOTOR_1  6                                                                          // Pin am Arduino, der die Drehrichtung von Motor_1 gegen den Uhrzeigersinn festlegt
12
#define PWM_SIGNAL_MOTOR_0        11                                                                         // Pin am Arduino, der das PWM-Signal für Motor_0 ausgibt
13
#define PWM_SIGNAL_MOTOR_1        10                                                                         // Pin am Arduino, der das PWM-Signal für Motor_1 ausgibt
14
#define PIN_ADC_JOYSTICK_X        A5                                                                         // Pin am Arduino, an den der Joystick (X-Achse) angeschlossen ist
15
#define PIN_ADC_JOYSTICK_Y        A6                                                                         // Pin am Arduino, an den der Joystick (Y-Achse) angeschlossen ist   
16
17
   
18
uint8_t PIN_CLOCKWISE_DIR[2] = { CLOCKWISE_MOTOR_0, CLOCKWISE_MOTOR_1 };
19
uint8_t PIN_COUNTERCLOCKWISE_DIR[2] = { COUNTERCLOCKWISE_MOTOR_0, COUNTERCLOCKWISE_MOTOR_1 };
20
uint8_t PWM_SIGNALS[2] = { PWM_SIGNAL_MOTOR_0, PWM_SIGNAL_MOTOR_1 };
21
22
uint8_t STATUS_LED = 13;
23
24
25
void setup() 
26
{
27
    Serial.begin(BAUDRATE);                                                                                    // Baudrate für Terminalprogramm
28
    pinMode(STATUS_LED, OUTPUT);                                                                               // Status-LED am Arduino Nano initialisieren (dig. Ausgang)
29
    
30
    pinMode(PIN_CLOCKWISE_DIR[0], OUTPUT);                                                                     // setzt entsprechende Pins des Arduinos auf "Ausgang"...
31
    pinMode(PIN_COUNTERCLOCKWISE_DIR[0], OUTPUT);
32
    pinMode(PWM_SIGNALS[0], OUTPUT);
33
    pinMode(PIN_CLOCKWISE_DIR[1], OUTPUT);
34
    pinMode(PIN_COUNTERCLOCKWISE_DIR[1], OUTPUT);
35
    pinMode(PWM_SIGNALS[1], OUTPUT);
36
37
    digitalWrite(PIN_CLOCKWISE_DIR[0], LOW);                                                                   // setzt sämtliche Drehrichtungs-Zustände auf "Low"...
38
    digitalWrite(PIN_COUNTERCLOCKWISE_DIR[0], LOW);
39
    digitalWrite(PIN_CLOCKWISE_DIR[1], LOW);
40
    digitalWrite(PIN_COUNTERCLOCKWISE_DIR[1], LOW); 
41
42
    
43
}
44
45
46
void loop()
47
{
48
   /*        Derzeit auskommentiert, hier funktioniert alles einwandfrei!
49
    motorGo(0,CLOCKWISE,128);
50
    motorGo(1,CLOCKWISE,128);
51
    delay(5000);
52
   */
53
     
54
   if( get_X_from_Joystick() <= 518 )                                           // wenn eingelesene X-Achse vom Joystick nach "links" geht,....
55
   {
56
        
57
        motorOff(1);                                                            // ...stoppe linken Motor....                 
58
59
        unsigned int y =  518 - get_X_from_Joystick();
60
        unsigned int pwm_signal = y/4;
61
        Serial.println(y);                              
62
        motorGo(0,CLOCKWISE,pwm_signal);                                               // ...stelle Drehzahl des rechten Motors entsprechend der Position des Potis
63
        Serial.println("PWM: ");
64
        Serial.println(pwm_signal);
65
        
66
        if( get_Y_from_Joystick() >= 526 )                                      // Wenn gleichzeitig beim nach "links" drücken des Joysticks der Joystick nach "vorne" geschoben wird....
67
        { 
68
            motorGo(1,COUNTERCLOCKWISE,(get_X_from_Joystick() / 4));            // ...schalte zusätzlich den linken Motor entsprechend der Y-Position des Joysticks
69
        }
70
   }
71
}
Die beiden Motoren werden über einen Joystick gesteuert. Schiebe ich den 
Joystick ganz nach links, erhalte ich einen ADC-Wert von annähernd 0.
Schiebe ich den Joystick ganz nach rechts, erhalte ich entsprechend 
einen ADC-Wert von annähernd 1023. In der Mittelstellung 
("Leerlaufposition" des Joysticks) erhält man demnach einen Wert von 
ungefähr 528.
Die Werte stimmen auch via Terminalausgabe korrekt überein, die mir der 
Arduino auch wunderbar ausgibt ("Serial.println()"), allerdings 
übernimmt der Arduino irgendwie nicht die Werte, die er vom ADC 
(Joystick) eingelesen hat, wenn er die Funktion "motorGo(...)" aufruft.
Kodiere ich (wie ganz am Anfang der loop()-Funktion) einen festen 
PWM-Wert, wird auch alles korrekt angesteuert (derzeit auskommentiert).

Warum aber steuert der Arduino denn nicht mittels "motorGo(...);" den 
Motor entsprechend an, wenn ich den Joystick bewege?

Das Ganze funktioniert wiegesagt einwandfrei, solange man den PWM-Wert 
"hardkodiert" der Funktion als Argument übergibt.

Hier der Code der Funktion motorGo():
1
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2
// Schaltet den entsprechenden Motor ein:  Motor(0 oder 1), Richtung (CLOCKWISE oder COUNTERCLOCKWISE) und PWM-Tastverhältnis (0..255)
3
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
4
void motorGo(uint8_t motor, uint8_t dir, unsigned int pwm)         
5
{
6
    if (motor <= 1)
7
    {
8
        if (dir <=4)
9
        {
10
                if (dir <= 1)
11
                {
12
                    digitalWrite(PIN_CLOCKWISE_DIR[motor], HIGH);
13
                }
14
              
15
                else
16
                {            
17
                    digitalWrite(PIN_CLOCKWISE_DIR[motor], LOW);
18
                }
19
                
20
                if ((dir == 0)||(dir == 2))
21
                {
22
                   digitalWrite(PIN_COUNTERCLOCKWISE_DIR[motor], HIGH);
23
                }
24
                
25
                else
26
                {
27
                   digitalWrite(PIN_COUNTERCLOCKWISE_DIR[motor], LOW);
28
                }
29
            
30
                analogWrite(PWM_SIGNALS[motor], pwm);
31
        }
32
   }
33
}
Das Terminal gibt auch die richtigen PWM-Werte aus, die ich der Funktion 
übergebe. Warum aber steuert der Arduino kein PWM-Signal an die H-Brücke 
aus, in Abhängigkeit von der Joystick-Bewegung "nach links"?
"motorOff(...)" schaltet einfach den jeweiligen Motor aus.

Ich hoffe, ich konnte mich entsprechend ausdrücken.

Bei Fragen stehe ich jederzeit zur Verfügung.

Das Projekt betrifft den "motorisierten Kinderwagen", deshalb zwei 
Motoren zum Lenken, die über einen Joystick gesteuert werden sollen.


Vielen Dank schon mal!


Grüße

von STK500-Besitzer (Gast)


Lesenswert?

erst fragst du ab, ob der Wert kleiner oder gleich 518 ist, um das eine 
zu tun, und später dann, ob er größer als 526 ist. Das kann aber nie 
wahr sein, da er die Abfrage nur erreicht, wenn der Wert kleiner als 518 
ist.
Du musst die beiden Abfragen entkoppeln, also nacheinander ausführen.

von Joh (Gast)


Lesenswert?

>Du musst die beiden Abfragen entkoppeln, also nacheinander ausführen.
Das verstehe ich nicht ganz, denn wenn er an die Codestelle nicht 
hinkäme, warum führt er den darüber/darunterliegenden Befehl mit 
"Serial.println(..);" aus und nicht den motorGo()   ?

von Wolfgang (Gast)


Lesenswert?

Joh schrieb:
> unsigned int y =  518 - get_X_from_Joystick();

Joh schrieb:
> allerdings übernimmt der Arduino irgendwie nicht die Werte, die er vom ADC
> (Joystick) eingelesen hat, wenn er die Funktion "motorGo(...)" aufruft.

Was heißt "übernimmt der Ardnuino nicht". Der ist doch nicht plötzlich 
schreibgeschützt ;-)

Allerdings können bei denem Programm Joystickpositionen über 518 nicht 
richtig funbktionieren. 0 ist die kleinste Zahl, die in dein y 
reinpasst.

von Jan L. (ranzcopter)


Lesenswert?

STK500-Besitzer schrieb:
> erst fragst du ab, ob der Wert kleiner oder gleich 518 ist, um das eine
> zu tun, und später dann, ob er größer als 526 ist. Das kann aber nie

1. get_X_from_Joystick()
2. get_Y_from_Joystick()

warum sollte das "nie erreicht werden"? es sind 2 verschiedene Werte, 
warum auch immer... (ich hätte auch angenommen, dass der Joystick nur 
auf einer Achse benutzt wird)

von Joh (Gast)


Lesenswert?

>(ich hätte auch angenommen, dass der Joystick nur
>auf einer Achse benutzt wird)

Nein, denn ich möchte damit ja "vorwärts"/"rückwärts" und gleichzeitig 
"links/"rechts" steuern.

Auf der Y-Achse verhält sich der Wertebereich übrigens im selbigen.

von Stefan F. (Gast)


Lesenswert?

Kann es sein, dass du da x und y durcheinandergebracht hast?

Außerdem solltest du mal genau die Werte ausgeben, die du mit if 
überprüfst und an motorGo übergibst.
1
Serial.println(whatever);
2
if( whatever >= 526 ) 
3
{ 
4
    unsigned int motorValue=get_X_from_Joystick() / 4;
5
    Serial.println(motorValue);
6
    motorGo(1,COUNTERCLOCKWISE,motorValue);
7
}

von Joh (Gast)


Lesenswert?

>Kann es sein, dass du da x und y durcheinandergebracht hast?

>Außerdem solltest du mal genau die Werte ausgeben, die du mit if
>überprüfst und an motorGo übergibst.

>Serial.println(whatever);
>if( whatever >= 526 )
>{
>    unsigned int motorValue=get_X_from_Joystick() / 4;
>    Serial.println(motorValue);
>    motorGo(1,COUNTERCLOCKWISE,motorValue);
>}


Ich überprüfe ja die Werte per Terminal. Terminal liefert die korrekten 
Werte, während ich den Joystick bewege, der Arduino "schickt" aber 
leider nicht das entsprechende Tastverhältnis an die H-Brücke.

Die unterste If-Anweisung kann übrigens bzgl. "Logik" vernachlässigt 
werden.
Das Entscheidende liegt in der motorGo() in der if-Anweisung zwischen 
den beiden Serial.println().


Grüße und danke für eure rege Hilfe.

von HG (Gast)


Lesenswert?

nimm das motoroff() aus der schleife raus. Du rechnest rum, setzt in 
Motorgo() den motor, und nach dem return aus der Funktion wird beim 
nächsten Schleifendurchlauf der Motor sofort wieder ausgeschaltet.

Ausserdem : Im auskommentierten Text schaltest du Motor 0 und 1 ein, im 
jetzigen Programm geht aber alles auf Motor 1. Ist evtl. der Motor an 
den falschen Anschlüssen?

von Joh (Gast)


Lesenswert?

>nimm das motoroff() aus der schleife raus.

motoroff() schaltet den Motor-1 ab. Motor-1 befindet sich auf der linken 
Seite, Motor-0 auf der Rechten.
Möchte ich also nach links fahren (Joystick nach ganz links, während 
Y-Achse des Joysticks==0), schaltet/blockiert der Motor-1 und es dreht 
nur Motor-0.
Das ist von Nöten, damit nur der Rechte dreht, sodass man damit 
"elektrisch lenkend" um die Kurve kommt (Heckantrieb).

>und nach dem return aus der Funktion wird beim
>nächsten Schleifendurchlauf der Motor sofort wieder ausgeschaltet
Das return liefert nur einen Wert, der dem der Achse entsprechenden 
Wertes entspricht.
Mehr macht diese Funktion ja nicht, als das Poti des Joysticks über den 
ADC einzulesen um dann diesen Wert "gewandelt" als PWM-Wert 
(Tastverhältnis) zu übergeben.

>Im auskommentierten Text schaltest du Motor 0 und 1 ein, im
>jetzigen Programm geht aber alles auf Motor 1.

Dann sollte sich aber doch wenigstens einer der beiden angeschlossenen 
Motoren bewegen, die das ja auch tun, wenn ich die ersten Zeilen der 
loop() in den Code nehme. ;-)
Verdrahtungsfehler kann ich somit ausschließen, und es soll ja 
tatsächlich nur der eine Motor drehen, während der andere blockiert (a 
la Panzer-Lenkungsprizip).


Grüße

von Wolfgang (Gast)


Lesenswert?

Joh schrieb:
> Ich überprüfe ja die Werte per Terminal. Terminal liefert die korrekten
> Werte, während ich den Joystick bewege, der Arduino "schickt" aber
> leider nicht das entsprechende Tastverhältnis an die H-Brücke.

Jetzt mal Butter bei die Fische:
Angenommen dein Joystick liefert einen hohen Wert (bspw. 900), welchen 
Wert besitzt dann pwm in motorGo() und welchen Wert erwartest du?

von Joh (Gast)


Lesenswert?

>Angenommen dein Joystick liefert einen hohen Wert (bspw. 900)
Tut er ja nicht, sonst bekäme ich ja auch nicht die Ausgabe via Terminal 
mit der vorangehenden If-Anweisung "if( get_X_from_Joystick() <= 518 )", 
weshalb ich ja sagte, dass die Terminal-Ausgaben korrekt sind, aber 
nicht durch "motorGo()" angenommen werden.
Wäre der Wert > 900, käme er ja garnicht in die If-Anweisung.
Da ich aber den Joystick "ganz nach links drücke" und somit der zu 
übergebende Wert 128 entspricht, sollte sich der Motor bewegen.
Zumindest sehe ich das so...

von HG (Gast)


Lesenswert?

ok, das MotorOn(0,..) hatte ich übersehen. So sollte ja zumindest Motor 
0 laufen.

Ist die Portzuordnung richtig, nicht das du z. B. die Richtung von Motor 
0 setzt und PWM von Motor 1? Ansonsten sollte ja, wenn Joystick X einen 
Wert nahe 0 liefert, motorGo(0,CLOCKWISE,129) ausgeführt werden, was ja 
ziemlich genau dem auskommentierten Aufruf entspricht.

von Arno (Gast)


Lesenswert?

...und bist du sicher, dass
1
motorOff(1)
 nur einen der beiden Motoren abschaltet? Nimm es doch mal (testweise) 
raus oder bau es in deinen derzeit auskommentierten Testcase mit ein.

Wird in motorGo irgendwas aktiviert, das nicht beliebig schnell 
hintereinander aufgerufen werden darf? In deinem Testcase hast du ja ein 
5-Sekunden-Delay, bevor wieder ein motorGo auf dem gleichen Motor 
aufgerufen wird.

MfG, Arno

von Johann Haller (Gast)


Lesenswert?

Hi,
wo ist denn die Funktion getXFromJoystick()?

Zur Sicherheit würde ich am Anfang der loop den Wert auslesen und 
speichern
uint16_t x = getXFromJoystick();
Hat sich der Wert geändert von der einen Abfage zur nächsten, kann es 
sein, dass der Wert > 518 ist und deine Rechnung 518-neuer Wert einen 
Überlauf ergibt.

1. uint16_t x = getXfromJoystick();
if (500 <= x && 600 >= x)
{
//Motor stopp
}
else if(500 > x)
{
//Motor links
}
else if (600 < x && 1023 >= x)
{
//motor rechts
}
else
{
//error
}

von Joh (Gast)


Lesenswert?

>Ist die Portzuordnung richtig, nicht das du z. B. die Richtung von Motor
>0 setzt und PWM von Motor 1?
Dann würde auch das Auskommentierte nicht richtig funktionieren, wenn da 
eine Port-Zuordnung inkorrekt wäre, was es aber tut. -Nämlich richtig zu 
funktionieren.

>Ansonsten sollte ja, wenn Joystick X (...)
Ja genau so sehe ich das auch! :-) Das ist ja genau das Problem.




>nur einen der beiden Motoren abschaltet? Nimm es doch mal (testweise)
>raus oder bau es in deinen derzeit auskommentierten Testcase mit ein.

Ich habe vorher in der Loop(), bevor ich das ganze If-Gedönse 
programmiert habe, mit motorOff() beide Motoren korrekt abgeschaltet und 
anschließend durch motorGo() während der Laufzeit des Programms auch 
wieder korrekt eingeschaltet...und wieder ausgeschaltet...und wieder 
eingeschaltet.
somit kann ich ausschließen, dass motorOff() nicht nur einen/keinen/den 
"falschen" Motor ausschaltet.

Diese 5 Sekunden habe ich übrigens selbst eingebaut, damit ich sehe, ob 
mein geflashtes Programm auch tatsächlich auf dem Chip gelandet ist ;-)
Da standen auch schon "1 Sekunde" und "500 ms" drin, was dem Ganzen 
somit keinen Abbruch getan hat.

Grüße und wiedermals: Danke schonmal für eure Mühe! Ich bin froh, dass 
ihr mir helft!

von Joh (Gast)


Lesenswert?

Hier noch der Code von get_X_from_Joystick()   :

Die get_Y_ .. verhält sich entsprechend äquivalent.
1
unsigned int get_X_from_Joystick()
2
{
3
    unsigned int value = analogRead(PIN_ADC_JOYSTICK_X);
4
    return value;
5
}

von Arno (Gast)


Lesenswert?

Joh schrieb:
>>Ist die Portzuordnung richtig, nicht das du z. B. die Richtung
> von Motor
>>0 setzt und PWM von Motor 1?
> Dann würde auch das Auskommentierte nicht richtig funktionieren, wenn da
> eine Port-Zuordnung inkorrekt wäre, was es aber tut. -Nämlich richtig zu
> funktionieren.

Nein, bei dem auskommentierten Code startest du ja beide Motoren. Also 
falls du z.B. die Richtung von Motor 0 und 1 verwechselst, wäre nach dem 
ersten motorGo(0) die Richtung von Motor 1 und die PWM von Motor 0 
korrekt, nach dem zweiten motorGo(1) stimmt auch die Richtung von Motor 
0 und die PWM von Motor 1, nach beiden Aufrufen drehen sich also beide 
Motoren...

Oder hast du das auch einzeln probiert?

MfG, Arno

von HG (Gast)


Lesenswert?

Joh schrieb:
> Dann würde auch das Auskommentierte nicht richtig funktionieren, wenn da
> eine Port-Zuordnung inkorrekt wäre, was es aber tut. -Nämlich richtig zu
> funktionieren.

im auskommentierten Testcode schaltest du aber beide Motoren 
gleichzeitig, im fertigen Programm aber Motor 0 und 1 unabhängig, und 
Motor 1 immer wieder aus. Klappt denn der Testfall auch wenn du nur 
einen der MotorOn-Aufrufe ausführst?

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Joh schrieb:
> Das Terminal gibt auch die richtigen PWM-Werte aus, die ich der Funktion
> übergebe. Warum aber steuert der Arduino kein PWM-Signal an die H-Brücke
> aus, in Abhängigkeit von der Joystick-Bewegung "nach links"?
> "motorOff(...)" schaltet einfach den jeweiligen Motor aus.

 Bist du sicher, dass es so richtig ist ?
1
                if (dir <= 1)
2
                {
3
                    digitalWrite(PIN_CLOCKWISE_DIR[motor], HIGH);
4
                }
5
                else
6
                {            
7
                    digitalWrite(PIN_CLOCKWISE_DIR[motor], LOW);
8
                }
9
10
                if ((dir == 0)||(dir == 2))
11
                {
12
                   digitalWrite(PIN_COUNTERCLOCKWISE_DIR[motor], HIGH);
13
                }
14
                else
15
                {
16
                   digitalWrite(PIN_COUNTERCLOCKWISE_DIR[motor], LOW);
17
                }

 Probiere es mal mit dir = 1.

von Joh (Gast)


Angehängte Dateien:

Lesenswert?

Hier ein Screenshot mit Code und Terminal (siehe Anhang).

Ich habe auch in der goMotor() den Wert auf "1" geändert, was zu keinem 
brauchbaren Ergebnis führte.

von HG (Gast)


Lesenswert?

Probier als Testprogramm mal nur das in der loop():

    motorOff(0);
    motorOff(1);

    motorGo(0,CLOCKWISE,129);
    delay(5000);
    motorOff(0);
    delay(5000);
    motorGo(0,COUNTERCLOCKWISE,129);
    delay(5000);
    motorOff(0);
    delay(5000);

    motorGo(1,CLOCKWISE,129);
    delay(5000);
    motorOff(1);
    delay(5000);
    motorGo(1,COUNTERCLOCKWISE,129);
    delay(5000);
    motorOff(1);
    delay(5000);

Damit sollte Motor 0 ja 5 sek vorwärts laufen, dann 5 sek aus bleiben, 
dann 5 sek rückwärts laufen und wieder 5 sek pause. Ich hab mal 129 als 
PWM-Wert genommen weil das ja im seriellen protokoll auch verwendet 
wird.

Danach passiert dasselbe für Motor 1.

Wenn das klappt sind die motorOn und motorOff-Prozeduren erstmal in 
Ordnung.

von Joh (Gast)


Lesenswert?

Aha, ändere ich in der If-Anweisung den Aufruf der motorGo() auf 
"COUNTERCLOCKWISE" um, kommt zumindest beim Betätigen des Joysticks 
"nach links" ein PWM-Signal an. Drehen tut jedoch keiner der Motoren.

von Joh (Gast)


Lesenswert?

>Wenn das klappt sind die motorOn und motorOff-Prozeduren erstmal in
>Ordnung.

Dein "Programm" funktioniert tadellos. Genau wie du es beschreibst, 
verhalten sich die Motoren, nachdem ich es in die loop() kopiert habe.

von HG (Gast)


Lesenswert?

Dann poste bitte nochmal die komplette Loop() mit den Joystickabfragen, 
im letzten Bildschirmdruck steht ja mehr als im ersten Programmlisting.

von Joh (Gast)


Angehängte Dateien:

Lesenswert?

Ich poste hiermit die komplette Quellcode-Datei:

(siehe Anhang)

von Joh (Gast)


Lesenswert?

Jetziger Status wie im Listing:
Motor "knackert" bzw. PWM-Signal kommt an Motor-1 an, wenn ich den 
Joystick bewege. Das ist schon mal "mehr" als vorher.
Leider bewegt sich Motor-1 trotzdem keinen Ruck.
Kommentiere ich die If-Anweisung nach dem ersten motorGo() aus ("
        if( get_Y_from_Joystick() >= 526 )    "), kommt auch kein 
PWM-Signal mehr an der H-Brücke an, was ich ebenfalls nicht verstehe.

Wiegesagt, dein Programm lief einwandfrei.

von HG (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab die Loop() mal was geändert:

1. die Joystickpositionen werden nur einmal pro Schleife gelesen, damit 
kann es keine inkonsistenten Zustände geben wenn sich die 
Joystickposition während eines Schleifendurchlaufs ändert.

2. am Ende der else-pfad war verkehrt, dieses else bezieht sich nur auf 
das zweite if. Dadurch wurden die Motoren sofort wieder ausgeschaltet 
wenn  'if( get_X_from_Joystick() >=538 )' nicht erfüllt war, also immer 
dann wenn die erste if-Bedingung true war.

von Cyborg (Gast)


Lesenswert?

Warum nutzt du keinen Debugger? Forum bequemer?

von HG (Gast)


Lesenswert?

Mir ist doch noch was aufgefallen:

in der motorOff-Prozedur schaltest du die Richtungs-Pins beider Motoren 
aus, und dann die PWM des übergebenen Motors. Du solltest da aber nur 
den übergebenen Motor ändern, damit der andere Motor weiterlaufen kann.

von Joh (Gast)


Lesenswert?

@HG:
Danke für deine Mühe!

Ich schaue es mir an und berichte.
Jetzt ist leider mein Nano abgebrannt, da ich mich auf dem Steckbrett 
"versteckt" habe, vor lauter Aufregung.

Es funktioniert nun alles soweit, die Motoren hörten auf die 
Joystick-Befehle.

von Johann Haller (Gast)


Lesenswert?

Ein kleiner Tipp noch wg übersichtlichkeit:
mach für jeden motor ne eigene funktion, wenn du das nicht um weitere 
motoren ergänzen willst. Macht den code nicht schneller, aber besser zu 
lesen, wenn ein x motor und ein y motor da ist.

x = readJoyX();
y = reayJoyY();
handleMotorX();
if( x < wert){
handleMotorY();
}

von Stefan F. (Gast)


Lesenswert?

> Warum nutzt du keinen Debugger?

Bei Arduino ist das nicht vorgesehen. Daher auch mein Tipp, die 
Logmeldungen zu verbessern.

von Joh (Gast)


Angehängte Dateien:

Lesenswert?

Also danke erstmal für eure Hilfe!

Wiegesagt, als letztes hat der Code so funktioniert wie er sollte, ich 
habe dann nur noch mit CLOCKWISE und COUNTERCLOCKWISE herumgespielt.

Dummerweise vergaß ich, die Versorgungsspannung abzuklemmen, als ich den 
Arduino aus dem Sockel auf meiner Leiterplatte gezogen habe und ihn dann 
während die Versorgungsspannung an der Leiterplatte anlag wieder 
reingesteckt.

Daraufhin hat es in einer "Ecke" des kleinen ATmega ordentlich geblitzt 
und geraucht.

Frage: Kann das mit der Software zusammenhängen? Oder lag es schlichtweg 
daran, dass ich den Arduino im laufenden Betrieb in den Sockel der 
Leiterplatte steckte?

Hier nochmal mein komplettes Listing im Anhang, welches das 
"Platinen-Gewitter" verursachte...

Gruß

von Stefan F. (Gast)


Lesenswert?

> Daraufhin hat es in einer "Ecke" des kleinen ATmega ordentlich
> geblitzt und geraucht.

> Kann das mit der Software zusammenhängen?

Ich glaube, du hast zu viel Star Trek geschaut. Da blitzt und raucht die 
Elektronik auch andauernd ohne kaputt zu gehen.

von HG (Gast)


Lesenswert?

Joh schrieb:
> Frage: Kann das mit der Software zusammenhängen? Oder lag es schlichtweg
> daran, dass ich den Arduino im laufenden Betrieb in den Sockel der
> Leiterplatte steckte?

Das wird nicht an der Software liegen, sondern am Einstecken bei 
eingeschalteter Spannung.

von Joh (Gast)


Lesenswert?

Hallo zusammen.

Ich habe es heute mit einem neuen Arduino versucht, hochgeladen habe ich 
zuletzt den von mir hier zuletzt hochgeladenen Code.

Das Bluetooth-Modul scheint seit dem letzten "Aufblitzen" des alten 
Arduino-Boards geschossen zu sein.
Komisch ist auch, dass über das Terminal nichts ausgegeben wird, wenn 
ich den Joystick in die besagte Position bewege. Das Motormodul wird 
jedoch richtig angesteuert, sodass sich einer der beiden Motoren 
entsprechend der Knüppelposition "nach links" bewegt. Der andere Motor 
dreht jedoch nicht, wenn ich den Knüppel "nach vorne" drücke.

1) Wie kann es sein, dass Serial.println() nicht mehr den AD-Wert im 
Terminal ausgibt, seitdem ich den neuen Arduino verwende?
2) Wie kann es sein, dass das Bluetooth-Modul nun auch nicht mehr 
reagiert/vermutlich kaputt ist?


Hier nochmal der Code im Anhang:
https://www.mikrocontroller.net/attachment/highlight/324132

von Stefan F. (Gast)


Lesenswert?

Komplexe Probleme zerlegt man in viele kleine einfache.

Sowohl das Blutooth Modul als auch die Funktion serial.println() kannst 
du einzeln mit einem minimalen Testprogramm überprüfen. Wenn das klappt, 
wird dein Anwendungsprogramm die Fehlerursache sein.

von Joh (Gast)


Lesenswert?

Nachtrag:
Die "Serial.println()"-Methoden wurden bei mir im Programm vor dem 
Flashen natürlich ent-kommentiert, sodass sie somit während der Laufzeit 
eine Terminalausgabe liefern sollten.

von Joh (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

ich muss euch nochmal fragen, wegen meiner Joystick-Problematik zum 
genannten Projekt.

Der Joystick wird nach links bewegt, und der MOTOR_RECHTS wird 
angesteuert so wie er soll. Je nach Intensität des "nach links-Drückens" 
wird der Motor entsprechend mit der PWM angesteuert. Soweit so gut.

Jetzt habe ich versucht, dass wenn man den Joystick gleichzeitig wenn 
man ihn nach "vorne" drückt, der zweite Motor (MOTOR_LINKS) entsprechend 
der Intensität des "nach vorne-Drückens" per PWM angesteuert wird. 
(siehe Anhang)

Dies funktioniert aber nicht. MOTOR_RECHTS tut was er soll, MOTOR_LINKS 
macht keinen Mucks. Auch nicht, wenn ich den Knüppel nur nach vorne 
schiebe...aber das kommt später.

Nun eine kleine "Skizze", welche AD-Werte man geliefert bekommt, wenn 
man nach links/rechts bzw vor/zurück den Joystick bewegt:

          1020
           ^
           |
           |
           |
0 <------ 516 -----> 1020
           |
           |
           |
           0


In den If-Anweisungen habe ich eine kleine Toleranz eingebaut, da die 
Mittelstellung des Joysticks nicht immer exakt "516" liefert.

Irgendwo habe ich da wohl noch einen Denkfehler...

Hier der Code der besagten Abfragen:
1
void loop()
2
{
3
   if( get_X_from_Joystick() <= 518 )                                                                          // wenn eingelesene X-Achse vom Joystick nach "links" geht,....
4
   {
5
        unsigned int x =  518 - get_X_from_Joystick();
6
        unsigned int pwm_signal_x = (x/4);
7
                                    
8
        motorGo(MOTOR_RECHTS,COUNTERCLOCKWISE,pwm_signal_x);                                                   // ...stelle Drehzahl des rechten Motors entsprechend der Position des Potis
9
        Serial.println("X-PWM: ");
10
        Serial.println(pwm_signal_x);
11
12
    
13
        if( get_Y_from_Joystick() >= 526 )                                                                     // Wenn gleichzeitig beim nach "links" drücken des Joysticks der Joystick nach "vorne" geschoben wird....
14
        { 
15
              Serial.println("JETZT Y!");
16
              unsigned int diff = 504;
17
              float faktor = 0.5;
18
              unsigned int pwm_signal_y = faktor * 256;
19
              Serial.println("Y-PWM: ");
20
              Serial.println(pwm_signal_y);
21
              motorGo(MOTOR_LINKS,COUNTERCLOCKWISE,pwm_signal_y);                                              // ...schalte zusätzlich den linken Motor entsprechend der Y-Position des Joysticks
22
        }
23
   }


Könnt ihr mir auf die Sprünge helfen, warum der MOTOR_LINKS nicht 
anläuft, obwohl im Terminal die richtigen AD-gewandelten Y-Werte 
ausgegeben werden, die ich dann der motorGo()-Funktion übergebe?


Vielen Dank!

von Stefan F. (Gast)


Lesenswert?

Erzähle uns erstmal, welche Ausgaben du im fehlerfall von

> Serial.println("JETZT Y!");
> Serial.println("Y-PWM: ");

zu sehen bekommst.

von Joh (Gast)


Lesenswert?

Hallo Stefan,

>Erzähle uns erstmal, welche Ausgaben du im fehlerfall von

Die Ausgaben sind im angehängten Screenshot im Terminal zu sehen.


Ich habe meinen Code ein wenig erweitert, sodass nun das "nur nach 
vorwärts-Drücken" zumindest einigermaßen funktioniert. Nach "10 Uhr" 
drücken funktioniert aber nach wie vor nicht.
Bei "nur nach vorne" drücken (weder nach links noch nach rechts) laufen 
zwar beide Motoren an (siehe Code), jedoch gehen sie auf volle Leistung 
ganz am Anfang, wenn ich den Joystick nur ganz leicht nach vorne drücke. 
Danach lassen sich beide Motoren parallel abhängig von der Intensität 
des nach Vornedrückens drehzahlsteuern.

Hier der aktualisierte Code. Im alten Code habe ich gesehen, dass 
keinerlei Bezug zur aktuellen X-Position des Joysticks implementiert 
war. Dies habe ich nun nach meinem Dafürhalten entsprechend abgeändert. 
Es führt aber dennoch zu keinem Ergebnis, wenn ich den Joystick nach 
links und gleichzeitig nach "oben" drücke (ein Motor bleibt immer 
"AUS").
1
void loop()
2
{
3
   if( get_X_from_Joystick() <= 518 )                                                                          // wenn eingelesene X-Achse vom Joystick nach "links" geht,....
4
   {
5
        unsigned int x =  518 - get_X_from_Joystick();
6
        unsigned int pwm_signal_x = (x/4);
7
                                    
8
        motorGo(MOTOR_RECHTS,COUNTERCLOCKWISE,pwm_signal_x);                                                   // ...stelle Drehzahl des rechten Motors entsprechend der Position des Potis
9
        Serial.println("X-PWM: ");
10
        Serial.println(pwm_signal_x);
11
12
    
13
        if( get_Y_from_Joystick() >= 526 )                                                                     // Wenn gleichzeitig beim nach "links" drücken des Joysticks der Joystick nach "vorne" geschoben wird....
14
        { 
15
              Serial.println("JETZT Y!");
16
              unsigned int diff = 504;
17
              float faktor = 0.5;
18
              unsigned int pwm_signal_y = (faktor * get_Y_from_Joystick())-384;
19
              Serial.println("Y-PWM: ");
20
              Serial.println(pwm_signal_y);
21
              motorGo(MOTOR_LINKS,COUNTERCLOCKWISE,pwm_signal_y);                                              // ...schalte zusätzlich den linken Motor entsprechend der Y-Position des Joysticks
22
        }
23
   }
24
25
26
   
27
   if( (  (get_X_from_Joystick() >=510) | (get_X_from_Joystick() <=526)) & (get_Y_from_Joystick() >=566 ))        // wenn Joystick nur nach vorne geht und nicht nach links oder rechts....
28
   {
29
        float faktor = 0.5;
30
        unsigned int pwm_signal_y = (faktor * get_Y_from_Joystick())-384;
31
        Serial.println("JETZT NUR Y!");
32
        motorGo(MOTOR_LINKS,CLOCKWISE,pwm_signal_y);                                                          // ...stelle Drehzahl des linken Motors entsprechend der Position des Potis
33
        motorGo(MOTOR_RECHTS,COUNTERCLOCKWISE,pwm_signal_y);
34
   }

Danke und Gruß

von myasuro (Gast)


Lesenswert?

Also wenn du die Bewegung überlagern willst, geht's am besten wenn du 
die 2 Bewegungen zuerst einzeln berechnest und dann vereinst (da kommen 
jetzt halt die Vorlieben von dir vor:
a) y Achse gibt Drehrate vor
b) y Achse gibt Kurvenradius vor
c) ...
)

von Joh (Gast)


Lesenswert?

Ich möchte halt "einfach" folgendes Szenario implementieren:

 - Wenn NUR nach links gedrückt wird (ohne nach "oben"), soll ein Motor 
stillstehen und nur ein Motor drehen (der Rechte)
 - Wenn WÄHREND links gedrückt wird nach oben gedrückt wird, sollen 
beide Motoren entsprechend X-/Y-AD-Wert laufen
 - Szenario für rechts/rechts+runter/nur runter ensprechend Punkt 1) und 
2)

Gruß

von Joh (Gast)


Lesenswert?

Ich hoffe, ihr könnt mir noch irgendwie weiterhelfen. Ansonsten werde 
ich mal das spezielle Problem in einem neuen Beitrag eröffnen (auch wenn 
mich dafür der Admin hier im Forum hassen wird) ;-)

Grüße und Danke, dass ihr stets Ohr seid!
Joh

von Stefan F. (Gast)


Lesenswert?

Kann es sein, dass du einen Kurzschluss zwischen zwei Leiterbahnen hast?

Teste mal folgendes
1
void loop()
2
{
3
   Serial.println("A");
4
   motorGo(MOTOR_LINKS,CLOCKWISE,100); 
5
   motorGo(MOTOR_RECHTS,CLOCKWISE,100);
6
   delay(2000);
7
8
   Serial.println("B");
9
   motorGo(MOTOR_LINKS,COUNTERCLOCKWISE,100); 
10
   motorGo(MOTOR_RECHTS,CLOCKWISE,100);
11
   delay(2000);
12
13
   Serial.println("C");
14
   motorGo(MOTOR_LINKS,COUNTERCLOCKWISE,100); 
15
   motorGo(MOTOR_RECHTS,COUNTERCLOCKWISE,100);
16
   delay(2000);
17
18
   Serial.println("D");
19
   motorGo(MOTOR_LINKS,CLOCKWISE,100); 
20
   motorGo(MOTOR_RECHTS,COUNTERCLOCKWISE,100);
21
   delay(2000);
22
}

Bei diesem Programm müssten beide Motor ständig laufen, und zwar zeitich 
versetzt immer abwechselns vorwärts und rückwärts.

Erzähl mal, was dabei heraus kommt.

Wenn das nicht klappt, dann steckt der Fehler vermutlich in der 
Hardware. Man könnte dann ja mal die Signale kontrollieren (notfalls mit 
LED's), die vom µC zum Motortreiber gehen.

von Joh (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Stefan,

die beiden Motoren drehen gleichzeitig und wechseln ihre Drehrichtung.
Auch im Terminal sieht man die Ausgabe (siehe Anhang) von "A", "B", "C" 
und  "D".

Gruß

von Stefan F. (Gast)


Lesenswert?

Also vermutlich kein Hardware defekt.

Dein letzter Quelltext sieht schon wieder wirr aus.
1
if( get_X_from_Joystick() <= 518 )                                                                             {
2
    tuwas
3
}
4
5
if( (  (get_X_from_Joystick() >=510) | (get_X_from_Joystick() <=526)) & (get_Y_from_Joystick() >=566 )) 
6
{
7
    tu was anderes
8
}

Wenn X < 518 ist, dann macht er oben was, und unten macht er was 
anderes. Das ist widersprüchlich.

Außerdem ist das "&" Zeichen falsch, es muss && heissen.

Ich befürchte, dass deine Logik "Beim Lenken soll nur ein Motor drehen" 
nicht klappen wird. Stell Dir vor, du fährst vollgas vorwärts und lenkst 
dann ein bisschen nach inks. Dann wird einer der beiden Motor abrupt 
stoppen und dein Gefährt versuchen, sich fast auf der Stelle nach links 
zu drehen. Das kann nicht gut gehen.

Ich würde deine Aufgabe daher völlig anders angehen.

Zuerst würde ich die Werte der Joystick ADC's zunächst in X un Y 
Koordinaten umrechnen, so dass sowohl Y als auch X die Werte -512 bis 
+511 annehmen können. X=0/Y=0 wäre der Mittelpunkt, die Ruheposition.

Die Y-Achse bestimmt die Geschwindigkeit, wobei negative Werte 
"Rückwärts" bedeuten.

Die X-Achse bestimmt die Lenkung, wobei negative Werte "nach links" 
bedeuten und positive Werte "nach rechts" bedeuten.

Wenn sowohl die Lenkung als auch die Geschwindigkeit nahe dem Ruhepunkt 
0 sind, dann sollen die Motoren gar nicht drehen.

Auf Geschwindigkeit und Lenkung berechnest du die Drehzahl und Richtung 
der Motoren. Positive zahlen=vorwärts, negative Zahlen=rückwärts.

Dann rechnest du diesn beiden Motorwerte in Richtungs-Signale und PWM 
Werte um. Potitiv/Negative bestimmt die Richtung und als PWM Wert 
verwendest du den Absolut-Wert der Zahl. Also z.B würde -200 Rückwärts 
mit PWM 200 bedeuten.

Ungetesteter Pseudo Code:
1
lenkung=512-get_X_from_Joystick();
2
geschwindigkeit=512-get_Y_from_Joystick();
3
4
if (abs(lenkung)>20 && abs(geschwindigkeit)>20)
5
{
6
    motorLinks=geschwindigkeit+lenkung; 
7
    motorRechts=geschwindigkeit-lenkung;
8
    
9
    pwmLinks=abs(motorLinks)/4;
10
    pwmRechts=abs(motorRechts)/4;
11
12
    if (pwmLinks<0)
13
    {
14
        motorGo(MOTOR_LINKS,COUNTERCLOCKWISE,pwmLinks);
15
    }
16
    else
17
    {
18
        motorGo(MOTOR_LINKS,CLOCKWISE,pwmLinks);
19
    }
20
21
    if (pwmRechts<0)
22
    {
23
        motorGo(MOTOR_RECHTS,COUNTERCLOCKWISE,pwmRechts);
24
    }
25
    else
26
    {
27
        motorGo(MOTOR_RECHTS,CLOCKWISE,pwmRechts);
28
    }
29
}
30
else
31
{
32
     motorOff(0); 
33
     motorOff(1);
34
}

Die ganzen Variablen solltest du zum Debuggen wieder mit println 
ausgeben.

Folgende Funktionen ergeben sich aus dem obigen Code:

Wenn der Joystick nur in der Y-Achse betätigt wird, fahren beide Motoren 
gleich schnell vorwärts und Rückwärts.

Wenn der Joystick nur in der X-Achse betätigt wird, dreht sich das 
Gefährt aus der Stelle.

Wenn der Joystick während der Fahrt nach links oder rechts bewegt wird, 
lenkt er in diese Richtung.

Eventuell möchtest du der Lenkung etwas weniger Priorität geben, damit 
das Gefährt nicht allzu krasse Lenkmanöver vollführt. Du könntest dazu 
den "geschwindigkeit" Wert mit 1,5 Multiplizieren und dafür den 
"lenkung" Wert durch 1,5 dividieren.

Dies alles geht allerdings davon aus, dass PWM-Wert = Geschwindigkeit 
ist. Für erste Versuche mag das ausreichen. Für ein angenehmes 
Fahrverhalten wirst du allerdings Odometrie-Sensoren brauchen, sowie 
zwei PI-Regler (einen für die Geschwindigkeit und einen für die 
Lenkung). Außerdem wirst du eventuell noch auf das Problem Stoßen, dass 
die beiden Motoren unterschiedlich effizient sind, so dass das Gefährt 
nicht korrekt geradeaus fährt. Das ist sogar sehr warscheinlich, wenn 
beim Vorwärtsfahren ein Motor links herum dreht und der andere rechts 
herum (aufgrund der spiegelverkehrten Einbaulage).

von Arno (Gast)


Lesenswert?

Stefan U. schrieb:
> Also vermutlich kein Hardware defekt.
>
> Dein letzter Quelltext sieht schon wieder wirr aus.
> if( get_X_from_Joystick() <= 518 )
> {
>     tuwas
> }
>
> if( (  (get_X_from_Joystick() >=510) | (get_X_from_Joystick() <=526)) &
> (get_Y_from_Joystick() >=566 ))
> {
>     tu was anderes
> }
>
> Wenn X < 518 ist, dann macht er oben was, und unten macht er was
> anderes. Das ist widersprüchlich.
>
> Außerdem ist das "&" Zeichen falsch, es muss && heissen.

Fiel mir auch gerade auf - und das | muss || heißen.

Unterschied zwischen bitweisen und logischen Verknüpfungen.

MfG, Arno

von Patrick J. (ho-bit-hun-ter)


Lesenswert?

Hi

Verstehe ich Dich richtig:

Nur Links/Rechts steuert jeweils den gegenüberliegenden Motor mit 100% 
vorwärts an
Nur Vor/Zurück steuert beide Motoren mit je 100% vor/zurück an

Vor-Links wäre somit linke Motor 100%, rechte Motor 200%
- da 200% blöd sind, beide Werte proportional runterrechnen
-> linke Motor 50%, rechte Motor 100% (also Beide :2, um auf Maximum von 
100 zu kommen)

Würde mir für beide Motoren die Soll-Drehzahl durch die 
Joystick-Position errechnen und dann sehen, ob ein Wert davon >100 oder 
<-100 (wenn Rückwärts als negativer Wert erscheint) ist und dann auf 
'maximal 100%' runter rechnen.

(wenn der absolut-Wert 120 ist, dann durch 1,2 teilen - hoffe, 
verständlich genug beschrieben)

MfG

von Stefan F. (Gast)


Lesenswert?

> Nur Links/Rechts steuert jeweils den gegenüberliegenden Motor mit 100%
vorwärts an

Nein 50% - wenn du keine Prio-Faktoren verwendest.

> Nur Vor/Zurück steuert beide Motoren mit je 100% vor/zurück an

Nein, auch hier sind es 50% - wenn du keine Prio-Faktoren verwendest.

Die Extreme wären dann die äußeren vier Ecken des Joysticks, nur da 
würden die Motoren 100% bekommen. Das ist so auch absolut richtig. Wenn 
du 5kmH vorwärts fährst und dann lenkst, muss ein Motor noch schneller 
drehen und einer nlangsamer, ansonsten ändert sich die Geschwindigkeit. 
Und dann würde die Y-Achse nicht mehr das bewirken, wass der Bediener 
erwarten würde.

von Joh (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen.

Ich habe nun mal Stefans Pseudocode in meinen Code kopiert und ihn 
getestet.
Ich habe den Variablen den Datentyp "unsigned int" gegeben und alles 
soweit 1:1 übernommen.
Die Variablen lasse ich über das Terminal ausgeben
Nach dem Flashen und dem Ausführen des Terminals erhalte ich folgende 
Werte (siehe Screenshot im Anhang).

Direkt nach dem Flashen dreht einer der Motoren auf max. Drehzahl,
irgendwie lässt sich schon etwas steuern, aber nicht für mich 
nachvollziehbar.

Ich hoffe die Terminalausgabe kann weiterhelfen?!

Ich versuche mal anhand des Codes von Stefan weiter zu experimentieren..

Grüße und Danke für den Code! :)

von Stefan F. (Gast)


Lesenswert?

> Ich habe den Variablen den Datentyp "unsigned int" gegeben und
> alles soweit 1:1 übernommen.

Wie passen dort negative Werte rein? Verstehst du die Bedeutung von 
"unsigned"?

von Joh (Gast)


Lesenswert?

Negativ sind sie ja anscheinend nicht...sondern der Überlauf veranlasst 
das Ganze ja, so meine Vermutung. ... :(

von Stefan F. (Gast)


Lesenswert?

Die Variablen sollen negative Werte aufnehmen können, weil die ganzen 
Berechnungen darauf aufbauen. Habe ich das nicht klar beschrieben?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.