(versteckt)
Inbetriebnahme
Programmieradapter:
Die für die Programmierung benötigten Leitungen werden beim c't-Bot auf zwei Standard-Steckern herausgeführt. Um Programme in den Bot zu bekommen, braucht man also immer einen Programmieradapter. Dieser verbindet dann den Stecker ST6 mit dem PC.
Makefile:
Unter dem Link Tools für die Programmierung der CtBots auf der Projektseite der Vorgruppe kann man ein Makefile finden, dass zur Übersetzung benötigt wird. Darin müssen für alle .c Dateien die zu erzeugenden .o Dateien hingeschrieben werden.
Beispiel:
OBJ = zusammentest.o adc.o display.o ena.o fahrdrehung.o fahrgeradeaus.o geschwindigkeitsteuerung.o init.o led.o maus.o menue.o motor.o sensoren.o shift.o timer.o uart.o vorbereitung.o wait.o
Die zwei wichtigsten Befehle, die schließlich in das ctbot2 Verzeichnis im Terminal eingegeben werden müssen, lauten make und make prog_do. Der erste Befehl kompiliert die Dateien und der zweite sorgt für eine Übertragung in den Mikrocontroller. Der c't-Bot muss dazu allerdings eingeschaltet sein. Ist die Firmware übertragen, kann man den Adapter abziehen.
Codeveränderungen:
[ctbot2-Codeänderungen]
Funktionstest:
Nach Übertragung der Dateien der Vorgruppe konnte eine Funktionsüberprüfung der Sensoren und des dazu gehörenden Verhaltens vorgenommen werden. Dabei sind folgende Probleme aufgetreten:
ENTRY:unterseite1
(versteckt)
Problem 1: Wie lässt sich der c't-Bot steuern?
Serielle Schnittstelle:
Der c't-Bot erhält seine Befehle über die Tastatur eines PC's. Das bedeutet, dass man für die Ansteuerung des Roboters eine serielle Schnittstelle benötigt.
Einer ihrer Steckverbinder wird auf die Stiftleidte J4, welche sich auf der Hauptplatine befindet, gesteckt.
Der Massepin der Stiftleiste befindet sich dabei ganz oben am äußeren Rand der Platine.
Der andere Verbindungsstecker muss jetzt wie unten gezeigt auf die Stiftleiste der seriellen Schnittstelle gesteckt werden. Dabei sollte darauf geachtet werden,
dass das Massekabel als zweites von links auf die Stiftleiste gesteckt wird.
Achtung!
Um den c't-Bot allerdings im Raum auf dem Fußboden testen zu können, muss die serielle Schnittstelle immer wieder vom Roboter abgezogen werden, was wiederum ihre gelöteten Verbindungen belastet. Lässt sich der c't-Bot also nicht mehr über die Tastatur steuern, sollte man zuallererst die Lötverbindungen der seriellen Schnittstelle überprüfen und eventuell neu nachlöten.
GtkTerm:
Um über die Tastatur Steuerungsbefehle eingeben zu können, benötigt man zusätzlich den GtkTerm. Dieser lässt sich in der Panel-Leiste unter Anwendungen und Zubehör als Serial port terminal
bezeichnet auffinden. Hat man diesen dann auf seinem Bildschirm geöffnet, muss man noch unter Configuration Port anklicken und dort unter Speed "19200" einstellen. Diese Baudrate bezieht sich allerdings nur auf den c't-Bot(2). Für den ersten c't-Bot muss man bei Speed nämlich noch "9600" eingeben. Die anderen Einstellungen bleiben erhalten.
Wenn man jetzt entweder Akku- oder Netzbetrieb einschaltet und den Reset-Button drückt, sollte im GtkTerm folgende Auflistung erscheinen:
|
ENTRY:unterseite2 (versteckt)
Problem 2: Keine Stromversorgung beim Betrieb mit Akkus
Zusammenkleben der Batteriefächer nicht vergessen!
Nach Überprüfung der Funktionsfähigkeit der Akkus wurden die gelöteten Verbindungen des Batteriefachs mit einem Multimeter getestet und für fehlerhaft befunden.
Durch die etwas unvorteilhafte Konstruktion der zwei recht lose zusammengesetzten Batteriefächer waren die Lötstellen starken mechanischen Kräften ausgesetzt.
Es ist anzuraten, die zwei losen Teile mit einer Heißklebepistole rechtzeitig fest zu verkleben.
Vorsicht der Kunststoff schmilzt sehr leicht!
Außerdem kam noch hinzu, dass beim Löten der Kunststoff um die Kontakte geschmolzen war. Ein Metallkontakt war nicht mehr fest mit dem Gehäuse verbunden.
Lösung:
Letztendlich musste ein neues Batteriefach verwendet werden.
|
ENTRY:unterseite3 (versteckt)
Problem 3: Display schien nicht zu funktionieren
Kontrastspannung:
Eine der Ursachen war, dass die Kontrastspannung nicht richtig eingestellt war. Mithilfe eines kleinen Schraubenziehers lässt sich diese jedoch am Potentiometer verändern.
Ein gutes Ergebnis kann mit einer Einstellung, die im Bereich von 0...0,5 V liegt, erzielt werden.
Resetbutton:
Ausserdem war es komisch, dass sich sowohl bei Verwendung des Akkupacks als auch des Netzteils das Display ziemlich häufig nicht wie in gewohnter Weise ansteuern ließ.
In diesen Fällen sollte man den Reset-Button drücken. Unterbricht man nämlich den c't-Bot in seinem Programmablauf und versucht dann den Zusammentest später wieder von vorne zu starten, muss man diesen ohne Benutzung des Reset-Buttons erst einmal wieder auf den Mikrocontroller neu übertragen.
Display.c:
Eine weitere Ursache für eine unzulängliche Displayansteuerung lag allerdings noch im Code des Displays verborgen:
#include "display.h"
int x,j;
static char puffer[PUFFER_GROESSE]; /*string fuer Displayausgaben */
void write_data(char data){ //ein Zeichen aus data in den Displayspeicher schreiben
int i;
for (x=0;x<100 ;x++ )
{
for (j=0;j<100 ;j++ ){}
}
schieberegister_data_schicken(0x38,(1<<1),0x04);
PORTC &= ~0x07; // Alles zurueck setzen ==> Fallende Flanke von Enable portc &=~ 0x07 (&=~0b111)
for (x=0;x<40 ;x++ )
{
for (j=0;j<100 ;j++ ){}
}
schieberegister_data_schicken(data,(1<<1),0x04|(1<<0));
// Enable muss fuer mind. 450 ns High bleiben, bevor es fallen darf!
// ==> Also mind. 8 Zyklen warten
for (i=0; i<250; i++){
asm("nop");
}
PORTC &= ~0x07;
}
void befehl_schicken(unsigned char befehl{ //ein Befehl an das Display senden
unsigned char i;
schieberegister_data_schicken(befehl,(1<<1),0x04); /*SRCLK = PORTC.1 = 1 und RCLK=PC2=1*/
for (i=0; i<100; i++){
asm("nop");
}
PORTC &= ~0x07;
}
Neuere Compiler optimieren die leeren geschweiften Klammern {} einfach weg, deshalb wurden diese durch { __asm volatile("nop"); } ersetzt, wobei _asm ein Schlüsselwort darstellt,
dass eine Inline-Assembler Sequenz einleitet. Das nachgestellte volatile sorgt dafür, dass die Sequenz keinesfalls wegoptimiert werden darf. Zu "nop" ist nicht viel zu sagen, außer dass
nop weder Input- noch Output-Operanden hat und sich Register/RAM nicht ändern.
Nebenbei haben wir die Header Datei util/delay.h eingefügt, um eine Funktion, die eine Verzögerung von 47 Mikrosekunden bewirkt, in den Code einbringen zu können. Dazu musste die Taktfrequenz F_CPU noch einmal definiert werden.
Display_neu.c:
#include "display.h"
#ifdef F_CPU
#undef F_CPU
#endif
#define F_CPU 16000000UL // Quarz 16 MHz
#include <util/delay.h>
int x,j;
static char puffer[PUFFER_GROESSE]; /*string fuer Displayausgaben */
void write_data(char data) //ein Zeichen aus data in den Displayspeicher schreiben
{
for (x=0;x<100 ;x++ )
{
for (j=0;j<200 ;j++ ){ __asm volatile("nop"); } // _asm kennzeichnet eine Inline-Assembler Sequenz
// volatile verbietet eine Wegoptimierung der Sequenz
// "nop" hat weder Input noch Output-Operanden
}
schieberegister_data_schicken(0x38,(1<<1),0x04);
PORTC &= ~0x07; // Alles zurueck setzen ==> Fallende Flanke von Enable portc &=~ 0x07 (&=~0b111)
for (x=0;x<40 ;x++ )
{
for (j=0;j<200 ;j++ ){ __asm volatile("nop"); }
}
schieberegister_data_schicken(data,(1<<1),0x04|(1<<0));
// Enable muss fuer mind. 450 ns High bleiben, bevor es fallen darf!
// ==> Also mind. 8 Zyklen warten
_delay_us(47); // 47 Mikrosekunden warten
PORTC &= ~0x07;
}
void befehl_schicken(unsigned char befehl) //ein Befehl an das Display senden
{
schieberegister_data_schicken(befehl,(1<<1),0x04); /*SRCLK = PORTC.1 = 1 und RCLK=PC2=1*/
_delay_us(47); // 47 Mikrosekunden warten
PORTC &= ~0x07;
}
|
ENTRY:unterseite4 (versteckt)
Problem 4: Mitsenden merkwürdiger Zeichen beim HyperTerminal
Die erste Ungereimtheit, die auffiel, war, dass im GtkTerm fuer die Ansteuerung des HyperTerminals der Buchstabe "s" vorgesehen war.
Sowohl im Code von menue.c als auch in der int main(void) des zusammentest.c wurde dafür allerdings ein "h" benutzt. Deshalb sollte auf dem GtkTerm auch ein "h" ausgegeben werden, womit jedoch noch nicht alle Probleme behoben waren.
Denn die Zeichenketten die auf dem HyperTerminal erschienen, waren nicht alle erwünscht.
Kurzerhand wurden alle \r gelöscht und die Zeilenlänge angepasst, da neuere Compiler automatisch an den Zeilenanfang springen. Nebenbei haben wir gleich noch die Rechtschreibung
und die Sensornamen einheitlich gestaltet, damit ungeübte Benutzer nicht durch unterschiedliche Bezeichnungen für die dieselben Sensoren zwischen Display und HyperTerminal, verwirrt werden. Aber auch das brachte noch nicht das ersehnte Ergebnis.
Als der entscheidende Durchbruch stellte sich eine kleine Änderung in void PrintInt(long int wert) im Code von uart.c heraus.
Über den UART kann ein AVR-Mikrocontroller leicht mit einer RS-232-Schnittstelle eines PC verbunden werden.
uart.c
void PrintInt(long int wert)
{ char text[10]=" ";
ltoa(wert,text,10); //Diese Funktionen wandelt eine Zahl vom angegebenen Format in einen String.
CTWrite(text,10); //Hierbei wird eine 0 gesendet, aber aus irgendwelchen Gruenden bedeutet das
//eine Verwirrung fuer GtkTerm,
}
Statt des vorherigen "CTWrite(text,10)", welches Probleme verursachte, da eine Null mitgesendet wurde, wird in uart_neu.c jetzt "CTWrite(text,strlen(text))" verwendet.
Strlen liefert die Länge einer Zeichenkette OHNE das '\0' Endezeichen.
Der Text wird also solange hochgezählt bis eine 0 kommt.
uart_neu.c
void PrintInt(long int wert)
{ char text[10]=" ";
ltoa(wert,text,10); //Diese Funktionen wandelt eine Zahl vom angegebenen Format in einen String.
CTWrite(text,strlen(text)); // Hochzaehlen des Textes bis die 0 kommmt
}
Nach dieser einfachen Änderung wurden über das HyperTerminal keine unerwünschten Zeichen mehr mitgesendet und die GtkTerm-Ansicht war lesbar geworden.
Zum Schluß wurde noch ein Stop-Befehl für beide Motoren mit der Nummer 7 in den GtkTerm eingefügt und die Auflistung der Befehle und der Sensorwerte sowohl im GtkTerm als auch im HyperTerminal ein klein wenig lesbarer gemacht.
|
ENTRY:unterseite5 (versteckt)
Problem 5: Test der Lichtsensoren
Die Werte der beiden Lichtsensoren LDR1 und LDR2 können auf dem Display angezeigt werden:
|
Taschenlampe |
Deckenlicht |
Dunkelheit |
---|
LDR1(links) |
0-5 mV |
6-20 mV |
> 300 mV |
LDR2(rechts) |
0-5 mV |
10-25 mV |
> 300 mV |
Die grobe Tendenz dieser Spannungswerte scheint zu stimmen, da eine inverse Beziehung zu den Lichtverhältnissen erkennbar ist.
Sind die Lichtverhältnisse umso dunkler, werden umso höhere Spannungswerte auf dem Display ausgegeben.
Leider weisen sie jedoch eine gewisse Schwankungsbreite auf. Der linke und der rechte Sensorwert stimmen bei gleichen Lichtverhältnissen so gut wie nie überein,
was in der Funktion Lichtverfolgung berücksichtigt werden muss.
|
ENTRY:unterseite6 (versteckt)
Problem 6: Test der Lichtverfolgung
Es ist keine gute Idee einen direkten Vergleich der Spannungswerte der beiden Lichtsensoren durchzuführen, da diese leider auch unter denselben Lichtverhältnissen
eine gewisse Differenz aufweisen. Das bedeutet, dass die Spannungswerte niemals gleich groß sein können. So bleibt dem c't-Bot bei ungefähr gleicher Lichteinstrahlung,
die prinzipiell eine Geradeausfahrt bewirken sollte, nichts anderes übrig, als sich mal nach links und mal nach rechts zu drehen.
lichtverfolgung.c
void lichtverfolgung(void){
int l_speed=100,r_speed=100;
if (adc_wert[4]>adc_wert[5]){ // bot soll sich nun nach links drehen
led_set(LED_RECHTS);
CTMotor(l_speed,40);
}
if (adc_wert[5]>adc_wert[4]){ // bot soll sich nun nach rechts drehen
led_set(LED_LINKS);
CTMotor(40, r_speed);
}
if(adc_wert[5]==adc_wert[4]){
led_set(LED_LINKS|LED_RECHTS);
CTMotor(l_speed,r_speed);
}
}
Im Programm lichtverfolgung_neu.c wird eine Differenz der beiden Sensorwerte verwendet.
Der c't-Bot biegt nur ab, wenn die Differenz der Spannungswerte, die die beiden Sensoren liefern, größer als 40 ist.
lichtverfolgung_neu.c
void lichtverfolgung(void)
{
int l_speed=100,r_speed=100;
if ((adc_wert[5]-adc_wert[4]) < -40) // wenn rechte Seite sehr heller als linke
{ led_set(LED_RECHTS); // Rechtsblinker LED an
CTMotor(l_speed,40); //c't-Bot soll sich nun nach rechts drehen
}
if ((adc_wert[5]-adc_wert[4]) > 40) // wenn linke Seite sehr heller als rechte
{ led_set(LED_LINKS); // Linksblinker LED an
CTMotor(40, r_speed); // c't-Bot soll sich nun nach links drehen
}
if((adc_wert[5]-adc_wert[4]) > -40 && (adc_wert[5]-adc_wert[4]) < 40) // wenn beide Seiten ungefaehr gleich hell
{ led_set(LED_LINKS|LED_RECHTS); // beide LEDs an
CTMotor(l_speed,r_speed); // c't-Bot geradeaus
}
}
|
ENTRY:unterseite7 (versteckt)
Problem 7: Test der Distanzsensoren
Die ersten Tests liessen vermuten, dass die Distanzssensoren (GP2D12) nicht funktionierten. Wenn ein weisses Blatt Papier in einiger Entfernung
der Distanzsensoren positioniert und dabei die Abstände zu den Sensoren mittles eines Maßbandes ermittelt wurden, stimmten diese Werte nicht mit den Displaywerten
der Distanzsensoren überein. Dabei befand sich das Blatt Papier durchaus im messfähigem Bereich (10 bis 80 cm) der Sensoren.
Es musste also irgendetwas grundlegend falsch sein.
Vorgehen:
Als nächstes schien es sinnvoll, zu überprüfen, ob die GP2D12-Sensoren nur im eingebauten Zustand unsinnige Werte lieferten oder grundsätzlich defekt waren.
Sie wurden also vom Alu-Träger losgeschraubt und schließlich nur mit der Hand gehalten, wobei sie allerdings noch durch drei Kabel mit dem betriebsbereiten c't-Bot verbunden waren.
Zur Überprüfung der Funktionalität der Sensoren musste der Spannungs- Abstandswert zwischen V_oo und V_GND (Erdung) des Sensors bestimmt werden.
Dazu wurde ein Spannungsmessgerät an die entsprechenden Pins auf der Rückseite der Sensoren angelegt.
GP2D12-Sensor
Es ergab sich eine Abhängigkeit, die mit der folgenden Messkurve übereinstimmte.
Problembehebung:
Erstaunlicherweise klappte jetzt die Distanzmessung, was nahelegte, dass die Art des Einbaus das Übel verursachte.
Bei genauerem Hinsehen konnte man erkennen, dass jeweils die untere Metallschraube, mit der die Distanzsensoren an den Alu-Träger geschraubt waren, in direktem
Kontakt mit den Pins der Radencoder- platinen standen. Um Kurzschlüsse zu verhindern, mussten diese gekürzt und Kunststoffunterlegscheiben zwischen die Alu-Träger
und die Sensorplatinen geschraubt werden, da auch das Gehäuse der GP2D12- Sensoren als nicht perfekt isolierend zu bezeichnen ist.
Nach diesen Maßnahmen gab es fürs erste keine Probleme mehr.
|
ENTRY:unterseite8 (versteckt)
Problem 8: Test der Kollisionserkennung
Die Kollisionserkennung funktionierte an und für sich recht gut. Hin und wieder ist der Roboter jedoch gegen ein Hindernis gefahren.
kollisionserkennung.c
void kollisionserkennung(void){
int left_speed=40,right_speed=40,minus_speed=-40;
if (abs(entfernung(adc_wert[1]))> 17 && abs(entfernung(adc_wert[0]))> 17){
led_aus(LED_ALL);
CTMotor(left_speed,right_speed);
}
else if (abs(entfernung(adc_wert[0])) <= 17 && abs(entfernung(adc_wert[1]))<= 17){
CTMotor(left_speed,minus_speed);
led_set(LED_LINKS); // wieso links ?
if (abs(entfernung(adc_wert[1]))< 17 && abs(entfernung(adc_wert[0]))< 17 && abs(entfernung(adc_wert[0]))==abs(entfernung(adc_wert[1]))){
led_aus(LED_ALL);
CTMotor(left_speed,right_speed); // vorwaerts
}
}
else if ( abs(entfernung(adc_wert[0]))<= 17 && abs(entfernung(adc_wert[1]))> 17){
CTMotor(left_speed,minus_speed);
led_set(LED_RECHTS);
if (abs(entfernung(adc_wert[1]))< 17 && abs(entfernung(adc_wert[0]))< 17 && abs(entfernung(adc_wert[0]))==abs(entfernung(adc_wert[1]))){
led_aus(LED_ALL);
CTMotor(left_speed,right_speed); // vorwaerts
}
}
else if (abs(entfernung(adc_wert[1])) <= 17 && abs(entfernung(adc_wert[0]))> 17){
CTMotor(minus_speed,right_speed);
led_set(LED_LINKS);
if (abs(entfernung(adc_wert[1]))< 17 && abs(entfernung(adc_wert[0]))< 17 && abs(entfernung(adc_wert[0]))==abs(entfernung(adc_wert[1]))){
led_aus(LED_ALL);
CTMotor(left_speed,right_speed); // vorwaerts
}
}
}
Da der c't-Bot aufgrund der Überlänge der Kabel keinen schlanken Umfang besitzt, war es ratsam, die Distanz bis zum Hindernis zu vergrößern.
Der neue Grenzwert wurde auf 20 cm festgelegt. Auf diese Weise eckt der Roboter nicht mehr so leicht an einer Wand an.
Außerdem wird jetzt für den Fall, dass der c't-Bot eine geringere Distanz als 20 cm zu einem Hindernis aufweist, vorgeschrieben, dass er rückwärts fahren soll.
Im alten Code sollte er in diesem Fall genau das Gegenteil tun.
kollisionserkennung_neu.c
void kollisionserkennung(void)
{
int left_speed=40,right_speed=40,minus_speed=-40;
if (abs(entfernung(adc_wert[1]))> 20 && abs(entfernung(adc_wert[0]))> 20) //wenn rechter u. linker Distanzsensor > 20
{
led_aus(LED_ALL);
CTMotor(left_speed,right_speed); // geradeaus (kein wirkliches geradeaus, eher eine Kurve)
}
else if (abs(entfernung(adc_wert[0])) <= 20 && abs(entfernung(adc_wert[1]))<= 20)// wenn beide <= 20
{
CTMotor(left_speed,minus_speed); // flotte Rechtsdrehung
led_set(LED_RECHTS); // Rechtssblinker LED an (das ist neu, vorher LED_LINKS)
if (abs(entfernung(adc_wert[1]))< 20 && abs(entfernung(adc_wert[0]))< 20 && abs(entfernung(adc_wert[0]))==abs(entfernung(adc_wert[1])))
// wenn beide Distanzsensoren < 20 & Distanz bei beiden gleich
{
led_aus(LED_ALL);
CTMotor(minus_speed,minus_speed); // rueckwaerts (das ist neu)
}
}
else if ( abs(entfernung(adc_wert[0]))<= 20 && abs(entfernung(adc_wert[1]))> 20) // wenn linker Sens. <= 20 & rechter > 20
{
CTMotor(left_speed,minus_speed); // flotte Rechtsdrehung (logisch)
led_set(LED_RECHTS); // Rechtsblinker LED an
if (abs(entfernung(adc_wert[1]))< 20 && abs(entfernung(adc_wert[0]))< 20 && abs(entfernung(adc_wert[0]))==abs(entfernung(adc_wert[1])))
// wenn beide Sensoren < 20 & Distanz bei beiden gleich
{
led_aus(LED_ALL);
CTMotor(minus_speed,minus_speed); // rueckwaerts (das ist neu)
}
}
else if (abs(entfernung(adc_wert[1])) <= 20 && abs(entfernung(adc_wert[0]))> 20)// wenn rechter Sens. <= 20 & linker Sens. > 20
{
CTMotor(minus_speed,right_speed); // flotte Linksdrehung (logisch)
led_set(LED_LINKS); // Linksblinker LED an
if (abs(entfernung(adc_wert[1]))< 20 && abs(entfernung(adc_wert[0]))< 20 && abs(entfernung(adc_wert[0]))==abs(entfernung(adc_wert[1])))
// wenn beide Sensoren < 20 & Distanz bei beiden gleich
{
led_aus(LED_ALL);
CTMotor(minus_speed,minus_speed); // rueckwaerts (das ist neu)
}
}
}
|
ENTRY:unterseite9 (versteckt)
Problem 9: Test der Liniensensoren
Der c't-Bot besitzt zwei Liniensensoren (CNY70), die sich auf der Maussensorplatine befinden.
Wenn diese über demselben Untergrund stehen, werden jedoch noch lange nicht die gleichen Werte auf dem Display ausgegeben. Stehen die Sensoren beispielsweise über einer schwarz gedruckten Spur, so wird sie als Linie = 750 562 angezeigt. Eine Überprüfung der Widerstände ergab allerdings keine Abweichungen mit dem Original-Bestückungsplan des Maussensors.
Erklärung:
Der CNY70 ist ein Reflex Optokoppler. Sowohl eine IR-LED als auch ein Foto Transistor befinden sich beide zusammen in einem Gehäuse. Das von der IR-LED ausgestrahlte Licht wird vom Fototransistor wieder empfangen. Je nach Menge des reflektierten Lichts wird der Fototransistor mehr oder weniger leitend. Die Reichweite des Sensors beträgt nur wenige mm. Da das Licht der IR-LED nicht getaktet wird, kann eine Fremdlichteinstrahlung, wie z.B die rote LED auf der Maussensorplatine Störungen verursachen.
Lösung:
Mit der recht großen Wertedifferenz kann allerdings problemlos umgegangen werden, indem man in der Funktion Spurverfolgung einen Wertebereich zwischen 200 mV und 800 mV für schwarzen Untergrund festlegt.
|
ENTRY:unterseite10 (versteckt)
Problem 10: Test der Spurverfolgung
Zuallererst zog der c't-Bot nur Kreise, denn eine mit Filsschreiber gemalte Spur konnten die Liniensensoren des c't-Bots nicht ausreichend erkennen. Als eine wesentliche Verbesserung stellte sich die Verwendung einer mit schwarzer Farbe gedruckten Spur von 3 cm Breite heraus.
Die Funktion Spurverfolgung funktionierte ebenfalls nicht optimal. Der c't-Bot verlor noch sehr häufig seine auf einem Brett aufgeklebte schwarz gedruckte Spur, hauptsächlich deshalb, weil er auf längeren geraden Spurabschnittsstücken zu viel Geschwindigkeit aufnahm und dann in Kurven über die schwarze Spur hinaussauste. Die Drehungen, die er dann vollführte, um die schwarze Spur wiederzufinden, halfen nur in Ausnahmefällen weiter. Dieses Problem konnte aber durch kleine Änderungen im Code beseitigt werden:
Spurverfolgung.c:
void spurverfolgung(void){
if (abs(adc_wert[2])<400){
CTMotor(23,0);
led_set(LED_RECHTS);
}
else if (abs(adc_wert[3])<400){
CTMotor(0,23);
led_set(LED_LINKS);
}
else if (abs(adc_wert[2])>400 && abs(adc_wert[2])<800 &&abs(adc_wert[3])>400 && abs(adc_wert[3])<800){
CTMotor(23,23);
led_set(LED_LINKS|LED_RECHTS);
}
else if (abs(adc_wert[2])>800 && abs(adc_wert[3])>800){
CTMotor(0,0);
led_aus(LED_ALL);
}
}
Es erwies sich als sehr hilfreich, an den Drehzahlwerten für die Motoren (CTMotor(23,0)) herumzuspielen. Die Geschwindigkeit des c't-Bots sollte dem Schwierigkeitsgrad der Bahnführung angepasst sein.
Die in Spurverfolgung_neu.c gewählten Werte funktionierten für unsere Bahngestaltung recht gut.
Außerdem schien es sinnvoll zu sein, dass, wenn beide Liniensensoren weißen Untergrund detektieren, der c't-Bot eine langsame Rückwärtsfahrt mit sehr leichter Drehung in Fahrtrichtung nach rechts ausführen soll. Auf diese Weise gelingt es ihm, die schwarze Spur wiederzufinden.
Spurverfolgung_neu.c:
void spurverfolgung(void)
{
if (abs(adc_wert[2])<200 && (abs(adc_wert[3])>200 && abs(adc_wert[3])<800)) //wenn der linke Liniensensor weissen Untergr. && der rechte schwarzen Untergr. detektiert,
{
CTMotor(23,-23); // dann soll der c't-Bot eine fluessige Drehung nach rechts ausfuehren,
led_set(LED_RECHTS); // und die rechte LED soll leuchten
}
else if (abs(adc_wert[3])<200 && (abs(adc_wert[2])>200 && abs(adc_wert[2])<800)) // es sei denn der rechte Liniensensor detektiert weiss && der linke schwarz,
{
CTMotor(-23,23); //dann fluessige Drehung nach links
led_set(LED_LINKS); //und die linke LED soll leuchten
}
else if (abs(adc_wert[2])>200 && abs(adc_wert[2])<800 &&abs(adc_wert[3])>200 && abs(adc_wert[3])<800) // wenn beide Sensoren schwarzen Untergrund detektieren,
{ CTMotor(15,15); // dann mittellangsame Geradeausfahrt
led_set(LED_LINKS|LED_RECHTS); // mit beiden LEDs an
}
else if (abs(adc_wert[2])<200 && abs(adc_wert[3])<200) // wenn beide Sensoren weissen Untergrund detektieren,
{ CTMotor(-10,-9); // langsame Rueckwaertsfahrt mit sehr leichter Drehung in Fahrtrichtung nach rechts
}
else if (abs(adc_wert[2])>800 && abs(adc_wert[3])>800) // wenn beide Sensoren einen tiefen Abgrund detektieren,
{ CTMotor(0,0); // dann Motoren bei voller Fahrt Stop
led_aus(LED_ALL); // alle LEDs aus
}
}
|
ENTRY:unterseite11 (versteckt)
Problem 11: Test der Radencoder
Schwachstelle Radencoder:
Die Radsensoren (CNY70) sind grundsätzlich als kritisch einzustufen, da sie sehr fehleranfällig sind.
Ein Radencoder sollte aus jedem Hell-Dunkel-Wechsel der rotierenden Enoderscheiben einen analogen Puls erzeugen. Dieser wird dann vom Schmitt-Trigger in ein Rechtecksignal umgewandelt.
Das geschieht jedoch nicht immer. Es kann vorkommen, dass Pulse unterschlagen werden. Der Prozessor zählt dann zu wenig Pulse pro Radumdrehung und es ist nahezu unmöglich, einen Gleichlauf
der Motoren herzustellen oder eine Position exakt anzufahren.
Als Ursache dafür sind mehrere Fehlerquellen zu nennen: Schlechte Qualität der Encoderscheibe, Montagefehler, zu geringe Ansteuerspannung des Schmitt-Triggers, Klebstoffreste und Streulicht.
Das Infrarotspektrum des Reflexkopplers CNY70 verursacht ebenfalls Probleme. Schwarz wird nicht immer als schwarz erkannt, sodass selbst ein tiefdunkles Feld den Infrarotlichtstrahl fast vollständig reflektieren kann - wie ein weißes Feld. Der Puls des Sensors bleibt dann aus oder die Signale des CNY70 sind teilweise so schwach, dass der Schmitt-Trigger nicht auslöst.
Auf diese Weise kann ein Viertel der Impulse verloren gehen.
Bei den neueren c't-Bot-Versionen werden gefräste Encoderscheiben aus Kunststoff, die auf die Innenseite der Räder geklebt werden, mitgeliefert. Mit dem Kleber sollte man allerdings sparsam umgehen, damit er nicht unter den Scheiben herausquillt. Getrocknete Klebstoffkleckse absorbieren Infrarotlicht nämlich nahezu vollständig. In einer gefrästen Aussparung hat der Kleber dann den gleichen Effekt wie der schwarze Kunststoff. Wenn man auch mit den gefrästen Encoderscheiben keine zuverlässigen Impulse aus den invertierenden Schmitt-Triggern des IC3 herausbekommt, sollten die Vorteilerwiderstände R17 und R19 sowie R18 und R20 angepasst werden. Hier hilft nur probieren.
Unter Umständen bringt auch Streulicht mit hohem Infrarotanteil die Radencoder aus dem Takt, besonders dann wenn der Abstand der Sensoren zu den Scheiben zu groß ist. Dann erkennen die Sensoren die Übergänge zwischen hell und dunkel schlechter, was sogar zum „Prellen“ führen kann: Statt eines Pulses erzeugt ein CNY70 dann mehrere.
Quelle: www.heise.de/ct/projekte/ct-bot/artikelliste.shtml
c't 9/2006, S.222: c't-Bot
Steuermann:
Mit einer Drehzahlregelung fährt der c't-Bot geradeaus und mit konstanter Geschwindigkeit
Steuermann-Artikel
Bisher noch ungeklärt:
Wie bei der Vorgruppe erscheinen auf dem Display für die Radencoder des c't-Bot(2) unrealistische Werte.
Wenn z.B. das linke Rad mit sehr geringer Drehzahl angesteuert wird, dann werden auf dem Display die linken Radencoderwerte in mehreren Tausenderschritten hochgezählt.
Dieses Problem muss noch gelöst werden.
|
ENTRY:unterseite12 (versteckt)
Problem 12: Test des Geradeausfahrens
Gibt man beiden Motoren des c't-Bots die gleichen Drehzahlwerte vor, so fährt er in den allermeisten Fällen eine Kurve, weil die Räder z.B. Schlupf haben oder die Gewichtsverteilung des Roboters nicht gleichmäßig ist. Aus diesem Grunde benötigt man für eine Geradeausfahrt eine Drehzahlregelung.
Solange die Radencoder aber keine vernünftigen Werte liefern, kann ein Programm, das die Drehzahl regeln soll, nicht funktionieren.
|
|