PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : GoTurn () Winkel und Strecke



Wo2le
01.06.2008, 14:40
Hallo
ich habe die GoTurnfunktion ausprobiert und fand es schade, dass man entweder einen Winkel oder eine Strecke eingeben konnte, aber nicht beides zusammen. Deshalb versuche ich grade ein Quelltext zu schreiben, bei dem (erstmal mit anderen Bezeichnungen) dann beides in Abhängigkeit berechnet wird.

Ich hab dabei nur folgendes Problem ... ich will erstmal experimentel ermitteln, welchen Wert ich für X einsetzen muss, damit er genau grade einen Meter fährt.

Auf ähnliche weise will ich dann auch später die nötigen Verrechnungsfaktoren für die Winkel und den damit zusammenhängenden Speed ermitteln. Nun hab ich den Quellcode soweit geschreiben, allerdings fährt er, wenn X ca. 1-20 ist immer etwas schneller, wie ers soll, dann hört er auf und bleibt stehen, ich sehe aber über IR dass er die X weiter ausführt. Bei 90-100 macht er dann genau das selbe, mit den selben strecken wie am anfang und hört dann wieder auf.



#include "asuro.h"

int main(void)
{
Init();
int distance = 1000;
int degree = 0;
int x, c;
unsigned char speed = 200, speedd;
unsigned char speedl = speed;
unsigned char speedr = speed;

for (x=0;x<500;x++)
{
c = PollSwitch();

if (distance > 0)
{
MotorDir (FWD,FWD);
}
else
{
MotorDir (RWD,RWD);
}

if (degree == 0)
{
speedl = speed;
speedr = speed;
}


if (degree < 0)
{
speedd = degree / distance;
speedl = speed + speedd;
speedr = speed - speedd;
}
if (degree > 0)
{
speedd = degree / distance;
speedl = speed - speedd;
speedr = speed + speedd;
}
if (speedl > 255)
{
speedl = 255;
speedr = speedr - (speedl + 255);
}
if (speedr > 255)
{
speedl = speedl - (speedr + 255);
speedr = 255;
}

SerPrint ("\n\rX: ");
PrintInt (x);
SerPrint ("\n\rWinkel: ");
PrintInt (degree);
SerPrint ("\n\rWeg: ");
PrintInt (distance);
SerPrint ("\n\rGeschwindigkeit: ");
PrintInt (speed);
SerPrint ("\n\rGeschwindigkeit Rechts: ");
PrintInt (speedr);
SerPrint ("\n\rGeschwindigkeit Links: ");
PrintInt (speedl);
SerPrint ("\n");

Msleep (200);
MotorSpeed (speedl,speedr);
Msleep (distance * x / speed);
MotorSpeed (0,0);
Msleep (200);
if (c >= 0) {Msleep (1000);}
}
BackLED (ON,ON);
while (1);
return 0;
}

hai1991
01.06.2008, 15:44
hallo Wo2le,

bei deinem programm habe ich eine stelle gefunden, die ich nicht verstehe:



if (speedl > 255)
{
speedl = 255;
speedr = speedr - (speedl + 255);
}


du setzt doch zuerst speedl auf 255, dann addierst du zu speedl 255, das ergibt 510, ziehst diesen wert von speedr ab und speicherst ihn in speedr

dh. in speedr steht dann ein wert, der speedr -510 ist, also zwischen -510 und -255. diese zahl kann man doch nicht in ein unsigned char speicher, und hatt in dienem programm auch keinen sinn.

oder habe ich dein programm falsch verstanden?

Wo2le
01.06.2008, 18:17
Danke ... das war ein Denkfehler. Ich wollte damit absichern, dass er wenn der eine Motor durch diese Speedd größer als 255 wird, beide Werte um die Selbe zahl nach unten gehen, damit dann das Verhältnis in etwa wieder stimmt ... muss dann mal schauen ob das proportional bleibt. Ist ja aber eh erst im Anfangsstadium. Ich hab das jetzt folgendermaßen geändert, obwohl das zurzeit keine Rolle spielt, weil die beiden Motoren mit einer konstanten Geschwindigkeit von 200 in diesem Fall fahren.



if (speedl > 255)
{
speedd = speedl - 255;
speedr = 255 - speedd;
speedl = 255;
}
if (speedr > 255)
{
speedd = speedr - 255;
speedl = 255 - speedd;
speedr = 255;
}



Seltsamerweise geht das erste Intervall nun bis 32 bevor der Motor stoppt, obwohl das X nur etwas mit dem Msleep zutun hat und die Geschwindigkeit konstant ist!

Ich finde da wirklich keinen Fehler

trapperjohn
03.06.2008, 11:33
Wenn die ganzen Variablen immer noch "unsigned char" (= 1 Byte) sind, dann geht sowieso nur max. 0xFF = 255 hinein und eine Abfrage wie "if speed1 > 255" wird niemals true.

Sternthaler
04.06.2008, 02:51
Hallo Wo2le,
erst einmal ein willkommen im Forum.

Das mit den 'unsigned char'-Variablen solltest du auf alle Fälle austauschen. Variable als 'int'-Typ definieren gibt zwar ein paar Compilerwarnings, aber damit kann man erst einmal leben.


Versuche doch mal die Anweisung
- Msleep (distance * x / speed);

zu ersetzen mit:
- NeueIntVariable = (int)((float)distance * (float)x / (float)speed);
- Msleep (NeueIntVariable);

Eventuell hilft es dem Compiler vor allem die Division mit Nachkommaanteil zu erzwingen, damit zum Schluß hoffentlich etwas funktionierendes raus kommt.

Gruß Sternthaler

P.S.: Ansonsten kann ich auch keine Stelle finden die mir fehlerhaft vorkommen würde.

Wo2le
04.06.2008, 17:23
Ersteinmal ... findet ihr es realistisch, das man ein Program schreiben kann, wobei man erstmal die Variablen für die Strecke und den Winkel auf jeden Asuro individuell Kallibrieren kann, sodass die Werte immer ziemlich genau sind und dass man dann nurnoch die Strecke und den Winkel eingeben muss?

Danke für die Tipps. Ich habe sie versucht einzubauen und will die Zahlen jezt nur zum testen sozusagen die Werte über IR senden. Ich weis, dass die Werte bei SerRead nur unsigned char sind und ich das auf int oder float eingeben können muss. hat vielleicht jemand eine idee wie ich das machen kann?

ich hab schoneinmal solchein Programtext versucht, allerdings funktioniert dies nicht aus besagten Gründen.

Hier einmal der Quelltext





#include "asuro.h"

int main (void)
{
Init();
int x, c, n, r, k = 0, o;
int degree;
int distance;
int speed;
int speedd;
int sl, sr;
unsigned char speedl;
unsigned char speedr;
char emfangene_daten [1];
degree = 90;
distance = 500;
speed = 200;
o = 25;
do
{
for (x=0;x<50;x++)
{

r = x * 10;

c = PollSwitch();
sr = speed;
sl = speed;

switch (c)
{
// Tasten um zum ermitteln der Werte bestimmte Werte einzugeben.
// Problem mit unsigned char und int ???

case 1: SerPrint ("X (49 = Ende) Erste Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
x = emfangene_daten [0] * 10;
SerPrint ("X (49 = Ende) Zweite Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
x = x + emfangene_daten [0];
break;

case 2: SerPrint ("R (Winkelkalibrierung) Erste Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
r = emfangene_daten [0] * 10;
SerPrint ("R (Winkelkalibrierung) Zweite Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
r = r + emfangene_daten [0];
break;

case 4: SerPrint ("O (Streckenkalibrierung (~25)) Erste Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
o = emfangene_daten [0] * 10;
SerPrint ("O (Streckenkalibrierung (~25)) Zweite Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
o = o + emfangene_daten [0];
break;

case 8: SerPrint ("Winkel Erste Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
degree = emfangene_daten [0] * 10;
SerPrint ("Winkel Zweite Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
degree = degree + emfangene_daten [0];
break;

case 16:SerPrint ("Strecke Erste Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
distance = emfangene_daten [0] * 10;
SerPrint ("Strecke Zweite Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
distance = 10 * (distance + emfangene_daten [0]);
break;

case 32:SerPrint ("Geschwindigkeit Erste Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
sr = emfangene_daten [0] * 100;
SerPrint ("Geschwindigkeit Zweite Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
sl = emfangene_daten [0] * 10;
SerPrint ("Geschwindigkeit Dritte Zahl: \n\r: ");
SerRead (emfangene_daten, 1, 0);
speed = emfangene_daten [0] + sl + sr;
break;
}
sr = speed;
sl = speed;

r = x * 10;

if (speed > 255)
{
speed = 255;
}

if (speed < 0)
{
speed = 0;
}

if (distance >= 0)
{
MotorDir (FWD,FWD);
k = 1;
}

if (distance < 0)
{
MotorDir (RWD,RWD);
k = 2;
}

if (degree < 0)
{
speedd = degree * r / distance;
sl = speed + speedd;
sr = speed - speedd;
}
if (degree > 0)
{
speedd = degree * r / distance;
sl = speed - speedd;
sr = speed + speedd;
}

if (speedl > 255)
{
speedd = sl - 255;
sr = 255 - speedd;
sl = 255;
}
if (speedr > 255)
{
speedd = sr - 255;
sl = 255 - speedd;
sr = 255;
}

SerPrint ("\n\rX: ");
PrintInt (x);
SerPrint ("\n\rWinkel: ");
PrintInt (degree);
SerPrint ("\n\rWeg: ");
PrintInt (distance);
SerPrint ("\n\rGeschwindigkeit: ");
PrintInt (speed);
SerPrint ("\n\rGeschwindigkeit Rechts: ");
PrintInt (speedr);
SerPrint ("\n\rGeschwindigkeit Links: ");
PrintInt (speedl);
SerPrint ("\n\rC: ");
PrintInt (c);
SerPrint ("\n\rO: ");
PrintInt (o);
SerPrint ("\n\rR (Winkelkalibrierung): ");
PrintInt (r);
SerPrint ("\n");

if (c > 0) {Msleep (10000);}

speedr = sr;
speedl = sl;

n = distance * o / speed;

Msleep (200);
MotorSpeed (speedl,speedr);
for (c=0;c<n;c++) {Msleep (30);}
MotorSpeed (0,0);
Msleep (200);

if (k == 1)
{MotorDir (RWD,RWD);}
if (k == 2)
{MotorDir (FWD,FWD);}

MotorSpeed (speedl,speedr);
for (c=0;c<n;c++) {Msleep (30);}
MotorSpeed (0,0);
}
}
while (1);
return 1;
BackLED (ON,ON);
}




Ich hab die Zeit, also für die Distanz, auch in eine Schleife gesetzt, da es jetzt nicht bei einer bestimmten Zahl abbricht und wieso würdest du fload statt int nehmen? Ich hab das Problem, dass mein einer Motor schneller als der andere läuft und deshalb müsste noch eine Odemerie-messung mit eingebaut werden, oder man kann es im Programm am anfang Kallibrieren. Hat jemand eine Idee?

Sternthaler
04.06.2008, 18:50
Hallo Wo2le,

nein, realistisch ist es nicht über eine Zeitvorgabe den Weg vorzugeben.
Du hast ja schon den Ansatz mit der Odometrie angeführt. Nicht umsonst macht das die GoTurn()-Funktion schon lange.

Ging das mit der NeueIntVariable?

Gruß

trapperjohn
05.06.2008, 08:59
Wenn du es einigermaßen genau haben möchtest, wirst du um die Odometrie wohl nicht herumkommen.

Zum einlesen von Zahlen musst du deren ASCII-Darstellung (also den String) nach int (etc.) wandeln. Bspw. könntest du die einzelnen Bytes in ein Array einlesen bis du einen Zeilenumbruch bekommst, danach hängst du eine 0 an und steckst den Zeiger auf das Array in die Funktion atoi(char*). Schon hast du dein Int ;)

Wenn du noch ein wenig Fehlerüberprüfung machen willst, kannst du die Funktion auch selbst schreiben - die Ansätze dazu hast du in deinem Code oben ja schon:



int iVal = 0;
char c;
int count=0;
const int MAX_COUNT = 6;
char multiplier = 1;

for (SerRead(&c,1,0);
((c >= '0') && (c <= '9')) || (c=='-'); //nur Zahlen und Minus
SerRead(&c,1,0))
{
count++;
if ( count > MAX_COUNT )
break; //Zu viele Zeichen
else if ( c=='-' )
{
if (count == 1)
multiplier = -1;
else break; // Minus an der falschen Position
else
{
iVal *= 10;
iVal += c-'0';
}
}
iVal *= multiplier; //evtl. Vorzeichen beachten

//iVal enthält jetzt ein signed int


Code da oben ist ohne Gewähr, aber ich denke man sieht ungefähr, wie es funktionieren sollte ... ;) Wenn man will, kann man noch auf Überlauf prüfen und vorne bspw. ein Plus-Zeichen zulassen etc.pp.