PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Arduino Roboter - Servo reagiert nicht korrekt



wendtdir
16.11.2016, 19:05
Hallo,

momentan bin ich dabei mit einem Arduino Uno, eimem Motorshield, einem Servo, einem Ultraschall-Sensor und einer RP5-Chassis einen Roboter zu konstruieren.

Wenn er mein Sketch durchläuft und aur ein 10cm oder weniger entferntes Hindernis trifft, soll er stehen bleiben, den Sensor um 45° nach links und dann nach rechts, ebenfalls um 45° drehen. Dabei soll überprüft werden, in welcher Richtung kein Hindernis in 10cm auftaucht. In die Richtung drehen und weiterfahren. Also eigentlich "Standard". Der Sensor wird nach links gedreht, aber nicht nach rechts. Anbei mein Sketch, ich sehe den Fehler nicht.


#include <Servo.h>
#define echoPin 7 // Echo Pin
#define trigPin 6 // Trigger Pin

Servo myservo;

int richtungA = 12; // Motor A
int richtungB = 13; // Motor B
int geschwindigkeitA = 3; // Geschwindigkeit Motor A
int geschwindigkeitB = 11; // Geschwindigkeit Motor B
int bremseA = 9; // Bremse Motor A
int bremseB = 8; // Bremse Motor B

int geschwindigkeit = 255 ; // Geschwindigkeit der Motoren. 255 ist der Maximalwert!

int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long a, b, duration, distance; // Duration used to calculate distance

void kopflinks(){
//Kopf links
myservo.write(125);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);

digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
b = duration/58.2;
}


void kopfrechts(){
//Kopf rechts
myservo.write(35);
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);

digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
a = duration/58.2;
}


void setup()
{

myservo.attach(5);

// Pins für Motorenrichtungen als Ausgang
pinMode(richtungA, OUTPUT);
pinMode(richtungB, OUTPUT);

// Pins für Bremsen als Ausgang
pinMode(bremseA, OUTPUT);
pinMode(bremseB, OUTPUT);

// Geschwindigkeiten setzen
analogWrite(geschwindigkeitA, geschwindigkeit);
analogWrite(geschwindigkeitB, geschwindigkeit);

// Bremse an (Motoren aus)
digitalWrite(bremseA, HIGH);
digitalWrite(bremseB, HIGH);

// 2 Sekunden warten nach einschalten
delay(2000);

//US-Sensor
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);

//LEDs
pinMode(2, OUTPUT);
pinMode(4, OUTPUT);

//Servo 0-Position (etwas schief, daher 80°)
myservo.write(80);

}

void loop()
{

digitalWrite(trigPin, LOW);
delayMicroseconds(2);

digitalWrite(trigPin, HIGH);
delayMicroseconds(10);

digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);

//Distanzberechnung des Ultraschall-Signals.
distance = duration/58.2;


//Distanz größer 10cm, fährt vorwärts
if (distance > 10){
digitalWrite(richtungA, HIGH);
digitalWrite(richtungB, HIGH);
digitalWrite(bremseA, LOW);
digitalWrite(bremseB, LOW);
digitalWrite(2, HIGH);
digitalWrite(4, LOW);
}

//Distanz kleiner gleich 10cm, Bremse ein, LED wechsel und Kopf drehen.
else if (distance <=10){

digitalWrite(bremseA, HIGH);
digitalWrite(bremseB, HIGH);
digitalWrite(2, LOW);
digitalWrite(4, HIGH);
delay(1000);

kopflinks();
delay(500);
kopfrechts();
myservo.write(80);

if (a > 10 && b <=10){
digitalWrite(richtungA, HIGH);
digitalWrite(richtungB, LOW);
digitalWrite(bremseA, LOW);
digitalWrite(bremseB, LOW);
delay(500);
digitalWrite(bremseA, HIGH);
digitalWrite(bremseB, HIGH);
digitalWrite(richtungA, HIGH);
digitalWrite(richtungB, HIGH);
digitalWrite(bremseA, LOW);
digitalWrite(bremseB, LOW);
}

else if (a<=10 && b > 10){
digitalWrite(richtungA, LOW);
digitalWrite(richtungB, HIGH);
digitalWrite(bremseA, LOW);
digitalWrite(bremseB, LOW);
delay(500);
digitalWrite(bremseA, HIGH);
digitalWrite(bremseB, HIGH);
digitalWrite(richtungA, HIGH);
digitalWrite(richtungB, HIGH);
digitalWrite(bremseA, LOW);
digitalWrite(bremseB, LOW);
}
}
}

Ohne Servofunktion läuft der Roboter normal.

i_make_it
17.11.2016, 07:09
Versuchs mal mit


kopflinks();
delay(500);
kopfrechts();
delay(500);


Beim Überfliegen, scheint es mir so als ob Du dem RC-Servo gar keine Zeit lässt nach rechts zu fahren.
Allerdings wird Dir das nichts bringen, Soweit ich das sehe, dürfte Kopflinks nahezu das selbe Messergebniss liefern wie wenn der Kopf gradeaus schaut.
So ein RC-Servo hat ja eine Stellzeit z.B. 0,6s für 60°.
Soweit ich das sehe startest Du die Servobewegung und trigerst danach sofort den Sensor.
Die Messung müsste also erfolgen wärend sich der RC_Servo grade anfängt auf den Weg zur Zielposition zu machen.
Da RC-Servos intern regeln, hat man keine Rückmeldung wann ein Servo seine Zielposition erreicht hat.
Man schätzt entweder die Zeit die der RC_Servo braucht und arbeitet mit einem Delay und hofft das es keine Fehlersituation gibt in der der RC_Servo blokiert, oder man braucht ein Messystem daß einem das Erreichen der Zielposition anzeigt.
Im Zweifelsfall auf jeder Seite einen Taster.
Und wenn man rafiniert ist, spendiert man dem ganzen Betätigungsnocken, die bei Endlage 1 Taster 1 öffnen und bei Endlage 2 Taster 2 öffnen.
in Mittelstellung sind beide Taster dann offen.
Das heist wärend der Drehung sind beide Taster geschlossen.
Strohm fließt also nur wärend der Bewegung (Strom sparen) und man kann kabelbrüche erkennen, da ja nach dem Drehbefehl beide Taster auf 1 gehen müssen und in den Endlagen jeweils 1 Taster auf 1 bleibt.
kommen diese Bitmuster nicht zustande, dann ist irgendwo ein Fehler und der Roboter kann in einen Fehlermodus gehen. (z.B. blinken und piepen)

wendtdir
17.11.2016, 18:22
Danke für den Hinweis mit dem Delay. Das hat ein Teil des Problems gelöst. Der Servo dreht sich nun von nach links, dann kommt der "ping", dann dreht er sich nach rechts "ping". Aber die Werte werden nicht in den Variable a und b gespeichert. Ich habe die Bedingungen angepasst auf if (a<b), dann drehe dich in die eine Richtung oder (a>b), dann in die andere Richtung. Wenn ich mir die Werte für a und b ausgeben lasse, steht immer 0 da, damit ist keine Bedingung erfüllt und der Kopf geht hin und her und hin und her.

Sisor
17.11.2016, 20:06
Hallo wendtdir,
ich habe deinen Code mal ein wenig aufgeräumt (nicht vollständig). Vergleiche mal mit deinem Code.
Ich hoffe es fällt auf, dass der aufgeräumte Code deutlich lesbarer ist. Wenn es um Fehlersuche geht, ist Lesbarkeit ein sehr wichtiger Faktor. Da fallen dann Dinge ins Auge, die vorher im "Gewusel" untergegangen sind.

#include <Servo.h>

#define echoPin 7
#define trigPin 6
#define motorAPin 12
#define motorBPin 13
#define vAPin 3
#define vBPin 11
#define bremseAPin 9
#define bremseBPin 8
#define led1Pin 2
#define led2Pin 4
#define servoPin 5

Servo myservo;

void kopf_rechts(){
myservo.write(35);
}

void kopf_links(){
myservo.write(125);
}

void kopf_mitte(){
//Servo 0-Position (etwas schief, daher 80°)
myservo.write(80);
}

void geradeaus_fahren() {
digitalWrite(motorAPin, HIGH);
digitalWrite(motorBPin, HIGH);
digitalWrite(bremseAPin, LOW);
digitalWrite(bremseBPin, LOW);
digitalWrite(led1Pin, HIGH);
digitalWrite(led2Pin, LOW);
}

unsigned long ping_cm() {
// Ultraschall-Messung
// gibt Distanz in cm zurück
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// maximale Pulslänge bei 3m Distanz, v_Schall = 340m/s
const unsigned long maxPulse_us = (3 * 2 * 1000000) / 340;
unsigned long duration = pulseIn(echoPin, HIGH, maxPulse_us);
if (duration == 0) return 300; //kein Echo -> Rückgabe max.Messweite
return duration / 58.2;
}

void setup(){
myservo.attach(servoPin);
kopf_mitte();

// Pins für Motorenrichtungen als Ausgang
pinMode(motorAPin, OUTPUT);
pinMode(motorBPin, OUTPUT);

// Pins für Bremsen als Ausgang
pinMode(bremseAPin, OUTPUT);
pinMode(bremseBPin, OUTPUT);

// Geschwindigkeiten voll setzen
analogWrite(vAPin, 255);
analogWrite(vBPin, 255);

// Bremse an (Motoren aus)
digitalWrite(bremseAPin, HIGH);
digitalWrite(bremseBPin, HIGH);

// 2 Sekunden warten nach einschalten
delay(2000);

//US-Sensor
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);

//LEDs
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
}

void loop(){
//Distanz mit Ultraschall-Sensor ermitteln
long distance = ping_cm();

//Distanz größer 10cm, fährt vorwärts
if (distance > 10) {
geradeaus_fahren();
}
else { //Distanz kleiner gleich 10cm
// Bremse ein, LED wechsel und Kopf drehen.
digitalWrite(bremseAPin, HIGH);
digitalWrite(bremseBPin, HIGH);
digitalWrite(led1Pin, LOW);
digitalWrite(led2Pin, HIGH);

kopf_links();
delay(500);
long links_cm = ping_cm();

kopf_rechts();
delay(500);
long rechts_cm = ping_cm();

if (links_cm > 10 && rechts_cm <= 10){
digitalWrite(motorAPin, HIGH);
digitalWrite(motorAPin, LOW);
digitalWrite(bremseAPin, LOW);
digitalWrite(bremseBPin, LOW);
delay(500);
geradeaus_fahren();
}
else if (links_cm <= 10 && rechts_cm > 10){
digitalWrite(motorAPin, LOW);
digitalWrite(motorAPin, HIGH);
digitalWrite(bremseAPin, LOW);
digitalWrite(bremseBPin, LOW);
delay(500);
geradeaus_fahren();
}

kopf_mitte();
delay(500);
}
}

i_make_it
18.11.2016, 07:50
Was mir persöhnlich an dem Code nicht gefällt, ist die verwendung der vielen Delays
delay()
delayMicroseconds()
PulseIn()
sind ja alles Befehle die das Programm solange anhalten bis sie fertig sind.
Das wird also ein extrem langsam reagierneder Roboter.
Da der Prozessor die meiste Zeit damit verbringt zu warten.
Duch geschickte Programmierung und Verwendung von Interrupts und Timern sowie Vergleichen, kann mann das Programm weiterlaufen lassen und somit auch andere Aufgaben ausführen.
Soll der Roboter also später mehr Funktionern bekommen wäre es sinnvoll sich frühzeitig mit den anderen Möglichkeiten zu befassen, bevor man sehr viel komplett neu entwickeln muß.

Ist halt meine persöhnliche Meinung.

Momentan lasse ich mit einem Arduino Nano, zwei HC-SR04 auf zwei RC-Microservos, drei IR Reflexlichtschranken (Für Linienfolger), 4 Schalter (Bumper für Kolisionserkennung) und zwei gehackte RC-Servos (als Getriebemotoren für die Räder), laufen.
Das sind 4 Ausgänge für die RC-Servos, 2 Ausgänge für die Trigger der HC-SR04, die beiden Interrupteingänge für die HC-SR04, 3 Digitaleingänge für die IR-Lichtschranken, und ein Analogeingang für die Bumper (ein Widerstandsnetzwerk generiert verschiedene Spannungen für die Schalterkombinationen).
Als nächstes kommt Odometrie hinzu womit nochmal 4 Digitaleingänge belegt werden.
Da der dann nicht ständig Denkpausen einlegen soll, gibt es bisher im Code kein einziges Delay.
Und es soll auch keins hinzukommen.

Sisor
18.11.2016, 08:14
Die Servo-Bibliothek verwendet Timer und Interrupts.

i_make_it
18.11.2016, 12:15
Ich meinte ja auch explizit:
delay()
delayMicroseconds()
PulseIn()
und nicht die Servo Lib.

PulseIn wartet im Fehlerfall z.B. per Default eine Sekunde bis es weitergeht.
Mit den beiden "delay(500)" wären das im Extremfall bei einem Messzyklus (links-rechts) 3 Sekunden.
Und beim Gradeausfahren eine Sekunde von einer Fehlmessung bis zur nächsten Messung die dann eventuell ein gültiges Ergebniss liefert.
Der HC-SR04 z.B. ist bei einer Fehlmessung nach maximal 0,2 Sekunden wieder bereit zur nächten Messung

wendtdir
19.11.2016, 12:15
Hallo,

erstmal danke ich euch für die Hilfe. Es ist mein erster Roboter den ich momentan am Basteln bin, daher ist mein Wissen natürlich auch nicht besonders groß.

Ich glaube Sisor hatte mir auch mal Links zu den Interrupt-Programmierungen gepostet, als ich nicht klar kam mit meiner Schaltung Alarmanlage/Temeperaturmesser.

Ich möchte erstmal mit den zugegebenermaßen beschränkten Fertigkeiten ein kleines Ziel erreichen. Ich bin auch am überlegen, wie ich es einrichten kann, wenn er denn endlich so läuft, wie ich es möchte, dass er gleichzeitig zwei Abläufe ausführt, nämlich wendet und den Kopf wieder in "0"-Position bringt. Ist das möglich durch Interrupts?

Hier ein Bild meines kleinen:

32206

Sisor
19.11.2016, 14:10
Ich möchte erstmal mit den zugegebenermaßen beschränkten Fertigkeiten ein kleines Ziel erreichen. Ich bin auch am überlegen, wie ich es einrichten kann, wenn er denn endlich so läuft, wie ich es möchte, dass er gleichzeitig zwei Abläufe ausführt, nämlich wendet und den Kopf wieder in "0"-Position bringt. Ist das möglich durch Interrupts?
Hallo wenddir,

lass dich nicht verrückt machen. Z.Z. hat dein Programm vier Hauptaufgaben:
- Fahren
- Kopfposition ändern
- Ultraschallmessung
- Entscheidungen aufgrund der Messung treffen

Das Fahren passiert in dem Programm automatisch. Dein Roboter kann Messungen machen oder die Kopfposition ändern, während er fährt.
Da dein Roboter nur einen Sensor besitzt, ist für die Entscheidung, was zu tun ist, auch nur das eine Messergebnis entscheidend. Der Roboter muss nicht gleichzeitig mehrere Sensoren auswerten. Daher muss dein Programm auch keine weiteren Dinge parallel abarbeiten. Interupt- oder schedulerbasierte Programmierung ist also z.Z. nicht nötig.

Der Post von I_make_it bezieht sich darauf, dass das Programm umgeschrieben werden müsste, wenn du das System um weitere Sensoren erweiterst wie z.B. Kontaktsensoren oder ähnliches.

Das von dir oben genannte Verhalten wäre dann so realisierbar.


void kopf_mitte() {
//Servo 0-Position (etwas schief, daher 80°)
myservo.write(80);
}
void wenden() {
digitalWrite(motorAPin, HIGH);
digitalWrite(motorAPin, LOW);
digitalWrite(bremseAPin, LOW);
digitalWrite(bremseBPin, LOW);
delay(500); // Hier Wendezeit eintragen
}
void loop() {
// ...
kopf_mitte(); // Servo beginnt Bewegung
wenden(); // Servo bewegt sich während des Wendens rasch zur Mittelposition
// ...

oberallgeier
19.11.2016, 14:16
.. möchte, dass er gleichzeitig zwei Abläufe ausführt, nämlich wendet und den Kopf wieder in "0"-Position bringt. Ist das möglich durch Interrupts? ..Die triviale Antwort ist : ja.

Das hatte ich zuerst mit meinem Dottie (siehe "Innenleben" - klick (https://www.roboternetz.de/community/threads/36121-Autonom-in-kleinen-Dosen-R2_D03-Nachfolger-R3D01?p=356984&viewfull=1#post356984)) gemacht. Servo agiert (https://www.roboternetz.de/community/threads/36121-Autonom-in-kleinen-Dosen-R2_D03-Nachfolger-R3D01?p=358097&viewfull=1#post358097) - und gleichzeitig schwenkt der Fahrebot, siehe Video (https://www.youtube.com/watch?v=sRNSIBpK8sQ) durch Klick auf Bild. Nur - ich habs in C programmiert, Arduino-language kann ich nit. Aber es sollte sicher gehen - und Sisor schrieb ja auch schon wie´s geht.

i_make_it
19.11.2016, 21:28
Der Post von I_make_it bezieht sich darauf, dass das Programm umgeschrieben werden müsste, wenn du das System um weitere Sensoren erweiterst wie z.B. Kontaktsensoren oder ähnliches.


Exakt das.
Wenn Der Roboter also für einige Zeit so bleiben soll, kann man das lassen.
Wenn man aber plant noch Bumper (Kollisionserkennung) und ggf. weitere Fernsensoren (US oder IR) oder Odometriesensoren hinzuzufügen, dann sollte man sich frühzeitig überlegen ob es nicht sinnvoll ist die Programmierung zu ändern bevor man irgendwann ein unterirdisches Timingverhalten hat und dann erst mal Wochen oder Monate damit verbringt alles noch mal neu zu machen.

Mein erstes Arduino Programm war eine Fußgängerampel mit Delays. mein zweites Programm zwei HC-SR04 und die drei Reflexlichtschranken fürs Linienfolgen.
Das wurde dann um die beiden gehackten Servos als Antriebe erweitert und um die Bumper.
Dann kam der Wunsch die HC-SR04 jeweils um 180° in 10° schritten zu drehen und so eine 360° Abdeckung zu bekommen.
Schon bei den beiden parallel betriebenen HC-SR04 und den drei Reflexlichtschranken, war mit Delay und Co kein Blumentopf mehr zu gewinnen.
Weil da keiner Linie mehr gefolgt werden konnte oder man dazu so langsam hätte fahren müssen, daß das gar keinen Sinn mehr macht.

Es ist also eine Anregung etwas vorzuplanen und sich Gedanken zu machen, wo man denn hin will.
Klar, erst mal will man überhaupt ein Ergebniss bekommen das irgendwie funktioniert, Aber wenn man es noch besser hinbekommen kann ist ja auch nicht grade schlecht.

Bei mir selbst geht es momentan halt darum wie viel kann man mit einem Nano denn erreichen.
Der nächste Umbau ist Hardware, um alle Eingänge per IRQ überwachen zu können.
Sprich alles mit UND versehen (Eigenlich ja umgekehrt da 2 Eingänge Gesetzt werden müssen ohne das es zu einem Übersprechen auf die Anderen Eingänge über den gemeinsam genutzten IRQ Eingang kommt) so das immer auch der IRQ ausgelöst wird und dann in der ISR den Status der Eingänge auswerten und entsprechende Merker Variablen für den normal Programmablauf Setzen.
Der zweite IRQ Eingang des Nano ist dann Frei für wirklich wichtige Sachen.

wendtdir
20.11.2016, 18:50
Danke für die Hilfe an alle.

Natürlich hast du Recht I_make_it, aber einen Schritt nach dem anderen :-).

Jetzt macht mein Roboter, was er soweit machen soll. Ein bisschen Feintuning fehlt noch. Doch er fährt und ändert die Richtungen.

Hier das Ergebnis:
https://youtu.be/kUii8QT-6iU

Jetzt werde ich weiter basteln. Am Ende schwebt mir ein Roboter vor, der eine Kamera auf dem Rücken hat, die über W-Lan verbunden ist. Damit ich von ausserhalb der Wohnung zum Beispiel die Wohnung befahren kann. Eine andere Version soll Sensoren durch die Gegen fahren zum Messen des Luftdrucks, der Luftfeuchtigkeit, des CO2 Gehalts und der Temperatur.

i_make_it
21.11.2016, 09:15
Das ist doch schon ein schöner Anfang.
Allerdings sieht man auch bei 0:31 wie nah er war den Karton mit der Linken vorderen Ecke zu erwischen.
Wäre der Winkel noch flacher gewesen wäre er trotz US-Sensor kollidiert.
Deshalb habe ich die Bumper (und wegen Drehungen auch noch zwei Hinten an den Seiten)
Wie man in dem Link unten sieht, sind die recht simpel aufzubauen:
https://www.roboternetz.de/community/threads/68437-Vorstellung-eines-aktuellen-kleinen-Weihnachtsurlaub-Projekts-(ab-22-12-)/page2?p=622164&viewfull=1#post622164
Etwas einseitig Cu kaschierte Platine, ein Stück Lochraster, zwei Printmontage Taster (aus Mäusen), etwas Schaltdraht und Litze.
Die Taster sind parallel, also verodert, geschaltet. Ist das selbe Prinzip wie bei der SPACE Taste, da sind auch zwei Tasten drunter, damit es egal ist ob man sie Links, rechts oder in der Mitte drückt.
Zwei Posts weiter unten sieht man die Anordnung der vorderen Bumper am Roboter.

PS: Ich Stelle auch fest, ich sollte mal den aktuellen Bauzustand in dem Tread nachpflegen.

wendtdir
22.11.2016, 12:00
Du hast Recht, ich bin da noch am justieren. Gestern habe ich ihn auf meinem Flur fahren lassen, da schlief er auch an der Wand lang und mir fielen deine Worte ein, dass ich da Bumper anbringen sollte. Zumal er nicht 100% gerade fährt (Odometrie zum Angleich der Geschwindigkeit?), müsste ich mit zwei Geschwindigkeiten spielen.

Gerade bin ich am überlegen, wie ich nun das Programm umschreibe, um wie du schon geschrieben hattest, mit Interrupts zu arbeiten und diversen Fallen. Geplant ist unteranderem ein Bluetooth Receiver für die Steuerung über Handy zuzufügen. Also, ich lasse ihn fahren und prüfen, ob ein BT-Signal eingeht, wenn BT-Signal, dann Steuerung über Handy, wenn Signal "off", wieder eigenständiger Betrieb. Das sehe ich als Vorarbeit für die Schnittstelle übers Internet.

Ich muss mal schauen, ob ich nicht sowas wie Bumber daheim habe, um wieder zurück zu deinem Beitrag zu kommen.

i_make_it
22.11.2016, 13:21
Odometrie ist der Erste Schritt für einen Gleichlauf der Antriebe.
Bei einseitigen Traktionsproblemen, kan nes aber trotzdem passieren das er Kurven fährt.
Ein Kettenfahrwerk wie das vom RP5 ist da nicht unbedingt von Vorteil, da das Wenden und Enge Kurven eher ein Rutschen ohne definierten Drehpunkt ist.
Aber die Gradeausfahrt verbessert es schon.

Wenn Du in meinem Tread, im ersten Post den letzten Code ansiehst, findest Du die erste Version meines HC-SR04 Codes (noch ohne Fehlerauswertung falls kein Hinderniss innerhalb der Maximalreichweite vorhanden ist).
Da verwende ich aber schon ISRs um im den Echopin zu verarbeiten. Die Hauptschleife kann also derweil andere Aufgaben ausführen. In dem Code halt die drei Eingänge des Linefollow Moduls auswerten.

Beim Umschreiben kannst Du im Code ja erst mal lauter Print() und Println() Befehle einfügen und so Marken und Zeitstempel ausgeben lassen.
Dann siehst Du was wann durchlaufen wird.
Das hilft dann beim Testen ob der Code auch das macht was man sich denkt was er machen soll.


Der nächste schritt wäre dann z.B den Servo ständig die Positionen -30°,0° und +30° anfahren zu lassen und während der Fahrt ohne Anhalten zu messen.
Bei einem Abstand von 20 cm kann dann während der Fahrt der Kurs in etwa 10° Schritten korrigiert werden. bei Erreichen von 10 cm Abstand dann wie bisher anhalten und z.B. in 5, 45° Schritten messen und abhängig vom Abstand ausweichen.

Damit lässt sich dann schon ein flexibleres Verhaltensmuster erzeugen.

Sind z.B. in einer Sackgasse alle 5 Messpositionen Mit Abständen unter 20oder 30cm belegt, kannst Du ihn um ca. 130° drehen lassen und erneut messen lassen. Selbst wenn dann nur eine Ausfahrt vorhanden ist, die knapp 1,5 Roboterbreiten breit ist, sollt er einen Ausgang finden.
Bei 130° würde er mit einer Auflösung von 10° in 12 Umdrehungen die ganze Umgebung mit dem Sensor in Position 0° erfassen.

Eine Andere Strategie ist bei Gradeausfahrt und freiem Weg bei Sensor Position 0° und Hinderniss bei 30° zwar weiterhin in 10° Schritten zu korrigieren, aber wenn Gradeaus ein Hinderniss ist und bei Sensor 45° keins, dann direkt um die 45° zu drehen.

Da fallen Dir aber bestimmt noch andere Strategien ein.

Mein Ziel war es die Bumper nur für dünne Stuhl und Tischbeine sowie zu flache Gegenstände zu benötigen.

wendtdir
23.11.2016, 17:00
Ich werde jetzt anfangen mit den Interrupts. Mittlerweile, denke ich, es ist klar, dass meine Programmierfertigkeiten eingeschränkt sind. Daher meine Frage, ich habe bis jetzt ja nur den US-Sensor angebaut. Ich würde also jetzt programmieren, dass mein Roboter im Loop erstmal gerade aus fährt. Eine Unterbrechung findet statt, wenn der US-Sensor etwas "sieht", also AttachInterrupt (Interruptpin 0, Funktion "Ich sehe was, was du nicht siehst", change). In der Funktion "Ich sehe was, was du nicht siehst" müsste dann die Drehung kommen. Demnach müsste der Sensor durchgehend die Entfernung messen im Loop bzw. in einer Extra-Funktion?

i_make_it
23.11.2016, 19:57
Bau das Programm nach dem Prinzip auf was willst du vermeiden.
Also eine Kollision z.B. (deshalb hast Du ja den US-Sensor)

Bei der Initialisierung sollten also der US-Sensor soweit vorbereitet werden (Variablen vorbelegen, etc.)
das er messen kann und seine Ausgabe an die Fahrroutine so als ob bereits ein Hinderniss da ist.
Damit steht der Roboter erst mal und der Sensor geht in die Routine in der sich erst mal einen Überblick verschafft.

Das Einschalten kann nämlich nicht nur eintreten wenn Du den Roboter auf eine garantiert freie Fläche setzt sondern auch nach einem Reset
(z.B. durch Brown out) wenn er grade vor einem Hinderniss war und eigentlich drehen wollte.
Ich habe die Sensoren in der Hauptschleife, und habe nur den Echopin in der ISR.
Wenn also der Echo Pin triggert springt die Verarbeitung in die ISR und setzt den Zeitstempel für das Ende der Messung.

Update:

Wenn dann Bumper dazukommen, kann man die entweder zum Pin Sparen über ein Widerstandsnetzwerk auf einen Analogeingang führen, oder Digital abfragen.
Wenn Das Programm längere Zykluszeiten hat, ist so ein Polling natürlich nichts mehr, spätestens dann müssen Bumper über IRQ laufen.
Man kann aber selbst bei Bumpern mit Widerstandsnetzwerk Interrupteingänge nehmen, wenn man einen Amplituden-Diskriminator aufbaut,
der beim niedrigsten Spannungswert den ein Bumper verursacht bereits auf High geht.
Wenn man zu wenige IRQ-Eingänge hat, kann man z.B. einen 74HC541 (nicht invertierender Leitungstreiber) nehmen um 8 Leitungen auf einen IRQ zusammenzuführen.
Somit wird jeweils der entsprechende Eingang angesprochen plus der IRQ-Eingang.
Die ISR würde dann prüfen welcher der Eingänge betroffen ist und entsprechende Handlungen ausführen.
Z.B. bei US-Sensor Echo die Zeit speichern und bei Bumper sofort Motoren Stop und ggf. welcher Bumper ausgelöst hat.
Momentan hast Du ja erstmal einen US-Sensor und siehst den Bedarf für Bumper.
Wenn es darum geht, das der Roboter mal an einen Treppenabsatz kommt und nicht abstürzen soll, kommen auch noch Sensoren die überwachen ob Boden vorhanden ist oder ein Abgrund.

Parallel zum umschreiben des Codes kannst Du ja bereits darüber nachdenken was Du in den nächsten Erweiterungen dazunehmen willst.
Mir ist es z.B. bisher nicht gelungen mehr wie 4 Bumper in einem Widerstandsnetzwerk zusammenzufassen ohne dabei die Fähigkeit zu verlieren parallele Mehrfachbetätigungen sicher unterscheiden zu können.
Wenn Es laso auf mehr wie 4 Bumper rausläuft, macht es Sinn diese aufzuteilen.
damit entsteht aber ggf. schon der Bedarf IRQ Quellen zusammenzuführen.


Im Hauptprogramm prüft man zuerst ob die Variable für Hinderniss vorraus gesetzt ist wenn ja verzweigt man in den Teil für das Drehen des Servos um sich einen Überblick verschaffen.
Wenn kein Hinderniss vorraus ist, prüft man ob bereits eine Messung läuft (Merkervariable). Wenn nicht startet man eine Messung und setzt den Zeitstempel für den Start der Messung.
Dann setzt man den Zeitstempel für das Erreichen der maximalen Messdauer.
Dann wird geprüft ob die Variable für ein vorhandenes Echo gesetzt ist und wenn ja die Entfernungsberechnung durchgeführt und Variablen zurückgesetzt (Merker ob ein Echo vorhanden ist).
Wenn kein Echo vorhanden ist kommt der Vergleich ob der Zeitstempel für die maximale Messdauer minus dem Zeitstempel für den Start der Messung größer oder gleich 0,2 Sekunden ist.

Jetzt kommt die Fahrroutine. Ist die Variable für kein Hinderniss vorraus gesetzt, wird gradeaus gefahren.
oder halt entsprechend links bzw. rechts gedreht.