| Projektvorstellung selbststeuernder
Roboter "Roberta" Die Idee:
|
![]() Roberta von oben |
|
Nachdem ich früher schon
mal ein fertiges (billiges) Roboter-Chassis mit zwei einfachen Elekromotoren
als Antrieb getestet und enttäuscht nach einem Tag wieder zurückgeschickt
hatte, machte ich mich auf die Suche nach einem beseren Antriebskonzept,
das präzise zu steuern und trotzdem nicht zu teuer in der Anschaffung
ist. |
|
![]() Die Spindeltrimmer (blau) zum Kablibrieren der Antriebsservos |
|
|
![]() Ich schau dir in die Augen... |
| Die Steuerung Die Versorgung der beiden Servos erfolgt über einen L293D. Nachdem erste Prototypen immer mit einem Breadboard rumgefahren sind, was entsprechend wackelig war, fand ich es an der Zeit, mein erstes Arduino-Shield selbst zu entwerfen und zu ätzen - was im zweiten Anlauf ganz passabel geworden ist. Neben dem L293D auf einem IC-Sockel beherbergt es Steckontakte für die Antriebs-Servos, das Display und die vordere Platine. Die Stromversorung übernimmt ein LiPo-Akku mit 7,4V und 2200mAh - das hat bisher immer gereicht :-) Falls es mal eng werden sollte, schützt ihn ein LiPo-Saver vor gefährlicher Tiefentladung. |
![]() |
![]() |
| Das Display Das Display, das ursprüglich nur zum Überwachen der Werte und Debugging diente, ist inzwischen fester (und neuerdings auch fest montierter) Bestandteil von Roberta geworden. In der oberen Zeile werden die Entfernungen der nächsten Hindernisse in cm angezeigt (oder 99 bei > 1 Meter). Unten wird die Geschwindigkeit der beiden Antriebsmotoren mittels Sternchen angezeigt. Das Display wird über I2C vom Arduino angesteuert. |
![]() |
Der Sketch (das "Programm"):
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
Servo s1;
Servo s2;
Servo s3;
int s1o=8;
int s2o=7;
int pingpin=2;
int cm=0;
int abst[6];
int winkel[]={130,110,90,70,50};
int pos=0;
int aufab=1;
int count=0;
void setup(){
s1.attach(9);
s2.attach(10);
s3.attach(4);
pinMode(s1o, OUTPUT);
pinMode(s2o, OUTPUT);
lcd.init();
lcd.backlight();
schaurum(200);
schaurum(100);
}
void loop(){
pos=pos+aufab;
if (pos==5){
pos=3;
aufab=-aufab;
}
if (pos==-1){
pos=1;
aufab=-aufab;
}
abst[pos]=mess(winkel[pos]);
if ((abst[1]<20 && abst[3]<20) || abst[0]<10 || abst[4]<10){
fahr(-40,-40,500);
if (abst[0]< abst[4]){
do{
fahr(-60,60,300);
schaurum(40);
count++;
}
while (abst[0]<5 || abst[1]<10 || abst[2]<20 || abst[3]<10 || abst[4]<5);
}
else{
do{
fahr(60,-60,300);
schaurum(40);
count++;
}
while (abst[0]<5 || abst[1]<10 || abst[2]<20 || abst[3]<10 || abst[4]<5);
}
count=0;
}
else
{
if (abst[0]<20 && abst[1]>40 && abst[2]>40 && abst[3]>40 && abst[4]>40){
fahr(50,0,0);
}
if (abst[0]>40 && abst[1]>40 && abst[2]>40 && abst[3]>40 && abst[4]<20){
fahr(0,50,0);
}
if (abst[0]>40 && abst[1]>40 && abst[2]>40 && abst[3]>40 && abst[4]>40){
fahr(50,50,0);
}
if (abst[0]>70 && abst[1]>70 && abst[2]>70 && abst[3]>70 && abst[4]>70){
fahr(60,60,0);
}
if (abst[1]<40 || abst[2]<40 || abst[3]<40){
if(abst[0]+abst[1]<abst[3]+abst[4]){
fahr(50,30,0);
}
else{
fahr(30,50,0);
}
}
}
}
int mess(int a){
s3.write(a);
delay(80);
schreib();
long del;
pinMode(pingpin, OUTPUT);
digitalWrite(pingpin, LOW);
delayMicroseconds(2);
digitalWrite(pingpin, HIGH);
delayMicroseconds(5);
digitalWrite(pingpin, LOW);
pinMode(pingpin, INPUT);
del = pulseIn(pingpin, HIGH);
cm=del/78;
return cm;
}
void schaurum(int srzeit){
fahr(0,0,0);
for (int j=0;j<5;j++){
abst[j]=mess(winkel[j]);
delay(srzeit);
}
}
void fahr(int li, int re, int zeit){
sterne(li,re);
if (abs(li)>5) digitalWrite(s1o,1);
else digitalWrite(s1o,0);
if (abs(re)>5) digitalWrite(s2o,1);
else digitalWrite(s2o,0);
if (li>100) li=100;
if (re>100) re=100;
li *=0.35;
re *=0.35;
s1.write(90+li);
s2.write(90-re);
delay(zeit);
}
void schreib(){
lcd.setCursor(0,0);
for(int i=0;i<6;i++){
lcd.print(" ");
if (abst[i]>99){
lcd.print("99");
}
if (abst[i]<10){
lcd.print(" ");
}
if (abst[i]<100){
lcd.print(abst[i]);
}
}
}
void sterne(int sli, int sre){
lcd.setCursor(0,1);
for (int k=0;k<7;k++){
if (sli>=10*(k+1)) lcd.print ("*");
else if (sli<0 && abs(sli)>=10*(k+1)) lcd.print ("-");
else lcd.print(" ");
}
lcd.print (" ");
for (int k=7;k>=0;k--){
if (sre>=10*(k+1)) lcd.print ("*");
else if (sre<0 && abs(sre)>=10*(k+1)) lcd.print ("-");
else lcd.print(" ");
}
}
|
Ein paar Erklärungen
zum Sketch:
Servo s1 ist für links, s2 rechts, s3 fürs "Radar"
Die Funktion fahr(int li, int re, int zeit) steuert die Antriebsservos
an, wobei li und re die Geschwindigkeiten
links und rechts bestimmen und zeit die Dauer. Die meisten
Fahrbefehle kommen mit Zeit 0, um schnell auf Änderungen der Umgebung
reagieren zu können. Nur die Routine zum Schwenken bei nahen Hindernissen
bringt eine Zeit mit.
Die Funktion schaurum(int srzeit) wird zum Start zweimal und ansonsten beim Ausweichen von Hindernissen ausgeführt. Hier werden alle Entferungen erfasst, bevor es weiter geht.
schreib() und sterne() dienen der Ausgabe aufs Display
mess(int a) führt eine Messung mit Winkel a durch und gibt die Entfernung in cm zurück.
Im loop() - Bereich findet die eigentliche Steuerung statt, wobei je nach Entfernungen entsprechende Geschwindigkeits-Änderungen durchgeführt werden.
Material-Liste:
- Kunststoffplatten: Otto Wolff Protex Light 3mm schwarz, z.B. bei Bauhaus
- passender Kleber, z.B. Pattex Repair Extreme
- Schrankrolle als drittes Rad
- Arduino UNO
- diverse Stift- und Buchsenleisten 2,54mm
- IC L293D
- optional: IC-Sockel für das L293D
- LiPo-Akku 7,4V 2200mAh
- passenden Stecker für den LiPo-Akku
- LiPo-Ladegerät
- 3 Stück Modellbau-Servos, hier Modelcraft Standard-Servo RS 2
- 2 Platinenstücke für Shield und "Radar"-Platine
- optional 1 LED mit Vorwiderstand für die "Radar-Platine"
- Seedstudio Ultraschall-Sensor (oder vergleichbarer Typ; der von Seedstudio kommt mit nur einem Pin zum Arduino aus!)
- Hauptschalter
- LCD-Display, hier I2C LCD1602 Module
- passende Verbindung Display > Shield
- Reifen
- Metallstange und Stellringe zur Stabilisation
- diverse Schrauben, Muttern und Abstandsbolzen in M3
Video von Roberta
in Aktion:
Ausblick, ToDo:
Falls jemand Vorschläge hat oder Fehler findet, darf er/sie sich gerne melden!
Alle in erwähnten
Marken- und Warenzeichen oder Produktnamen sind Eigentum ihrer jeweiligen Inhaber.
Für die Inhalte externer Links sind die jeweiligen Seitenbetreiber verantwortlich.
Keine Haftung für eventuelle Schäden.