In Teil 1 dieses Projekts haben wir bereits gesehen, wie wir unseren Roboter zusammenbauen, die ersten Bewegungen der Beine und die Abfolge der Bewegungen zu programmieren. In diesem Teil 2 des Projekts werden wir erklären, wie wir den SR04-Ultraschallsensor installieren und aktivieren, um Hindernisse zu erkennen. Wir werden auch einen Infrarotempfänger installieren, um unsere Befehle von einem Infrarotsender zu empfangen. Da wir außerdem wollen, dass er sich autonom bewegt, werden wir Batterien installieren und ihn damit von der Leine lassen.
Benötigte Hardwarekomponenten
12 |
|
|
1 |
|
|
1 |
||
1 |
||
1 |
||
1 |
||
1 |
IR Fernbedienung |
|
diverse |
Benötigte Materialien
Benötigte Software und Sketches
- Arduino IDE
- I2C Library (Wire.h, integriert)
- PCA9685 Library (Adafruit_PWMServoDriver.h)
- IR remote control Library (IRremote.h)
- Ultrasonics sensor Library (SR04.h)
- quadruped_robot_home.ino
- quadruped_robot_pushups.ino
- quadruped_robot_shoulder.ino
- quadruped_robot_walk.ino
- quadruped_robot_walk_sonic.ino
- quadruped_robot_ir_sonic.ino
Schaltplan und Beschreibung
Es wurde ein HC-SR04 Ultraschallsensor hinzugefügt, um die Entfernung zu einem Hindernis zu erkennen. Die Versorgungsspannung von 5 VDC wird von den Batterien geliefert. Sie können statt der USB-Buchse auch den VIN-Pin, oder den Power Supply verwenden. Dann müssen Sie allerdings darauf achten, dass Sie mehr als 5V anlegen, denn der VIN-Pin ist mit einem Spannungsregler verbunden.
Der Echo-Pin des Sensors wird mit dem digitalen Pin 8 des Mikrocontrollers verbunden, der Trig-Pin mit dem digitalen Pin 9. Echo sendet einen Ultraschallimpuls, Trig empfängt ihn. Der Sensor des Infrarotempfängers KY-022 wird an den Pin 11 des Mikrocontrollers angeschlossen. Dieser Sensor empfängt das Infrarotsignal der Fernbedienung. Die notwendige Spannung für dieses Modul ist ebenfalls 5 VDC, was mit dem Netzteil oder der Batterie gespeist werden kann.
Beschreibung des Sketches quadruped_robot_walk_sonic.ino
Mit der Installation des HC-SR04-Ultraschallsensors wollen wir die Eigenschaft in den Roboter implementieren, eine Aktion auszuführen, wenn er ein Hindernis in einer bestimmten Entfernung erkennt. In diesem Fall besteht die Aktion darin, sich in die Ausgangsposition von home() zu begeben, wenn ein Hindernis in einer Entfernung von weniger als 30 Zentimetern erkannt wird.
Damit unser Roboter diese Aktion ausführen kann, arbeiten wir mit dem letzten Sketch aus Teil 1, quadruped_robot_walk.ino, mit dem unser Roboter laufen konnte. Um den Ultraschallsensor zu aktivieren, wird die Bibliothek "SR04.h" am Anfang des Sketches inkludiert. Sie enthält die notwendigen Funktionen für den korrekten Betrieb des Sensors.
#include "SR04.h"
Als Nächstes müssen wir dem Mikrocontroller mitteilen, an welche Pins der Sensor angeschlossen ist. Dazu definieren wir zunächst zwei Konstanten: TRIG_PIN_FRONT an den digitalen Pin 9 und ECHO_PIN_FRONT an den digitalen Pin 8. Dann müssen wir ein Objekt aus der SR04-Bibliothek implementieren (ultrasonics_sensor_front) und als Parameter die Namen der Konstanten übergeben. Um die Entfernungsdaten zu speichern, werden wir eine globale Variable vom Typ long definieren.
#define TRIG_PIN_FRONT 9 #define ECHO_PIN_FRONT 8 SR04 ultrasonics_sensor_front = SR04(ECHO_PIN_FRONT,TRIG_PIN_FRONT); long front_distance;
Damit sollte nun der Sensor funktionstüchtig sein. Wenn Sie Probleme haben, sollten Sie sich einen kurzen Sketch schreiben und die Sensorwerte ausgeben lassen. In der setup()-Methode müssen wir in Bezug auf diesen Sensor keine Änderungen vornehmen.
Vielleicht erinnern Sie sich, dass wir in der loop() die Funktion walk() aufgerufen haben. An dieser Stelle müssen wir nun eine Bedingung einfügen. Sobald ein Hindernis erkannt wird, soll der Roboter anhalten. Mit der erweiterten Bedingung if-else sorgen wir dafür, dass er läuft, oder sich bewegt.
Zuerst rufen wir in der loop() die Funktion front_distance_object() auf.
front_distance_object();
Darin wird die Funktion Distance() des ultrasonics_sensor_front-Objekts unseres HC-SR04-Sensors ausgeführt. Diese Funktion wandelt das vom TRIG-Pin des Sensors empfangene Signal in eine Entfernung in Zentimetern um und speichert diesen Wert in der globalen Variable front_distance,. Anschließend wird der Entfernungswert über den seriellen Monitor mit der Funktion Serial.print() angezeigt. Die Ausgabe dient nur für Testzwecke. Die Ausgabe auf dem Seriellen Monitor können Sie später auch auskommentieren oder entfernen.
void front_distance_object() { front_distance = ultrasonics_sensor_front.Distance(); Serial.print("Distance to front obstacles "); Serial.print(front_distance); Serial.println(" cm"); delay(100); }
Nach der Rückkehr zur loop()-Funktion enthält die globale Variable front_distance einen Wert, der für die nachfolgende Bedingung verwendet wird. Wir vergleichen mit dem numerischen Wert 30 (also 30 cm). Abhängig von diesem Abstand wird walk(), oder home() aufgerufen. Der Roboter läuft, oder bleibt stehen.
if (front_distance >= 30) { walk(); } else { home();}
Das alles läuft in der loop() durchgehend. Mit jedem Durchlauf wird die Entfernung neu gemessen und dann neu entschieden, ob gelaufen oder stehen geblieben wird.
Der Rest des Codes sind die Funktionen walk() und home(), die bereits in Teil 1 beschrieben wurden.
Download quadruped_robot_walk_sonic.ino
Im Moment läuft der Roboter und wenn er ein Hindernis entdeckt, bleibt er stehen. Wir wollen das Projekt nun um die IR-Fernbedienung erweitern. Dafür nutzen wir das IR-Sensor-Modul. Mit der Fernbedienung werden wir durch drücken einer Zahl eine bestimmte Aktion ausführen. Wir nutzen die vorangegangen Sketches und fassen sie alle in diesem einen Sketch zusammen. Dann können wir alle einzelnen Bewegungen mit der Fernbedienung ausführen.
Beschreibung des Sketches quadruped_robot_ir_sonic.ino
Beginnen wir mit dem Einbinden des IR-Sensors. Auch hierfür wird die passende Bibliothek IRremote.h inkludiert und ein Objekt daraus instanziiert. Wir benötigen dann noch eine Variable, in der wir die Zahl der Fernbedienung speichern. Abhängig von diesem Wert werden später die dazugehörigen Aktionen ausgeführt.
Weiterhin benötigen wir die Bibliotheken für den Motortreiber, die I2C-Kommunikation und den Ultraschallsensor.
#include <Wire.h> #include <Adafruit_PWMServoDriver.h> #include "IRremote.h" #include "SR04.h"
Wir der Motortreiber angesprochen wird, kennen Sie aus Teil 1. Wir deklarieren noch zwei Konstanten für den Maximalwert der Servos und die Bewegungsgeschwindigkeit, die durch Pausen realisiert wird.
Adafruit_PWMServoDriver servoDriver_module = Adafruit_PWMServoDriver(); #define SERVOMIN 100 #define SERVOMAX 500 int movement_speed = 50;
Wir deklarieren eine Variable mit der Pinnummer, an die der IR-Sensor angeschlossen ist. Außerdem instanziieren wir ein Objekt aus der IRremote-Bibliothek, der wir diesen Pin übergeben. Als Nächstes brauchen wir dann noch eine Variable, in der wir die gedrückte Taste speichern. Das ist ein Objekt der Klasse decode_results, deren Adresse später der Decoder-Methode übergeben werden kann.
int receiver_IR_module = 11; IRrecv action_selected(receiver_IR_module); decode_results number;
In den nächsten vier Zeilen nutzen wir den gleichen Code wie bereits zuvor, um den Ultraschallsensor verwenden zu können. Trigger- und Echo-Pin, sowie ein SR04-Objekt und die front-distance-Variable, in der die Entfernung gespeichert wird.
#define TRIG_PIN_FRONT 9 #define ECHO_PIN_FRONT 8 SR04 ultrasonics_sensor_front = SR04(ECHO_PIN_FRONT,TRIG_PIN_FRONT); long front_distance;
In der setup()-Funktion werden der serielle Monitor und das Servotreiber-Modul initialisiert. Die PWM-Frequenz der Motoren beträgt 50 Hz. Dann wird mit der home()-Funktion der Roboter in seine Grundposition gebracht. Diese übernehmen wir auch aus dem ersten Teil. Zum Schluss initialisieren wir noch das Infrarotmodul.
void setup() { Serial.begin(9600); servoDriver_module.begin(); servoDriver_module.setPWMFreq(50); home(); action_selected.enableIRIn(); }
In der loop()-Funktion wird regelmäßig geprüft, welcher Wert vom Infrarotsensor empfangen wird. Die Funktion decode() bekommt die Adresse des decode_results-Objekts übergeben und prüft in der if-Anweisung, ob es sich bei dem empfangenen Wert um eine Zahl handelt. Wenn ja, wird translateIR() aufgerufen und anschließend der IR-Empfang zurückgesetzt, um einen neuen Wert zu erhalten. Wurde keine Zahl erkannt, wird trotzdem translateIR() aufgerufen, jedoch mit dem alten Wert.
void loop() { if (action_selected.decode(&number)) { translateIR(); action_selected.resume(); } else { translateIR(); } }
In der translateIR()-Funktion wird eine switch-case-Anweisung ausgeführt. Abhängig vom empfangenen Wert der Fernbedienung werden damit die verschiedenen Funktionen für die Bewegung des Roboters aufgerufen.
void translateIR() { switch(number.value) { case 0xFF6897: home(); break; case 0xFF30CF: pushups(); break; case 0xFF18E7: shoulder(); break; case 0xFF7A85: walk(); break; default: Serial.println("other button"); } }
Die Funktionen, die hier aufgerufen werden, wurden in Teil 1 dieses Artikels beschriebenen, nämlich: home(), pushups(), shoulder() und walk(). Die Zahlen, die zur Ausführung der oben genannten Methoden gedrückt werden, sind:
- Nummer 0xFF6897 (Nummer 0 auf der Fernbedienung) führt die Funktion home() aus
- Nummer 0xFF30CF (Nummer 1 auf der Fernbedienung) führt die Funktion pushups() aus
- Nummer 0xFF18E7 (Nummer 2 auf der Fernbedienung) führt die Funktion shoulder() aus
- Nummer 0xFF7A85 (Nummer 3 auf der Fernbedienung) führt die Funktion walk() aus
WICHTIGER HINWEIS: Die hexadezimalen Werte der Fernbedienungstasten ändern sich je nach Hersteller. Die Hexadezimalzahlen der Fernbedienung des Electronics Super Starter Kit sind:
- 0xFF629D entspricht der Taste "UP".
- 0xFF22DD entspricht der Taste "LINKS".
- 0xFF02FD entspricht der "OK"-Taste.
- 0xFFC23D entspricht der Taste "RECHTS".
- 0xFFA857 entspricht der Taste "AB".
- 0xFF9867 entspricht der Taste "2".
- 0xFFB04F entspricht der Taste "3".
- 0xFF6897 entspricht der Taste "1".
- 0xFF30CF entspricht der Taste "4".
- 0xFF18E7 entspricht der Taste "5".
- 0xFF7A85 entspricht der Taste "6".
- 0xFF10EF entspricht der Taste "7".
- 0xFF38C7 entspricht der Taste "8".
- 0xFF5AA5 entspricht der Taste "9".
- 0xFF42BD entspricht der Taste "*".
- 0xFF4AB5 entspricht der Taste "0".
- 0xFF52AD entspricht der Taste "#".
Sollten Sie eine andere Fernbedienung verwenden, nutzen Sie einen Sketch, der Ihnen die Werte im Seriellen Monitor anzeigt und übernehmen Sie diese für Ihren Quellcode.
Von den vier aufgerufenen Funktionen haben sich weder home(), noch pushups(), noch shoulder() im Vergleich zu dem, was in Teil 1 des Projekts erklärt wurde, verändert. Die walk()-Methode wird durch die Entfernungsmessung mit dem SR04-Ultraschallsensor erweitert. Ich zeige Ihnen nun noch, wie ich das in diesen Sketch implementiert habe.
Zuerst wird front_distance_object() aufgerufen, die die Entfernung zum nächsten frontalen Hindernis misst und den Wert in der globalen Variablen front_distance speichert. Es wird nun wieder verglichen, ob der Wert der größer oder gleich 30 (cm) ist. Ist die Bedingung wahr, wird die Bewegung ausgeführt. Ansonsten wird im else-Zweig die home()-Funktion aufgerufen und der Roboter bleibt stehen, bis das Hindernis außer Reichweiter ist.
void walk() { front_distance_object(); if (front_distance >= 30) { servoDriver_module.setPWM(0, 0, 450); delay(movement_speed); . . . . . . . . . . . . . . . servoDriver_module.setPWM(4, 0, 400); delay(movement_speed); } else { home(); } }
Damit sich der Roboter nun frei bewegen kann, habe ich zwei Akkupacks installiert und parallelgeschaltet. Das ergibt einen Strom von 2A bei 5 VDC. Ich habe sie, wie oben im Schaltbild zu sehen ist, an den USB-Port angeschlossen.
Somit sind wir nun am Ende des Projekts angekommen. Ich lade Sie herzlich dazu ein, das Projekt zu erweitern. Zum Beispiel könnten Sie Bewegungssequenzen implementieren, die die Richtung des Roboters ändern. Dadurch könnte er dann autonom den Hindernissen ausweichen.
Wir hoffen, dass Ihnen dieses Projekt gefallen hat.