Archiv verlassen und diese Seite im Standarddesign anzeigen : fahrzeug mit vier motoren und vier encodern
hallo allerseits,
in den letzten wochen habe ich ein vierrädriges fahrzeug entwickelt
30867
mit diesen getriebemotoren und encodern, verwendet wird ein arduino mega 2560 R3 und das motorshield L293D V1 von sainsmart (chinesischer clone):
308573085830861
der code für einen motor:
#include <AFMotor.h>
AF_DCMotor motor_1(1);
#define encoder_1 22
int wert_1;
int summe_1;
int zaehler_1;
void setup()
{
pinMode(encoder_1, INPUT_PULLUP);
Serial.begin(9600);
Serial1.begin(9600);
wert_1=0;
summe_1=0;
zaehler_1=0;
}
void loop()
{
wert_1=digitalRead(encoder_1);
if (summe_1 <= 19 && zaehler_1 == 0)
{
motor_1.setSpeed(120);
motor_1.run(FORWARD);
zaehler_1 = 1;
Serial.print(wert_1);
Serial.print(" ");
Serial.println(summe_1);
}
else if (summe_1 <= 19 && zaehler_1 == 1)
{
zaehler_1 = 0;
summe_1 = (summe_1 + wert_1);
Serial.print(wert_1);
Serial.print(" ");
Serial.println(summe_1);
motor_1.setSpeed(0);
motor_1.run(RELEASE);
}
}
hat auch (über den serialmonitor) durchaus brauchbare ergebnisse gebracht:
1 0
1 1
1 1
1 2
1 2
1 3
1 3
1 4
1 4
1 5
1 5
1 6
1 6
0 6
0 6
0 6
0 6
0 6
0 6
0 6
0 6
1 7
1 7
0 7
0 7
0 7
0 7
1 8
1 8
0 8
0 8
0 8
1 8
0 8
0 8
0 8
1 8
0 8
0 8
0 8
1 8
0 8
0 8
1 9
0 9
0 9
0 9
1 10
0 10
0 10
0 10
0 10
1 10
0 10
0 10
1 11
0 11
1 12
0 12
0 12
0 12
0 12
1 12
0 12
1 12
0 12
0 12
0 12
0 12
0 12
0 12
1 13
0 13
1 14
0 14
1 15
0 15
1 16
0 16
1 17
0 17
1 18
0 18
1 19
0 19
0 19
0 19
0 19
0 19
0 19
1 19
0 19
1 19
0 19
0 19
0 19
0 19
1 20
das rad dreht sich noch nicht genau 1x um 360° beim erreichen der 20 signale vom encoder, dass wäre aber - dachte ich - beherrschbar...
die erweiterung des codes für vier motoren (im prinzip das erste beispiel vervierfacht):
#include <AFMotor.h>
AF_DCMotor motor_1(1);
AF_DCMotor motor_2(2);
AF_DCMotor motor_3(3);
AF_DCMotor motor_4(4);
#define encoder_1 22
#define encoder_2 52
#define encoder_3 53
#define encoder_4 23
int wert_1;
int wert_2;
int wert_3;
int wert_4;
int summe_1;
int summe_2;
int summe_3;
int summe_4;
int zaehler_1;
int zaehler_2;
int zaehler_3;
int zaehler_4;
void setup()
{
pinMode(encoder_1, INPUT_PULLUP);
pinMode(encoder_2, INPUT_PULLUP);
pinMode(encoder_3, INPUT_PULLUP);
pinMode(encoder_4, INPUT_PULLUP);
Serial.begin(9600);
Serial1.begin(9600);
wert_1=0;
wert_2=0;
wert_3=0;
wert_4=0;
summe_1;
summe_2;
summe_3;
summe_4;
zaehler_1=0;
zaehler_2=0;
zaehler_3=0;
zaehler_4=0;
}
void loop()
{
wert_1=digitalRead(encoder_1);
wert_2=digitalRead(encoder_2);
wert_3=digitalRead(encoder_3);
wert_4=digitalRead(encoder_4);
if (summe_1 <= 9 && zaehler_1 == 0)
{
motor_1.setSpeed(150);
motor_1.run(FORWARD);
zaehler_1 = 1;
Serial.print(wert_1);
Serial.print(" ");
Serial.println(summe_1);
Serial1.print(wert_1);
Serial1.print(" ");
Serial1.println(summe_1);
}
else if (summe_1 <= 9 && zaehler_1 == 1)
{
zaehler_1 = 0;
summe_1 = (summe_1 + wert_1);
Serial.print(wert_1);
Serial.print(" ");
Serial.println(summe_1);
Serial1.print(wert_1);
Serial1.print(" ");
Serial1.println(summe_1);
motor_1.setSpeed(0);
motor_1.run(RELEASE);
}
if (summe_2 <= 9 && zaehler_2 == 0)
{
motor_2.setSpeed(150);
motor_2.run(FORWARD);
zaehler_2 = 1;
Serial.print(wert_2);
Serial.print(" ");
Serial.println(summe_2);
Serial1.print(wert_2);
Serial1.print(" ");
Serial1.println(summe_2);
}
else if (summe_2 <= 9 && zaehler_2 == 1)
{
zaehler_2 = 0;
summe_2 = (summe_2 + wert_2);
Serial.print(wert_2);
Serial.print(" ");
Serial.println(summe_2);
Serial1.print(wert_2);
Serial1.print(" ");
Serial1.println(summe_2);
motor_2.setSpeed(0);
motor_2.run(RELEASE);
}
if (summe_3 <= 9 && zaehler_3 == 0)
{
motor_3.setSpeed(150);
motor_3.run(FORWARD);
zaehler_3 = 1;
Serial.print(wert_3);
Serial.print(" ");
Serial.println(summe_3);
Serial1.print(wert_3);
Serial1.print(" ");
Serial1.println(summe_3);
}
else if (summe_3 <= 9 && zaehler_3 == 1)
{
zaehler_3 = 0;
summe_3 = (summe_3 + wert_3);
Serial.print(wert_3);
Serial.print(" ");
Serial.println(summe_3);
Serial1.print(wert_3);
Serial1.print(" ");
Serial1.println(summe_3);
motor_3.setSpeed(0);
motor_3.run(RELEASE);
}
if (summe_4 <= 9 && zaehler_4 == 0)
{
motor_4.setSpeed(150);
motor_4.run(FORWARD);
zaehler_4 = 1;
Serial.print(wert_4);
Serial.print(" ");
Serial.println(summe_4);
Serial1.print(wert_4);
Serial1.print(" ");
Serial1.println(summe_4);
}
else if (summe_4 <= 9 && zaehler_4 == 1)
{
zaehler_4 = 0;
summe_4 = (summe_4 + wert_4);
Serial.print(wert_4);
Serial.print(" ");
Serial.println(summe_4);
Serial1.print(wert_4);
Serial1.print(" ");
Serial1.println(summe_4);
motor_4.setSpeed(0);
motor_4.run(RELEASE);
}
}
brachte aber ergebnisse, die so nicht bleiben können:
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
1 0
0 0
0 0
0 0
1 1
1 1
0 0
1 0
1 1
0 1
0 0
0 0
1 2
0 1
0 0
0 0
0 2
0 1
0 0
1 1
1 3
1 2
0 0
0 1
1 3
0 2
1 0
0 1
1 4
0 2
0 0
0 1
0 4
0 2
0 0
1 2
0 4
1 3
0 0
0 2
0 4
0 3
0 0
1 3
1 5
0 3
0 0
0 3
0 5
0 3
1 0
0 3
0 5
1 4
1 1
1 3
0 5
1 4
0 1
1 4
1 6
0 4
0 1
1 4
1 6
1 4
1 1
0 4
0 6
0 4
0 1
0 4
0 6
0 4
0 1
0 4
0 6
0 4
1 2
0 4
1 6
1 4
0 2
0 4
1 7
0 4
0 2
0 4
0 7
0 4
0 2
0 4
0 7
0 4
0 2
0 4
1 7
0 4
1 2
0 4
0 7
1 5
0 2
1 4
1 7
0 5
0 2
0 4
0 7
0 5
0 2
0 4
1 7
0 5
0 2
0 4
0 7
1 6
1 3
0 4
0 7
1 6
0 3
0 4
0 7
0 6
0 3
0 4
0 7
0 6
0 3
0 4
1 8
1 7
0 3
0 4
0 8
1 7
0 3
0 4
0 8
0 7
0 3
0 4
1 8
0 7
0 3
0 4
0 8
1 8
0 3
1 4
0 8
1 8
0 3
1 5
1 9
0 8
1 4
0 5
0 9
0 8
0 4
0 5
0 9
0 8
1 5
0 5
0 9
0 8
0 5
1 6
1 10
1 9
0 5
0 6
1 9
0 5
1 7
1 10
0 5
0 7
0 5
0 7
1 6
1 7
0 6
1 8
0 6
1 8
1 6
0 8
0 6
0 8
0 6
0 8
0 6
0 8
0 6
0 8
1 7
1 8
0 7
0 8
1 8
0 8
0 8
0 8
1 9
0 8
0 9
0 8
0 9
0 8
1 9
1 9
0 9
0 9
1 9
0 9
0 9
1 9
0 9
0 9
0 9
0 9
0 9
0 9
1 10
0 9
0 9
1 9
0 9
0 9
0 9
0 9
1 10
die räder laufen unterschiedlich an, bleiben umterschiedlich stehen...
ich bin sicher, dass das an der struktur des vervierfachten codes liegt, an den einzelnen abfragen des zustandes der vier encoder und der davon abhängigen reaktionen. So kann die struktur also nicht bleiben, ich habe aber absolut keinen plan wie es anders sein könnte?
Ist der ansatz überhaupt richtig? Geht sowas überhaupt ohne interrupts? Wäre mir schon lieber, weil ich mich damit nicht gut auskenne und denke auch, dass das auslesen von 4 encodern und das gleichzeitige betreiben von vier motoren schon recht unkompliziert(?) ist und mit "normalem" code machbar sein müsste...
RoboHolIC
08.11.2015, 16:54
Ich habe ein wenig in deinem Code geschmökert, ohne allzuviel zu verstehen (liegt an meinen fehlenden Kenntnissen).
Was mir aber auffiel sind einerseits die fehlende explizite Initialisierung der Variablen 'summe_n', andererseits die endlos vielen serial.print-Befehle. Das dauert doch alles "ewig", zumindest im Zeitmaßstab eines Controllers.
Überschlage mal deine Zykluszeit der Hauptschleife - im Wesentlichen abhängig von Baudrate und Anzahl der übertragenen Zeichen - und schätze ab, ob das Programm bei der auftretenden Raddrehzahl und Encoderteilung überhaupt eine Chance hat, alle Zustände an den Radencodern wahrzunehmen.
Lass' alle serial.print aus der Schleife weg und dokumentiere lediglich den Zieleinlauf, wenn der erste Encoder bei 10 angekommen ist.
Wenn der Controller jemals auch noch andere Aufgaben als die Encoderauswertung machen soll - z.B. Übermittlung der Ergebnisse oder gar "höhere" Aufgaben wie eine Regelung oder ein Bedienmenü, dann wirst du kaum um die Verwendung eines Interrupts - Timer oder Pin-Change - herumkommen.
P.S.: Dass die Motoren - bei einheitlichem PWM-DutyCycle unterschiedlich schnell anlaufen/abbremsen, ist aber ganz normal und abhängig von der Streuung bei den Reibungsverhältnissen der einzelnen Antriebsexemplare, zumal bei derart billig gemachten Komponenten (soll keine Verunglimpfung sein; ich denke, das ist konsensfähig).
Rabenauge
08.11.2015, 19:48
Man kann die Zeit eines Durchlaufs auch leicht messen.
http://forum.arduino.cc/index.php?topic=292794.0
Sehr hilfreich bei diversen Anwendungen...
ein sehr gut funktionierender Code für AVR Arduinos ist dieser hier - er läuft über Timer Interrupts.
Alles andere über normale loops ist zu langsam!
/************************************************** **********
*
* Demo-Programm zur Auswertung eines händisch betriebenen
* Drehencoders (Quadraturencoder) mit dem Arduino im
* Timer-Interrupt mit einer Abfragefrequenz von rd. 1kHz
*
* Kann von jederman frei verwendet werden, aber bitte den
* Hinweis: "Entnommen aus http://www.meinDUINO.de" einfügen
*
************************************************** **********/
// An die Pins 2 und 3 ist der Encoder angeschlossen
#define encoderA 2
#define encoderB 3
// Globale Variablen zur Auswertung in der
// Interrupt-Service-Routine (ISR)
volatile int8_t altAB = 0;
volatile int encoderWert = 0;
// Die beiden Schritt-Tabellen für volle oder 1/4-Auflösung
// 1/1 Auflösung
//int8_t schrittTab[16] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
// 1/2 Auflösung ergibt bei Lego-Motoren 1 tick pro Grad (standard wie bei Lego)
int8_t schrittTab[16] = {0, 0,0,0,1,0,0,-1, 0,0,0,1,0,0,-1,0};
// 1/4 Auflösung
//int8_t schrittTab[16] = {0,0,0,0,0,0,0,-1,0,0,0,0,0,1,0,0};
/************************************************** ***********
*
* Interrupt Service Routine
*
* Wird aufgerufen, wenn der entsprechende Interrupt
* ausgelöst wird
*
************************************************** ***********/
ISR(TIMER1_COMPA_vect) {
altAB <<= 2;
altAB &= B00001100;
altAB |= (digitalRead(encoderA) << 1) | digitalRead(encoderB);
encoderWert += schrittTab[altAB];
}
/************************************************** ***********
*
* void setup()
*
* Wird einmal beim Programmstart ausgeführt
*
************************************************** ***********/
void setup() {
pinMode(encoderA, INPUT);
pinMode(encoderB, INPUT);
noInterrupts(); // Jetzt keine Interrupts
TIMSK1 |= (1<<OCIE1A); // Timer 1 Output Compare A Match Interrupt Enable
TCCR1A = 0; // "Normaler" Modus
// WGM12: CTC-Modus einschalten (Clear Timer on Compare match)
// Stimmen OCR1A und Timer überein, wird der Interrupt
// ausgelöst
// Bit CS12 und CS10 setzen = Vorteiler: 1024
TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10);
// Frequenz = 16000000 / 1024 / 15 = rd. 1kHz Abtastfrequenz;
// Überlauf bei 14, weil die Zählung bei 0 beginnt
OCR1A = 14;
interrupts(); // Interrupts wieder erlauben
Serial.begin(115200);
}
/************************************************** ***********
*
* void loop()
*
* Wird immer wieder durchlaufen
*
************************************************** ***********/
void loop() {
while(true) {
Serial.println(encoderWert);
delay(100);
}
}
danke für euere antworten...
@ HaWe,
den code kenne ich bereits von meinduino, habe aber das problem, dass die encoder keine zwei datenanschlüsse haben, sondern nur einen...
@ Rabenauge,
danke für den tipp mit dem millis() - werde ich mir anschauen
@ RoboHoliC,
- habe die "summen" mit "=0" versehen - kein einfluss auf den ablauf
- habe sämtliche printanweisungen entferrnt - geschockt - die räder 3 & 4 zuckten nur kurz, das wars...
- der controler soll nur der "motorfahrer" sein, es kommt dann noch kommunikation über IIc (wieder nur befehle für den motortreiber) mit dem RP6 - der RP6 soll den rest machen...
- das unterschiedliche anlaufen und abbremsen kann m.e. nach nicht alleine durch die chinesischen/billigen teile bedingt sein, es variiert um mehrere umdrehungen und wechselt von mal zu mal auch die reihenfolge der räder...
RoboHolIC
09.11.2015, 23:35
Hallo Inka.
- habe die "summen" mit "=0" versehen - kein einfluss auf den ablauf
Hatte ich auch nicht wirklich erwartet, weil die Zählungen ansich ja ganz vernünftig aussahen.
- habe sämtliche printanweisungen entferrnt - geschockt - die räder 3 & 4 zuckten nur kurz . . . das unterschiedliche anlaufen und abbremsen . . . variiert um mehrere umdrehungen und wechselt von mal zu mal auch die reihenfolge der räder...
Uiii. da liegt aber noch was ganz im Argen. digitalRead(encoder_n) klingt sehr nach Bibliotheksfunkion. Hast du die Doku dazu studiert? Wechselwirkungen im Einsatz mit anderen Funktionen? Evtl. Überschneidungen bei den Controllerpins?
'Encoder' klingt für mich auch nach mehreren Spuren für die Richtungserkennung (Quadraturencoder) oder Absolutposition. Passen Sensor und Auswertungscode wirklich zusammen?
Ich habe mich ein wenig vertieft in deinen Code, habe die Idee dahinter aber noch nicht verstanden (vllt. auch deswegen, weil es mir schwer fällt, mich auf andere Programmiergewohnheiten einzustellen):
- Steckt da an irgend einer Stelle die Erkennung einer Flanke (dunker --> hell) drin? Zehnmal "hell" gemessen müssen ja keine zehn Zählpulse sein!
- Sperrzeit nach der Flankenerkennung oder Schmitt-Trigger-Eingang, damit nicht mechanische Vibrationen aus einem Übergang mehrere Pulse machen können.
- Warum werden die Motoren nicht bestmöglich zeitgleichgestartet? Und ?immer wieder? gestartet - auch wenn das vielleicht nicht schadet.
"motorfahrer" . . . kommunikation über IIc
Das sind klassisch zwei verschiedene Aufgaben auf einem Controller: Eine zeitkritische, nämlich die Encoderauswertung - und eine zeitUNkritische, nämlich die I2C-Kommunikation.
Wenn du die beiden pollend in einer gemeinsamen Schleife bearbeitest, mag das zu Anfang funktionieren. Kommt dann mehr und mehr Code hinzu, steigt die Zykluszeit evtl. so weit an (vgl. deine seriellen Ausgaben!), dass der Controller bei der gewählten Drehzahl nicht mehr alle Inputs der Radsensoren mitkriegt. Besser ist es, die Encoderauswertung in einen Interrupt zu packen - dort kann sie mit Vorrang (ggf. in festem Zeitraster) abgearbeitet werden. Die Kommunikation und der ganze Rest darf meist innerhalb gewisser Grenzen mal ein wenig früher oder später in der Schleife passieren, ohne dass gleich das System aus dem Tritt gerät.
Mut zum Interrupt - das ist meine Devise. Keines meiner Projekte arbeitet ohne.
Gruß
Christian.
Hi RoboHolIC,
Uiii. da liegt aber noch was ganz im Argen. digitalRead(encoder_n) klingt sehr nach Bibliotheksfunkion. Hast du die Doku dazu studiert? Wechselwirkungen im Einsatz mit anderen Funktionen? Evtl. Überschneidungen bei den Controllerpins?
'Encoder' klingt für mich auch nach mehreren Spuren für die Richtungserkennung (Quadraturencoder) oder Absolutposition. Passen Sensor und Auswertungscode wirklich zusammen?
also: als encoder wird das teil vom hersteller/lieferanten bezeichnet, hat die anschlüsse Vcc / GND und OUT und ist eher eine lichtschranke mit einer lochscheibe, die 20x pro umdrehung hell und dunkel unterscheidet. Es ist noch eine rote LED und irgendein IC auf der platine, dessen funktion nicht klar ist. Die bibliothek für die motoren ist die von Adafruit, studiert habe ich sie nicht, die befehle aus einem beispiel so übernommen...
Ich habe mich ein wenig vertieft in deinen Code, habe die Idee dahinter aber noch nicht verstanden (vllt. auch deswegen, weil es mir schwer fällt, mich auf andere Programmiergewohnheiten einzustellen)
ich habe hier meinen code (den teil mit dem ersten motor) kommentiert, mir ist durchaus bewusst, dass bei einer 20er teilung und der relativ langsamen drehung des motors mehrere dutzend positive wie negative signale (null oder 1) beim arduino-pin ankommen bevor ein echter wechsel in der hardware passiert, habe also versucht nur das jeweils erste signal zu cashen (zaehler_1) und die abfrage damit zu steuern...
void(loop)
{
wert_1=digitalRead(encoder_1); //wert des encoders einlesen und speichern, 0 oder 1, hell oder dunkel
if (summe_1 <= 19 && zaehler_1 == 0) // wenn summe <= "19" UND keine "0-impulse" gezählt
{
motor_1.setSpeed(150); //geschwindigkeit auf 150 stellen (0 bis 250 möglich)
motor_1.run(FORWARD); // forwärts fahren
zaehler_1 = 1; //, zähler der "0-impulse" auf "1" stellen
}
else if (summe_1 <= 19 && zaehler_1 == 1) // wenn summe < als 19 UND der zähler der "0-impulse" = "1"
{
zaehler_1 = 0; // zähler der "0-impulse" wieder auf "0" stellen
summe_1 = (summe_1 + wert_1); // summe um "1" (den wert des encoders) erhöhen
motor_1.setSpeed(0); // geschwindigkeit auf "0" stellen
motor_1.run(RELEASE); // motor freigeben (kein antrieb, kein bremsen)
}
}
vielleicht wird das jetzt klarer, welcher gedanke dahintersteckt, habe aber bereits zweifel angekündigt, ob der ansatz so ok ist - bei einem motor funktioniert es ja halbwegs...
- Steckt da an irgend einer Stelle die Erkennung einer Flanke (dunker --> hell) drin? Zehnmal "hell" gemessen müssen ja keine zehn Zählpulse sein!
- Sperrzeit nach der Flankenerkennung oder Schmitt-Trigger-Eingang, damit nicht mechanische Vibrationen aus einem Übergang mehrere Pulse machen können.
siehe oben...
- Warum werden die Motoren nicht bestmöglich zeitgleichgestartet? Und ?immer wieder? gestartet - auch wenn das vielleicht nicht schadet.
Du meinst bei allen motoren im setup die geschwindigkeit festlegen und auch dort nacheinader starten? Oder teilen: geschwindigkeit im setup, start alle kurz hintereinander im loop? Ich hatte angst, dass die dann schon zu weit/zu lange drehen bis die abfrage nach dem signal kommt, ist aber wohl unbegründet...Muss ich probieren...
Das sind klassisch zwei verschiedene Aufgaben auf einem Controller: Eine zeitkritische, nämlich die Encoderauswertung - und eine zeitUNkritische, nämlich die I2C-Kommunikation.
Wenn du die beiden pollend in einer gemeinsamen Schleife bearbeitest, mag das zu Anfang funktionieren. Kommt dann mehr und mehr Code hinzu, steigt die Zykluszeit evtl. so weit an (vgl. deine seriellen Ausgaben!), dass der Controller bei der gewählten Drehzahl nicht mehr alle Inputs der Radsensoren mitkriegt. Besser ist es, die Encoderauswertung in einen Interrupt zu packen - dort kann sie mit Vorrang (ggf. in festem Zeitraster) abgearbeitet werden. Die Kommunikation und der ganze Rest darf meist innerhalb gewisser Grenzen mal ein wenig früher oder später in der Schleife passieren, ohne dass gleich das System aus dem Tritt gerät.
ich möchte erstmal den zeitkritischen teil bearbeiten, das mit dem IIc ist noch weit, weit weg :-)
Mut zum Interrupt - das ist meine Devise. Keines meiner Projekte arbeitet ohne.
Du hast gut reden. Aber auch recht...
RoboHolIC
11.11.2015, 00:29
Hallo inka.
Ich sehe da keine Flankenerkennung. Die IF-Anweisungen enthalten keinerlei Abhängigkeit vom Encodersignal. Stattdessen wird zaehler_1 im ersten IF auf 1 erhöht, erfüllt damit die Teil-Bedingung zaehler_1 ==1 im zweiten IF, wo dieselbe Variable sofort wieder auf Null gesetzt und der eigentliche Counter summe_1 erhöht wird.
Das bedeutet doch, dass in den ersten 19 Durchläufen die Bedingungen immer erfüllt sind und der rein zufällige Zustand des Encoders zu summe addiert wird. Das ist vielleicht ganz lustig, zählt aber keine Flanken, obwohl die Summe früher oder später 19 überschreitet. Das passiert nämlich selbst dann, wenn das Rad im Encoderzustand 1 (oder eben "H") blockiert.
Flanken erkennt man z.B., indem man pro Durchlauf den Input der vorherigen Runde mit dem aktuellen vergleicht, ggf. den Zähler erhöht (oder ein Flag setzt) und anschließend den aktuellen Input als "neuen alten" Vergleichswert für die nächste Runde speichert.
Warum in aller Welt die ständige Umschaltung zwischen Antrieb und Leerlauf? Das Teil soll doch fahren und nicht parken.
Und wo fährt wohl ein Rollstuhlfahrer hin, wenn er aus der Ruhe zunächst nur mit der Linken antreibt, mit der Rechten aber erst noch ein wenig UARTelefoniert, bevor er dann doch auch diese zum Vortrieb verwendet? Sicher übertrieben skizziert, könnte aber zur Erhellung beitragen.
Gruß
Christian.
Hi Rabenauge,
bevor ich mich mit den motoren und den encodern weiter beschäftige, wollte ich die zyklusmessung anschauen/ausprobieren,
http://forum.arduino.cc/index.php?topic=292794.0
dort ist folgender code aufgeführt:
/************************************************** *******************************
** LoopTiming() v06 by GuntherB & Doc_Arduino @ german Arduino Forum **
************************************************** ********************************
** Funktion um die Dauer der Loop-Zeiten zu ermitteln **
** wird in der Loop am Anfang und Ende aufgerufen **
** benötigt ca (AL * 4 + 16) Byte RAM **
************************************************** *******************************/
void LoopTiming()
{
const int AL = 100; // Arraylänge, NUR GERADE Zahlen verwenden!
static unsigned long LoopTime[AL];
static unsigned int Index=0, Messung=0, Min=0xFFFF, Max, Avg;
if (Messung % 2 == 0) // wenn Messung X gerade (0,2,4,6 usw.), entspricht immer Anfang der Loop
{
LoopTime[Index] = millis();
Messung++;
Index++;
return; // Funktion sofort beenden, spart bestimmt Zeit
}
if (Messung % 2 == 1) // wenn Messung X ungerade (1,3,5,7 usw.), entspricht immer Ende der Loop
{
LoopTime[Index] = millis();
LoopTime[Index-1] = LoopTime[Index] - LoopTime[Index-1]; // Loopdauer einen Index niedriger einspeichern wie aktuell
Messung++;
}
if (Index >= AL) // Array voll, Daten auswerten
{
for (int i = 0; i<AL; i++)
{
Min = min(Min, LoopTime[i]);
Max = max(Max, LoopTime[i]);
Avg += LoopTime[i];
}
Avg = Avg / AL;
SERIAL_IMPL.print(F("Minimal "));SERIAL_IMPL.print(Min);SERIAL_IMPL.println(" ms");
SERIAL_IMPL.print(F("Durchschnitt "));SERIAL_IMPL.print(Avg);SERIAL_IMPL.println(" ms");
SERIAL_IMPL.print(F("Maximal "));SERIAL_IMPL.print(Max);SERIAL_IMPL.println(" ms");
Min = 0xFFFF;
Max = 0;
Avg = 0;
Messung = 0;
Index = 0;
}
}
um den jetzt zum messen aufrufen zu können, muss ich den ja am ende meines programm als funktion einfügen und am anfang und am ende meines "loops" aufrufen. Beim kompilieren kommt dann aber:
LoopTiming.ino:54:6: error: ‘SERIAL_IMPL’ was not declared in this scope
wie deklariere ich denn das? Oder muss ich irgendwelche besondere lib einbinden? Darüber steht in dem thread leider nichts drinn...
danke...
Hallo inka,
diese SERIAL_IMPL ist eine andere Implemetierung von Serial.
Du kann die Zeilen
SERIAL_IMPL.print(F("Minimal "));SERIAL_IMPL.print(Min);SERIAL_IMPL.println(" ms");
SERIAL_IMPL.print(F("Durchschnitt "));SERIAL_IMPL.print(Avg);SERIAL_IMPL.println(" ms");
SERIAL_IMPL.print(F("Maximal "));SERIAL_IMPL.print(Max);SERIAL_IMPL.println(" ms");
nach
Serial.print("Minimal ");Serial.print(Min);Serial.println(" ms");
Serial.print("Durchschnitt ");Serial.print(Avg);Serial.println(" ms");
Serial.print("Maximal ");Serial.print(Max);Serial.println(" ms");
ersetzen, dann sollte es funktionieren.
Nachtrag: Noch eine Frage: sind die Pins 18-21 schon an deinem Board belegt bzw. kannst Du die Encoder auf diese Pins legen? Dann wäre das interruptgesteuerte Zählen der Ticks nicht so schwierig zu implementieren.
Gruß
Chris
hi botty,
danke, jetzt komme ich weiter...
die pinns 18-21 sind noch frei...
Hallo inka,
ich hab mir Deinen Code mal angeguckt und da ich gerade selbst an
meinem ersten Projekt dran bin, versuch ich hier mal Dir Deine Zurückhaltung
gegenüber Interrupts zu nehmen und zeig Dir meinen Code.
Falls es zu ausführlich wird, dann fasse das bitte nicht als Überheblichkeit auf.
Ich weiß halt einfach nicht auf welchem Programmierstand Du bist.
Die Code Beispiele nicht zusammenkopieren, ganz unten ist der ganze Sketch.
Los geht's:
Zuerst hab ich mir einen Datentypen gemacht, der die Infos für einen Motor hält.
struct motor {
AF_DCMotor mot;
uint8_t enc_pin;
// volatile damit der Compiler keine 'dummen' Optimierung macht.
volatile uint32_t ticks;
unsigned long start_time;
unsigned long stop_time;
};
mot ist das Objekt für den PWM Kanal, enc_pin ist der Pin an den der Encoder
kommt und ticks ist die Variable in der wir die Flankenwechsel zählen.
Das "volatile" davor ist wichtig. Ohne könnte der Compiler auf die Idee kommen
was wegzuoptimieren was er nicht soll.
Faustregel: Variablen die Interrupt Service Routinen und Hauptprogramm
benutzt werden sind immer "volatile".
Da Du vier Motoren hast (ich hab nur zwei) nehmen wir ein Array vom Typ
"struct motor" und initialisieren es.
struct motor motoren[M_MAX] = {
{ AF_DCMotor(1), 18, 0, 0, 0 }, // M_VL
{ AF_DCMotor(2), 19, 0, 0, 0 }, // M_HL
{ AF_DCMotor(3), 20, 0, 0, 0 }, // M_VR
{ AF_DCMotor(4), 21, 0, 0, 0 } // M_HR
};
Die Spalten entsprechen den obigen Zeilen. Sprich die "1" ist der PWM Kanal und
die "18" der Pin an den der Endocder vom Motor der mit dem ersten PWM Kanal
gesteuert wird angeschlossen ist.
Da ich lieber mit Namen als mit Zahlen arbeite habe ich noch einen Aufzählungstypen
deklariert:
enum motoren_e {
M_VL = 0, // Motor vorne links
M_HL,
M_VR,
M_HR,
M_MAX
};
Die Namen werden auf fortlaufende unsigned integer abgebildet M_MAX hat
den Wert "4".
Wenn Du die Zahlen bei der Initialisierung so anpaßt das dein erster PWM Kanal
den vorderen linken Motor antreibt und der Encoder am entsprechenden Pin liegt, läßt
sich der Motor mit
motoren[M_VL].mot.setSpeed(255/2);
motoren[M_VL].mot.run(FORWARD);
anschalten.
Wollte man das mit allen machen geht das mit:
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
motoren[idx].mot.setSpeed(255/2);
motoren[idx].mot.run(FORWARD);
}
Jetzt brauchen wir für jedes Element eine Interrupt Service Routine, die aufgerufen wird wenn
sich der Zustand am Pin ändert.
Grundsätzlich haben dies Funktionen diese Signatur:
void isr_name(void);
Faustregeln für den Inhalt so einer ISR sind:
Sie muß ihre Funktion erfüllen.
Sie soll so kurz wie möglich dabei sein.
Wir wollen unseren "ticks" Zähler raufzählen und zwar für jedes Element in unserem Array.
So brauchen wir vier Stück:
void motor_isr_m_vl(void) { motoren[M_VL].ticks++; }
void motor_isr_m_vr(void) { motoren[M_VR].ticks++; }
void motor_isr_m_hl(void) { motoren[M_HL].ticks++; }
void motor_isr_m_hr(void) { motoren[M_HR].ticks++; }
Der nächste Schritt ist den Pin zu initialisieren und dem System zu erklären, welcher Pin
zu welcher ISR gehört:
void setup() {
Serial.begin(9600);
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
pinMode(motoren[idx].enc_pin, INPUT_PULLUP);
}
attachInterrupt(digitalPinToInterrupt(motoren[M_VL].enc_pin), motor_isr_m_vl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HL].enc_pin), motor_isr_m_hl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_VR].enc_pin), motor_isr_m_vr, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HR].enc_pin), motor_isr_m_hr, CHANGE);
}
"digitalPinToInterrupt()" mapped die Pin Nummer auf das entsprechende Register und
"attachInterrupt()" setzt dafür die ISR als zweiten Parameter. Der letzte Parameter kann
die Werte RISING, FALLING oder CHANGE haben. CHANGE bedeutet bei jedem Wechsel
von HIGH nach LOW und vice versa wird die entsprechende ISR aufgerufen und in unserem Fall
der richtige "ticks" inkrementiert.
Was ist jetzt kritisch? Nun alle Elemente aus der Struktur außer "ticks" sind unkritisch.
Wenn Du auf "ticks" lesend zugreifst kann es schlimmstenfalls passieren das der Interrupt das
Lesen unterbricht und du mit einem Wert um eins verschoben weiterarbeitest.
Beim schreiben kann es passieren, daß wenn Du "ticks" einen neuen Wert zuweißt, der
Interrupt Dich unterbricht und dadurch der alte Wert verwendet wird.
Mag ersteres noch unkritisch sein,müssen wir uns vor Letzterem schützen.
Dafür gibt's im Arduino Framework die Funktionen "noInterrupts()", die alle Interrupts ausschaltet
und "interrupts()", die sie wieder einschaltet. Hier am Beispiel "motor_start()"
void motor_start(uint8_t idx, uint8_t pwm, uint8_t dir) {
if(idx >= M_MAX)
return;
noInterrupts();
motoren[idx].ticks = 0;
interrupts();
motoren[idx].start_time = motoren[idx].stop_time = millis();
motoren[idx].mot.setSpeed(pwm);
motoren[idx].mot.run(dir);
}
letzten Endes muß man jeden Zugriff auf "ticks" so schützen und damit man das beim Lesen
wie beim Schreiben nicht vergißt gibt's die Funktionen
inline uint32_t motor_hole_ticks(uint8_t idx) {
if(idx >= M_MAX)
return 0;
noInterrupts();
uint32_t tmp = motoren[idx].ticks;
interrupts();
return tmp;
}
inline void motor_setze_ticks(uint8_t idx, uint32_t val) {
if(idx >= M_MAX)
return;
noInterrupts();
motoren[idx].ticks = val;
interrupts();
}
die Du anstelle direkter Zuweisungen benutzt, so kann nichts passieren.
Zu guter Letzt der ganze Sketch in dem Du die PWM Kanäle und die
Encoder Pins anpassen müßtest. Dann kann's losgehen ob einer eine Umdrehung
macht und wenn das funktionert sind da "setupMulti()" und "loopMulti()" für alle
Motoren.
#include <AFMotor.h>
/*
* Benamte Indexe. Wichtig: Alle Schleifen basieren auf der
* Annahme, dass M_VL das erste Element und mit 0 initialisiert
* ist. M_MAX muss ausserdem _immer_ das letzte Element sein da
* es die Groesse des Arrays s.u. bestimmt.
*/
enum motoren_e {
M_VL = 0, // Motor vorne links
M_HL,
M_VR,
M_HR,
M_MAX
};
/*
* Infos zu einem Motor zusammenfassen.
*/
struct motor {
AF_DCMotor mot;
uint8_t enc_pin;
// volatile damit der Compiler keine 'dummen' Optimierung macht.
volatile uint32_t ticks;
unsigned long start_time;
unsigned long stop_time;
};
/*
* Hier werden die PWM Channel - Encoder Pin Paare gesetzt.
* Restliche Elemente muessen ebenfalls initialisiert werden.
* Werte pruefen ob sie zu den Namen oben passen.
* Fuer die externen Interrupts sind die Pins 2,5,18-21
* erlaubt. Hardware anpassen.
*/
struct motor motoren[M_MAX] = {
{ AF_DCMotor(1), 18, 0, 0, 0 }, // M_VL
{ AF_DCMotor(2), 19, 0, 0, 0 }, // M_HL
{ AF_DCMotor(3), 20, 0, 0, 0 }, // M_VR
{ AF_DCMotor(4), 21, 0, 0, 0 } // M_HR
};
// Anzahl der Encoderstriche fuer eine Umdrehung
const static double ticks_per_rev = 40;
const static double durchmesser = 6.5; // in cm;
const static double u_per_tick = (3.1415926535897932384626433832795 * durchmesser) / ticks_per_rev;
/*
* Interruptroutinen mit der gleichen Namenskonvention wie
* oben.
*/
void motor_isr_m_vl(void) { motoren[M_VL].ticks++; }
void motor_isr_m_vr(void) { motoren[M_VR].ticks++; }
void motor_isr_m_hl(void) { motoren[M_HL].ticks++; }
void motor_isr_m_hr(void) { motoren[M_HR].ticks++; }
void setup() {
//Serial.begin(115200);
Serial.begin(9600);
pinMode(motoren[M_VL].enc_pin, INPUT_PULLUP);
// motor_init_pos(M_VL);
/*
* Hier wird die Verbindung hergestellt zwischen Pin und Interruptroutine.
* Die Namen muessen zueinander passen.
* Durch CHANGE werden beide Uebergaenge beruecksichtigt.
*/
attachInterrupt(digitalPinToInterrupt(motoren[M_VL].enc_pin), motor_isr_m_vl, CHANGE);
}
void loop() {
unsigned long log_time;
String out_s = "";
motor_start(M_VL, 255/2+3, FORWARD);
log_time = millis();
while(motor_laeuft(M_VL)) {
if(motor_hole_ticks(M_VL) >= ticks_per_rev)
motor_stop(M_VL);
// Ticks und Strecke ausgeben
static const int wtime = 250;
if(log_time + wtime <= millis() ) {
log_time = wtime + millis();
out_s = "";
out_s += millis() + ": ";
out_s += M_VL + " ";
out_s += motoren[M_VL].ticks + " "; // Hier koennte jetzt ein Interrupt unterbrechen!
out_s += motor_strecke_gefahren(M_VL);
Serial.println(out_s);
}
}
while(1);
// oder
// delay(2000);
}
void setupMulti() {
//Serial.begin(115200);
Serial.begin(9600);
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
pinMode(motoren[idx].enc_pin, INPUT_PULLUP);
// motor_init_pos(idx);
}
/*
* Hier wird die Verbindung hergestellt zwischen Pin und Interruptroutine.
* Die Namen muessen zueinander passen.
* Durch CHANGE werden beide Uebergaenge beruecksichtigt.
*/
attachInterrupt(digitalPinToInterrupt(motoren[M_VL].enc_pin), motor_isr_m_vl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HL].enc_pin), motor_isr_m_hl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_VR].enc_pin), motor_isr_m_vr, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HR].enc_pin), motor_isr_m_hr, CHANGE);
}
/*
* Alle Motoren an, bis eine Umdrehung erreicht ist. Es wird alle
* halbe Sekunde der Zustand der Ticks pro Motor ausgeben.
*/
void loopMulti() {
unsigned long log_time = 0;
unsigned long ticks_tmp = 0;
unsigned long all_ticks_tmp[M_MAX] = { 0, 0, 0, 0 };
String out_s = "";
bool alle_aus = false;
// Alle Motoren an.
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
if( ! motor_laeuft(idx) )
motor_start(idx, 255/2+3, FORWARD);
}
while( ! alle_aus ) {
// Wenn die Anzahl der Ticks fuer eine Umdrehung
// erreicht ist - Motor aus.
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
if(motor_laeuft(idx) && motor_hole_ticks(idx) >= ticks_per_rev) {
motor_stop(idx);
}
}
// Ticks und Strecke ausgeben
static const int wtime = 250;
if(log_time + wtime <= millis() ) {
out_s = "";
out_s += millis() + ": ";
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
out_s += idx + " ";
out_s += motoren[idx].ticks + " "; // Hier koennte jetzt ein Interrupt unterbrechen!
out_s += motor_strecke_gefahren(idx);
ticks_tmp = 0;
motor_ticks_per_milli(idx, &ticks_tmp);
out_s += " " + ticks_tmp;
if(idx == M_MAX - 1)
out_s += "\n";
else
out_s += ", ";
}
for(uint8_t idx = 0; idx < M_MAX; idx++)
all_ticks_tmp[idx] = 0;
motor_ticks_per_milli_fuer_alle(all_ticks_tmp, M_MAX);
for(uint8_t idx; idx < M_MAX; idx++)
out_s += all_ticks_tmp[idx] + " ";
Serial.println(out_s);
log_time = wtime + millis();
}
// pruefen ob alle Motoren aus sind.
for(uint8_t idx = M_VL, alle_aus = true; alle_aus && idx < M_MAX; idx++) {
alle_aus = alle_aus && ( ! motor_laeuft(idx) );
}
}
while(1);
// Oder nach 2sec geht's von vorne los.
// delay(2000);
}
/*
* Faehrt den Motor auf den ersten HIGH Level des Encoderpins.
* Falls er schon HIGH ist wird erst in ein LOW gefahren und
* beim naechsten HIGH gestoppt.
*/
void motor_init_pos(uint8_t idx) {
if(idx >= M_MAX)
return;
if(motor_laeuft(idx))
motor_stop(idx);
// Wenn wir bereits eine 1 haben, dann fahren wir erstmal bis zur
// naechsten 0.
if(digitalRead(motoren[idx].enc_pin)) {
motoren[idx].mot.setSpeed(255/3);
motoren[idx].mot.run(FORWARD);
while(digitalRead(motoren[idx].enc_pin));
}
// Wir sind in ner 0, wissen aber nicht ob sich der Motor schon dreht.
if( ! digitalRead(motoren[idx].enc_pin) ) {
motoren[idx].mot.setSpeed(255/4);
motoren[idx].mot.run(FORWARD);
while( ! digitalRead(motoren[idx].enc_pin) );
motoren[idx].mot.setSpeed(0);
motoren[idx].mot.run(RELEASE);
// Bremsen evtl. nicht noetig oder muss angepasst werden.
/*
delayMicroseconds(75);
motoren[idx].mot.setSpeed(255/5);
motoren[idx].mot.run(BACKWARD);
delayMicroseconds(100);
motoren[idx].mot.setSpeed(0);
motoren[idx].mot.run(RELEASE);
*/
}
}
/*
*
*/
bool motor_laeuft(uint8_t idx) {
if(idx >= M_MAX)
return false;
return motoren[idx].start_time > 0 && motoren[idx].start_time == motoren[idx].stop_time;
}
/*
* idx - der Motor Index
* pwm und dir wie in AF_DCMotor.
*/
void motor_start(uint8_t idx, uint8_t pwm, uint8_t dir) {
if(idx >= M_MAX)
return;
motor_setze_ticks(idx, 0);
motoren[idx].start_time = motoren[idx].stop_time = millis();
motoren[idx].mot.setSpeed(pwm);
motoren[idx].mot.run(dir);
}
/*
* Fuer den Fall das zwischen motor_start und motor_stop die pwm nicht
* geaendert wird liesse sich aus der Zeit und der Strecke s.u. grob die
* Geschwindigkeit ermitteln (Be- und Entschleunigung vernachlaessgt).
*/
void motor_stop(uint8_t idx) {
if(idx >= M_MAX)
return;
motoren[idx].mot.setSpeed(0);
motoren[idx].mot.run(RELEASE);
motoren[idx].stop_time = millis();
}
/*
* Liesst den ticks Wert interrupt safe.
*/
inline uint32_t motor_hole_ticks(uint8_t idx) {
if(idx >= M_MAX)
return 0;
noInterrupts();
uint32_t tmp = motoren[idx].ticks;
interrupts();
return tmp;
}
/*
* Setzt den ticks Wert interrupt safe.
*/
inline void motor_setze_ticks(uint8_t idx, uint32_t val) {
if(idx >= M_MAX)
return;
noInterrupts();
motoren[idx].ticks = val;
interrupts();
}
/*
*
*/
void motor_ticks_per_milli(uint8_t idx, unsigned long *res) {
if(idx >= M_MAX) {
*res = 0;
return;
}
*res = motor_hole_ticks(idx) / (millis() - motoren[idx].start_time);
}
/*
* Zu _einem_ Zeitpunkt werden alle Ticks/Milli ausgerechnet.
*/
void motor_ticks_per_milli_fuer_alle(unsigned long *res, uint8_t n) {
unsigned long *b = 0;
unsigned long tstamp = 0;
if(n != M_MAX)
return;
b = res;
noInterrupts();
tstamp = millis();
while(b < res + n) {
*b = motoren[b - res].ticks;
b++;
}
interrupts();
for(b = res; b < res + n; b++) {
*b = *b / (tstamp - motoren[b - res].start_time);
}
}
/*
* Rechnet die gefahrenen Zentimeter anhand der Ticks aus.
*/
double motor_strecke_gefahren(uint8_t idx) {
if(idx >= M_MAX)
return 0.0;
return motor_hole_ticks(idx) * u_per_tick;
}
/*
* Rechnet fuer alle Motoren zu _einem_ Zeitpunkt die Strecke
* aus.
*/
void motor_strecke_fuer_alle(double *res, int n) {
if(n != M_MAX)
return;
double *b = 0;
unsigned long tmps[M_MAX];
uint8_t idx = 0;
noInterrupts();
while(idx < M_MAX) {
tmps[idx] = motoren[idx].ticks;
idx++;
}
interrupts();
for(b = res; b < res + n; b++) {
*b = tmps[b-res] * u_per_tick;
}
}
Der nächste Schritt wäre jetzt die Datenstruktur für einen Regler zu erweitern und diesen
zu implementieren.
Soweit bin hier noch nicht, da die Dinger Neuland für mich sind und ich jetzt erstmal
schaue ob mir eine gute Fee einen Drucker auf den heutigen Sperrmüll gestellt hat, den
für meinen Robby ausschlachten kann.
Viele Grüße
Chris
vielen dank, botty für den code...
mache Dir bitte keine gedanken über "zu viel erklärender text" und so, lieber mehr als weniger. Und auch wenn mein englisch ausreichend ist um beim lesen technischer texte halbwegs zu verstehen um was es geht - die deutschen kommentare und erklärungen sind richtig wohltuend...
für meinen "programmierstand" ist der code recht ambitioniert, ich brauche zeit um alles zu verstehen. Ich versuche so zu lernen, dass ich fremden code zuerst zu erfassen versuche, dann starte und durch veränderungen mir verborgen gebliebenes zu verstehen versuche. Dazu brauche ich - wie schon gesagt - zeit und einen funktionierenden sketch :-( ---- ist da evtl. beim copy und paste etwas verloren gegangen? Oder muss ich irgendwo etwas ergänzen/anpassen?
schon hier:
enum motoren_e {
M_VL = 0, // Motor vorne links
M_HL,
M_VR,
M_HR,
M_MAX
};
die reiehnfolge meiner motoren ist durch die lage des mega und des darauf gesteckten motorshilds eine andere (die zahlen entsprechen den motoren 1 bis 4 des motorshields...):
M_Hl = 1
M_Hr = 2
M_Vr = 3
M_Vl = 4
die eigentliche zuordnung zu den motorbezeichnungen aus der lib findet aber - wenn ich es richtig verstehe - erst hier statt:
/*
* Hier werden die PWM Channel - Encoder Pin Paare gesetzt.
* Restliche Elemente muessen ebenfalls initialisiert werden.
* Werte pruefen ob sie zu den Namen oben passen.
* Fuer die externen Interrupts sind die Pins 2,5,18-21
* erlaubt. Hardware anpassen.
*/
struct motor motoren[M_MAX] = {
{ AF_DCMotor(1), 18, 0, 0, 0 }, // M_VL
{ AF_DCMotor(2), 19, 0, 0, 0 }, // M_HL
{ AF_DCMotor(3), 20, 0, 0, 0 }, // M_VR
{ AF_DCMotor(4), 21, 0, 0, 0 } // M_HR
};
Beim versuch den sketch zu kompilieren bekomme ich folgende fehlermeldung:
botty_4_motoren_1.ino: In function ‘void setup()’:
botty_4_motoren_1.ino:70:62: error: ‘digitalPinToInterrupt’ was not declared in this scope
botty_4_motoren_1.ino: In function ‘void loop()’:
botty_4_motoren_1.ino:93:13: error: ambiguous overload for ‘operator+=’ (operand types are ‘String’ and ‘double’)
botty_4_motoren_1.ino:93:13: note: candidates are:
In file included from /usr/share/arduino/hardware/arduino/cores/arduino/Arduino.h:192:0,
from botty_4_motoren_1.ino:9:
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:108:11: note: String& String::operator+=(char)
String & operator += (char c) {concat(c); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:109:11: note: String& String::operator+=(unsigned char)
String & operator += (unsigned char num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:110:11: note: String& String::operator+=(int)
String & operator += (int num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:111:11: note: String& String::operator+=(unsigned int)
String & operator += (unsigned int num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:112:11: note: String& String::operator+=(long int)
String & operator += (long num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:113:11: note: String& String::operator+=(long unsigned int)
String & operator += (unsigned long num) {concat(num); return (*this);}
^
botty_4_motoren_1.ino: In function ‘void setupMulti()’:
botty_4_motoren_1.ino:116:62: error: ‘digitalPinToInterrupt’ was not declared in this scope
botty_4_motoren_1.ino: In function ‘void loopMulti()’:
botty_4_motoren_1.ino:157:15: error: ambiguous overload for ‘operator+=’ (operand types are ‘String’ and ‘double’)
botty_4_motoren_1.ino:157:15: note: candidates are:
In file included from /usr/share/arduino/hardware/arduino/cores/arduino/Arduino.h:192:0,
from botty_4_motoren_1.ino:9:
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:108:11: note: String& String::operator+=(char)
String & operator += (char c) {concat(c); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:109:11: note: String& String::operator+=(unsigned char)
String & operator += (unsigned char num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:110:11: note: String& String::operator+=(int)
String & operator += (int num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:111:11: note: String& String::operator+=(unsigned int)
String & operator += (unsigned int num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:112:11: note: String& String::operator+=(long int)
String & operator += (long num) {concat(num); return (*this);}
^
/usr/share/arduino/hardware/arduino/cores/arduino/WString.h:113:11: note: String& String::operator+=(long unsigned int)
String & operator += (unsigned long num) {concat(num); return (*this);}
^
an der verstehe ich nur, dass ‘digitalPinToInterrupt’ nicht deklariert wurde, deshalb die frage ob es beim kopieren passiert sein könnte, oder ob ich woanders suchen muss?
Hallo inka,
es tut mir leid, dass sich das bei Dir nicht kompilieren läßt und Dich unnötig Zeit kostet.
Die einzige Erklärung die ich habe ist, das wir unterschiedliche Arduino IDE Versionen benutzen.
Ich habe das Ganze unter Version 1.6.5 sowohl in meinen Nano hineinbekommen als auch gegen das Mega 2560 er Board fehlerfrei kompilieren können.
Ich meine das mit dem String ließe sich mit direkter Ausgabe auf Serial umgehen. Was aber an "attachInterrupt()" als Parameter übegeben werden muß wenn "digitalPinToInterrupt()" nicht da ist müßte ich nachschlagen (oder weiß daß jemand anderes hier aus dem Kopf?).
Die andere Variante, wenn Du 'ne ältere IDE Version benutzt, wäre die neueste Version zu installieren. Das würde ich aber nur machen, wenn andere Projekte von Dir dadurch nicht gefährdet werden, was nur Du abschätzen kannst.
Zu den Einstellungen:
Wenn das
M_Hl = 1
M_Hr = 2
M_Vr = 3
M_Vl = 4
Deine PWM Kanäle sind, sieht die Initialisierung so aus:
struct motor motoren[M_MAX] = {
{ AF_DCMotor(4), 18, 0, 0, 0 }, // M_VL
{ AF_DCMotor(1), 19, 0, 0, 0 }, // M_HL
{ AF_DCMotor(3), 20, 0, 0, 0 }, // M_VR
{ AF_DCMotor(2), 21, 0, 0, 0 } // M_HR
};
testen kannst Du das indem Du erstmal die Funktionen loopMulti, setupMulti, loop und setup auskommentierst oder löscht.
der Test ob die Zuordnung stimmt ohne Encoder/Interrupt geraffel sähe dann so aus:
void setup() {
}
void loop() {
motoren[M_VL].mot.setSpeed(128);
motoren[M_VL].mot.run(FORWARD);
delay(1000);
motoren[M_VL].mot.setSpeed(0);
motoren[M_VL].mot.run(RELEASE);
}
und synonym mit den anderen Symbolen aus "enum motor_e" für "M_VL".
Grüße
Chris
hallo botty,
es war die ältere version der IDE, die ich verwendet habe, unter ubuntu ist ja nicht immer das aktuellste installiert. Jetzt habe ich die 1.6.6 und konnte Deinen code bereits kompilieren, kann also weiter experimentieren...
was meine älteren projekte betrifft, da verlasse ich mich auf die abwärtskompatibilität der software:-), notfalls ist ja die alte version auch noch installiert...
zum sperrmüll und drucker: bei uns muss man nicht warten bis jemand einen drucker rausstellt, man kann es im wertstoffhof versuchen...- so habe ich mir auch schon teile besorgt...
hallo botty,
Zu den Einstellungen:
Wenn das
M_Hl = 1
M_Hr = 2
M_Vr = 3
M_Vl = 4
Deine PWM Kanäle sind, sieht die Initialisierung so aus:
struct motor motoren[M_MAX] = {
{ AF_DCMotor(4), 18, 0, 0, 0 }, // M_VL
{ AF_DCMotor(1), 19, 0, 0, 0 }, // M_HL
{ AF_DCMotor(3), 20, 0, 0, 0 }, // M_VR
{ AF_DCMotor(2), 21, 0, 0, 0 } // M_HR
};
kann es sein, dass wir hier beide von etwas anderen voraussetzungen ausgehen? Ich habe keine PWM kanäle/pins wie es sie direkt auf dem mega gibt, sondern schliesse meine vier motoren am motorshield (https://learn.adafruit.com/downloads/pdf/adafruit-motor-shield.pdf) (M1 bis M4) an...
Ich bin grad auf dem Handy und deshalb in aller Kürze: ohne Interrupts wird das nicht gut gehen.
Ich hab was ähnliches gebaut und es geht ganz gut (mit IRQs). Wenn Du keinen Mega2560 nutzt dann gibt es noch die PinChangeInterrupts, diese sind etwas langsamer und umständlicher aber funktionieren gut.
Hallo inka,
aus Deinem Beispiel mit den mehreren Motoren hast folgende Variablen definiert gehabt:
AF_DCMotor motor_1(1);
AF_DCMotor motor_2(2);
AF_DCMotor motor_3(3);
AF_DCMotor motor_4(4);
die Zahl n, die Du hier in motor_x(n) benutzt hast, muß in der ersten Spalte des Arrays in AF_DCMotor(n) eingetragen werden.
Probier doch bitte mal aus,wenn Du die Initialisierung von oben nimmst, ob
void loop() {
motoren[M_VL].mot.setSpeed(130);
motoren[M_VL].mot.run(FORWARD);
delay(3000);
motoren[M_VL].mot.setSpeed(0);
motoren[M_VL].mot.run(RELEASE);
delay(3000);
}
den linken vorderen Motor alle drei Sekunden an bzw aus schaltet.
hallo botty,
aus Deinem Beispiel mit den mehreren Motoren hast folgende Variablen definiert gehabt:
AF_DCMotor motor_1(1);
AF_DCMotor motor_2(2);
AF_DCMotor motor_3(3);
AF_DCMotor motor_4(4);
die Zahl n, die Du hier in motor_x(n) benutzt hast, muß in der ersten Spalte des Arrays in AF_DCMotor(n) eingetragen werden.
so?
struct motor motoren[M_MAX] =
{
{ AF_DCMotor(1), 4, 18, 0, 0 }, // M_VL
{ AF_DCMotor(2), 1, 19, 0, 0 }, // M_HL
{ AF_DCMotor(3), 3, 20, 0, 0 }, // M_VR
{ AF_DCMotor(4), 2, 21, 0, 0 } // M_HR
};
Probier doch bitte mal aus,wenn Du die Initialisierung von oben nimmst, ob
void loop() {
motoren[M_VL].mot.setSpeed(130);
motoren[M_VL].mot.run(FORWARD);
delay(3000);
motoren[M_VL].mot.setSpeed(0);
motoren[M_VL].mot.run(RELEASE);
delay(3000);
}
den linken vorderen Motor alle drei Sekunden an bzw aus schaltet.
der - so wie ich Dich verstanden habe geänderte code sieht so aus:
#include <AFMotor.h>
/*
* Benamte Indexe. Wichtig: Alle Schleifen basieren auf der
* Annahme, dass M_VL das erste Element und mit 0 initialisiert
* ist. M_MAX muss ausserdem _immer_ das letzte Element sein da
* es die Groesse des Arrays s.u. bestimmt.
*/
enum motoren_e
{
M_VL = 0, // Motor vorne links
M_HL,
M_VR,
M_HR,
M_MAX
};
/*
* Infos zu einem Motor zusammenfassen.
*/
struct motor
{
AF_DCMotor mot;
uint8_t enc_pin;
// volatile damit der Compiler keine 'dummen' Optimierung macht.
volatile uint32_t ticks;
unsigned long start_time;
unsigned long stop_time;
};
/*
* Hier werden die PWM Channel - Encoder Pin Paare gesetzt.
* Restliche Elemente muessen ebenfalls initialisiert werden.
* Werte pruefen ob sie zu den Namen oben passen.
* Fuer die externen Interrupts sind die Pins 2,5,18-21
* erlaubt. Hardware anpassen.
*/
struct motor motoren[M_MAX] =
{
{ AF_DCMotor(1), 4, 18, 0, 0 }, // M_VL
{ AF_DCMotor(2), 1, 19, 0, 0 }, // M_HL
{ AF_DCMotor(3), 3, 20, 0, 0 }, // M_VR
{ AF_DCMotor(4), 2, 21, 0, 0 } // M_HR
};
// Anzahl der Encoderstriche fuer eine Umdrehung
const static double ticks_per_rev = 40;
const static double durchmesser = 6.5; // in cm;
const static double u_per_tick = (3.1415926535897932384626433832795 * durchmesser) / ticks_per_rev;
/*
* Interruptroutinen mit der gleichen Namenskonvention wie
* oben.
*/
void motor_isr_m_vl(void) { motoren[M_VL].ticks++; }
void motor_isr_m_vr(void) { motoren[M_VR].ticks++; }
void motor_isr_m_hl(void) { motoren[M_HL].ticks++; }
void motor_isr_m_hr(void) { motoren[M_HR].ticks++; }
void setup()
{
//Serial.begin(115200);
Serial.begin(9600);
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
{
pinMode(motoren[idx].enc_pin, INPUT_PULLUP);
// motor_init_pos(idx);
}
/*
* Hier wird die Verbindung hergestellt zwischen Pin und Interruptroutine.
* Die Namen muessen zueinander passen.
* Durch CHANGE werden beide Uebergaenge beruecksichtigt.
*/
attachInterrupt(digitalPinToInterrupt(motoren[M_VL].enc_pin), motor_isr_m_vl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HL].enc_pin), motor_isr_m_hl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_VR].enc_pin), motor_isr_m_vr, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HR].enc_pin), motor_isr_m_hr, CHANGE);
}
/*
* Alle Motoren an, bis eine Umdrehung erreicht ist. Es wird alle
* halbe Sekunde der Zustand der Ticks pro Motor ausgeben.
*/
void loop() {
motoren[M_VL].mot.setSpeed(130);
motoren[M_VL].mot.run(FORWARD);
delay(3000);
motoren[M_VL].run(RELEASE);
delay(3000);
}
/*
void loop()
{
unsigned long log_time = 0;
unsigned long ticks_tmp = 0;
unsigned long all_ticks_tmp[M_MAX] = { 0, 0, 0, 0 };
String out_s = "";
bool alle_aus = false;
// Alle Motoren an.
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
{
if( ! motor_laeuft(idx) )
motor_start(idx, 200/2+3, FORWARD);
}
while( ! alle_aus )
{
// Wenn die Anzahl der Ticks fuer eine Umdrehung
// erreicht ist - Motor aus.
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
if(motor_laeuft(idx) && motor_hole_ticks(idx) >= ticks_per_rev)
{
motor_stop(idx);
}
}
// Ticks und Strecke ausgeben
static const int wtime = 250;
if(log_time + wtime <= millis() )
{
out_s = "";
out_s += millis() + ": ";
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
{
out_s += idx + " ";
out_s += motoren[idx].ticks + " "; // Hier koennte jetzt ein Interrupt unterbrechen!
out_s += motor_strecke_gefahren(idx);
ticks_tmp = 0;
motor_ticks_per_milli(idx, &ticks_tmp);
out_s += " " + ticks_tmp;
if(idx == M_MAX - 1)
out_s += "\n";
else
out_s += ", ";
}
for(uint8_t idx = 0; idx < M_MAX; idx++)
all_ticks_tmp[idx] = 0;
motor_ticks_per_milli_fuer_alle(all_ticks_tmp, M_MAX);
for(uint8_t idx; idx < M_MAX; idx++)
out_s += all_ticks_tmp[idx] + " ";
Serial.println(out_s);
log_time = wtime + millis();
}
// pruefen ob alle Motoren aus sind.
for(uint8_t idx = M_VL, alle_aus = true; alle_aus && idx < M_MAX; idx++)
{
alle_aus = alle_aus && ( ! motor_laeuft(idx) );
}
}
while(1);
// Oder nach 2sec geht's von vorne los.
// delay(2000);
}*/
/*
* Faehrt den Motor auf den ersten HIGH Level des Encoderpins.
* Falls er schon HIGH ist wird erst in ein LOW gefahren und
* beim naechsten HIGH gestoppt.
*/
void motor_init_pos(uint8_t idx)
{
if(idx >= M_MAX)
return;
if(motor_laeuft(idx))
motor_stop(idx);
// Wenn wir bereits eine 1 haben, dann fahren wir erstmal bis zur
// naechsten 0.
if(digitalRead(motoren[idx].enc_pin))
{
motoren[idx].mot.setSpeed(255/3);
motoren[idx].mot.run(FORWARD);
while(digitalRead(motoren[idx].enc_pin));
}
// Wir sind in ner 0, wissen aber nicht ob sich der Motor schon dreht.
if( ! digitalRead(motoren[idx].enc_pin) )
{
motoren[idx].mot.setSpeed(255/4);
motoren[idx].mot.run(FORWARD);
while( ! digitalRead(motoren[idx].enc_pin) );
motoren[idx].mot.setSpeed(0);
motoren[idx].mot.run(RELEASE);
// Bremsen evtl. nicht noetig oder muss angepasst werden.
/*
delayMicroseconds(75);
motoren[idx].mot.setSpeed(255/5);
motoren[idx].mot.run(BACKWARD);
delayMicroseconds(100);
motoren[idx].mot.setSpeed(0);
motoren[idx].mot.run(RELEASE);
*/
}
}
/*
*
*/
bool motor_laeuft(uint8_t idx)
{
if(idx >= M_MAX)
return false;
return motoren[idx].start_time > 0 && motoren[idx].start_time == motoren[idx].stop_time;
}
/*
* idx - der Motor Index
* pwm und dir wie in AF_DCMotor.
*/
void motor_start(uint8_t idx, uint8_t pwm, uint8_t dir)
{
if(idx >= M_MAX)
return;
motor_setze_ticks(idx, 0);
motoren[idx].start_time = motoren[idx].stop_time = millis();
motoren[idx].mot.setSpeed(pwm);
motoren[idx].mot.run(dir);
}
/*
* Fuer den Fall das zwischen motor_start und motor_stop die pwm nicht
* geaendert wird liesse sich aus der Zeit und der Strecke s.u. grob die
* Geschwindigkeit ermitteln (Be- und Entschleunigung vernachlaessgt).
*/
void motor_stop(uint8_t idx)
{
if(idx >= M_MAX)
return;
motoren[idx].mot.setSpeed(0);
motoren[idx].mot.run(RELEASE);
motoren[idx].stop_time = millis();
}
/*
* Liesst den ticks Wert interrupt safe.
*/
inline uint32_t motor_hole_ticks(uint8_t idx)
{
if(idx >= M_MAX)
return 0;
noInterrupts();
uint32_t tmp = motoren[idx].ticks;
interrupts();
return tmp;
}
/*
* Setzt den ticks Wert interrupt safe.
*/
inline void motor_setze_ticks(uint8_t idx, uint32_t val)
{
if(idx >= M_MAX)
return;
noInterrupts();
motoren[idx].ticks = val;
interrupts();
}
/*
*
*/
void motor_ticks_per_milli(uint8_t idx, unsigned long *res)
{
if(idx >= M_MAX)
{
*res = 0;
return;
}
*res = motor_hole_ticks(idx) / (millis() - motoren[idx].start_time);
}
/*
* Zu _einem_ Zeitpunkt werden alle Ticks/Milli ausgerechnet.
*/
void motor_ticks_per_milli_fuer_alle(unsigned long *res, uint8_t n)
{
unsigned long *b = 0;
unsigned long tstamp = 0;
if(n != M_MAX)
return;
b = res;
noInterrupts();
tstamp = millis();
while(b < res + n)
{
*b = motoren[b - res].ticks;
b++;
}
interrupts();
for(b = res; b < res + n; b++) {
*b = *b / (tstamp - motoren[b - res].start_time);
}
}
/*
* Rechnet die gefahrenen Zentimeter anhand der Ticks aus.
*/
double motor_strecke_gefahren(uint8_t idx)
{
if(idx >= M_MAX)
return 0.0;
return motor_hole_ticks(idx) * u_per_tick;
}
/*
* Rechnet fuer alle Motoren zu _einem_ Zeitpunkt die Strecke
* aus.
*/
void motor_strecke_fuer_alle(double *res, int n)
{
if(n != M_MAX)
return;
double *b = 0;
unsigned long tmps[M_MAX];
uint8_t idx = 0;
noInterrupts();
while(idx < M_MAX) {
tmps[idx] = motoren[idx].ticks;
idx++;
}
interrupts();
for(b = res; b < res + n; b++)
{
*b = tmps[b-res] * u_per_tick;
}
}
und lässt sich nicht kompilieren (ich sagte es schon, sehr sportlich der code für meine programmierkünste :-()
Arduino: 1.6.6 (Linux), Board: "Arduino Mega ADK"
/home/georg/Arduino/sainsmart_car/fahren_mit timer/botty_4_motoren_1/botty_4_motoren_1.ino: In function 'void loop()':
botty_4_motoren_1:95: error: 'struct motor' has no member named 'run'
motoren[M_VL].run(RELEASE);
^
exit status 1
'struct motor' has no member named 'run'
Dieser Report hätte mehr Informationen mit
"Ausführliche Ausgabe während der Kompilierung"
aktiviert in Datei > Einstellungen.
Sorry ich habe das nicht gut erklärt. Du hast ein Feld mehr eingeführt dadurch das du die Zahlen eingefügt hast. Die Anzahl der Zeilen der "struct motor" muß mit der Anzahl der Spalten bei der Initialisierung übereinstimmen.
#include <AFMotor.h>
/*
* Benamte Indexe. Wichtig: Alle Schleifen basieren auf der
* Annahme, dass M_VL das erste Element und mit 0 initialisiert
* ist. M_MAX muss ausserdem _immer_ das letzte Element sein da
* es die Groesse des Arrays s.u. bestimmt.
*/
enum motoren_e
{
M_VL = 0, // Motor vorne links
M_HL,
M_VR,
M_HR,
M_MAX
};
/*
* Infos zu einem Motor zusammenfassen.
*/
struct motor
{
AF_DCMotor mot;
uint8_t enc_pin;
// volatile damit der Compiler keine 'dummen' Optimierung macht.
volatile uint32_t ticks;
unsigned long start_time;
unsigned long stop_time;
};
/*
* Hier werden die PWM Channel - Encoder Pin Paare gesetzt.
* Restliche Elemente muessen ebenfalls initialisiert werden.
* Werte pruefen ob sie zu den Namen oben passen.
* Fuer die externen Interrupts sind die Pins 2,5,18-21
* erlaubt. Hardware anpassen.
*/
struct motor motoren[M_MAX] =
{
{ AF_DCMotor(4), 18, 0, 0, 0 }, // M_VL
{ AF_DCMotor(1), 19, 0, 0, 0 }, // M_HL
{ AF_DCMotor(3), 20, 0, 0, 0 }, // M_VR
{ AF_DCMotor(2), 21, 0, 0, 0 } // M_HR
};
// Anzahl der Encoderstriche fuer eine Umdrehung
const static double ticks_per_rev = 40;
const static double durchmesser = 6.5; // in cm;
const static double u_per_tick = (3.1415926535897932384626433832795 * durchmesser) / ticks_per_rev;
/*
* Interruptroutinen mit der gleichen Namenskonvention wie
* oben.
*/
void motor_isr_m_vl(void) { motoren[M_VL].ticks++; }
void motor_isr_m_vr(void) { motoren[M_VR].ticks++; }
void motor_isr_m_hl(void) { motoren[M_HL].ticks++; }
void motor_isr_m_hr(void) { motoren[M_HR].ticks++; }
void setup()
{
//Serial.begin(115200);
Serial.begin(9600);
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
{
pinMode(motoren[idx].enc_pin, INPUT_PULLUP);
// motor_init_pos(idx);
}
/*
* Hier wird die Verbindung hergestellt zwischen Pin und Interruptroutine.
* Die Namen muessen zueinander passen.
* Durch CHANGE werden beide Uebergaenge beruecksichtigt.
*/
attachInterrupt(digitalPinToInterrupt(motoren[M_VL].enc_pin), motor_isr_m_vl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HL].enc_pin), motor_isr_m_hl, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_VR].enc_pin), motor_isr_m_vr, CHANGE);
attachInterrupt(digitalPinToInterrupt(motoren[M_HR].enc_pin), motor_isr_m_hr, CHANGE);
}
/*
* Alle Motoren an, bis eine Umdrehung erreicht ist. Es wird alle
* halbe Sekunde der Zustand der Ticks pro Motor ausgeben.
*/
void loop() {
unsigned long time;
motoren[M_VL].mot.setSpeed(130);
motoren[M_VL].mot.run(FORWARD);
for(time = millis(); time + 3000 >= millis(); ) {
delay(10);
Serial.print(motoren[M_VL].ticks);
Serial.print(" ");
}
Serial.println("");
motoren[M_VL].mot.setSpeed(0);
motoren[M_VL].mot.run(RELEASE);
delay(3000);
}
Das Schlüsselwort struct ist hier falsch -> weglassen.
struct motor motoren[M_MAX] =
{
{ AF_DCMotor(1), 4, 18, 0, 0 }, // M_VL
{ AF_DCMotor(2), 1, 19, 0, 0 }, // M_HL
{ AF_DCMotor(3), 3, 20, 0, 0 }, // M_VR
{ AF_DCMotor(4), 2, 21, 0, 0 } // M_HR
};
hi botty,
jetzt läuft der motor 4 (VL) für 3 sec, 3 sec bleibt er stehen, mit oder ohne "struct" - was bedeutet das in dem zusammenhang?
struct erwartet normalerweise einen nachstehenden Bezeichner und keinen Datentyp (hier motor, den du vorher definiert hast). Daher wundert mich, dass der Code so kompiliert wird. Ohne 'struct' ist das eine simple Felddefinition mit direkter Initialisierung.
Sisor,
bei allem Respekt schau nochmal genau hin:
erst wird der Datentyp "struct motor" deklariert und dann die Array-Variable "motoren" definiert und die ist vom Typ "struct motor". Die Elemente des Arrays werden dann mit den Werten initialisiert, dat is aber mal ganz sicher so korrekt. Könnte es sein das Du hier
struct motor {
/// Elemente
};
mit
typedef struct {
// Elemente
} motor;
verwechselst? Dat sind nämlich zwei Paar unterschiedliche Schuhe.
inka, in dem Zusammenhang stehen lassen, das ist vollkommen korrektest C was ich da hingeschrieben habe.
Hat Dein Programm denn jetzt was auf der Konsole ausgegeben oder kam nix? Wenn der Encoder vom Rad das sich gedreht hat, am Pin 18 liegt, hätte er eigentlich fortlaufend aufsteigende Zahlen anzeigen müssen, was ja der Sinn der ganzen Sache ist.
Ist zwar Geschmackssache, aber statt struct würde ich C++Vererbung empfehlen. Beispiel:
#include <AFMotor.h>
class myMotor : public AF_DCMotor {
public:
uint8_t enc_pin;
volatile uint32_t ticks = 0;
uint32_t start_time = 0;
uint32_t stop_time = 0;
myMotor(uint8_t motornum, uint8_t enc_pin) : AF_DCMotor(motornum) {
this->enc_pin = enc_pin;
}
};
enum motoren_e { M_VL, M_HL, M_VR, M_HR, M_MAX };
myMotor motor[4] {
myMotor(1,18) , // M_VL
myMotor(2,19) , // M_HL
myMotor(3,20) , // M_VR
myMotor(4,21) // M_HR
};
void setup() {
motor[M_VL].ticks = 55;
}
void loop() {
motor[M_VL].setSpeed(127);
motor[M_VL].run(FORWARD);
}
hi botty,
Hat Dein Programm denn jetzt was auf der Konsole ausgegeben oder kam nix? Wenn der Encoder vom Rad das sich gedreht hat, am Pin 18 liegt, hätte er eigentlich fortlaufend aufsteigende Zahlen anzeigen müssen, was ja der Sinn der ganzen Sache ist.
ja, es kommen diese zahlen:
0 8 721 724 728 733 636 639 641 644 648 651 652 655 659 662 666 669 672 674 677 680 684 687 691 695 698 701 705 706 709 712 716 718 721 724 728 73�1 3 3 3 3 5 7 7 8 10 10 12 12 16 16 19 19 23 24 26 29 30 32 35 36 37 40 44 45 47 51 54 56 58 61 65 68 70 73 75 78 81 85 88 91 93 96 98 101 103 107 110 114 117 119 122 124 127 130 134 137 140 144 147 149 152 155 158 161 163 166 169 172 175 180 184 187 190 191 195 199 201 204 207 210 213 216 219 222 225 228 231 234 235 238 241 244 247 248 251 254 257 260 265 268 271 272 276 279 282 285 288 291 293 297 300 303 306 311 314 317 321 323 326 328 331 333 336 339 342 345 348 351 354 357 359 363 366 368 372 377 380 381 384 386 389 393 396 399 402 406 409 412 413 417 420 423 427 429 432 435 439 442 445 450 453 456 458 463 467 470 474 476 480 483 486 489 492 495 498 501 504 508 511 512 515 518 522 524 527 529 532 535 540 543 547 550 553 556 559 560 563 567 571 573 576 579 582 585 587 591 594 597 598 602 605 608 611 614 616 618 621 624 627 631 635 638 641 644 645 648 651 653 657 660 663 667 671 675 678 681 684 687 691 694 698 701 702 704 707 710 712 715 719 722 725 728 732 735 738 741 745 748 750 751 754 757 761 764 766 769 772 775 778 780 783 786 789 794 797 798 801 804 806 808 811 812 815 819 823 826 829 832 835 839 840
935 935 935 937 937 937 939 941 941 943 945 945 947 949 950 952 953 955 959 961 963 965 967 971 973 976 980 982 984 988 991 992 995 997 1001 1004 1007 1010 1013 1015 1018 1021 1024 1027 1028 1032 1034 1038 1041 1043 1047 1050 1051 1054 1057 1059 1062 1067 1070 1073 1078 1081 1084 1087 1088 1091 1095 1098 1100 1103 1106 1109 1113 1116 1120 1123 1124 1127 1131 1134 1137 1140 1143 1146 1149 1152 1155 1158 1162 1165 1169 1171 1174 1177 1180 1183 1188 1192 1195 1198 1202 1205 1209 1212 1215 1219 1220 1223 1226 1230 1235 1237 1241 1243 1247 1250 1253 1257 1260 1263 1264 1268 1271 1274 1277 1280 1282 1286 1289 1293 1297 1300 1303 1306 1309 1311 1314 1317 1321 1323 1327 1330 1333 1337 1340 1343 1346 1349 1353 1356 1360 1361 1366 1370 1373 1374 1377 1380 1383 1386 1390 1393 1396 1399 1402 1406 1409 1411 1414 1417 1420 1424 1426 1429 1434 1438 1441 1443 1447 1450 1453 1455 1458 1462 1465 1468 1471 1473 1476 1481 1485 1489 1492 1495 1499 1502 1504 1508 1509 1511 1515 1517 1518 1520 1524 1527 1530 1535 1538 1541 1544 1547 1550 1552 1553 1555 1558 1562 1565 1567 1570 1573 1576 1579 1581 1584 1587 1590 1594 1595 1598 1601 1604 1607 1610 1612 1615 1618 1622 1626 1628 1631 1634 1638 1639 1643 1648 1651 1654 1656 1661 1664 1667 1670 1673 1677 1680 1683 1686 1690 1693 1696 1698 1701 1704 1707 1710 1714 1718 1721 1724 1728 1731 1734 1737 1742 1746 1747 1750 1752 1755 1759 1761 1766 1770 1774 1778 1781 1785 1789 1793 1795 1800 1805
1898 1898 1898 1898 1900 1902 1902 1902 1904 1906 1906 1910 1910 1912 1914 1916 1918 1922 1922 1926 1928 1930 1933 1934 1936 1939 1942 1943 1945 1948 1952 1955 1957 1960 1962 1966 1969 1973 1974 1979 1983 1985 1989 1992 1995 1996 1999 2002 2004 2007 2010 2013 2017 2020 2023 2026 2029 2030 2033 2037 2041 2042 2046 2050 2053 2056 2059 2062 2064 2065 2069 2072 2076 2080 2082 2086 2089 2092 2096 2099 2101 2104 2106 2110 2114 2115 2119 2122 2125 2128 2131 2135 2138 2141 2144 2149 2152 2155 2158 2161 2164 2165 2167 2170 2174 2178 2181 2184 2188 2191 2194 2197 2201 2204 2207 2208 2211 2215 2218 2221 2224 2227 2229 2232 2234 2237 2241 2245 2248 2251 2254 2255 2258 2262 2267 2270 2272 2275 2279 2282 2285 2288 2291 2294 2297 2301 2304 2307 2311 2313 2316 2318 2320 2323 2326 2330 2333 2336 2339 2344 2347 2350 2353 2356 2359 2360 2363 2367 2370 2373 2375 2378 2381 2384 2387 2390 2395 2398 2400 2401 2405 2408 2411 2414 2417 2420 2422 2424 2427 2430 2434 2438 2441 2445 2448 2451 2452 2456 2459 2462 2466 2468 2470 2474 2477 2480 2483 2486 2488 2492 2495 2498 2501 2503 2504 2507 2510 2512 2516 2519 2522 2525 2528 2533 2536 2539 2541 2544 2547 2550 2551 2554 2558 2562 2565 2568 2572 2576 2579 2582 2585 2588 2590 2591 2596 2599 2602 2605 2609 2611 2613 2616 2620 2623 2626 2629 2632 2635 2636 2639 2642 2645 2648 2652 2655 2658 2662 2664 2667 2671 2674 2677 2680 2683 2685 2688 2693 2695 2697 2699 2702 2705 2708 2711 2715 2717 2719 2722 2725 2728 2729 2732 2735 2739
2833 2833 2833 2833 2833 2833 2833 2833 2833 2838 2838 2838 2840 2840 2840 2840 2840 2842 2842 2844 2844 2844 2844 2846 2848 2848 2848 2848 2850 2852 2852 2852 2854 2854 2856 2856 2856 2858 2860 2860 2860 2862 2862 2864 2864 2864 2866 2868 2868 2868 2870 2870 2872 2872 2872 2874 2876 2876 2876 2876 2878 2880 2880 2880 2880 2882 2882 2884 2884 2884 2884 2886 2886 2888 2888 2888 2890 2890 2892 2892 2892 2892 2892 2894 2894 2895 2895 2895 2895 2897 2897 2899 2899 2899 2899 2899 2901 2901 2901 2903 2903 2903 2903 2905 2905 2907 2907 2907 2907 2909 2909 2909 2911 2911 2911 2911 2913 2915 2915 2915 2915 2917 2917 2919 2919 2919 2921 2923 2923 2923 2925 2925 2927 2927 2927 2929 2931 2931 2931 2933 2935 2935 2935 2937 2939 2939 2939 2941 2943 2943 2943 2945 2947 2947 2947 2949 2949 2951 2951 2951 2953 2955 2955 2955 2955 2957 2959 2959 2959 2959 2961 2961 2963 2963 2963 2963 2965 2965 2967 2967 2967 2967 2969 2971 2971 2971 2971 2971 2973 2973 2975 2975 2975 2975 2975 2977 2977 2979 2979 2979 2979 2979 2981 2981 2983 2983 2983 2983 2983 2985 2985 2987 2987 2987 2987 2989 2989 2989 2991 2991 2991 2991 2993 2995 2995 2995 2995 2997 2997 2999 2999 2999 3001 3003 3003 3003 3005
wobei der anfang aus der reihe tanzt und auch zwischendrin gibt es sprünge...
bei dem bespiel mit 4 motoren (bei gleicher hardwarekonstellation) kommt:
�oJ���n�x������/�SUo� �L�H���]�5X�s������z[<x8nY��l��R�_8w����/�c͗������b�����GuQ�;;���5oc�*�as���&�k���3w�_�_���������v��.��mz��s8{&�۹��L���.|�2.�t��ԗ�k9�J?�Hv���6����-������Hf��~�n������=��������<Q��7�W?���zןn���M�K����%[d^��{V������}�{�����8�n�}���0^&U�>������������<������ɖ�yϤ�^�����o��v�e����V��z~w'�v��U�]?��yt����V�Oc����|��W��?�M��ɯ��.���`��R�������\�� R����Z�5�;�\��B_�o[&�������^>��-;z7�����nl?���~�s�?TL���+�z_��Z�wW��͜����m���u���� ��O���\�T����x����|G�{��k6�ʝ/7��v����N�����ژ�3]�z�^�[�w�p;�������t<�j��������������:k�sۍH<��We<�n�OdJ��',�;{Kz�۴W����*��nƲi�y��ބ��%��V�w���R��� �L�B�]�ѷ���|�0�G���4«���� �_f|�N��jK>o�gZ�z��''�c��gx,����yk/�%ם��-��6�s��z��r}��%\_��vn���߱x������������f���|R�����~ ���V\�{��s��Y�i������>JN��@ǩ:~ק����~������Y�{��ڑ�[o�t�[>���;�Ŏ������_���{���ߏo�C�7�/]�^W�ԯ��Sz�m�?�$�������r���~��3W>�7?��e�[�>��?��=��Mv��y_������yl���zzI���}C�z�˚���UsN&�D�M����-J�6��Y3�_���}�u�^�?��5�\~s?���F8�������9k0S �}px� {5ۯ���3��_������w��g��?���v��W��c���Fl?q��~�;t� �/��({��g��]M:k��ٮO���Ε�y��^����]>{��^��#��Ϸ6}��أ���w�1������ߵ����M�}�>O���t��N�|�ʂ�y�������D�{�����?�c���U�)ǵ����K����{� ��8��<u��;[��K��/x3|�?>z��̬/�B}��N��������.�e�{o�����y���������R�[���6/�����V���.�u�y����@4�����w�t2�����}�]������/��r�����5ߍ���H��W_c4�Q���:o~{O��WZ��������Xu
�s�;ރ����j���~�����c���T����L���_�-��9��c]>g���X�:������m���;�=�8��7������Lt�������mvyg��J.{w �E���e^{|�� \�����o�R��<�k;��}��^y^�7^��<�ۄ�9��ު����g����,5\$��D���h� �}�#�[�9�����bߋW}�7��ة/u�3����{�u������_�X���b�|�U�e��p�3��2��{���7s�\� LvS���=�o���������xo`]����?�=��V�j���on�����k�<Y�W�£������n���z�s5����'#q���?�&c���Oߥ��;^������,�vO��%�t�����e��H=��?��i�
L"�]_%{�?�ƅ��om��շ��,z�U?{�畧����������}��z������%���Ԏ� ��I�"����ޥ�ά�q�[E��~&>4R��]���rg�������Y_9^����|މ�6W����w��Ђ�����fT��ƭN��w�α� ���v�1������^T��'w_��B���g��.���ϳ����2�VL�Aj�f�yw� ����7��w������5R����~;6��Z��G�S�m!��������es����� ����;�7�H'���������IG�A����p��:/�S2��Xn��n��?���ƉW�]��Կ������}��_��������}����l�*R��~����6��(�p� �f���]v��w���oN�'S�m�7M�����oVY<����ϧ�}�S^��}������<Q�su���b�����VI�;���S�����SϦ��ߑ��:o��g���vp����i� x�v���k��?T�L���-{�y�/���/~�kʥ�~?��.�%��6���_0��3���m����.��S�z8���)3������} ������O������>����nݪ���˵+k�w��|�d>���f����}����~��n��|S���J�����_�G_�����ݘ��#��l���_ �R�Y.��˿]�����k�������w��O�~9�w���C�?������N�U�;���M� �B�[��>�������G~m��H���������7~2��\v��0�k�7�����e�Z1��Q�� ���yWO�F�������gG����5���{R�~��������6����{��}� `|��^��]Z����VO���>Lh(���s�o����6�r{q�*���N�d�( ������~���������3�����+����E�68i�Ǐ����]����m��;�=�{���]_��q��W�WSZ�^�k�� �Ы�}]���u_~�������/��l��s�n6�|�Z�6�,7�].����o"���_�}��5���B7%_��'�~���V^e�i>�o�������ny�'>�_��O�^�6��Vv�u���/w�N���}�4����G�9W���M�7�\�/R��^�����2����x1;����FV�{=������ ��#m����?����������RͿ��e=��n����m�������mY���yI�5^ �m�s�~�f����{�����暤��S������(��=<�a�k{�ׯ������*���%�����ޡݝ��_����Rwi������+�.s@t� ����뎚���{�7�N��xx���G��T�-������C��Y��ί�g��^�s�F���^�觾[��|}����c٫?:?�^��~�?W^��ʉ�u{�w����zuYf�G� o-�?�N��J�;�R;��~����D�S���$Ҧ���\���{������x�d�'��� ��{�7`%A�����O�e?Q
�2�#w�t�K�� ZNf0��ڒǎ��Wwk+Yc�jE��%-���w���ْ����c}���?�N���z�o֏�krJ���w����}�����v�� ��u]�����W��T��?�c��Ȯ������_�|�/��l?�W��;.mk��[��9���Zz���lM����u���){�7_WQ[o~�^m���ތ�w���.��]�����F!��î�`�'���\�x�Vz���h�i�����/}��2��L���������ӯ��c��0-IdgT�(Mw���U�����SXV�������Esz蒃�Y���Gf���܄�;f�=�=� ��|�Kg?��h��������mx�����[�q��Q~k[�L����o����%��U���yo�T��m�jR����}��~�b����.���_U? ���=6S^+_�g����qev`����S�͜_;��B���k�_����z����O��� ��lQ���*/���yF�VM�;��rG�m�m�$�>�^��������P_߾5������YVUޱ~��������+������������og 9ܻ=��kyR͖��r��j?#�����ƪ�g)��z�����!���������؟����N ������,k�)��_�gW�6�����j�;˫1��2�� -�x�?����݊cO�z��5ͽ���������g���߶����w���9����|�Ռ�m �F���m�x�^��p�y��u����Y�����a{U_9��k���~���}sFy��� �Mu�ں���O?Km�_M�y�,������jE�í���|�즾�.[Fn��D��.��[�Wk[���垫���\z�I 0.00 , 0.00 , 0.00 , 0.00
0.00 , 0.00 , 0.00 , 0.00
32.67 , 29.10 , 32.16 , 43.90
�+k�w��|�d>���f��}����~��n��|S���J�����_�G_�����ݘ��#��l���_� R�Y.��˿]�����k������w��O�~9�w���C�?������N�U�;���M�� B�[��>�ә��ߞG~m��H���������7~2��\v��0�k�7�����e�Z1��Q���� �yWO�F�������gG����5���{R�~ÿ������6����{��}�`|� �^��]Z����VO���>Lh(���s�o����6�r{q�*���N�d�( ������~���������3�����+����E�68i�������]���m��;�=�{���]_��q��W�WSZ�^�k��� �Ы�}]���u_~�������/��l��s�n6�|�Z�6�,7�].����o"���_�}��5���B7%_��'�~���V^e�i>�o��������ny�'>�_��O�^�6��Vv�u���/w�N���}�4����G�9W���M�7�\�/R��^�����2����x1;����FV�{=������ ��#m����?����������RͿ��e=��n����m�������mY����yI�5 ^�m�s�~�f����{�����暤��S������(��=<�a�k{�ׯ������*���%�����ޡ����_����Rwi������+�.s@t �����뎚���{�7�N��xx���G��T�-������C��Y��ί�g��^�s�F���^�觾[��|}ݽ��c٫?:?�^��~�?W^�����u{�w����zuYf�G� o-�?�N��J�;�R;��~����D�S���$Ҧ���\���{������x�d�'��� ��{�7`%A�����O�e?Q
�2�#w�t�K�� ZNf0����ǎ��Wwk+Yc�jE��%-���w��������c}���?�N���z�o���krJ���w����}�����v� ���u]�����W��T��?�c��Ȯ������_�|�/��l?�W��;.mk��[��9���Zz���lM����u���){�7_WQ[o~�^m������w���.��]�����F!�î�`�'���\�x�Vz���h�i�����/}��2��L���������ӯ��c��0-IdgT�(Mw���U�����SXV��������Esz����Y���Gf���܄�;f�= �=����|�Kg?��h��������mx����[�q��Q~k[�L����o����%��U���yo�T��m�jR����}��~�b����.���_U? ���=6S^+_�g����qev`����S�͜_;��B���k�_����z����O��� ��lQ���*/����yF�VM�;��rG�m�m�$�>�^�܅����P_߾5������YVUޱ~��������+������������og9� �=��kyR����r��j?#��������g)��z�����!������΄�؟����N ������,k�)��_�gW�6�����j�;˫1��2�� -�x�?����݊cO�z��5ͽ���������g���������w���9����|�Ռ� m�F���m�x�^��p�y��u����Y���a{U_9��k���~���}sFy��� Mu������O?Km�_M�y�,������jE�í���|�����.[Fn��D��.��[�Wk[���垫���\z�I ����ny�'>�_��O�^�6��Vv�u���/w�N���}�4����G�9W���M�7�\�/R��^�����2����x1;����FV�{=������� ��#m����?�����짇��RͿ��e=��n����m��������mY���yI�5^� m�s�~�f����{�����暤��S�����(��=<�a�k{�ׯ������*���%�������ݝ��_�����Rwi�ޛ���+�.s@t �����뎚���{�7�N��xx���G��T�-������C��Y�����g��^�s�F���^�觾[��|}����c٫?:?�^��~�?W^��ʉ�u{�w����zuYf�G� o-�?�N���J�;�R;��~����D�S���$Ҧ���\���{������x�d�'�� ���{�7`%A�����O�e?Q
�2�#w�t�K�� ZNf0��ڒ����Wwk+Yc�jE��%-���w���ْ�����c}���?�N���z�o֏�krJ���w����}�����v� ���u]�����W��T��?�c��Ȯ������_�|�/��l?�W��;.mk��[��9���Zz���lM����u���){�7_WQ[o~�^m���ތ�w���.��]ְ���F!��î�`�'���\�x�Vz���h�i�����/}��2��L�������������c��0-IdgT�(Mw���U�����SXV�������Esz蒃�Y���Gf���܄�;f�=�=� ���|�Kg?��h���ڹ���mx�����[�q��Q~k[�L����o����%��U���yo�T��m�jR����}��~�b����.���_U? ���=6S^+_�g����qev`����S���_;��B���k�_����z��ɶO��� �lQ���*/���yF�VM�;��rG�m�m�$�>�^�܅����P_߾5������YVU��~������+������������og9ܻ =��kyR͖��r��j?#�����ƪ�g)��z�����!���������؟����N�� ����,k�)��_�gW�6�����j�;��1���2�� -�x�?����݊cO�z��5ͽ���������g���߶����w���9����|��Ռ� m�F���m�x�^��p�yҔu���Y�����a{U_9��k���~���}sFy���M u�ں���O?Km�_M�y�,������jE������|�즾�.[Fn��D��.��[�Wk[��������\z�I ����ny�'>�_��O�^�6��Vv�u���/w�N���}�4����G�9W���M�7�\�/R��^�����2����x1;����FV�{=������ ��#m����?���������RͿ��e=��n����m�������mY���yI�5^� m�s�~�f����{����������S�����(��=<�a�k{�����������*����%�����ޡݝ��_�����Rwi�ޛ���+�.s @t�����������{�7�N��xx���G��T�-������C��Y��ί�g��^�s�F���^�觾[��|}ݽ��c��?:?�^��~�?W^��ʉ�u{�w����zuYf�G� o-�?�N��J�;�R;��~����D�S���$�����\���{������x�d�'�� ����{�7`%A�����O�e?Q
�2�#w�t�K�� ZNf0��ڒǎ��Wwk+Yc�jE��%-���w���ْ���c}���?�N���z�o֏�krJ���w����}�����v��� �u]�����W��T��?�c����������_�|�/��l?�W��;.��mk��[��9���Zz���lM����u���){�7_WQ[o~�^m���ތ�w���.��]ְ���F!����`�'���\�x�Vz���h�i�����/}��2��L���������ӯ��c��0-IdgT�(Mw���U�����SXV�������Esz���Y���Gf������;f�=� =���|�Kg?��h���ڹ���mx����[�q��Q~k[�L�����o����%��U���yo�T��m�jR����}��~�b����.���_U ?���=6S^+_�g�����qev`����S�͜_;��B���k�_����z��ɶO�� ��lQ���*/���yF�VM�;��rG�m�m�$�>�^�܅����P_��5�������YVUޱ~������+������������og9 ܻ=��kyR͖��r��j?#�����ƪ�g)��z�����!������΄�؟����N�� ����,k�)��_�gW�6������j�;˫1��2�� -�x�?����݊cO�z��5ͽ���������g���߶����w���9����|�Ռ�m �F���m�x�^��p�yҔu���Y���a{U_9��k���~���}sFy���Mu� ں���O?Km�_M�y�,������jE�í�����|����.[Fn��D��.��[�Wk[���������\z�I ����ny�'>�_��O�^�6��Vv�u���/w�N���}�4����G�9W���M�7�\�/R��^�����2����x1;�����FV�{=������ ��#m����?����������RͿ��e=��n����m�������mY���yI�5^ �m�s�~�f����{�����暤��S������(��=<�a�k{�ׯ������*���%�����ޡݝ��_����Rwi������+�.s@t� ����뎚���{�7�N��xx���G��T�-������C��Y��ί�g��^�s�F���^�觾[��|}ݽ��c٫?:?�^��~�?W^��ʉ�u{�w����zuYf�G�o-�?�N��J�;�R;��~����D�S���$Ҧ���\���{������x�d�'��� ��{�7`%A�����O�e?Q
�2�#w�t�K�� ZNf0����ǎ��Wwk+Yc�jE��%-���w���ْ����c}���?�N���z�o���krJ���w����}�����v� ���u]�����W��T��?�c��Ȯ������_�|�/��l?�W��;.mk��[��9���Zz���lM����u���){�7_WQ[o~�^m���ތ�w���.��]�����F!�î�`�'���\�x�Vz���h�i�����/}��2��L���������ӯ��c��0-IdgT�(Mw���U�����SXV��������Esz蒃�Y���Gf���܄�;f�=�= ���|�Kg?��h��������mx����[�q��Q~k[�L����o����%��U���yo�T��m�jR����}��~�b����.���_U? ���=6S^+_�g����qev`����S�͜_;��B���k�_����z����O��� ��lQ���*/����yF�VM�;��rG�m�m�$�>�^��������P_߾5������YVUޱ~��������+������������og 9ܻ=��kyR͖��r��j?#�����ƪ�g)��z�����!������΄�؟����N� �����,k�)��_�gW�6�����j�;˫1��2�� -�x�?����݊cO�z��5ͽ���������g���߶����w���9����|�Ռ�m �F���m�x�^��p�y��u����Y���a{U_9��k���~���}sFy���� Mu�ں���O?Km�_M�y�,������jE�í���|�����.[Fn��D��.��[�Wk[���垫���\z�I ����ny�'>�_��O�^�6��Vv�u���/w�N���}�4����G�9W���M�7�\�/R��^�����2����x1;����FV�{=������� ��#m����?�����짇��R����e=��n����m��������mY���yI�5^ �m�s�~�f����{���������S�����(��=<�a�k{�ׯ������*���%�������ݝ��_�����Rwi�ޛ����+�.s@ t����������{�7�N��xx���G��T�-������C��Y�����g��^�s�F���^����[��|}ݽ��c٫?:?�^��~�?W^��ʉ�u{�w����zuYf�G�o-�?�N��J�;�R;��~����D�S���$Ҧ���\���{������x�d�'��� ��{�7`%A�������O�e?Q
�2�#w��t�K�� ZNf0��ڒ����Wwk+Yc�jE��%-���w���ْ�����c}���?�N���z�o֏�krJ���w����}�����v� ���u]�����W��T��?�c��Ȯ������_�|�/��l?�W��;.mk��[��9���Zz���lM����u���){�7_WQ[o~�^m���ތ�w���.��]ְ�
Rabenauge
14.11.2015, 12:00
Ähm-das untere sieht aus als wäre einfach die falsche Baudrate eingestellt.
habs nochmals kontrolliert: beides, im serialmonitor wie auch in den beiden sketches ist auf 9600 eingestellt...
Hallo inka,
sorry diese WE ist bei mir volles Programm.
Ich habe das Ganze nochmal auf einen Motor und Encoder heruntergebrochen. Das Programm zeigt nach dem alles initialisiert ist im Wechsel "Regeln" und "andere Aktion" an. Wobei Letzteres mehrfach hintereinander vorkommen kann.
Wie Du sehen kannst wird die Ticker Variable dabei hochgezählt, ohne das Du Dich darum weiter kümmern mußt. Genau das ist das Praktische mit Interrupts, Aktionen laufen quasi paralel ab und Du kannst in Deiner loop Dich mit anderen Aktionen beschäftigen. Hoffe dieses Beispiel ist verständlicher als der andere uberfrachtete Sketch.
#include <AFMotor.h>
// Motor
AF_DCMotor motor(4);
// Die Anzahl der Flankenwechsel
volatile unsigned long ticks = 0;
// passender Encode Pin für den Motor
static const uint8_t enc_pin = 18;
/*
* Die Interrupt Routine die beim Flankenwechsel aufgerufen wird
*/
void motor_isr(void){
ticks++;
}
/*
* Serial und den Pin initialisieren, die Interrupt Routine
* zuordnen.
*/
void setup() {
Serial.begin(9600);
pinMode(enc_pin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(enc_pin), motor_isr, CHANGE);
Serial.println("setup fertig");
}
void loop() {
unsigned long start_zeit, regel_zeit, aktions_zeit;
/*
* Ticks beschreiben, dabei wollen wir nicht von einem
* Interrupt unterbrochen werden
*/
noInterrupts();
ticks = 0;
interrupts();
motor.setSpeed(130);
motor.run(FORWARD);
Serial.println("ticks initialisiert und Motor laeuft");
/*
* Fuer 10 sec "Regeln" und eine andere Aktion parallel
* dazu ausführen.
*/
start_zeit = regel_zeit = aktions_zeit = millis();
while(start_zeit + 10000 > millis() ) {
/*
* Motor "regeln" alle 0,5sec
*/
static const unsigned long rdiff = 500;
if(regel_zeit + rdiff <= millis()) {
regel_zeit = rdiff + millis(); // nächstes Intervall setzen.
Serial.print(millis());
Serial.print(": Regeln ");
/*
* Wir lesen unseren Zaehler und wollen nicht
* von Interrupts gestört werden
*/
noInterrupts();
unsigned long tmp = ticks;
interrupts();
Serial.println(tmp);
}
/*
* Die andere Aktion die Parallel zum "Regeln" ausgeführt wird
* und nur unterbrochen wird, wenn ein Interrupt auftritt.
*/
static const unsigned long adiff = 333;
if(aktions_zeit + adiff <= millis()) {
aktions_zeit = adiff + millis(); // Nächste Intervall setzen
// Hier irgendetwas anderes machen
Serial.print(millis());
Serial.println(": andere Aktion");
}
}
Serial.println("Motor stop");
motor.setSpeed(0);
motor.run(RELEASE);
delay(2000);
}
Grüße
Chris
super, danke, botty,
läuft und wird zum begreifen von interrupts verwendet. Aber auch das andere war nicht umsonst. Ich wäre z.b. nie auf die idee gekommen, dass man so
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
{
pinMode(motoren[idx].enc_pin, INPUT_PULLUP);
}
quasi auf einen schlag vier motoren initialisieren kann
und so
for(uint8_t idx = M_VL; idx < M_MAX; idx++) {
if( ! motor_laeuft(idx) )
motor_start(idx, 255/2+3, FORWARD);
für alle 4 motoren abfragen kann, ob sie laufen und wenn nicht diese dann starten kann!
was bewirkt dieses "255/2+3" eigentlich genau??
p.s.
sorry diese WE ist bei mir volles Programm.
keinen stress mit antworten!
Hallo inka,
"255/2+3" bedeutet das der Duty Cycle ca 51% lang ist. War in Gedanken wohl noch bei Brüchen und Prozent, da schreib ich schonmal sowas umständlich. Aber der Compiler rechnet das ja zur Übersetzungszeit aus, da kann man das mal machen.
Zu den for()-Schleifen, die sind so gedacht, so kann man z.B.
// Fuer die linke Seite
for(uint8_t idx = M_VL; idx < M_VR; idx++) {
motor_stop(idx);
}
// Fuer die rechte Seite
for(uint8_t idx = M_VR; idx < M_MAX; idx++) {
motor_stop(idx);
}
machen. Sprich die Indexe geben an, mit welcher Seite man arbeitet. Die Funktion/en im Schleifenrumpf beschreibt/en was passieren soll.
Falls Du Lust und die Zeit hast, wäre es gut, wenn Du nochmal in 'nem C-Buch oder Tutorial nachschlägst, was Arrays (dt. Felder) sind und wie man sie benutzt. Das gleiche gilt für Strukturen (struct) und Aufzählungstypen (enum), diese drei Dinge spielen hier mit den Funktionen zusammen.
Grüße
Chris
hi botty,
#include <AFMotor.h>
// Motor
AF_DCMotor motor(4);
// Die Anzahl der Flankenwechsel
volatile unsigned long ticks = 0;
// passender Encode Pin für den Motor
static const uint8_t enc_pin = 18;
/*
* Die Interrupt Routine die beim Flankenwechsel aufgerufen wird
*/
void motor_isr(void){
ticks++;
}
/*
* Serial und den Pin initialisieren, die Interrupt Routine
* zuordnen.
*/
void setup() {
Serial.begin(9600);
pinMode(enc_pin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(enc_pin), motor_isr, CHANGE);
Serial.println("setup fertig");
}
void loop() {
unsigned long start_zeit, regel_zeit, aktions_zeit;
/*
* Ticks beschreiben, dabei wollen wir nicht von einem
* Interrupt unterbrochen werden
*/
noInterrupts();
ticks = 0;
interrupts();
motor.setSpeed(130);
motor.run(FORWARD);
Serial.println("ticks initialisiert und Motor laeuft");
/*
* Fuer 10 sec "Regeln" und eine andere Aktion parallel
* dazu ausführen.
*/
start_zeit = regel_zeit = aktions_zeit = millis();
while(start_zeit + 10000 > millis() ) {
/*
* Motor "regeln" alle 0,5sec
*/
static const unsigned long rdiff = 500;
if(regel_zeit + rdiff <= millis()) {
regel_zeit = rdiff + millis(); // nächstes Intervall setzen.
Serial.print(millis());
Serial.print(": Regeln ");
/*
* Wir lesen unseren Zaehler und wollen nicht
* von Interrupts gestört werden
*/
noInterrupts();
unsigned long tmp = ticks;
interrupts();
Serial.println(tmp);
}
/*
* Die andere Aktion die Parallel zum "Regeln" ausgeführt wird
* und nur unterbrochen wird, wenn ein Interrupt auftritt.
*/
static const unsigned long adiff = 333;
if(aktions_zeit + adiff <= millis()) {
aktions_zeit = adiff + millis(); // Nächste Intervall setzen
// Hier irgendetwas anderes machen
Serial.print(millis());
Serial.println(": andere Aktion");
}
}
Serial.println("Motor stop");
motor.setSpeed(0);
motor.run(RELEASE);
delay(2000);
}
im zusammenhang mit diesem sketch versuche ich die ausgabezeiten meiner serial.print befehle zu verkürzen, ähnlich diesem hier (das ist doch der hintergrund, oder?):
// Ticks und Strecke ausgeben
static const int wtime = 250;
if(log_time + wtime <= millis() )
{
out_s = "";
out_s += millis() + ": ";
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
{
out_s += idx + " ";
out_s += motoren[idx].ticks + " "; // Hier koennte jetzt ein Interrupt unterbrechen!
out_s += motor_strecke_gefahren(idx);
ticks_tmp = 0;
motor_ticks_per_milli(idx, &ticks_tmp);
out_s += " " + ticks_tmp;
if(idx == M_MAX - 1)
out_s += "\n";
else
out_s += ", ";
}
for(uint8_t idx = 0; idx < M_MAX; idx++)
all_ticks_tmp[idx] = 0;
motor_ticks_per_milli_fuer_alle(all_ticks_tmp, M_MAX);
for(uint8_t idx; idx < M_MAX; idx++)
out_s += all_ticks_tmp[idx] + " ";
Serial.println(out_s);
log_time = wtime + millis();
}
da werden ja verschiedene ausgaben zu einem string "addiert" und dann als ganzes ausgedruckt. Beim einsatz dieser zeilen:
out_VL += " " + millis();
out_VL += " " + tmp_VL;
out_VL += " "+ tmp_VL_ges;
out_VL += " " + v;
Serial.print (out_VL);
kommt aber etwas ähnliches im serial monitor wie das hier:
setup fertig
ticks_VL initialisiert und Motor_VL laeuft
333: andere Aktion
500: motor dreht schneller: 102
999: andere Aktion
1500: motor dreht schneller: 104
nfnf�1665: andere Aktion
2331: andere Aktion
2500: motor dreht schneller: 106
nfnf�on
00: motor dreht schneller: 106
dere Aktion
31: ander��2997: andere Aktion
3500: motor�setup fertig
ticks_VL initialisiert und Motor_VL laeuft
335: andere Aktion
502: motor dreht schneller: 102
1001: andere Aktion
1502: motor dreht schneller: 104
7o_��i����i__��߱������i�:�x�[�W����>:3�ԯ��������k�����=EM|-v�Zz/�n��o�)}���W�v��!>������?+���,���Z��~�{��vN�s�}�1�3N���n5��v�s�KO��u ���:���{m��߾�����?g������_�k� �{��g��=^�{7����w��5wr�W?_ky���ܻ���s|4��u�.����D� \·�=���li�����R�~����t��?ٵ���I|,�R�؟��Մn�Wڎ^7��Ÿ�� ���C9������������4�Z������7�?�eh>�������~y������������Jz ~�>_�~�����FZ{��G����������i����'�� 'ܿ��'/o�������ۖ�W�G�/~-�o���6o�uFl�>l��������/D�E�^أ�O�{��=�#���1���Nw�Cq̎���E�\�h����<|������[q��vx\����~������{�����{�{��Ol��}d��u_������,�}� ��iH?����eU=�7A������O,a���9������Y���|�L}�e^X��^ ���n�j>���R����������r������<i�������K�?z:�ϗ�#�j�;�\ߍb���������}W�?�m�O���릟� ��b���y���,�"�����{���ֽ}��ۚ����;M��s�K��Z��[�8�Ү���sW�u�j,�3,~Ⱥ/���[��m���_��-� ~���y{k�T���F��������/�u��(>��tv�WJ��g��zgF�����ۅ�+��|��T�S���緖��>�-�Zcпm���`�%�{���p��������c��ϗ������Wm)���\ܲ�γ���� ��v��~_)���n'�?����+�=������zZG^��'�z�H���N{7�� ��w��5wr�W?_ky�ܻ���s|4��u�.�ī�D�\���=���li�����R� ~����t��?ٵ���I|,�R�؟��Մn�W��^7��Ÿ�����C9����� ����
muss man vor dem addieren nicht die arten der ausgaben in eine gleiche art umwandeln?
Hallo,
ursprünglich war das so mit demString gedacht. Leider scheint die String-Klasse in der Arduino Umgebung einige Quirks zu haben, die zu diesem Kuddelmuddel führen können. Da ich zwar schon 'ne Weile programmiere aber neu in der Arduino Welt bin, lerne ich diese Besonderheiten gerade erst kennen.
Zu Deiner Frage der Umwandlung: eigentlich sollte das die String-Klasse mit ihren überladenen '+' und '+=' Operatoren automatisch machen, leider klappt das nicht immer sauber.
Erstmal muß man den String wohl immer ordentlich initialisieren
String out_s = String("Init"); // mindestens
String other = String();
ob die letztere Variante als ordentlich gilt, kann ich hier gerade nicht probieren.
Außerdem steht in der Doku:
Caution: You should be careful about concatenating multiple variable types on the same line, as you may get unexpected results.
sprich wenn ich mit '+' zwei unterschiedliche Datentypen "addiere", kann besagter Kuddelmuddel rauskommen. Das Gleiche gilt wohl auch für '+='
https://www.arduino.cc/en/Tutorial/StringAdditionOperator
sicherer ist wohl immer nur einstellig zu arbeiten
String out_VL = String(" "); // keinen Leerstring verwenden
out_VL += millis();
out_VL += " "; out_VL += tmp_VL;
out_VL += " "; out_VL += tmp_VL_ges;
out_VL += " "; out_VL += v;
Serial.print (out_VL);
Serial.flush()
Ist zwar mehr Tipparbeit aber spart einem die Zeit beim Suchen wenn es mal nicht klappt.
Sollte das trotzdem nicht gehen, dann bleibt einem nix anderes übrig als das gewohnte Serial.print/ln zu verwenden.
Außerdem wäre es gut, die Baudrate so hoch wie möglich einzustellen. Also Serial.begin(115200) oder höher und entsprechend im Serial Monitor abändern.
Gruß
Chris
hi,
ich habe jetzt die ausgabe routine so abgeändert:
// Ticks und Strecke ausgeben
static const int wtime = 250;
if(log_time + wtime <= millis() )
{
String out_s = String("");
out_s += millis(); out_s += ": ";
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
{
out_s += idx; out_s += " ";
out_s += motoren[idx].ticks; out_s += " "; // Hier koennte jetzt ein Interrupt unterbrechen!
out_s += motor_strecke_gefahren(idx);
ticks_tmp = 0;
motor_ticks_per_milli(idx, &ticks_tmp);
out_s += " "; out_s += ticks_tmp;
if(idx == M_MAX - 1)
out_s += "\n";
else
out_s += ", ";
}
for(uint8_t idx = 0; idx < M_MAX; idx++)
all_ticks_tmp[idx] = 0;
motor_ticks_per_milli_fuer_alle(all_ticks_tmp, M_MAX);
for(uint8_t idx; idx < M_MAX; idx++)
out_s += all_ticks_tmp[idx]; out_s += " ";
Serial.print(out_s);
log_time = wtime + millis();
}
das ist die ausgabe:
250 293.03 0, 1 418 229.81 0, 2 494 271.59 0, 3 396 217.71 0
210.57 0, 1 282 155.04 0, 2 355 195.17 0, 3 260 142.94 0
3762: 0 533 293.03 0, 1 418 229.81 0, 2 494 271.59 0, 3 396 217.71 0
250: 0 33 18.14 0, 1 16 8.80 0, 2 24 13.19 0, 3 17 9.35 0
752: 0 172 94.56 0, 1 109 59.93 0, 2 144 79.17 0, 3 88 48.38 0
1254: 0 324 178.13 0, 1 231 127.00 0, 2 280 153.94 0, 3 206 113.25 0
1756: 0 477 262.24 0, 1 364 200.12 0, 2 415 228.16 0, 3 340 186.92 0
2258: 0 630 346.36 0, 1 506 278.19 0, 2 558 306.78 0, 3 483 265.54 0
2760: 0 783 430.48 0, 1 654 359.56 0, 2 698 383.75 0, 3 632 347.46 0
3262: 0 937 515.14 0, 1 801 440.37 0, 2 839 461.26 0, 3 781 429.38 0
3764: 0 1088 598.16 0, 1 951 522.84 0, 2 982 539.88 0, 3 933 512.94 0
4267: 0 1239 681.18 0, 1 1102 605.86 0, 2 1126 619.05 0, 3 1083 595.41 0
4769: 0 1394 766.39 0, 1 1257 692.17 0, 2 1266 696.02 0, 3 1231 676.78 0
5271: 0 1541 847.21 0, 1 1410 775.19 0, 2 1409 774.64 0, 3 1377 757.05 0
5773: 0 1693 930.78 0, 1 1569 862.60 0, 2 1550 852.16 0, 3 1526 838.96 0
6275: 0 1849 1016.54 0, 1 1726 948.92 0, 2 1693 930.78 0, 3 1672 919.23 0
6777: 0 1997 1097.91 0, 1 1881 1034.13 0, 2 1832 1007.19 0, 3 1827 1004.45 0
7280: 0 2146 1179.83 0, 1 2035 1118.80 0, 2 1972 1084.16 0, 3 1976 1086.36 0
7783: 0 2295 1261.74 0, 1 2192 1205.11 0, 2 2114 1162.23 0, 3 2127 1169.38 0
8286: 0 2448 1345.86 0, 1 2348 1290.88 0, 2 2255 1239.75 0, 3 2279 1252.95 0
8790: 0 2603 1431.07 0, 1 2514 1382.14 0, 2 2400 1319.47 0, 3 2430 1335.96 0
9293: 0 2755 1514.64 0, 1 2671 1468.46 0, 2 2540 1396.44 0, 3 2577 1416.78 0
9796: 0 2905 1597.11 0, 1 2828 1554.77 0, 2 2681 1473.96 0, 3 2729 1500.35 0
10299: 0 3060 1682.32 0, 1 2986 1641.64 0, 2 2821 1550.93 0, 3 2880 1583.36 0
10802: 0 3209 1764.24 0, 1 3148 1730.70 0, 2 2964 1629.54 0, 3 3031 1666.38 0
11305: 0 3363 1848.91 0, 1 3312 1820.87 0, 2 3107 1708.16 0, 3 3180 1748.30 0
11809: 0 3516 1933.02 0, 1 3474 1909.93 0, 2 3253 1788.43 0, 3 3330 1830.76 0
12312: 0 3670 2017.69 0, 1 3638 2000.10 0, 2 3396 1867.05 0, 3 3478 1912.13 0
12815: 0 3827 2104.00 0, 1 3796 2086.96 0, 2 3539 1945.67 0, 3 3629 1995.15 0
13318: 0 3978 2187.02 0, 1 3959 2176.57 0, 2 3682 2024.29 0, 3 3784 2080.36 0
13821: 0 4131 2271.14 0, 1 4127 2268.94 0, 2 3826 2103.45 0, 3 3932 2161.73 0
14325: 0 4284 2355.25 0, 1 4295 2361.30 0, 2 3971 2183.17 0, 3 4086 2246.40 0
14828: 0 4436 2438.82 0, 1 4458 2450.91 0, 2 4118 2263.99 0, 3 4238 2329.96 0
15331: 0 4590 2523.48 0, 1 4624 2542.18 0, 2 4260 2342.06 0, 3 4389 2412.98 0
15834: 0 4738 2604.85 0, 1 4789 2632.89 0, 2 4406 2422.33 0, 3 4543 2497.65 0
16337: 0 4872 2678.52 0, 1 4940 2715.91 0, 2 4528 2489.40 0, 3 4682 2574.06 0
16840: 0 4910 2699.41 0, 1 5006 2752.19 0, 2 4555 2504.24 0, 3 4744 2608.15 0
17343: 0 4927 2708.76 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4771 2622.99 0
17846: 0 4944 2718.11 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
18349: 0 4962 2728.00 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
18852: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
19355: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
19858: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
20361: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
20864: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
21367: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
21870: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
22373: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
22876: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
23379: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
23883: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
24386: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
24889: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
25392: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
25895: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
26399: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
26902: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
27405: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
27908: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
28411: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
28914: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
29417: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
29920: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
30423: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
30926: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
31429: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
31932: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
32435: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
32939: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
33442: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
33945: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
34448: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
34951: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
35454: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
35958: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
36461: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
36964: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
37467: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
37970: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
38474: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
38977: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
39480: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
39983: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
40486: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
40989: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
41492: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
41995: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
42498: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
43001: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
43504: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
44007: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
44510: 0 4970 2732.40 0, 1 5015 2757.14 0, 2 4555 2504.24 0, 3 4781 2628.49 0
ich weiss jetzt noch nicht genau was was ist, entspricht das in etwa dem, was herauskommen sollte?
Hallo inka,
ja das entspricht dem was herauskommen sollte, mit einer Ausnahme,dazu gleich.
Die werte bedeuten folgendes:
zeit: motor_idx ticks abgerollter_umfang ticks/milli, das gleiche mit dem nächsten motor usw
Die Ausnahme ist die letzte Schleife
for(uint8_t idx; idx < M_MAX; idx++)
out_s += all_ticks_tmp[idx]; out_s += " ";
Serial.print(out_s);
log_time = wtime + millis();
die muß natürlich 'idx' initialisieren:
// hier
// |
// v
for(uint8_t idx = M_VL; idx < M_MAX; idx++)
out_s += all_ticks_tmp[idx]; out_s += " ";
// und
out_s += "\n";
Serial.print(out_s);
log_time = wtime + millis();
Der ganze Abschnitt dauert überings etwas über 2ms, wie man an den Zeitstempeln sehen kann.
Gruß
Chis
hallo allerseits,
das fahrzeug hat jetzt die endgültigen räder bekommen:
30963
das anflanschen der räder an die getriebeachsen sieht so aus:
30964
hier kann man die fahrweise sehen:
https://youtu.be/UuRWhUiWCaY
das im video gezeigte wird weder über irgendwelche sensoren, noch über die klicks der encoder gesteuert (kommt noch), es ist nur eine aneindander gereihte folge von einzelnen codeschnipseln für die eine oder andere fahrweise...
Rabenauge
04.12.2015, 12:02
Na hoffentlich geht das mal gut- diese Räder an den Getriebewellchen.
Wie sind denn diese Getriebe, taugen die was?
Ansonsten: mit Encodern kann man mit dem Teil bestimmt ne Menge hübsche Sachen anstellen, dank den Allseitenrädern (muss ich auch mal irgendwann was mit machen) kann man das Teil sehr genau positionieren, oder?
Na hoffentlich geht das mal gut- diese Räder an den Getriebewellchen.
Wie sind denn diese Getriebe, taugen die was?
- ach, so wild ist es nicht. Das Omniwheel wiegt nur ca. 100gramm und die welle macht einen durchaus stabilen eindruck, sieht nur so zerbrechlich aus :-)...
- Es war gar nicht so easy ein omniwheel zu dem preis (ca 9€ / stück) und in der passenden größe etwas zu finden...
- Die getriebe sind für meine bedürfnise ok, über die genauigkeit (ich meine reproduzierbarkeit beim hin- und zurückfahren, also getriebespiel) kann ich nicht viel sagen, die übersetzung (1:48 ) hätte durchaus noch ein bischen größer sein können, so ist's entweder ein bischen zu schnell, oder nicht kräftig genug um die räder noch durchzudrehen, je nach dem was ich bei PWM einstelle. Das scheint auch ein problem beim "querfahren" zu sein, - das geht in der jetzigen konstellation (motor/getriebe/rad) nicht. Aber mit dem "auf der stelle drehen" bin ich durchaus zufrieden :-)
Ansonsten: mit Encodern kann man mit dem Teil bestimmt ne Menge hübsche Sachen anstellen, dank den Allseitenrädern (muss ich auch mal irgendwann was mit machen) kann man das Teil sehr genau positionieren, oder?
da bin ich noch am rumprobieren... :-)
hallo allerseits,
mein künftiges roboter-fahrgestell war mir mit den DC-motoren und getriebe zu schnell, mit hilfe von PWM ließ sich das zwar verlangsamen, der antrieb wurde dadurch aber schwächer....
Der nächste versuch findet mit schrittnotoren statt ( DC 5V 28YBJ-48 (http://www.instructables.com/id/BYJ48-Stepper-Motor/?ALLSTEPS) )
3102831029
angepasstes beispiel aus der CustomStepper lib (als demosoftware für das video (https://www.youtube.com/watch?v=uyfUQFpJ7fQ)):
#include <CustomStepper.h>
CustomStepper stepper_VL(22, 24, 26, 28);
CustomStepper stepper_HL(23, 25, 27, 29);
CustomStepper stepper_HR(47, 49, 51, 53);
CustomStepper stepper_VR(46, 48, 50, 52);
boolean rotate_li;
boolean rotate_deg_li;
boolean rotate_re;
boolean rotate_deg_re;
boolean vorwaerts;
boolean rueckwaerts;
void setup()
{
rotate_li = false;
rotate_deg_li = false;
rotate_re = false;
rotate_deg_re = false;
vorwaerts = false;
rueckwaerts = false;
Serial1.begin(115200);
}
void loop()
{
if (stepper_VL.isDone() && rueckwaerts == false)
{
alle_stepper_rueckwaerts();
}
if (stepper_VL.isDone() && rueckwaerts == true && rotate_li == false)
{
rotieren_links();
}
if (stepper_VL.isDone() && rotate_li == true && vorwaerts == false)
{
alle_stepper_vorwaerts();
}
if (stepper_VL.isDone() && vorwaerts == true && rotate_re == false)
{
rotieren_rechts();
}
if (stepper_VL.isDone() && rotate_re == true && vorwaerts == true)
{
alle_stepper_vorwaerts();
}
stepper_VL.run();
stepper_HL.run();
stepper_HR.run();
stepper_VR.run();
}
/************************************************** *********/
void alle_stepper_vorwaerts()
{
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CW);
stepper_VL.rotate(2);
stepper_HL.setDirection(CW);
stepper_HL.rotate(2);
stepper_HR.setDirection(CW);
stepper_HR.rotate(2);
stepper_VR.setDirection(CW);
stepper_VR.rotate(2);
vorwaerts = true;
}
void alle_stepper_rueckwaerts()
{
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CCW);
stepper_VL.rotate(2);
stepper_HL.setDirection(CCW);
stepper_HL.rotate(2);
stepper_HR.setDirection(CCW);
stepper_HR.rotate(2);
stepper_VR.setDirection(CCW);
stepper_VR.rotate(2);
rueckwaerts = true;
}
void rotieren_links()
{
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CCW);
stepper_VL.rotate(2);
stepper_HL.setDirection(CCW);
stepper_HL.rotate(2);
stepper_HR.setDirection(CW);
stepper_HR.rotate(2);
stepper_VR.setDirection(CW);
stepper_VR.rotate(2);
rotate_li = true;
}
void rotieren_rechts()
{
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CW);
stepper_VL.rotate(2);
stepper_HL.setDirection(CW);
stepper_HL.rotate(2);
stepper_HR.setDirection(CCW);
stepper_HR.rotate(2);
stepper_VR.setDirection(CCW);
stepper_VR.rotate(2);
rotate_re = true;
}
es funktionirt ( video (https://www.youtube.com/watch?v=uyfUQFpJ7fQ) hier ), ich wäre mit dieser geschwindigkeit zufrieden, was mir nicht gelungen ist, ist die elegante lösung von botty hier nachzubauen (um das hier realisieren zu können):
// stepper xyz...
for (uint8_t idx = ST_VL; idx < ST_MAX; idx++)
{
// die 4 stepper mit den verschiedenen, aber doch irgendwie 4x den gleichen anweisungen, bzw. variablen/konstanten zu "versehen"...
}
muster für die DC-motoren (AF_Motor lib)
enum motoren_e
{
M_VL = 0, // Motor vorne links
M_HL,
M_VR,
M_HR,
M_MAX
};
struct motor
{
AF_DCMotor mot;
uint8_t enc_pin;
// volatile damit der Compiler keine 'dummen' Optimierung macht.
volatile uint32_t ticks;
unsigned long start_time;
unsigned long stop_time;
};
struct motor motoren[M_MAX] =
{
{ AF_DCMotor(4), 18, 0, 0, 0 },//M_VL
{ AF_DCMotor(1), 19, 0, 0, 0 },//M_HL
{ AF_DCMotor(2), 21, 0, 0, 0 },//M_HR
{ AF_DCMotor(3), 20, 0, 0, 0 } //M_VR
};
mein versuch das nachzuempfinden:
enum stepper_e
{
ST_VL = 0, // Motor vorne links
ST_HL,
ST_VR,
ST_HR,
ST_MAX
};
struct stepper motoren[ST_MAX]=
{
{CustomStepper(4),22, 24, 26, 28},
{CustomStepper(1),23, 25, 27, 29},
{CustomStepper(2),47, 49, 51, 53},
{CustomStepper(3),46, 48, 50, 52}
}
wird vom compiler mit verschiedenen fehlermeldungen (bei verschiedenen kombinationen des aufbaus beim "stepper_motoren" struct) quittiert...
--------------------------------------
Was ich herausgefunden habe ist, dass die AFMotor lib eine möglichkeit beinhaltet die motoren mit einer "nummer" zu versehen, das bietet die CustomStepper lib nicht. Daran liegt sicher ein teil meiner probleme, aber ist das alles? Bzw. wie muss die vorarbeit aussehen, um die for-schleife (idx) realisieren zu können?
#include <CustomStepper.h>
enum stepper_e { ST_VL, ST_HL, ST_VR, ST_HR, ST_MAX };
CustomStepper motoren[ST_MAX]
{
CustomStepper(22, 24, 26, 28),
CustomStepper(23, 25, 27, 29),
CustomStepper(47, 49, 51, 53),
CustomStepper(46, 48, 50, 52)
}
vielen dank erstmal für Deine zeit,
#include <CustomStepper.h>
enum stepper_e { ST_VL, ST_HL, ST_VR, ST_HR, ST_MAX };
CustomStepper motoren[ST_MAX]
{
CustomStepper(22, 24, 26, 28),
CustomStepper(23, 25, 27, 29),
CustomStepper(47, 49, 51, 53),
CustomStepper(46, 48, 50, 52)
}
ist das jetzt so, dass die zuordnung der 4 stepper durch die reihenfolge der einträge im "CustomStepper motoren[ST_MAX]" zu den laufenden nummer des enumerators zugeordnet werden? Und wie ist der zusammenhang zwischen stepper_e und motoren? Sind es nur beliebige bezeichnungen? Irgendwie fehlt mir hier doch noch der entscheidender impuls um da durchzublicken :-(
und deshalb komme ich wohl auch nicht drauf wie das hier aussehen könnte:
for (uint8_t idx = ST_VL; idx < ST_MAX; idx++)
{
CustomStepper stepper_e(idx) .run(); //oder CustomStepper(idx).run(); //oder CustomStepper motoren(idx).run() // oder CustomStepper(idx).run(idx) ...
}
ist das jetzt so, dass die zuordnung der 4 stepper durch die reihenfolge der einträge im "CustomStepper motoren[ST_MAX]" zu den laufenden nummer des enumerators zugeordnet werden?
Das enum zählt nur Symbole auf, denen von 0 aufsteigend eine ganze Zahl zuordnet wird.
Ähnlich wie z.B.
#define ST_VL 0
#define ST_HL 1
etc.
Folgender Code erzeugt ein Feld mit Bezeichner "motoren"aus 4 Objekten vom Typ "CustomStepper":
CustomStepper motoren[ST_MAX]
{
CustomStepper(22, 24, 26, 28),
CustomStepper(23, 25, 27, 29),
CustomStepper(47, 49, 51, 53),
CustomStepper(46, 48, 50, 52)
}
Folgender Code iteriert durch dieses Feld und ruft in jedem Objekt die Methode "run" auf.
for (uint8_t idx = ST_VL; idx < ST_MAX; idx++)
{
motoren[idx].run();
}
hervorragend erklärt, kurz, prägnant - dank dafür...
ich bin jetzt noch einmal zurück zu der "normalen" steuerung der stepper zurück, der code sieht nun so aus:
#include <CustomStepper.h>
#include <NewPing.h>
#define TRIGGER_PIN 8 // Arduino pin tied to trigger pin on the ultrasonic sensor. //12
#define ECHO_PIN 7 // Arduino pin tied to echo pin on the ultrasonic sensor. //11
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
uint16_t distanz;
uint16_t uS;
//uint8_t hindernis, start_ping;
CustomStepper stepper_HL(23, 25, 27, 29);
CustomStepper stepper_VL(31, 33, 35, 37);
CustomStepper stepper_HR(47, 49, 51, 53);
CustomStepper stepper_VR(46, 48, 50, 52);
boolean rotate_li;
boolean rotate_deg_li;
boolean rotate_re;
boolean rotate_deg_re;
boolean vorwaerts;
boolean rueckwaerts;
boolean start_ping;
boolean hindernis;
void setup()
{
rotate_li = false;
rotate_deg_li = false;
rotate_re = false;
rotate_deg_re = false;
vorwaerts = false;
rueckwaerts = false;
start_ping = false;
hindernis = false;
Serial.begin(115200);
}
void loop()
{
hindernis_vorh();
/****************************************/
if (stepper_VL.isDone() && rueckwaerts == false && hindernis == true)
{
alle_stepper_rueckwaerts();
//alle_stepper_stop();
}
else if (stepper_VL.isDone() && rueckwaerts == false && hindernis == false)
alle_stepper_vorwaerts();
/*************************************/
if (stepper_VL.isDone() && rueckwaerts == true && rotate_li == false)
{
rotieren_links();
}
/**************************************/
if (stepper_VL.isDone() && rotate_li == true && vorwaerts == true)
{
alle_stepper_vorwaerts();
}
/**********************************/
if (stepper_VL.isDone() && vorwaerts == true && rotate_re == false)
{
rotieren_rechts();
}
/********************************/
if (stepper_VL.isDone() && rotate_re == true && vorwaerts == true)
{
alle_stepper_vorwaerts();
}
/*****************************/
stepper_VL.run();
stepper_HL.run();
stepper_HR.run();
stepper_VR.run();
}
habe nicht alle funktionen hier reinkopiert, nur die für vorwärts:
void alle_stepper_vorwaerts()
{
vorwaerts = true;
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CW);
stepper_VL.rotate(1);
stepper_HL.setDirection(CW);
stepper_HL.rotate(1);
stepper_HR.setDirection(CW);
stepper_HR.rotate(1);
stepper_VR.setDirection(CW);
stepper_VR.rotate(1);
//vorwaerts = true;
}
ping distanz:
void ping_distanz(void)
{
delay(500);// Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
Serial.print("Ping: ");
Serial.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance in cm and print result (0 = outside set distance range)
Serial.println(" cm");
start_ping = true;
}
und der hindernis erkennung:
void hindernis_vorh(void)
{
if (start_ping == false) ping_distanz();
if (((uS / US_ROUNDTRIP_CM) <= 10))
hindernis = true;
}
an und für sich funktioniert die hinderniserkennung, am start fährt der robby an, oder eben nicht (bei hindernis vorne)
wo es noch klemmt ist das mit den blockierenden funktionen für die stepper. Die reagieren also während der fahrt nicht auf hindernisse und das stört natürlich :-(
mir ist es bis jetzt nicht gelungen das irgendwie zu lösen - hab ich da keine chance in diese blockierenden funktionen einzugreifen? Oder reicht es, wenn die ping funktion vor dem aufruf der stepperfunktion erfolgt? Irgendwie klappte es aber auch nicht...
Eine idee?
Rabenauge
27.12.2015, 09:57
Du wirst aus dem Motorprogramm raus das Sonar auch abfragen müssen, oder?
Bau dir mal irgendeine Meldung in die entsprechenden Unterprogramme ein,die du auf die Konsole ausgeben lässt. Dann siehst du, ob die betreffenden Routinen überhaupt aufgerufen werden.
Du wirst aus dem Motorprogramm raus das Sonar auch abfragen müssen, oder?
ja sicher, hatte ich schon, habs aber bei meiner vorhergehenden frage nicht so explizit erwähnt...
Das hier ist nur eine alternative von vielen:
void alle_stepper_vorwaerts()
{
hindernis_vorh();
if (hindernis == true)
{
Serial.print("hindernisabfrage in - alle_stepper_vorwärts -");
alle_stepper_rueckwaerts();
}
else alle_stepper_vorwaerts();
vorwaerts = true;
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CW);
stepper_VL.rotate(1);
stepper_HL.setDirection(CW);
stepper_HL.rotate(1);
stepper_HR.setDirection(CW);
stepper_HR.rotate(1);
stepper_VR.setDirection(CW);
stepper_VR.rotate(1);
//vorwaerts = true;
}
void alle_stepper_rueckwaerts()
{
Serial.print("fahre rückwärts nach hindernisabfrage in - alle_stepper_vorwärts -");
rueckwaerts = true;
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CCW);
stepper_VL.rotate(1);
stepper_HL.setDirection(CCW);
stepper_HL.rotate(1);
stepper_HR.setDirection(CCW);
stepper_HR.rotate(1);
stepper_VR.setDirection(CCW);
stepper_VR.rotate(1);
//rueckwaerts = true;
}
- beim start MIT hindernis davor fährt er sofort nach hinten los, ausgabe im terminal:
Ping: 4 cm
fahre rückwärts nach hindernisabfrage in - alle_stepper_vorwärts -
- beim start OHNE ein hindernis davor bleibt er stehen, fährt also nicht nach vorne los, ausgabe im terminal:
Ping: 80 cm
Ping: 79 cm
Ping: 79 cm
Ping: 79 cm
das ist die ausgabe von "ping_distanz", kommt ungefähr alle 8 sekunden...
- wenn sich ihm in dieser phase ein hindernis von vorne nähert (handfläche) fährt er nach hinten los. Dann kommt im terminal:
Ping: 3 cm
fahre rückwärts nach hindernisabfrage in - alle_stepper_vorwärts -
ich schliesse daraus nur, dass er die freie strecke vor sich zwar erkennt, irgendwas hindert ihn aber daran die fahrbefehle in "alle_stepper_vorwaerts" auch auszuführen, er wartet nur (in etwas so lange, wie auch die fahrt dauern würde) und pingt...
Timingprobleme?
Rabenauge
28.12.2015, 00:27
Gut möglich.
Versuch mal, das Sonar zu Fuss zu programmieren, ohne die NewPing-Bibliothek.
Das Problem hat man bei Arduino recht oft, dass mehrere Bibliotheken sich da in die Quere kommen, weil irgendjemand Timer oder Interrupts einfach benutzt ohne zu fragen, und schlimmer: ohne es zu dokumentieren.
Du hast nicht allzu viele US-Sensoren dran, wenn du da nen halbwegs knapp bemessenes Timeout setzt, dann sollte sich die Verzögerung in Grenzen halten, du brauchst also die NewPing nicht unbedingt.
der code mit NewPing war der erste, der bei mir auf anhieb funktionierte und auch die richtigen ergebnisse lieferte, da wollte ich natürlich dabei bleiben. Habe den code nun geändert
von:
void ping_distanz(void)
{
delay(500);// Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
Serial.print("Ping: ");
Serial.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance in cm and print result (0 = outside set distance range)
Serial.println(" cm");
start_ping = true;
}
in:
void ping_distanz(void)
{
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration / 58, 1; //58.2 /52,3
delay(500);
if (distance >= maximumRange || distance <= minimumRange)
{
Serial.println("-1");
}
else
{
Serial.println(distance);
}
start_ping = true;
}
die daten bei der pindefinition und im setup natürlich angepasst. Die art des aufrufs der "ping_distanz" funktion erfolgt auf die gleiche art wie vorher....
Der neue code funktioniert nun wie der alte, im wahrsten sinne des wortes, das verhalten ist identisch... :-(
noch eine idee?
Rabenauge
28.12.2015, 11:58
Noch ne Idee: schreib mal in deinen Vergleichen TRUE statt true und FALSE statt false.
Das ist eigentlich eher üblich bei Arduino- und wird in den Beispielen immer so gemacht. K.A. obs nötig ist, probieren schadet nicht.
Da er scheinbar ja das erste "if" im Hauptprogramm abarbeitet, wärs denkbar....
Auch möglich: er verhaspelt sich in den If()'s irgendwo.
Wenn man mehrere if()-Entscheidungen hinter einander schreibt, werden die auch der Reihe nach abgearbeitet.
Wenn also if(1) zutrifft, wird sie abgearbeitet. Tritt dabei der Zustand auf, der bei if(2) TRUE geben wird, wird anschliessend die abgearbeitet, und so weiter. So kann man Endlosschleifen basteln, die schwer zu finden sind.
Da eben hilft es, in jedem if() einfach mal ne Ausgabe zu machen "ich bin hierund hier jetzt".
Sowas umgehe ich dann mit switch/case: dort wird nach jedem break alles von vorne begonnen!
Noch ne Idee: schreib mal in deinen Vergleichen TRUE statt true und FALSE statt false.
Das ist eigentlich eher üblich bei Arduino- und wird in den Beispielen immer so gemacht. K.A. obs nötig ist, probieren schadet nicht.
Da er scheinbar ja das erste "if" im Hauptprogramm abarbeitet, wärs denkbar....
seitenweise fehlermeldungen in der art: "cruise_avoid_collision_4_einfacher_ping:34: error: 'FALSE' was not declared in this scope" - das ist es also nicht :-(
Auch möglich: er verhaspelt sich in den If()'s irgendwo.
Wenn man mehrere if()-Entscheidungen hinter einander schreibt, werden die auch der Reihe nach abgearbeitet.
Wenn also if(1) zutrifft, wird sie abgearbeitet. Tritt dabei der Zustand auf, der bei if(2) TRUE geben wird, wird anschliessend die abgearbeitet, und so weiter. So kann man Endlosschleifen basteln, die schwer zu finden sind. das ist auch meine befürchtung, leicht zu überblicken sind die if's in dem beispiel von CustomStepper wirklich nicht und da habe ich das her...
Sowas umgehe ich dann mit switch/case: dort wird nach jedem break alles von vorne begonnen!
werde ich probieren...
danke erstmal...
Rabenauge
28.12.2015, 12:32
Du kannst deine If()'s ja mal debuggen: schreib einfach in jedes if() ne spezielle Ausgabe und lass dir die auf die Konsole geben. Ggf. zusammen mit nen paar Variablen. Dann siehst du ja, wo er eventuell hängen bleibt.
Hallo inka,
mir fallen mehrere Sachen in Deinen Beispielen auf.
Erstmal konkurieren die "run()" Aufrufe damit die Motoren laufen mit Deinen Aufrufen für die Sensormessungen.
Egal welche Variante der Sensormessungen die Du uns gezeigt hast, beide blockieren den Rest des Systems während der Messung, weil Du auf das Ergebnis wartest. Und nicht nur das, Du hast die Sache noch verschärft, da in den Funktionen "delay(500)" drin steht. Sprich jedes Mal wenn Du die Messfunktion aufrufst vergehen 1/2sec plus der Zeit für die Messung. Deine Stepper könnten also gerade mal einen Step/sec machen.
Sicher nicht was Du willst. Die Messfunktion muss also so geschrieben sein, daß sie nicht blockiert. Die NewPing-Lib kann das s.u.
Die andere Sache, womit der Code klarer werden würde, ist die Verwendung von zwei Schleifen in der Loop-Funktion. Die äußere Schleife sorgt für den Fortschritt Deiner Fahrkommandos und die innere Schleife führt sie aus. In Pseudocode sähe das in etwa so aus (hab's nicht durch den Compiler gejagt!):
void loop() {
while(1) {
// Kommando auswählen
// Motoren konfigurieren z.B.
geradeaus_unendlich();
do {
// Fortschritt der Motoren
stepper_VL.run();
stepper_HL.run();
stepper_HR.run();
stepper_VR.run();
// Bis die Aufgabe erledigt ist
} while ( ! (stepper_VL.isDone() && stepper_HL.isDone() && stepper_VR.isDone() && stepper_HR.isDone()) );
}
}
wie immer Du die Auswahl der Fahrkommandos organisierst, hast Du so eine klare Trennung zwischen Auswahl und Ausführung!
Jetzt weiß ich nicht was Dein Roboter alles können soll. Ich nehme hier mal an er soll immer geradeaus fahren und wenn ein Hinderniss erkannt wird nach Rechts drehen. Beim Drehen soll er den Sensor ignorieren. Dann erweitert sich das Bsp. so:
void loop() {
bool sensor_benutzen = true;
while(1) {
// Kommando auswählen
// Motoren konfigurieren z.B.
geradeaus_unendlich();
sensor_benutzen = true;
do {
if(sensor_benutzen && hindernis_vorh()) {
motoren_stop();
drehen_rechts(); // Konfiguriert die Motoren um und wird so lange
// ausgeführt bis die innere Schleife abbricht.
sensor_benutzen = false;
}
// Fortschritt der Motoren
stepper_VL.run();
stepper_HL.run();
stepper_HR.run();
stepper_VR.run();
// Bis die Aufgabe erledigt ist
} while ( ! (stepper_VL.isDone() && stepper_HL.isDone() && stepper_VR.isDone() && stepper_HR.isDone()) );
}
}
Die NewPing-Lib stellt Dir die Funktion "ping()" zur Verfügung, leider blockiert die das System, kommt also nicht in Frage.
Statt dessen müssen wir "ping_timer()" und "check_timer()" benutzen.
"hindernis_vorh()" soll uns immer den letzten gültigen Wert liefern und dafür sorgen, daß der Sensor immer wieder neu mißt.
Also gibt uns die Funktion einen bool zurück:
bool hindernis_vorh() {
}
wir müssen uns merken ob der Sensor läuft "sensor_misst" und was das letzte Ergebnis war "erg_vorher", beide sollen nur lokal sichtbar sein. Ausserdem sollen die Werte erhalten bleiben, sprich die Variablen dürfen nicht auf dem Stack liegen sondern müssen ins Datensegment. Dafür gibt's "static".
Dann brauchen wir eine Dummy Funktion,weil "ping_timer()" 'nen Funktionspointer als Argument haben will.
Das Ganze sollte dann so aussehen (nicht durch den Compiler gejagt!):
void sonarDummyFunc() { return; }
bool hindernis_vorh() {
static bool sensor_misst = false; // Beim Prg Start läuft der Sensor noch nicht
static bool erg_vorher = false; // Beim Start noch keine Messung vorhanden
if(sensor_misst) {
if(sonar.check_timer()) {
erg_vorher = (sonar.ping_result / US_ROUNDTRIP_CM) < 4; // Oder welche Entfernung auch immer
sensor_misst = false;
}
} else {
sonar.timer_stop();
sonar.ping_timer(sonarDummyFunc);
sensor_misst = true;
}
return erg_vorher;
}
jetzt läßt sich "hindernis_vorh()" immer wieder aufrufen und startet den Sensor immer wieder neu und liefert das letzte Ergebnis zurück.
Ein anderes Beispiel findest Du sonst noch https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home in der Mitte ist ein Beispiel das den Callback-Mechanismus benutzt aber eine globale Variable verwendet,wovon ich kein Freund bin.
Hoffe die Ideen bringen Dich ein bischen weiter.
Gruß
Chris
Hallo inka,
solltest Du momentan diese Variante
void alle_stepper_vorwaerts()
{
hindernis_vorh();
if (hindernis == true)
{
Serial.print("hindernisabfrage in - alle_stepper_vorwärts -");
alle_stepper_rueckwaerts();
}
// !!! Im Fall das hinderniss == false ist führt das zu einer Rekursion ohne Widerkehr !!!
else alle_stepper_vorwaerts();
vorwaerts = true;
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CW);
stepper_VL.rotate(1);
stepper_HL.setDirection(CW);
stepper_HL.rotate(1);
stepper_HR.setDirection(CW);
stepper_HR.rotate(1);
stepper_VR.setDirection(CW);
stepper_VR.rotate(1);
//vorwaerts = true;
}
void alle_stepper_rueckwaerts()
{
Serial.print("fahre rückwärts nach hindernisabfrage in - alle_stepper_vorwärts -");
rueckwaerts = true;
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CCW);
stepper_VL.rotate(1);
stepper_HL.setDirection(CCW);
stepper_HL.rotate(1);
stepper_HR.setDirection(CCW);
stepper_HR.rotate(1);
stepper_VR.setDirection(CCW);
stepper_VR.rotate(1);
//rueckwaerts = true;
}
im Einsatz haben, landest Du für den Fall das kein Hindernis erkannt wird in einer endlos Rekursion. Dein Program hängt sich schlicht auf und ich vermute das System rebootet immer wieder. Prüfen könntest Du das, wenn Du in die setup-Funktion am Ende mal ein "Serial.println("setup ende")" oder so schreiben würdest. Das sollte dann mehrfach in der Console zwischen den "Ping: xxx cm" erscheinen.
Falls Du noch die NewPing lib benutzt gibt es bei "ping()" einen Sonderfall zu berücksichtigen:
Wenn der US-Sensor ins Unendliche zeigt, liefert die Funktion eine Null zurück. In Deiner Funktion:
void hindernis_vorh(void)
{
if (start_ping == false) ping_distanz();
if (((uS / US_ROUNDTRIP_CM) <= 10))
hindernis = true;
}
kann "hindernis" also auch "true" sein. Daher muß eine weitere Abfrage da hinein:
void hindernis_vorh(void)
{
if (start_ping == false) ping_distanz();
if(uS > 0) {
if (((uS / US_ROUNDTRIP_CM) <= 10))
hindernis = true;
} else {
hindernis = false;
}
}
meine Funktion funktionert so leider auch nicht. Weil mir "check_timer()" bei einem Blick hinter die Sensorreichweite keine Info darüber gibt, dass ein Time-Out stattgefunden hat. Muss man sich also selbst merken.
void sonarDummyFunc() { return; }
bool hindernis_vorh() {
static bool sensor_misst = false; // Beim Prg Start läuft der Sensor noch nicht
static bool erg_vorher = false; // Beim Start noch keine Messung vorhanden
static unsigned long start_zpkt = 0; // Fuer's timeout
if(sensor_misst) {
if(sonar.check_timer()) {
erg_vorher = (sonar.ping_result / US_ROUNDTRIP_CM) <= 10; // Oder welche Entfernung auch immer
sensor_misst = false;
} else if( (start_zpkt - millis()) >= 50 ) { // Falls Distanz hinter Sensorreichweite,
// nach 50ms erneut messen ermöglichen.
erg_vorher = false;
sensor_misst = false;
}
} else {
sonar.timer_stop();
sonar.ping_timer(sonarDummyFunc);
sensor_misst = true;
start_zpkt = millis();
}
return erg_vorher;
}
Gruß
Chris
hallo botty,
solltest Du momentan diese Variante
void alle_stepper_vorwaerts()
{
hindernis_vorh();
if (hindernis == true)
{
Serial.print("hindernisabfrage in - alle_stepper_vorwärts -");
alle_stepper_rueckwaerts();
}
// !!! Im Fall das hinderniss == false ist führt das zu einer Rekursion ohne Widerkehr !!!
else alle_stepper_vorwaerts();
vorwaerts = true;
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CW);
stepper_VL.rotate(1);
stepper_HL.setDirection(CW);
stepper_HL.rotate(1);
stepper_HR.setDirection(CW);
stepper_HR.rotate(1);
stepper_VR.setDirection(CW);
stepper_VR.rotate(1);
//vorwaerts = true;
}
void alle_stepper_rueckwaerts()
{
Serial.print("fahre rückwärts nach hindernisabfrage in - alle_stepper_vorwärts -");
rueckwaerts = true;
stepper_VL.setRPM(12);
stepper_HL.setRPM(12);
stepper_HR.setRPM(12);
stepper_VR.setRPM(12);
stepper_VL.setSPR(4075.7728395);
stepper_HL.setSPR(4075.7728395);
stepper_HR.setSPR(4075.7728395);
stepper_VR.setSPR(4075.7728395);
stepper_VL.setDirection(CCW);
stepper_VL.rotate(1);
stepper_HL.setDirection(CCW);
stepper_HL.rotate(1);
stepper_HR.setDirection(CCW);
stepper_HR.rotate(1);
stepper_VR.setDirection(CCW);
stepper_VR.rotate(1);
//rueckwaerts = true;
}
im Einsatz haben,
nein habe ich nicht...
Falls Du noch die NewPing lib benutzt gibt es bei "ping()" einen Sonderfall zu berücksichtigen:
........Daher muß eine weitere Abfrage da hinein:
void hindernis_vorh(void)
{
if (start_ping == false) ping_distanz();
if(uS > 0)
{
if (((uS / US_ROUNDTRIP_CM) <= 10))
hindernis = true;
} else {
hindernis = false;
}
}
habe ich berücksichtigt, danke für den tipp...
- - - Aktualisiert - - -
hi botty,
ich habe jetzt eine einigermassen funktionierende version in der ich ein paar sachen die Du hier erwähnst auch schon drin habe:
- das delay(500) im ping distanz habe ich entfernt, geht auch ohne
- die schleife do - while bei dem run() der stepper habe ich eingefügt, meine aber das wäre doppelt gemoppelt hier, oder?
der roboter:
- prüft erstmal ob vor ihm ein hindernis ist
- fährt entsprechend nach vorne, oder zurück
- nach vorne arbeitet er die (zunächstmal vorgegeben kommandor links, rechts usw) ab
- nach hindernis wird immer nur im voraus geprüft, ausgewichen nach links (warum auch immer)
hier der code (habe auch einen ohne "enum, idx" und was sonst noch zu der elegenteren lösung gehört :-)"
#include <CustomStepper.h>
#include <NewPing.h>
#define TRIGGER_PIN 8 // Arduino pin tied to trigger pin on the ultrasonic sensor. //12
#define ECHO_PIN 7 // Arduino pin tied to echo pin on the ultrasonic sensor. //11
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
uint8_t idx;
uint16_t distanz;
uint16_t uS;
//uint8_t hindernis, start_ping;
enum stepper_e
{ stepper_VL, stepper_HL, stepper_VR, stepper_HR, stepper_MAX };
CustomStepper stepper[stepper_MAX]
{
CustomStepper(23, 25, 27, 29),
CustomStepper(31, 33, 35, 37),
CustomStepper(47, 49, 51, 53),
CustomStepper(46, 48, 50, 52)
};
boolean rotate_li;
boolean rotate_deg_li;
boolean rotate_re;
boolean rotate_deg_re;
boolean vorwaerts;
boolean rueckwaerts;
boolean start_ping;
boolean hindernis;
boolean stepper_stop;
void setup()
{
rotate_li = false;
rotate_deg_li = false;
rotate_re = false;
rotate_deg_re = false;
vorwaerts = false;
rueckwaerts = false;
start_ping = false;
hindernis = false;
stepper_stop = false;
Serial.begin(115200);
Serial.println("setup_ende");
}
void loop()
{
hindernis_vorh();
/****************************************/
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (stepper[idx].isDone() && rueckwaerts == false && hindernis == true)
{
Serial.println("start - stepper rückwärts- if-abfrage_1");
alle_stepper_rueckwaerts();
}
else if (stepper[idx].isDone() && vorwaerts == false && hindernis == false)
{
Serial.println("start - stepper vorwärts- else-abfrage_1");
alle_stepper_vorwaerts();
}
}
/*************************************/
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (stepper[idx].isDone() && rueckwaerts == true && rotate_li == false)
{
Serial.println("loop - rotiere_links - if-abfrage_2");
rotieren_links();
}
}
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (stepper[idx].isDone() && rotate_li == true && vorwaerts == false)
{
Serial.println("loop - alle_stepper_vorwärts - if-abfrage_3");
alle_stepper_vorwaerts();
}
}
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (stepper[idx].isDone() && vorwaerts == true && rotate_re == false)
{
Serial.println("loop - rotiere_rechts - if-abfrage_4");
rotieren_rechts();
}
}
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (stepper[idx].isDone() && rotate_re == true && vorwaerts == true)
{
Serial.println("loop - alle_stepper_vorwärts - if-abfrage_5");
alle_stepper_vorwaerts();
}
}
/*****************************************/
do
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].run();
}
} while ( ! (stepper[idx].isDone()));
}
/************************************************** *********/
void ping_distanz(void)
{
//delay(500);// Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
Serial.print("Ping: ");
Serial.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance in cm and print result (0 = outside set distance range)
Serial.println(" cm");
start_ping = true;
}
void hindernis_vorh(void)
{
if (start_ping == false) ping_distanz();
if (uS > 0)
{
if (((uS / US_ROUNDTRIP_CM) <= 10))
hindernis = true;
} else
{
hindernis = false;
}
}
void alle_stepper_stop()
{
stepper_stop = true;
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(0);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(STOP);
}
}
void alle_stepper_vorwaerts(void)
{
if (start_ping == true) ping_distanz();
//Serial.print(hindernis);
if (hindernis == true)
{
rueckwaerts = true;
Serial.print(hindernis);
Serial.println(" hindernis - true - alle_stepper_rückwärts - if-abfrage_6");
hindernis = false;
//alle_stepper_rueckwaerts();
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotate(1);
}
}
else
{
vorwaerts = true;
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotate(1);
}
}
}
void alle_stepper_rueckwaerts(void)
{
rueckwaerts = true;
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotate(1);
}
}
void rotieren_links(void)
{
rotate_li = true;
for (idx = stepper_VL; idx < stepper_VR; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotate(1);
}
for (idx = stepper_VR; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotate(1);
}
}
void rotieren_rechts(void)
{
rotate_re = true;
for (idx = stepper_VL; idx < stepper_VR; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotate(1);
}
for (idx = stepper_VR; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotate(1);
}
}
Die NewPing-Lib stellt Dir die Funktion "ping()" zur Verfügung, leider blockiert die das System, kommt also nicht in Frage.
Statt dessen müssen wir "ping_timer()" und "check_timer()" benutzen.
hier stellt sich mir die frage warum ist es ein problem, wenn - hier sogar beide wesentlichen funktionen - ping() und run() der stepper blockierend sind? Der roboter fährt, sogar recht zügig, misst zwischendurch und weicht auch hindernissen aus, wo ist das problem? Kannst Du es mir bitte erklären?
In einem würde ich Dir recht geben: Der roboter fährt nach der messung seine strecke die er vorgegeben bekommen hat noch ab, bleibt also noch der fsetstellung - da vorne ist ein hindernis - nicht sofort stehen. Das kann man aber über die gemessene entfernung lösen, oder?
Ein anderes Beispiel findest Du sonst noch https://bitbucket.org/teckel12/arduino-new-ping/wiki/Home in der Mitte ist ein Beispiel das den Callback-Mechanismus benutzt aber eine globale Variable verwendet,wovon ich kein Freund bin.
das muss ich noch lesen...
Grüß Dich inka,
ich fange mal Hinten an.
"ping()" würde "run()" blockieren, nicht umgekehrt. die "run()" Funktionen müssen nachdem die Stepper konfiguriert sind immer wieder aufgerufen werden und das so schnell wie möglich, sonst hakt es.
Sowie Du Dein Programm aufgebaut hast, gibt's zwei kritische Dinge zu beachten:
Nachdem Du "gepingt" hast, fährst Du los. Wenn jetzt plötzlich etwas vor dem Roboter auftaucht - Eure Katze, Deine Füße oder die Schienbeine Deiner Liebsten - bekommt das das System nicht mit, sondern fährt einfach weiter - schlimmstenfalls "Aua" ;) .
Das andere Problem hast Du schon richtig erkannt, die gemessene Distanz vom Sensor muss größer sein als der Fahrweg.
Du legst im Moment bei gerade Fahren immer eine Umdrehung zwischen den "pings" zurück. Dein Grenzwert zum potentiellen Hinderniss sind aktuell 10cm. Das ist zu wenig, denn ich schätze Dein Raddurchmesser wird größer als 10cm/pi sein, oder?
Rechne mal nach Raddurchmesser * pi - dann muss "hindernis_vorh()" so aussehen:
{
if (start_ping == false) ping_distanz();
if(uS != NO_ECHO)
{
/* richtige Werte einsetzen */
if (((uS / US_ROUNDTRIP_CM) <= (Raddurchmesser * M_PI))
hindernis = true;
} else {
hindernis = false;
}
}
eine weitere Möglichkeit wäre statt "rotate(1)" "rotateDegrees(180)" oder mit anderen Werten kleinere Schritte zu machen. Das könnte dann zum Stottern führen. Momentan, vermute ich, bewegt die Trägheit den Robbi während des "pings" weiter, so das man das mit bloßem Auge nicht wahr nimmt. Einfach mal kleinere Werte mit "rotateDegrees()" ausprobieren.
Zum Thema "do{...}while()" und "doppelt gemoppelt":
Deine "loop()" sah auszugsweise so aus:
void loop() {
if (stepper[idx].isDone() && rueckwaerts == false && hindernis == true)
{
Serial.println("start - stepper rückwärts- if-abfrage_1");
alle_stepper_rueckwaerts();
}
else if (stepper[idx].isDone() && vorwaerts == false && hindernis == false)
{
Serial.println("start - stepper vorwärts- else-abfrage_1");
alle_stepper_vorwaerts();
}
// andere if's
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].run();
}
}
Du testes zwangsweise am Anfang immer ab, ob die Stepper schon das letzte Kommando ausgeführt haben oder nicht.
Dadurch mischt Du inhaltlich "Sind die Stepper fertig?" mit "Wie wähle ich das nächste Kommando aus?".
Führst Du jetzt die innere Schleife ein egal ob "while(){}" oder "do{...}while()":
void loop() {
// Kommando Auswahl treffen
if (rueckwaerts == false && hindernis == true)
{
Serial.println("start - stepper rückwärts- if-abfrage_1");
alle_stepper_rueckwaerts();
}
else if (vorwaerts == false && hindernis == false)
{
Serial.println("start - stepper vorwärts- else-abfrage_1");
alle_stepper_vorwaerts();
}
// andere if's
// Stepper ausführen lassen
// Es muessen alle Stepper gleichzeitig getestet werden, sonst ist's falsch!
while( ! (stepper[stepper_VL].isDone() && stepper[stepper_HL].isDone()
&& stepper[stepper_VR].isDone() && stepper[stepper_HR].isDone() ) )
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].run();
}
}
}
dann ist nach der inneren Schleife und vor dem nächsten "loop()" Ablauf absolut sicher, dass die Stepper ihre angewiesene Arbeit getan haben.
Dadurch reduzieren sich Deine "if()" Ausdrücke, die sich nur noch mit der Auswahl beschäftigen und sind meiner Meinung nach einfacher lesbar.
Das Konzept der CustomStepper-Lib basiert darauf 1) die Stepper zu konfigurieren was sie tun sollen "rotate()", "setDirection()" etc. und dann 2) sie solange mit "run()" in Schwung zu halten, bis "isDone()" wahr wird. Genau das spiegelt sich in letzterem Aufbau wieder.
Ich hoffe ich hab's verständlich erklärt?
Gruß
Chris
ein gutes neues jahr 2016 allen,
hallo botty,
Deinen erklärungen konnte ich folgen, danke...
irgendwie funktioniert bei mir die erkennung ob die stepper mit der vorgesehen einen drehung fertig sind aber nicht und ich finde keinen unterschied zu Deinen codebeispielen in meinem loop:
void loop()
{
hindernis_vorh();
/****************************************/
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (rueckwaerts == false && hindernis == true)
{
Serial.println("start - stepper rückwärts- if-abfrage_1");
alle_stepper_rueckwaerts();
}
else if (vorwaerts == false && hindernis == false)
{
Serial.println("start - stepper vorwärts- else-abfrage_1");
alle_stepper_vorwaerts();
}
}
/*************************************/
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (rueckwaerts == false && rotate_li == false)
{
Serial.println("loop - rotiere_links - if-abfrage_2");
rotieren_links();
}
}
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (rotate_li == true && vorwaerts == false)
{
Serial.println("loop - alle_stepper_vorwärts - if-abfrage_3");
alle_stepper_vorwaerts();
}
}
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (vorwaerts == true && rotate_re == false)
{
Serial.println("loop - rotiere_rechts - if-abfrage_4");
rotieren_rechts();
}
}
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (rotate_re == true && vorwaerts == true)
{
Serial.println("loop - alle_stepper_vorwärts - if-abfrage_5");
alle_stepper_vorwaerts();
}
}
/*****************************************/
while ( ! (stepper[stepper_VL].isDone() && stepper[stepper_HL].isDone()
&& stepper[stepper_VR].isDone() && stepper[stepper_HR].isDone() ) )
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].run();
// delay(1);
}
}
}
hier noch die ausgabe im terminal, wie man sehen kann werden zwar die if abfragen mit "rotiere links" und "rotiere rechts" erreicht, die befehle selbst aber nicht ausgeführt, daraus würde ich schliessen, dass die stepper eben noch nicht fertig sind?
setup_ende
Ping: 83 cm
start - stepper vorwärts- else-abfrage_1
Ping: 71 cm
loop - rotiere_links - if-abfrage_2
loop - rotiere_rechts - if-abfrage_4
loop - alle_stepper_vorwärts - if-abfrage_5
Ping: 82 cm
loop - alle_stepper_vorwärts - if-abfrage_5
Ping: 82 cm
ergänze ich einer dieser if abfragen mit der afrage ob z.b. der "stepper_VL" fertig ist, wird der printbefehl auch übersprungen, die abfrage 2 also gar nicht ausgeführt...
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (stepper[stepper_VL].isDone())
if (rueckwaerts == false && rotate_li == false)
{
Serial.println("loop - rotiere_links - if-abfrage_2");
rotieren_links();
}
}
RoboHolIC
06.01.2016, 14:20
Ich versuche mich grad mal wieder am lesen von C-Code. Dabei tauchen Fragen auf, die eventuell den Weg zum Fehler weisen ...:
Warum wird der Funktionsaufruf "alle_stepper_vorwaerts();"in der Funktion hindernis_vorh() in eine for-Schleife über alle vorhandenen Stepper verpackt? Ist der Namensanteil "alle_..." irreführend? Ist im Augenblick nur ein Stepper dem Programm bekannt? Falls es mehrere sind - warum erscheint die serielle Ausgabe "start - stepper vorwärts- else-abfrage_1" trotz Motor-unabhängiger boolescher Aussage nur ein einziges mal auf dem Terminal?
es sind vier stepper. "alle" im funktionsnamen deshalb, weil ja evtl. auch nur zwei laufen sollen...
es sind hier aufrufe zweier verschiedener funktionen:
1) hindernis_vorh() - prüft ob hindernis vorne (funktion selbst ist im codebeispiel nicht zu sehen - ist ausserhalb von loop())
2) in dieser schleife
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (rueckwaerts == false && hindernis == true)
{
Serial.println("start - stepper (http://www.rn-wissen.de/index.php/Schrittmotoren) rückwärts- if-abfrage_1");
alle_stepper_rueckwaerts();
}
else if (vorwaerts == false && hindernis == false)
{
Serial.println("start - stepper (http://www.rn-wissen.de/index.php/Schrittmotoren) vorwärts- else-abfrage_1");
alle_stepper_vorwaerts();
}
}
wird eine andere funktion aufgerufen - alle_stepper_rueckwaerts() - wenn hindernis vorne
oder alle_stepper_vorwaerts() - wenn kein hindernis
serial.print soll nur einmal melden wo man gerade ist...
und die funktionen "alle_stepper***" sind natürlich auch ausserhalb von loop()...
RoboHolIC
06.01.2016, 17:05
OK, bei "hindernis_vorh();"hab ich übersehen, dass das der Aufruf einer Funktion ist und das Nachfolgende weiterer Code.
Trotzdem:
es sind vier stepper. "alle" im funktionsnamen deshalb, weil ja evtl. auch nur zwei laufen sollen...
Dann müssten es angesichts der for-Parameter dennoch vier Schleifendurchläufe und vier serielle Meldungen werden, oder ??
serial.print soll nur einmal melden
We das? Es wird doch viermal aufgerufen, oder? Das ist ja mein Zweifel, ob an dieser Stelle der Programmfluss anders als gewünscht verläuft.
Ich gestehe, dass ich nicht heimisch bin in diesem Thread und deinen Arbeiten. Ich hab halt mal versucht, den gelieferten Programmausschnitt auf Auffälligkeiten hin zu studieren.
Wenn ich hier neben der Spur sein sollte, darfst du gerne deine Zeit sparen und meine Beiträge ignorieren.
jetzt hast Du mich etwas verunsichert (ist nicht schwierig :-))...
hier in diesem
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
if (rueckwaerts == false && hindernis == true)
{
Serial.println("start - stepper (http://www.rn-wissen.de/index.php/Schrittmotoren) rückwärts- if-abfrage_1");
alle_stepper_rueckwaerts(); <-----hier
}
else if (vorwaerts == false && hindernis == false)
{
Serial.println("start - stepper (http://www.rn-wissen.de/index.php/Schrittmotoren) vorwärts- else-abfrage_1");
alle_stepper_vorwaerts();
}
}
springt er hierhin:
void alle_stepper_rueckwaerts(void)
{
rueckwaerts = true;
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotate(1);
}
}
void rotieren_links(void)
{
rotate_li = true;
for (idx = stepper_VL; idx < stepper_VR; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotate(1);
}
for (idx = stepper_VR; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotate(1);
}
}
und dann wieder, nach dem er diese funktion abgearbeitet hat, zurück, ignoriert die else-if abfrage und geht weiter. Und muss die schleife noch 3x durchlaufen?
Die serialprint meldung kommt wirklich nur einmal! ich muss es noch ohne die schleife mit den "idx" testen...
Danke inka, Dir auch gutes neues Jahr!
Es tut mir leid, ich war so fixiert darauf Deine if's ein bischen zu vereinfachen, dass ich einen Seiteneffekt nicht gesehen habe:
Du triffst die Entscheidungen was als nächstes kommt in den if's, die sich jetzt gegenseitig nicht mehr ausschliessen.
Das klar aus dieser Ausgabe ablesbar
Ping: 71 cm
loop - rotiere_links - if-abfrage_2
loop - rotiere_rechts - if-abfrage_4
loop - alle_stepper_vorwärts - if-abfrage_5
Ping: 82 cm
das Programm springt ins zweite if, ändert die Variablen und eigentlich müßte hier jetzt die Fahrt ausgeführt werden, bevor es weiter zu den folgenden if's geht.
Oder die if's müssten prüfen ob vorangegangene if's ein neues Fahrkommando angewiesen haben, dass noch nicht ausgeführt wurde.
Im Beispiel muss im 4. if geprüft werden ob alle stepper.isDone() eben gegeben ist oder nicht.
Ich hatte ein andere Auswahlmethode im Hinterkopf, deswegen hatte das übersehen das diese Prüfung doch immer gemacht werden muss.
Wie lässt sich's ändern?
Zuerst einmal ein Wort zu den for(idx...)-Schleifen mit denen Du über die Stepper iterierst: In Anweisungen ist das praktisch, in logischen Aussagen wie
while ( ! (stepper[stepper_VL].isDone() && stepper[stepper_HL].isDone()
&& stepper[stepper_VR].isDone() && stepper[stepper_HR].isDone() ) )
leider nicht. Das wir diese Bedingung mehrfach brauchen lässt sich das in eine Funktion lesbarer zusammenfassen
boolean fahrt_fertig() {
return stepper[stepper_VL].isDone() && stepper[stepper_HL].isDone()
&& stepper[stepper_VR].isDone() && stepper[stepper_HR].isDone();
}
Ausserdem bietet es sich an, noch eine Funktion zu schreiben:
void fahrt_ausfuehren() {
while ( ! fahrt_fertig() )
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].run();
// delay(1);
}
}
}
damit ändert sich Dein letztes loop-Beispiel so ab:
void loop()
{
hindernis_vorh();
/****************************************/
if(fahrt_fertig()) {
if (rueckwaerts == false && hindernis == true)
{
Serial.println("start - stepper rückwärts- if-abfrage_1");
alle_stepper_rueckwaerts();
}
else if (vorwaerts == false && hindernis == false)
{
Serial.println("start - stepper vorwärts- else-abfrage_1");
alle_stepper_vorwaerts();
}
}
/*************************************/
if (fahrt_fertig())
{
if (rueckwaerts == false && rotate_li == false)
{
Serial.println("loop - rotiere_links - if-abfrage_2");
rotieren_links();
}
}
if (fahrt_fertig())
{
if (rotate_li == true && vorwaerts == false)
{
Serial.println("loop - alle_stepper_vorwärts - if-abfrage_3");
alle_stepper_vorwaerts();
}
}
if (fahrt_fertig())
{
if (vorwaerts == true && rotate_re == false)
{
Serial.println("loop - rotiere_rechts - if-abfrage_4");
rotieren_rechts();
}
}
if (fahrt_fertig())
{
if (rotate_re == true && vorwaerts == true)
{
Serial.println("loop - alle_stepper_vorwärts - if-abfrage_5");
alle_stepper_vorwaerts();
}
}
/*****************************************/
fahrt_ausfuehren();
}
ich kann das gerade hier gerade leider nicht durchcompilieren doch ich hoffe das Schema ist klar.
Die Äusseren if(fahrt_fertig()) sorgen jetzt dafür das nur etwas geändert wird, wenn noch kein neues Fahrtkommando gesetzt wurde.
Natürlich könntest Du Deine if's auch so
if (fahrt_fertig() && vorwaerts == true && rotate_re == false)
{
Serial.println("loop - rotiere_rechts - if-abfrage_4");
rotieren_rechts();
}
schreiben, das ist Geschmackssache.
Dadurch das es jetzt "fahrt_ausfuehren()" gibt kannst Du die Stepper auch einfach an anderen Stellen ein vorgegebenen Kommando ausführen lassen. Damit lassen sich dann Sequenzen wie
alle_stepper_vorwaert();
fahrt_ausfuehren();
rotieren_rechts();
fahrt_ausfuehren();
usw...
schreiben.
Noch ein ganz anderer Gedanke.
In allen deinen Kommandofunktionen hast Du "setSPR()" "setRPM()" mit immer wieder den gleichen Werten drin. Du könntest _einmal_ das in die "setup()" Funktion schreiben und das sonst überall löschen. Dazu dann aber
void alle_stepper_stop()
{
stepper_stop = true;
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setDirection(STOP);
}
fahrt_ausfuehren();
}
abändern.
"setDirection(STOP)" hält die Stepper erst an, wenn "run()" einen internen Step ausführt (die CostumStepper-Lib implementiert das so).
Wenn Du die mehrfachen "setSPR", setRPM" dann löschen kannst, wird Dein Sketch kürzer und dadurch etwas übersichtlicher.
Gruss
Chris
hallo,
der ausbau des fahrgestells geht weiter, linienfolgesensoren sind dazugekommen (hier steht das fahrgestell auf der induktiven ladestation):
31265
auch habe ich wohl den großteil (so hoffe ich zumindest) der lib "customStepper" verstanden, trotzdem gibt es da noch lücken, ich komme jetzt wieder nicht weiter:
aus dem gesamtcode habe ich die die loopschleife und die funktionen herauskopiert wo ich den fehler vermute, der ganze code schien mir zu viel und auch nicht unbedingt erforderlich, ich poste den aber gerne nach...
Problem nr.1:
nach dem starten prüft der robby ob hindernis vorhanden, wenn keines da ist, fährt er nach vorne, reagiert auf ein hindernis, in dem er auf rückwärts schaltet, allerdings sollte er nur eine umdrehung der räder von 30° durchführen, er kommt aber aus dem rückwärtsgang nicht mehr raus:
hier die loopschleife:
void loop()
{
hindernis_vorh();
if (fahrt_fertig())
{
if (hindernis == true)
{
Serial1.println("start - stepper rückwärts- hindernis if-abfrage_1");
Serial.println("start - stepper rückwärts- hindernis if-abfrage_1");
hindernis = false;
alle_stepper_rueckwaerts();
}
else
{
Serial1.println("start - stepper vorwärts- hindernis else-abfrage_1");
Serial.println("start - stepper vorwärts- hindernis else-abfrage_1");
// rechts_oder_links();
alle_stepper_vorwaerts();
}
}
fahrt_ausfuehren();
}
"fahrt fertig" und "fahrt ausführen" funktionen:
boolean fahrt_fertig()
{
return stepper[stepper_VL].isDone() && stepper[stepper_HL].isDone()
&& stepper[stepper_VR].isDone() && stepper[stepper_HR].isDone();
}
void fahrt_ausfuehren()
{
while ( ! fahrt_fertig() )
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].run();
// delay(1);
}
}
}
"alle_stepper_vorwaerts" und "alle_stepper_rueckwaerts" funktionen:
void alle_stepper_vorwaerts(void)
{
if (fahrt_fertig()) rechts_oder_links();
if (start_ping == true) ping_distanz();
if (hindernis == true)
{
Serial1.print(hindernis);
Serial1.println(" hindernis - true - alle_stepper_rückwärts - if-abfrage_6");
Serial.print(hindernis);
Serial.println(" hindernis - true - alle_stepper_rückwärts - if-abfrage_6");
hindernis = false;
for (idx = stepper_VL; idx < stepper_MAX; idx++) //alle stepper rückwärts
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(30); //rotate(1)
}
}
else
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)//alle stepper vorwärts
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotateDegrees(30);//rotate(1)
}
}
}
void alle_stepper_rueckwaerts(void)
{
if (hindernis = true)
{
hindernis = false;
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(30);//rotate(1)
}
}
}
problem nr.2:
ich vermute eine ähnliche ursache, wie beim problem nr.1. Der robby prüft in der funktion "alle_stepper_vorwaerts" - da er ja auf einer linie fährt - ob er evtl. nach rechts, bzw. links rotieren soll, weil die werte der beiden seitlichen IR-sensore zu unterschiedlich sind. Er gibt per print noch zurück, dass er rotiert (reagiert also auf die sich verändernden werte der sensoren li/re), rotiert aber nicht...
die funktionen "rechts_oder_links", "rotieren_links" und rotieren_rechts"
void rechts_oder_links (void)
{
read_IR ();
print_IR ();
wert_li_A0 = analogRead(Analog_Pin_0);//links
//basis_A1 = (analogRead(Analog_Pin_1) + 20); //mitte
wert_re_A2 = analogRead(Analog_Pin_2);//rechts
if (wert_li_A0 > wert_re_A2) rotieren_links();
else rotieren_rechts();
}
void rotieren_links(void)
{
rotate_li = true;
Serial1.println("rotiere_links");
Serial.println("rotiere_links");
for (idx = stepper_VL; idx < stepper_VR; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(180);//rotate(1)
}
for (idx = stepper_VR; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotateDegrees(180);//rotate(1)
}
}
void rotieren_rechts(void)
{
rotate_re = true;
Serial1.println("rotiere_rechts");
Serial.println("rotiere_rechts");
for (idx = stepper_VL; idx < stepper_VR; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotateDegrees(180);//rotate(1)
}
for (idx = stepper_VR; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(180);//rotate(1)
}
}
könnte sich jemand bitte die zeit nehmen und drüberschauen?
danke...
Hallo inka,
Dein robby nimmt ja richtig Gestalt an, klasse!
Dein erstes Problem liegt in
void alle_stepper_rueckwaerts(void)
{
if (hindernis = true)
im "if" ist eine Zuweisung und kein Vergleich, sprich der Ausdruck ist immer wahr und daher rennt er da immer rein.
Dein zweites Problem liegt daran, das du in "rotieren_links()" bzw. "rotieren_rechts()" zwar die Stepper richtig konfigurierst, dann die Konfiguration aber nicht mit "fahrt_ausfuehren()" durchführen läßt.
Statt dessen wird die Stepperkonfiguration in "alle_stepper_vorwaerts()" wieder überschrieben und diese dann in "loop()" ausgeführt.
Wenn Du die Funktionsaufruffolge
alle_stepper_vorwaerts
> rechts_oder_links
-> z.B. rotieren_rechts
gedanklich durchgehst, siehst Du das dieses Überschreiben der Seiteneffekt auf die Stepper ist.
Du mußt also immer auch Überlegen ob nach Deiner Entscheidungsfindung die Stepper nicht nur konfiguriert sondern auch ausgeführt werden müssen.
Hoffe das bringt Dich einen Schritt weiter.
Gruß
Chris
Hi botty,
Hallo inka, Dein erstes Problem liegt in
void alle_stepper_rueckwaerts(void)
{
if (hindernis = true)
im "if" ist eine Zuweisung und kein Vergleich, sprich der Ausdruck ist immer wahr und daher rennt er da immer rein.
zu blöd, dass ich immer wieder über so etwas stolpere :-(
Dein zweites Problem liegt daran, das du in "rotieren_links()" bzw. "rotieren_rechts()" zwar die Stepper richtig konfigurierst, dann die Konfiguration aber nicht mit "fahrt_ausfuehren()" durchführen läßt.
........
Du mußt also immer auch Überlegen ob nach Deiner Entscheidungsfindung die Stepper nicht nur konfiguriert sondern auch ausgeführt werden müssen.
ich dachte dieses " fahrt_ausfuehren();" reicht einmal in der loop? Muss ich dann doch jedes mal nach dem aufruf einer funktion wie z.b. " alle_stepper_vorwaerts();" dieses "fahrt_ausfuehren();" aufrufen?
übrigens, habe ich - einem vorschlag von Rabenauge (https://www.roboternetz.de/community/members/31104-Rabenauge) folgend - die unübersichtlichen if-abfragen durch switch / case ersetzt. Jetzt sieh es so aus, dass ich hindernisse abfragen kann, mit dem mittleren IR-sensor abfragen kann ob der robby auf einer linie ist und per abfrage der Li/Re IR-sensoren entscheiden kann, ob links zu der linienmitte oder rechts rotiert werden soll. Die grenzparameter für alle abfragen der IR sensoren stimmen noch nicht, da bin ich noch dran...
// entstanden aus "cruise_avoid_collision_4_2_enum_idx_new_ping"
#include <CustomStepper.h>
#include <NewPing.h>
#define TRIGGER_PIN 6 // Arduino pin tied to trigger pin on the ultrasonic sensor. //12
#define ECHO_PIN 7 // Arduino pin tied to echo pin on the ultrasonic sensor. //11
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
uint8_t idx;
uint16_t distanz;
uint16_t uS;
uint8_t bewegung, li_re;
uint8_t Analog_Pin_0 = A0; //analog pin 0
uint8_t Analog_Pin_1 = A1; //analog pin 1
uint8_t Analog_Pin_2 = A2; //analog pin 2
uint8_t IR_Reading_A0; //IR wert analog sensor_0 - links
uint8_t IR_Reading_A1; //IR wert analog sensor_1 - mitte
uint8_t IR_Reading_A2; //IR wert analog sensor_2 - rechts
uint8_t wert_li_A0;
uint8_t basis_A1;
uint8_t wert_re_A2;
enum stepper_e
{ stepper_VL, stepper_HL, stepper_VR, stepper_HR, stepper_MAX };
CustomStepper stepper[stepper_MAX]
{
CustomStepper(23, 25, 27, 29),
CustomStepper(31, 33, 35, 37),
CustomStepper(47, 49, 51, 53),
CustomStepper(46, 48, 50, 52)
};
boolean start_ping;
boolean hindernis;
void setup()
{
start_ping = false;
hindernis = false;
Serial.begin(115200);
Serial1.begin(115200);
Serial.println("setup_ende");
Serial1.println("setup_ende");
}
void loop()
{
hindernis_vorh();
read_IR ();
print_IR();
switch (bewegung)
{
default:
{
alle_stepper_vorwaerts();
if (bewegung == 1)
{
read_IR ();
wert_li_A0 = analogRead(Analog_Pin_0);//links
basis_A1 = analogRead(Analog_Pin_1); //mitte
wert_re_A2 = analogRead(Analog_Pin_2);//rechts
if ((basis_A1 <= 240) && (basis_A1 >= 210)) //auf der linie?
{
if (wert_li_A0 > 1, 5 * (wert_re_A2)) rotieren_links();
else if (wert_re_A2 < 1, 5 * (wert_li_A0)) rotieren_rechts();
}
}
break;
}
}
fahrt_ausfuehren();
}
/************************************************** *********/
boolean fahrt_fertig()
{
return stepper[stepper_VL].isDone() && stepper[stepper_HL].isDone()
&& stepper[stepper_VR].isDone() && stepper[stepper_HR].isDone();
}
void fahrt_ausfuehren()
{
while ( ! fahrt_fertig() )
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].run();
// delay(1);
}
}
}
void ping_distanz(void)
{
//delay(500);// Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.
uS = sonar.ping(); // Send ping, get ping time in microseconds (uS).
Serial1.print("Ping: ");
Serial1.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance in cm and print result (0 = outside set distance range)
Serial1.println(" cm");
Serial.print("Ping: ");
Serial.print(uS / US_ROUNDTRIP_CM); // Convert ping time to distance in cm and print result (0 = outside set distance range)
Serial.println(" cm");
start_ping = true;
}
void hindernis_vorh(void)
{
if (start_ping == false) ping_distanz();
if (uS != NO_ECHO)
{
if (((uS / US_ROUNDTRIP_CM) <= 25))
{
hindernis = true;
bewegung = 4;
}
else
{
hindernis = false;
bewegung = 1;
}
}
}
void alle_stepper_stop()
{
// stepper_stop = true;
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(0);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(STOP);
}
}
void alle_stepper_vorwaerts(void)
{
read_IR ();
wert_li_A0 = analogRead(Analog_Pin_0);//links
basis_A1 = (analogRead(Analog_Pin_1) + 20); //mitte
wert_re_A2 = analogRead(Analog_Pin_2);//rechts
if (wert_li_A0 < wert_re_A2) rotieren_links(); //bewegung = 2; //rotiere links
else rotieren_rechts(); //bewegung = 3;//rotiere rechts
if (start_ping == true) ping_distanz();
if (hindernis == true)
{
bewegung = 4;
Serial1.print(hindernis);
Serial1.println(" hindernis - true - alle_stepper_rückwärts - if-abfrage_6");
Serial.print(hindernis);
Serial.println(" hindernis - true - alle_stepper_rückwärts - if-abfrage_6");
hindernis = false;
for (idx = stepper_VL; idx < stepper_MAX; idx++) //alle stepper rückwärts
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(60); //rotate(1)
}
}
else
{
hindernis = false;
bewegung = 1;
for (idx = stepper_VL; idx < stepper_MAX; idx++)//alle stepper vorwärts
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotateDegrees(60);//rotate(1)
}
}
}
void alle_stepper_rueckwaerts(void)
{
for (idx = stepper_VL; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(60);//rotate(1)
}
}
void rotieren_links(void)
{
Serial1.println("rotiere_links");
Serial.println("rotiere_links");
for (idx = stepper_VL; idx < stepper_VR; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(30);//rotate(1)
}
for (idx = stepper_VR; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotateDegrees(30);//rotate(1)
}
}
void rotieren_rechts(void)
{
Serial1.println("rotiere_rechts");
Serial.println("rotiere_rechts");
for (idx = stepper_VL; idx < stepper_VR; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CW);
stepper[idx].rotateDegrees(30);//rotate(1)
}
for (idx = stepper_VR; idx < stepper_MAX; idx++)
{
stepper[idx].setRPM(12);
stepper[idx].setSPR(4075.7728395);
stepper[idx].setDirection(CCW);
stepper[idx].rotateDegrees(30);//rotate(1)
}
}
void read_IR (void)
{
IR_Reading_A0 = analogRead(Analog_Pin_0);//links
IR_Reading_A1 = analogRead(Analog_Pin_1);//mitte
IR_Reading_A2 = analogRead(Analog_Pin_2);//rechts
}
void print_IR (void)
{
Serial.print("links: ");
Serial1.print("links: ");
Serial.print(IR_Reading_A0);
Serial1.print(IR_Reading_A0);
Serial.print(" mitte: ");
Serial1.print(" mitte: ");
Serial.print(IR_Reading_A1);
Serial1.print(IR_Reading_A1);
Serial.print(" rechts: ");
Serial1.print(" rechts: ");
Serial.println(IR_Reading_A2);
Serial1.println(IR_Reading_A2);
}
Powered by vBulletin® Version 4.2.5 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.