Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Linienfolger-Roboter - PID-Steuerung - Android-Setup

Komponenten und Verbrauchsmaterialien

Arduino Nano R3
× 1
SparkFun RedBot Sensor - Linienfolger
× 1
TCRT5000 4CH Infrarot-Linienspurfolger-Sensormodul
× 1
Android-Gerät
× 1
4xAA Batteriehalter
× 2
RobotGeek Kontinuierlicher Rotationsservo
× 2

Apps und Onlinedienste

Arduino-IDE
MIT App Inventor 2

Über dieses Projekt

Der Zweck dieses Projekts ist es, einen Linienfolger-Roboter mit PID-Steuerung zu bauen. Wir werden auch ein Android-Gerät verwenden, um die wichtigsten Steuerungsparameter für eine bessere und schnelle Abstimmung einfach einzurichten.

Dieses Projekt ist das erste eines zweiteiligen komplexeren Projekts, bei dem es meine Absicht ist, das Potenzial von Line Follower Robots zu erkunden. Im 2. Teil:Maze Solver Robot, der künstliche Intelligenz mit Arduino verwendet, erforscht und löst der Roboter Labyrinthe mit einfachen Techniken der künstlichen Intelligenz.

Unten sehen Sie ein Video, das den Roboter zeigt, der einer Leitungsschaltung folgt:

Schritt 1:Stückliste

Die Liste der benötigten Materialien ist sehr einfach und der endgültige Roboter ist sehr günstig (ca. 75,00 $):

Körper (kann an Ihre Bedürfnisse angepasst werden):

  • 2 Holzquadrate (80X80mm)
  • 3 Ordner-Clips
  • 2 Holzräder (Durchmesser:50 mm)
  • 1 Kugelwerfer
  • 9 Gummibänder
  • 3M-Befehlsrahmenleiste
  • Kunststoffgelenke für Sensorfix
  • BreadBoard und Verkabelung
  • 2 Sätze 4XNi-Metallhydrid-Akku (5V pro Satz)
  • 2 X SM-S4303R Kontinuierlicher 360-Grad-Kunststoffservo
  • Arduino Nano
  • HC-06 Bluetooth-Modul
  • 5 X-Liniensensoren (TCRT5000 4CH Infrarot-Linien-Track-Follower-Sensormodul + 1 unabhängiger Track-Sensor)
  • 1 LED
  • 1 Schaltfläche

Schritt 2:Einstellen der Motoren

Für Motoren wurden 2 kontinuierliche Servos (SM-S4303R) verwendet. Sie werden zusammen "geklebt" und bilden einen einzigen und festen Block, wie Sie auf dem Foto sehen können (verwenden Sie den 3M-Befehlsstreifen, Kleber oder doppelseitiges Klebeband). Diese Servos laufen mit einer bestimmten Geschwindigkeit, die durch die Impulsbreite definiert ist, die an ihrem Dateneingang empfangen wird. Für dieses spezielle Servo reicht die Impulsbreite von 1,0 ms (1.000 Mikrosekunden) bis 2,0 ms (2.000 Mikrosekunden). Andere Servos können mit anderer Pulsbreite arbeiten.

Im Detail suchen:

  • Ein Impuls von 1,5 ms bringt das Servo in die neutrale Position oder "gestoppt".
  • Ein Impuls von 1,0 ms befiehlt dem Servo die volle Geschwindigkeit (ca. 70 U/min) in eine Richtung
  • Ein Impuls von 2,0 ms voller Geschwindigkeit in die entgegengesetzte Richtung.
  • Impulse zwischen 1,0 und 1,5 ms oder 1,5 ms und 2,0 ms erzeugen eine proportionale Geschwindigkeit.

Sobald Sie beide Servos physisch angeschlossen haben, folgen Sie der obigen Zeichnungsschaltung, um sie zu versorgen (externe 5 V oder 6 V) und speisen Sie sie mit dem Arduino-Signal:

  • Linker Servo:Arduino Pin 5
  • Rechter Servo:Arduino Pin 3

Sobald alle angeschlossen sind, muss als Erstes ein 1,5-ms-Impuls gesendet werden, um zu überprüfen, ob die Motoren "gestoppt" sind (nicht laufen). Wenn nicht, müssen die Servos bis zum Anschlag eingestellt werden (achten Sie auf den gelben Bolzen, der sich unterhalb des Servos befindet).

HINWEIS :Wenn Ihr Servo diese physikalische Einstellung nicht hat, versuchen Sie den Parameter "1500" Mikrosekunde innerhalb der Funktion (nach oben oder unten) zu ändern, bis Sie den Punkt erreichen.

Der folgende Arduino-Code kann die Aufgabe erledigen:

#include  // Servobibliothek Servo leftServo;Servo rightServo;Void setup () { leftServo.attach (5); rightServo.attach(3); leftServo.writeMicroseconds(1500); rightServo.writeMicroseconds(1500);}void loop(){} 

Schritt 3:Körper und Motoren für den Bewegungstest zusammenbauen

  • Befestigen Sie mit der 3M Command Rahmenleiste die 2 Servos an einem des Kantholzstücks.
  • Befestigen Sie das zweite Kantholz mit den Binder-Clips am obigen. Passen Sie die Länge der Plattform an Ihre Bedürfnisse an.
  • Befestigen Sie den Ball Caster mit dem Binder Clip.
  • Die Stromversorgung der Motoren erfolgt über einen der 5V-Batterien. Dieser Batteriesatz wird zwischen dem Steckbrett und dem Karosserierahmen installiert.
  • Verbinden Sie den mit Servos zu verwendenden Akku:Linke Seite des seitlichen Stromnetzes ausschließlich für Servosquelle
  • Verbinde den Arduino Nano mit dem Steckbrett
  • Verbinden Sie den GND des Stromnetzes mit Arduino GND.
  • Verbinden Sie die Servos mit Arduino:LINKS ==> Pin 5; RECHTS ==> Pin 3
  • Verbinde die LED mit Arduino Pin 13
  • Verbinde die Taste mit Arduino Pin 9

Beachten Sie, dass aufgrund der Montage der Servos (gegenüber) der Geschwindigkeitsbereich:

  • Vorwärtsgeschwindigkeit des rechten Servos geht von 1.500 us (angehalten) auf 2.000 us (volle Geschwindigkeit)
  • Die Vorwärtsgeschwindigkeit des linken Servos geht von 1.500 us (gestoppt) auf 1.000 (volle Geschwindigkeit)

An Pin13 wird eine externe LED zu Signalisierungs- und Testzwecken hinzugefügt (Sie können die interne Arduino-LED verwenden, statt einer externen, wenn Sie möchten, aber bedenken Sie, dass sie in der Mitte der Kabel schwer zu sehen ist).

An Pin 9 ist auch ein Taster angeschlossen. Dieser Taster ist sehr nützlich für Testzwecke und zum Starten des Roboters.

Zum Beispiel:

während(digitalRead(buttonPin)) {}motorTurn (LEFT, 500);motorTurn (RIGHT, 500); 

Beachten Sie, dass die 2 Zeilen, die dem Roboter befehlen, nach LINKS zu drehen, 500 ms zu warten und RECHTS abzubiegen, erst nach dem Drücken der Taste (buttonPin =0) erfolgen. Davor wird das Programm in der Endlosschleife angehalten.

Der folgende Code kann als Grundlage für einen vollständigen Motortest verwendet werden (vorwärts, rückwärts, vollständiger Stopp, links abbiegen, rechts abbiegen). Gegebenenfalls müssen Sie die Verzögerungen für den erforderlichen Drehwinkel abhängig von Ihren Motoren anpassen (auch die linken und rechten Impulswerte sollten manchmal etwas unterschiedlich sein, um eine Unwucht der Motoren auszugleichen.

FDDQRQOIN4TTVY0.ino

Schritt 4:Das Bluetooth-Modul (optional)

Das Bluetooth-Modul HC-06 sollte wie in der Zeichnung gezeigt am Steckbrett installiert werden. Die Arduino-Bibliothek SoftSerial wird verwendet.

Unterhalb der HC-06-Pin-Anschlüsse:

  • Sende-Pin zu Arduino Pin 10 (Rx)
  • RX-Pin zu Arduino Pin 11 (Tx)
  • VCC/GND zu Arduino 5V/GND

Der Roboter funktioniert mit oder ohne Bluetooth. Der Code ist so aufgebaut, dass die Standardparameter vom Roboter verwendet werden, wenn Sie das BT nicht aktivieren. Machen Sie sich also keine Sorgen, wenn Sie das HC-06-Modul nicht installieren möchten, der Code funktioniert trotzdem einwandfrei. Im letzten Teil dieses Tutorials werde ich untersuchen, wie Sie eine Android-App zum Senden von Daten verwenden, um die Roboterparameter besser abzustimmen und/oder den Roboter im manuellen Modus zu bewegen. Ich werde die Verwendung von Bluetooth und der App als optional belassen, falls jemand mehr über die Verwendung eines Line Follower-Roboters für beispielsweise Wettbewerbe erfahren möchte.

Schritt 5:Hinzufügen der Zeilensensoren

Verbinden Sie die Kabel wie folgt mit den Arduino-Pins:

  • Sensor 0 =12
  • Sensor 1 =18
  • Sensor 2 =17
  • Sensor 3 =16
  • Sensor 4 =19
  • Befestige die 5 Sensoren an einer Plastikstange wie auf den Fotos gezeigt
  • Es empfiehlt sich, die Sensoren zu Testzwecken zu beschriften. Der Name des Sensors reicht von „0“ (mehr nach links) bis „4“ (mehr nach rechts)
  • Führen Sie die Kabel unter dem Rahmen durch und verwenden Sie die Gummibänder, um sie zu befestigen. Achten Sie darauf, nicht mit den Rädern oder der Laufrolle zu verwechseln.
  • Der zweite Satz von 5V-Batterien wurde repariert und an Arduino Vin angeschlossen.

In meinem Fall verwende ich ein Modul mit 4 integrierten Sensoren + 1 extra. Alle sind kompatibel. Der Einfachheit halber habe ich in das Diagramm 5 eigenständige Sensoren aufgenommen, die miteinander verbunden sind. Die Endergebnisse sind in beiden Konfigurationen gleich.

Schritt 6:Implementieren der IR-Sensorlogik

Der IR-Sensor besteht aus einer einzelnen IR-LED und einer IR-Photodiode. Das von der LED emittierte IR-Licht trifft auf die Oberfläche und wird zur IR-Photodiode zurückreflektiert. Die Photodiode erzeugt dann eine Ausgangsspannung proportional zum Reflexionsgrad der Oberfläche (höhere Werte für "helle Oberflächen" und niedrigere für "schwarze/dunkle Oberflächen").

Bei den verwendeten Sensoren erzeugt ein integrierter Schaltkreis am Modul als Ausgang ein einfaches digitales Signal (HIGH:Dark; LOW:Light). Ein am Modul installiertes Potentiometer (siehe Foto) stellt die richtige Lichtstärke ein, die als "dunkel" oder "hell" gilt. Es funktioniert so, dass wenn die reflektierte Lichtfarbe schwarz/dunkel ist, an seinem Ausgang ein HIGH ("1") Digitalpegel und ein LOW ("0") für eine andere hellere Farbe erzeugt wird. Ich habe hier ein integriertes Modul mit 4 Sensoren und ein zusätzliches Modul mit einem einzigen Sensor verwendet (andere Form, aber gleiche Logik). Die Kombination ist ein Array von 5 Sensoren, die meiner Meinung nach gut für eine schöne und reibungslose Steuerung sind, wie unten erklärt.

Das Array von 5 Sensoren ist so montiert, dass nur dieser spezifische Sensor ein HIGH erzeugt, wenn nur ein Sensor in Bezug auf die schwarze Linie zentriert ist. Auf der anderen Seite sollte der Abstand zwischen den Sensoren so berechnet werden, dass 2 Sensoren gleichzeitig die volle Breite der schwarzen Linie abdecken können, was auch ein HIGH auf beiden Sensoren erzeugt (siehe Bilder oben).

Die möglichen Sensor-Array-Ausgaben beim Folgen einer Zeile sind:

  • 0 0 0 0 1
  • 0 0 0 1 1
  • 0 0 0 1 0
  • 0 0 1 1 0
  • 0 0 1 0 0
  • 0 1 1 0 0
  • 0 1 0 0 0
  • 1 1 0 0 0
  • 1 0 0 0 0

Mit 5 Sensoren kann eine "Fehlervariable" generiert werden, die hilft, die Position des Roboters über der Linie zu kontrollieren, wie unten gezeigt.

Nehmen wir an, der optimale Zustand ist, wenn der Roboter zentriert ist und die Linie gerade unterhalb des "mittleren Sensors" (Sensor 2) liegt. Die Ausgabe des Arrays ist:0 0 1 0 0 und in dieser Situation ist der "Fehler" "Null". Beginnt der Roboter nach links zu fahren (die Linie "scheint sich zu bewegen" rechts") muss der Fehler bei einem positiven Signal zunehmen. Wenn der Roboter beginnt sich nach rechts zu bewegen (die Linie "scheint sich zu bewegen" links"), in der genauso muss der Fehler zunehmen, aber jetzt mit negativem Signal.

Die mit dem Sensorstatus verbundene Fehlervariable ist:

0 0 1 0 0 ==> Fehler =0

  • 0 0 0 0 1 ==> Fehler =4
  • 0 0 0 1 1 ==> Fehler =3
  • 0 0 0 1 0 ==> Fehler =2
  • 0 0 1 1 0 ==> Fehler =1
  • 0 1 1 0 0 ==> Fehler =-1
  • 0 1 0 0 0 ==> Fehler =-2
  • 1 1 0 0 0 ==> Fehler =-3
  • 1 0 0 0 0 ==> Fehler =-4

Wenn man sich den Arduino-Code ansieht, wird jeder der Sensoren mit einem bestimmten Namen definiert (beachten Sie, dass der weiter links liegende Zeilenfolgesensor mit einem Label „0“ zugewiesen werden muss):

const int lineFollowSensor0 =12;const int lineFollowSensor1 =18;const int lineFollowSensor2 =17;const int lineFollowSensor3 =16;const int lineFollowSensor4 =19; 

Um die Werte jedes Sensors zu speichern, wird eine Array-Variable erstellt:

int LFSensor[5]={0, 0, 0, 0, 0}; 

Jede Position des Arrays wird ständig mit der Ausgabe jedes einzelnen der Sensoren aktualisiert:

LFSensor[0] =digitalRead(lineFollowSensor0);LFSensor[1] =digitalRead(lineFollowSensor1);LFSensor[2] =digitalRead(lineFollowSensor2);LFSensor[3] =digitalRead(lineFollowSensor3);LFSensor[4] =digitalRead(lineFollowSensor4); 

Mit dem Wert jedes einzelnen der Sensoren muss eine Logik implementiert werden, um die Fehlervariable zu erzeugen:

if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor [4]==1 )) Fehler =4;sonst if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3] ==1 )&&(LFSensor[4]==1 )) Fehler =3; else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =2;sonst if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =1;sonst if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[ 3]==0 )&&(LFSensor[4]==0 )) Fehler =0;sonst if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==1 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) Fehler =- 1;sonst if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) Fehler =-2;sonst if((LFSensor[0]==1 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) Fehler =-3;sonst if((LFSensor [0]==1 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) Fehler =-4; 

Schritt 7:Richtung steuern (Proportionalsteuerung - P)

Perfekt! An diesem Punkt ist unser Roboter montiert und betriebsbereit. Sie sollten einige grundlegende Tests mit den Motoren durchführen, die Ausgabe von Sensoren lesen und diese über eine Leitung testen. Was fehlt, ist das echte „Gehirn“, die ersten Schritte einer „künstlichen Intelligenz“. Wir erhalten dies, indem wir eine Steuerlogik implementieren, die garantiert, dass der Roboter der Linie folgt.

Einfache proportionale Steuerung:

Angenommen, der Roboter fährt über eine Linie und die Ausgabe des Sensorarrays lautet:"0 0 1 0 0 " . Der entsprechende Fehler ist "0". In dieser Situation sollten beide Motoren mit konstanter Geschwindigkeit vorwärts laufen.

Zum Beispiel:

Definieren der Variablen:iniMotorSpeed ​​=250 ; bedeutet, dass das LINKE Servo Impulse von 1.250us und das RECHTE Servo 1.750us empfängt. Mit diesen Parametern bewegt sich der Roboter mit halber Geschwindigkeit vorwärts. Denken Sie daran, dass die Vorwärtsgeschwindigkeit des RECHTEN Servos mit einer Impulslänge von 1.500 us (gestoppt) bis 2.000 us (volle Geschwindigkeit) und das LINKE Servo von 1.500 us (gestoppt) bis 1.000 us (volle Geschwindigkeit) reicht.

rightServo.writeMicroseconds(1500 + iniMotorPower);leftServo.writeMicroseconds(1500 - iniMotorPower); 

Angenommen, der Roboter fährt nach links (es ist wie die "LINE goes to right") und bedeckt auch den Sensor 3. Die Array-Ausgabe ist:"0 0 1 1 0 " und der Fehler =1 . In dieser Situation müssen Sie den Roboter nach rechts drehen. Um dies zu tun, müssen Sie die Geschwindigkeit des RECHTEN Servos verringern, was bedeutet, dass die Länge des Impulses verringert wird. Außerdem muss die Geschwindigkeit des LINKEN Servos erhöht werden, was bedeutet, dass die Länge des LINKEN Servoimpulses verringert wird. Dazu müssen wir die Motorsteuerungsfunktion ändern:

rightServo.writeMicroseconds(1500 + iniMotorPower - Fehler); ==> Positiver Fehler:Geschwindigkeit verringernleftServo.writeMicroseconds(1500 - iniMotorPower - Fehler); ==> Positiver Fehler:Geschwindigkeit erhöhen 

Die obige Logik ist richtig, aber es ist leicht zu verstehen, dass das Addieren oder Subtrahieren von "1" Mikrosekunden bei der Impulslänge nicht die erforderliche Korrektur zu einer realistischen Zeit erzeugt. Es ist intuitiv, dass die zu addierende oder zu subtrahierende Zahl größer sein sollte, zum Beispiel 50, 100 usw. Um dies zu erhalten, muss der "Fehler" mit einer Konstanten multipliziert werden (nennen wir ihn "K"). Sobald der Einfluss dieser Konstante proportional zum Fehler ist, nennen wir sie "Proportionale Konstante:Kp" .

Die Motorfunktion ist:

int Kp =50;rightServo.writeMicroseconds(1500 + iniMotorPower - Kp*Fehler);leftServo.writeMicroseconds(1500 - iniMotorPower - Kp*Fehler); 

Wir können wie folgt fortfahren, was mit den Motoren passieren wird:

  • Sensor-Array:0 0 1 0 0 ==> Fehler =0 ==> Impulslänge des rechten Servos =1.750 us ==> Impulslänge des linken Servos =1.250 us (beide Motoren mit gleicher Geschwindigkeit)
  • Sensor-Array:0 0 1 1 0 ==> Fehler =1 ==> Impulslänge des rechten Servos =1.700 us (langsamer) ==> Impulslänge des linken Servos =1.200 us (schneller)

Wenn die Situation umgekehrt ist und der Roboter nach rechts gefahren wird, wäre der Fehler "negativ" und die Geschwindigkeit der Servos sollte sich ändern:

  • Sensor-Array:0 0 1 0 0 ==> Fehler =0 ==> Impulslänge des rechten Servos =1.750 us ==> Impulslänge des linken Servos =1.250 us (beide Motoren mit gleicher Geschwindigkeit)
  • Sensor-Array:0 1 1 0 0 ==> Fehler =-1 ==> Impulslänge des rechten Servos =1.800 us (schneller) ==> Impulslänge des linken Servos =1.300 us (langsamer)

An dieser Stelle ist klar, dass der Fehler umso größer wird, je mehr der Roboter zur Seite gefahren wird und schneller in die Mitte zurückkehren muss. Die Geschwindigkeit, mit der der Roboter auf den Fehler reagiert, ist proportional dazu. Dies nennt man "Proportionale Kontrolle" , das ist die "P"-Komponente eines komplexeren Regelnetzes, dem PDI (Proportional, Derivative, Integral).

Schritt 8:PID-Steuerung (optional)

Falls Sie an diesem Teil springen möchten, ist es auch in Ordnung. Sie können bei der im letzten Schritt erklärten proportionalen Steuerung bleiben oder sich ein paar Köpfe verbrennen, um ein komplexeres Steuerungssystem in Ihrem Roboter zu implementieren, Sie haben die Wahl.

Wenn du dich entschieden hast, lass uns gehen!

PID (Proportional, Derivative and Integral) ist eines der am häufigsten verwendeten Regelschemata. Die meisten industriellen Regelkreise verwenden eine Art PID-Regelung. Es gibt viele Möglichkeiten, eine PID-Schleife abzustimmen, einschließlich der in diesem Beispiel verwendeten manuellen Technik.

Stellen Sie sich PID als einfache Feder vor. Eine Feder hat eine ursprüngliche Länge, die, wenn sie durch Dehnung oder Kontraktion gestört wird, dazu neigt, in kürzester Zeit ihre ursprüngliche Länge wiederzuerlangen. In ähnlicher Weise hat ein PID-Algorithmus in einem System einen Sollwert einer bestimmten zu steuernden physikalischen Größe, der als „Sollwert . bezeichnet wird “, das, wenn es aus irgendeinem Grund geändert wird, das System die anderen notwendigen Funktionen steuert, um in kürzester Zeit zum ursprünglichen Sollwert zurückzukehren. PID-Regler werden überall dort eingesetzt, wo eine physikalische Größe geregelt und auf einen vorgegebenen Wert gebracht werden soll. Beispiel, Cruise Controller in Autos, Robotern, Temperaturreglern, Spannungsreglern usw.

Wie funktioniert PID?

Das System berechnet den ‚Fehler “ oder „Abweichung ’ der physikalischen Größe vom Sollwert, indem der aktuelle Wert dieser physikalischen Größe mit einem oder mehreren Sensoren gemessen wird. Um zum Sollwert zurückzukehren, dieser „Fehler “ sollte minimiert und idealerweise gleich Null gemacht werden. Außerdem sollte dieser Vorgang so schnell wie möglich erfolgen. Idealerweise sollte die Reaktion des Systems auf die Änderung seines Sollwerts keine Verzögerung aufweisen.

Weitere Informationen finden Sie in vielen Büchern und Websites, auch hier.

PID implementieren

i) Fehlerbegriff (e):

Dies ist gleich der Differenz zwischen dem Sollwert und dem aktuellen Wert der zu regelnden Größe. Fehler =set_pointaktueller_Wert (in unserem Fall ist die Fehlervariable get aus der Position des Roboters über der Linie

ii) Proportionaler Begriff (P):

Dieser Term ist proportional zum Fehler.

P =Fehler

Dieser Wert ist für die Größe der Änderung der physikalischen Größe verantwortlich, die erforderlich ist, um den Sollwert zu erreichen. Der Proportionalterm bestimmt die Anstiegszeit des Regelkreises oder wie schnell er den Sollwert erreicht.

iii) Integralterm (I):

Dieser Term ist die Summe aller vorherigen Fehlerwerte.

I =I + Fehler

Dieser Wert ist für die Reaktionsschnelligkeit des Systems auf die Änderung vom Sollwert verantwortlich. Der Integralterm wird verwendet, um den vom Proportionalterm geforderten stationären Fehler zu eliminieren. Normalerweise verwenden kleine Roboter den Integralbegriff nicht, da wir uns nicht um stationäre Fehler kümmern und dies die "Schleifenabstimmung . erschweren kann ".

iv) Differential- oder Ableitungsterm (D):

Dieser Term ist die Differenz zwischen dem momentanen Fehler vom Sollwert und dem Fehler vom vorherigen Moment.

D =Fehler - vorherigerFehler

Dieser Wert ist dafür verantwortlich, die Änderungsgeschwindigkeit der physikalischen Größe zu verlangsamen, wenn sie sich dem Sollwert nähert. Der abgeleitete Term wird verwendet, um das Überschwingen zu reduzieren oder um wie viel das System "überkorrigieren" sollte ".

Gleichung:

PID-Wert =(Kp*P) + (Ki*I) + (Kd*D)

Wo:

Kp ist die Konstante, die verwendet wird, um den Ausmaß der Änderung . zu variieren erforderlich, um den Sollwert zu erreichen. Ki ist die Konstante, die verwendet wird, um die Rate zu ändern, mit der die Änderung sollte die physikalische Größe eingebracht werden, um den Sollwert zu erreichen. Kd ist die Konstante zum Variieren der Stabilität vom System.

Ein Ansatz zum Optimieren der Schleife kann die Versuchsfehlerversuchsmethode . sein :

Setzen Sie die Kd-Variable auf 0 und stimmen Sie zuerst den Kp-Term allein ab. Kp von 25 ist in unserem Fall hier ein guter Anfang. Im letzten Schritt haben wir einen Kp von 50 verwendet, der mit meinem Roboter sehr gut funktioniert. Sobald der Roboter vernünftig reagiert, stimmen Sie den Ableitungsteil des Regelkreises ab (Kd ). Stellen Sie zuerst den Kp- und Kd-Wert jeweils auf die Hälfte des Kp-Wertes ein. Wenn der Roboter beispielsweise mit einem Kp =50 vernünftig reagiert, dann setzen Sie Kp =25 und Kd =25, um zu starten. Erhöhen Sie die Kd-(Ableitungs-)Verstärkung, um das Überschwingen zu verringern, verringern Sie sie, wenn der Roboter instabil wird.

  • Wenn der Roboter zu langsam reagiert, erhöhen Sie den Wert.
  • Wenn der Roboter schnell zu reagieren scheint und instabil wird, verringern Sie den Wert.

Eine weitere zu berücksichtigende Komponente der Schleife ist die tatsächliche Sample/Loop-Rate . Das Beschleunigen oder Verlangsamen dieses Parameters kann einen erheblichen Unterschied in der Leistung des Roboters ausmachen. Dies wird durch die Verzögerung festgelegt Anweisungen, die Sie in Ihrem Code haben. Es ist eine Versuchsmethode, um das optimale Ergebnis zu erzielen.

Basierend auf dem obigen Ansatz wurde die folgende Funktion implementiert:

void computePID(){ P =error; ich =ich + Fehler; D =Fehler-vorheriger Fehler; PID-Wert =(Kp*P) + (Ki*I) + (Kd*D); previousError =error;} 

Die im letzten Schritt verwendete einfache Kp-Konstante wird durch diesen vollständigeren PID-Wert . ersetzt :

void motorPIDcontrol(){ int leftMotorSpeed ​​=1500 - iniMotorPower - PIDvalue; int rightMotorSpeed ​​=1500 + iniMotorPower - PID-Wert; leftServo.writeMicroseconds(leftMotorSpeed); rightServo.writeMicroseconds(rightMotorSpeed);} 

Beachten Sie jedoch, dass bei Kd und Ki =0 , PID-Wert wird nur im letzten Schritt Kp*Fehler verwendet.

Schritt 9:Der endgültige Code

In diesem Schritt kann der Roboter einer konstanten Schleife folgen und wird dies ohne Anhalten tun. Das Schleifenprogramm wäre:

void loop (){readLFSsensors(); // Sensoren lesen, Werte im Sensor-Array speichern und "Fehler" berechnencalculPID(); motorPIDcontrol();} 

Für eine vollständigere und realere Operation ist es jedoch wichtig, mindestens ein paar grundlegende "Befehle . hinzuzufügen " done "mit der Zeile ". Lassen Sie uns zum Beispiel eine neue Variable einführen:"mode ". Wir werden 3 Zustände für diese Variable definieren:

Modus:

  • #define GESTOPPT 0
  • #define FOLLOWING_LINE 1
  • #define NO_LINE 2

Wenn alle Sensoren eine schwarze Linie finden, wäre die Ausgabe des Sensor-Arrays:1 1 1 1 1. In diesem Zustand können wir den Modus als „STOPPED“ definieren und der Roboter sollte einen „vollen Stopp . ausführen ".

if((LFSensor[0]==1 )&&(LFSensor[1]==1 )&&(LFSensor[2]==1 )&&(LFSensor[3]==1 )&&(LFSensor [4]==1 )) { Modus =GESTOPPT;} 

Eine andere häufige Situation bei Follower-Line-Robotern ist, dass "keine Linie . gefunden wird ", oder die Ausgabe des Sensor-Arrays ist:0 0 0 0 0. In diesem Fall können wir es so programmieren, dass es um 180o zurückgedreht oder in kleinen Winkeln gedreht wird, bis eine Linie gefunden wird und der normale Linienfolgezustand wieder aufgenommen wird.

sonst if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&( LFSensor[4]==0 )) { mode =NO_LINE;} 

Die komplette Schleife() wäre:

void loop() { readLFSsensors(); Schalter (Modus) { Fall STOPPED:motorStop(); brechen; Fall NO_LINE:motorStop(); motorTurn (LINKS, 180); brechen; Fall FOLLOWING_LINE:berechnePID(); motorPIDcontrol(); brechen; }} 

Der eigentliche endgültige Code wird einige zusätzliche Logik und auch einige Variablen enthalten, die initialisiert werden müssen usw. Während der obigen Erklärung habe ich sie der Einfachheit halber weggelassen, aber mit Blick auf den endgültigen Code sollte alles klar sein.

Unten ist der endgültige Arduino-Code:

FUXCUEAIN699SZC.ino FLD2J3KIN699SZF.h FOFYXFZIN699SZT.ino FMPX9KJIN699SZU.ino FFE5AZ3IN699T06.ino

Schritt 10:Optimieren des PID-Reglers mit der Android-App

In the previous code, you can find at "robotDefines.h " tab the following definitions for the constants to be used with the PID control:

float Kp=50;float Ki=0;float Kd=0; 

As explained at previous step, the best way to define the correct constant to be used with a PID controller is using the "Try-error" methodology. The bad side of that is that you must re-compile the program each time that you must change it. One way to speed-up the process is to use the Android App to send the constants at the "Set-Up Phase" .

I developed an Android App exclusively for that. In short there are the traditional manual commands:

  • FW, BW, Left, Right and Stop where the app will send respectively to the BT module:'f', 'b', 'l', 'r' and 's'.

Also 3 sliders were included, one for each PID constants:

  • Kd:"d/XXX" where "XXX" it is a number from 0 to 100.
  • Kp:"p/XXX"
  • Ki:"i/XXX"

An extra button was included that will work exactly as the button connected on Arduino Pin9. You can use one or the other, it does not matter.

Below you can find the .aia file that can be modified at MIT AppInventor and the .apk file to be installed directly in your Android device.

FTH62BVIN699T4B.aia F60H7R0IN699T4I.apk

Step 11:Changing the Code for PID remote tuning

During the Setup, we will introduce a loop where you can send the PID parameters to the Robot before you put him over the line:

 while (digitalRead(buttonPin) &&!mode) { checkBTcmd(); // verify if a comand is received from BT remote control manualCmd (); command =""; } checkPIDvalues(); mode =STOPPED; 

The manual command function will be:

void manualCmd(){ switch (command[0]) { case 'g':mode =FOLLOWING_LINE; brechen; case 's':motorStop(); //turn off both motors break; case 'f':motorForward(); brechen; case 'r':motorTurn(RIGHT, 30); motorStop(); brechen; case 'l':motorTurn(LEFT, 30); motorStop(); brechen; case 'b':motorBackward(); brechen; case 'p':Kp =command[2]; brechen; case 'i':Ki =command[2]; brechen; case 'd':Kd =command[2]; brechen; }} 

In the video, you can see some tests using the Android App. Below the final code including the PID setup via Android:

FGAEB9BIN7QQQAW.ino FBMONSNIN7QQQCD.ino F8B3CDHIN7QQQCL.h FNOMRUNIN7QQQCP.ino FA3K57ZIN7QQQCR.ino

Step 12:Conclusion

This is the first part of a more complex project, exploring the potentiality of a line follower robot. In the next part, I will develop a Maze solve robot, based on this this project here. Hopefully I can contribute for others to learn more about electronics, robot, Arduino, etc.

The update files for this project can be found at GITHUB. For more tutorials, please visit my Blog:MJRoBot.org

Greetings from the south of the world!

Thanks

Marcelo

Code

  • Code-Snippet Nr. 1
  • Code-Snippet 2
  • Code-Snippet #3
  • Code-Snippet Nr. 5
  • Code snippet #6
  • Code snippet #10
  • Code-Snippet #11
  • Code-Snippet #12
  • Code snippet #15
  • Code snippet #17
  • Code snippet #18
Code-Snippet Nr. 1Nur-Text
#include  // Servo library Servo leftServo;Servo rightServo;Void setup(){ leftServo.attach(5); rightServo.attach(3); leftServo.writeMicroseconds(1500); rightServo.writeMicroseconds(1500);}void loop(){}
Code-Snippet #2Klartext
while(digitalRead(buttonPin)) { }motorTurn (LEFT, 500);motorTurn (RIGHT, 500);
Code-Snippet #3Kurztext
const int lineFollowSensor0 =12;const int lineFollowSensor1 =18;const int lineFollowSensor2 =17;const int lineFollowSensor3 =16;const int lineFollowSensor4 =19;
Code-Snippet #5Klartext
LFSensor[0] =digitalRead(lineFollowSensor0);LFSensor[1] =digitalRead(lineFollowSensor1);LFSensor[2] =digitalRead(lineFollowSensor2);LFSensor[3] =digitalRead(lineFollowSensor3);LFSensor[4] =digitalRead(lineFollowSensor4);
Code snippet #6Plain text
if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==1 )) error =4;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==1 )&&(LFSensor[4]==1 )) error =3; else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =2;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[3]==1 )&&(LFSensor[4]==0 )) error =1;else if((LFSensor[0]==0 )&&(LFSensor[1]==0 )&&(LFSensor[2]==1 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =0;else if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==1 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =- 1;else if((LFSensor[0]==0 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-2;else if((LFSensor[0]==1 )&&(LFSensor[1]==1 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-3;else if((LFSensor[0]==1 )&&(LFSensor[1]==0 )&&(LFSensor[2]==0 )&&(LFSensor[3]==0 )&&(LFSensor[4]==0 )) error =-4;
Code snippet #10Plain text
void calculatePID(){ P =error; I =I + error; D =error-previousError; PIDvalue =(Kp*P) + (Ki*I) + (Kd*D); previousError =error;}
Code-Snippet #11Kurztext
void motorPIDcontrol(){ int leftMotorSpeed =1500 - iniMotorPower - PIDvalue; int rightMotorSpeed =1500 + iniMotorPower - PIDvalue; leftServo.writeMicroseconds(leftMotorSpeed); rightServo.writeMicroseconds(rightMotorSpeed);}
Code-Snippet #12Kurztext
void loop (){ readLFSsensors(); // read sensors, storage values at Sensor Array and calculate "error" calculatePID(); motorPIDcontrol();}
Code snippet #15Plain text
void loop() { readLFSsensors(); switch (mode) { case STOPPED:motorStop(); brechen; case NO_LINE:motorStop(); motorTurn(LEFT, 180); brechen; case FOLLOWING_LINE:calculatePID(); motorPIDcontrol(); brechen; }}
Code snippet #17Plain text
 while (digitalRead(buttonPin) &&!mode) { checkBTcmd(); // verify if a comand is received from BT remote control manualCmd (); command =""; } checkPIDvalues(); mode =STOPPED;
Code snippet #18Plain text
void manualCmd(){ switch (command[0]) { case 'g':mode =FOLLOWING_LINE; brechen; case 's':motorStop(); //turn off both motors break; case 'f':motorForward(); brechen; case 'r':motorTurn(RIGHT, 30); motorStop(); brechen; case 'l':motorTurn(LEFT, 30); motorStop(); brechen; case 'b':motorBackward(); brechen; case 'p':Kp =command[2]; brechen; case 'i':Ki =command[2]; brechen; case 'd':Kd =command[2]; brechen; }}
Github
https://github.com/Mjrovai/MJRoBot-Line-Followerhttps://github.com/Mjrovai/MJRoBot-Line-Follower

Schaltpläne

oIDhLcHQ30lDgVBXZvb8.fzz

Herstellungsprozess

  1. Die Zukunft der Robotik
  2. Linienverfolgungssensor mit RPi
  3. Raspberry Pi Sensor- und Aktuatorsteuerung
  4. RASPBERRY PI WIFI-ROBOTER, KONTROLLIERT VON ANDROID SMART PHONE
  5. Automatisierung:Roboterlinie neu gestaltet
  6. SCARA-Roboterlinie erweitert
  7. Universelle Fernbedienung mit Arduino, 1Sheeld und Android
  8. Industrial Line Follower für die Materialversorgung
  9. PID-Steuerung eines Robotergreifers in Matlab / Simulink
  10. Automatisierte Qualitätskontrolle der Verpackungslinie