PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6 steuern mittels M32



vogel0815
12.09.2008, 15:42
Hmm wie isn das, wenn ich den RP6 über den M32 steuern will, was brauch ich denn da alles? Weil diese Beispielprogramme sind da ziemlich vollgestopft mit den ganzen I2C sachen. Sind die alle nötig?
Und was brauch ich eigentlich im Programm für die Basis damit das verarbeiten kann?

Ist zwar schön das es am Anfang der Programme meist beschrieben wird was da sganze programm macht, aber es wäre doch evtl ganz nett wenne manche einzelne Punkte genauer beschrieben werden.

SlyD
12.09.2008, 16:52
Hallo,

wenn mal irgendwo keine Kommentare da sind, dann sind es meist "sprechende" Namen für die Variablen und Funktionen die sich von selbst erklären.
Aber wenn Du fragen zu einem bestimmten Teil hast - dann kannst Du das hier natürlich gerne posten!


> Hmm wie isn das, wenn ich den RP6 über den M32
> steuern will, was brauch ich denn da alles?

Du musst dich eigentlich gar nicht großartig mit dem I2C Bus befassen wenn Du das nicht willst - nimm halt die fertige
RP6Control_I2CMasterLib.h und .c aus dem Example10_Move2.

Dann kannst Du den Roboter mal abgesehen von ein zwei kleinen Unterschieden die aber in den Kommentaren stehen fast so steuern als wäre der I2C Bus gar nicht da.
Also move, rotate, moveAtSpeed, changeDirection usw. alles wie gehabt.
setLEDs und setRP6LEDs ist ein kleiner Unterschied.
updateStatusLEDs funktioniert genau wie beim Mainboard auch.

Die Funktionen heissen also *fast* alle genauso wie in der BaseLib und funktionieren auch genauso. Einfach in der Hauptschleife immer diese beiden:
task_checkINT0();
task_I2CTWI();

Funktionen aufrufen, dann wird alles automatisch gemacht.

OK - nur die größeren Sensordaten (alles was nicht einfach nur 0 oder 1 wie ACS und Bumper ist) muss man bei Bedarf abgleichen.
s. getAllSensors() und getLightSensors() als Beispiele wie man das macht.
Die Variablen heissen dann auch genauso wie in der BaseLib.
Also adcBat, adcMotorCurrentLeft,... usw. alles identisch.


Du musst natürlich das I2CSlave Programm in den Controller auf dem Mainboard laden damit das alles funktioniert.

Btw. da ist mir gerade noch aufgefallen das im Example10_Move2 Beispiel die setRP6LEDs noch "inline" deklariert ist. Das klappt mit der neuesten WinAVR Version ja leider nicht mehr. Einfach das inline in beiden Dateien (.c und .h) löschen dann geht es. Wird demnächst behoben.
Mit den 2007er Versionen von WinAVR sollte es auch so funktionieren.

MfG,
SlyD

vogel0815
17.09.2008, 18:46
Vielen Dank für den tip, hab damit nu mal mein Programm weiter gebaut.
Nun hab ich aber ein anderes kleines Problem.
das I2CSlave auf der Basis werde ich noch etwas ändern, da die Basis selber etwas machen soll, bis vom M32 eine bestimmte variable gelöscht wird, dann übernimmt die und gibt später die Controlle sieder zurück an die Basis wenn die Variable wieder gesetzt wird.

Doch genau daran hapert es grad, wie kann ich denn eine einzelne Variable z.B. active auf der Basis löschen lassen?

SlyD
17.09.2008, 19:26
Schau Dir mal

void task_commandProcessor(void)

an.
Da einfach nen neues Kommando hinzufügen (neuen case) in dem halt irgendwas gemacht wird active = param1 z.B.
Der Aufruf geht dann genauso wie bei CMD_SETLEDS.

MfG,
SlyD

RP6conrad
17.09.2008, 19:28
Das muss in beide Programme etwas geandert werden. An sich halte ich das nicht gerade fur sinnfoll, da die Basis alle Sensorwerten weitergebt an den Master. Auch kan die Master alle Befehle weiter geben an die Basis. Ist der M32 schon ueberfordert mit ihre heutige Program ?
Aber basis sind die I2C Register in Master und Slave. Darueber laufen alle Werten die beide auswechselen. Diese Register können erweitert werden, und darueber kannst du dan die Variabele nutzen.

vogel0815
18.09.2008, 13:56
Danke schonmal für die Tips, werde ich dann demnächst umsetzen.
Hab da aber gerade irgendein anderes Problem.
Ich hab meiner Meinung nach eigentlich alles wichtige drin um die Basis über den M32 zu steuern aber ich bekomme immer eine Fehlermeldung mit 0x20.
Hab mal testweise das selftest programm auf den M32 geladen, das lief ohne Fehlermeldung.

Sieht jemand hier den Fehler?


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"

void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}

...
...
...

int main(void)
{
initRP6Control();


I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

setLEDs(0);

while(1)
{
task_checkINT0();
task_I2CTWI();
...
...
...
mSleep(500);
}
return 0;
}

Das ist jetzt nur ein Teil des Codes, der rest (die ...) betrifft aber eigentlich nur irgendwelche abfragen oder verarbeitung von sensorwerten etc.
Insgesamt sind es halt etwa 315 zeilen code von denen ich euch die unwichtigen ersparen wollte *g*
Das einzige was geschickt wird ist dann ein moveAtSpeed.

Kann man eigentlich auch ein moveAtspeed(0,0) schicken? bzw gibt das eine Fehlermeldung?

SlyD
18.09.2008, 14:55
Hallo,

mach erstmal 500ms oder mehr Pause am Anfang - das ist im Slave Programm am Anfang nämlich noch drin (LEDs aufblinken lassen usw.).

Hast Du das Slave Programm irgendwie geändert?

0x20 kommt entweder bei falscher Slave Adresse oder natürlich bei fehlerhafter Übertragung.
(die Fehlercodes stehen alle im RP6I2CmasterTWI.h Header)

Wenn das alles nicht zutrifft - komplettes Programm posten bitte und alles nennen was sonst geändert wurde!

MfG,
SlyD

vogel0815
18.09.2008, 15:59
Vielen Dank, das mit den 500 ms Pause scheint mein Problem behoben zu haben. Zumindest funktioniert es nun einigermassen richtig.
Nun ist nur noch das Problem, das er irgendwie immer vorwärts fährt und nur nach rechts dreht. Egal wie ich steuer.

Hier is nun eben dochmal das ganze Programm, ich hoffe ihr könnt es lesen.


#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"

void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}

extern uint8_t rc_input_right_y, rc_input_right_x, rc_input_active;
/*
Aufnahme der Servowerte des Empfaengers erfolgt in der ISR
in der Datei RP6ControlLib.c ab Zeile 752
*/

uint8_t speed_cruising, speed_rotating, speed_left, speed_right;
uint8_t dir_cruising, dir_rotating, dir_cruising_high, dir_cruising_low, dir_rotating_high, dir_rotating_low;
/*
speed_cruising := zu fahrende geschwindigkeit
speed_rotating := drehgeschwindigkeitsoffset
dir_cruising := zu fahrende richtung
dir_rotating := drehrichtung
dir_cruising_high := fahrrichtung mit hohen empfaengerwerten
dir_cruising_low := fahrrichtung mit niedrigen empfaengerwerten
dir_rotating_low := drehrichtung mit niedrigen empfaengerwerten
dir_rotating_high := drehrichtung mit hohen empfaengerwerten
speed_left := effektive geschwindigkeit links aus speed und speed_rotating
speed_right := effektive geschwindigkeit rechts aus speed und speed_rotating
*/

static uint8_t speed_cruising_max = 100;
static uint8_t speed_cruising_step = 30;
/*
speed_cruising_max := maximale fahrgeschwindigkeit
speed_cruising_step := geschwindigkeitsaenderung je schritt des empfaengers
*/

static uint8_t speed_rotating_max = 50;
static uint8_t speed_rotating_step = 20;
/*
speed_rotating_max := maximaler offset zum drehen
speed_rotating_step := drehgeschwindigkeitsaenderung je schritt des empfaengers
*/

static uint8_t speed_mid = 0;
/*
speed_mid := geschwindigkeitswerte bei mittelposition
*/

int main(void)
{
initRP6Control();


I2CTWI_initMaster(100);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

setLEDs(1);
mSleep(500);
setLEDs(0);

while(1)
{
task_checkINT0();
task_I2CTWI();

/*
writeString_P("RC active :");
writeInteger(rc_input_active, 10);
writeString_P(" - ");
writeString_P("RC vorwaerts :");
writeInteger(rc_input_right_y, 10);
writeString_P(" - ");
writeString_P("RC quer :");
writeInteger(rc_input_right_x, 10);
writeString_P("\n\r");
*/


//ist die fernsteuerung aktiviert
if ( rc_input_active >= 16 && rc_input_active <=18 )
{
//writeString_P(" RC aktiviert ");
//fahrgeschwindigkeit auswerten
switch( rc_input_right_y )
{
//minimale werte
case 8:
writeString_P("y 8");
dir_cruising = dir_cruising_low;
speed_cruising = 4 * speed_cruising_step;
break;
case 9:
writeString_P("y 9");
dir_cruising = dir_cruising_low;
speed_cruising = 3 * speed_cruising_step;
break;
case 10:
writeString_P("y 10");
dir_cruising = dir_cruising_low;
speed_cruising = 2 * speed_cruising_step;
break;
case 11:
writeString_P("y 11");
dir_cruising = dir_cruising_low;
speed_cruising = 1 * speed_cruising_step;
break;

//mittlere werte
case 12:
writeString_P("y 12");
dir_cruising = dir_cruising_low;
speed_cruising = speed_mid;
break;
case 13:
writeString_P("y 13");
dir_cruising = dir_cruising_low;
speed_cruising = speed_mid;
break;
case 14:
writeString_P("y 14");
dir_cruising = dir_cruising_low;
speed_cruising = speed_mid;
break;
case 15:
writeString_P("y 15");
dir_cruising = dir_cruising_low;
speed_cruising = speed_mid;
break;

//maximale werte
case 16:
writeString_P("y 16");
dir_cruising = dir_cruising_high;
speed_cruising = 1 * speed_cruising_step;
break;
case 17:
writeString_P("y 17");
dir_cruising = dir_cruising_high;
speed_cruising = 2 * speed_cruising_step;
break;
case 18:
writeString_P("y 18");
dir_cruising = dir_cruising_high;
speed_cruising = 3 * speed_cruising_step;
break;
case 19:
writeString_P("y 19");
dir_cruising = dir_cruising_high;
speed_cruising = 4 * speed_cruising_step;
break;

//fuer alle anderen werte
default:
writeString_P("y default");
dir_cruising = dir_cruising_high;
speed_cruising = speed_mid;
break;
}
writeString_P("\n\r");

//drehgeschwindigkeit auswerten
switch ( rc_input_right_x)
{
//niedrige werte
case 9:
writeString_P("x 9");
dir_rotating = dir_rotating_low;
speed_rotating = 5 * speed_rotating_step;
break;
case 10:
writeString_P("x 10");
dir_rotating = dir_rotating_low;
speed_rotating = 4 * speed_rotating_step;
break;
case 11:
writeString_P("x 11");
dir_rotating = dir_rotating_low;
speed_rotating = 3 * speed_rotating_step;
break;
case 12:
writeString_P("x 12");
dir_rotating = dir_rotating_low;
speed_rotating = 2 * speed_rotating_step;
break;
case 13:
writeString_P("x 13");
dir_rotating = dir_rotating_low;
speed_rotating = 1 * speed_rotating_step;
break;

//mittlere werte
case 14:
writeString_P("x 14");
dir_rotating = dir_rotating_low;
speed_rotating = speed_mid;
break;
case 15:
writeString_P("x 15");
dir_rotating = dir_rotating_low;
speed_rotating = speed_mid;
break;
case 16:
writeString_P("x 16");
dir_rotating = dir_rotating_low;
speed_rotating = speed_mid;
break;
case 17:
writeString_P("x 17");
dir_rotating = dir_rotating_low;
speed_rotating = speed_mid;
break;

//hohe werte
case 18:
writeString_P("x 18");
dir_rotating = dir_rotating_high;
speed_rotating = 1 * speed_rotating_step;
break;
case 19:
writeString_P("x 19");
dir_rotating = dir_rotating_high;
speed_rotating = 2 * speed_rotating_step;
break;
case 20:
writeString_P("x 20");
dir_rotating = dir_rotating_high;
speed_rotating = 3 * speed_rotating_step;
break;
case 21:
writeString_P("x 21");
dir_rotating = dir_rotating_high;
speed_rotating = 4 * speed_rotating_step;
break;
case 22:
writeString_P("x 22");
dir_rotating = dir_rotating_high;
speed_rotating = 5 * speed_rotating_step;
break;

//fuer alle anderen werte
default:
writeString_P("x default");
dir_rotating = dir_rotating_high;
speed_rotating = speed_mid;
break;
}
writeString_P("\n\r");
}
else
{
speed_cruising = 0;
speed_rotating = 0;
}

/*
writeString_P("X. ");
writeInteger(rc_input_right_x, 10);
writeString_P(" speed rot ");
writeInteger(speed_rotating, 10);
writeString_P(" Y. ");
writeInteger(rc_input_right_y, 10);
writeString_P(" speed crus ");
writeInteger(speed_cruising, 10);
writeString_P("\n\r");
*/


//beschraenkung der maximalen werte
if (speed_cruising > speed_cruising_max)
{
speed_cruising = speed_cruising_max;
}
if (speed_rotating > speed_rotating_max)
{
speed_rotating = speed_rotating_max;
}

//er soll fahren und sich evtl drehen
if ( speed_cruising != 0 )
{
writeString_P("1 ");
//vorwaerts fahren
if ( dir_cruising == dir_cruising_high )
{
writeString_P("1.1 ");
changeDirection(FWD);
speed_left = speed_cruising;
speed_right = speed_cruising;

//zusaetzlich drehen nach rechts
if ( dir_rotating == dir_rotating_high )
{
writeString_P("1.1.1 ");
speed_left += speed_rotating;
speed_right -= speed_rotating;

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

//zusaetzlich drehen nach links
else if ( dir_rotating == dir_rotating_low )
{
writeString_P("1.1.2 ");
speed_left -= speed_rotating;
speed_right += speed_rotating;

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

moveAtSpeed(speed_left,speed_right);

}

//rueckwarts fahren
else if ( dir_cruising == dir_cruising_low )
{
writeString_P("1.2 ");
changeDirection(BWD);
speed_left = speed_cruising;
speed_right = speed_cruising;

//zusaetzlich drehen nach rechts
if ( dir_rotating == dir_rotating_high )
{
writeString_P("1.2.1 ");
speed_left += speed_rotating;
speed_right -= speed_rotating;

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

//zusaetzlich drehen nach links
else if ( dir_rotating == dir_rotating_low )
{
writeString_P("1.2.2 ");
speed_left -= speed_rotating;
speed_right += speed_rotating;

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

moveAtSpeed(speed_left,speed_right);
}
}

//er soll auf der stelle drehen ohne zu fahren
else if ( speed_cruising == 0 )
{
writeString_P("2 ");
//auf der stelle nach rechts drehen
if ( dir_rotating == dir_rotating_high )
{
writeString_P("2.1 ");
rotate(speed_rotating,RIGHT,1,false);
}

//auf der stelle nach links drehen
else if ( dir_rotating == dir_rotating_low )
{
writeString_P("2.2 ");
rotate(speed_rotating,LEFT,1,false);
}
}
mSleep(200);
writeString_P("\n\r");
}
return 0;
}


Die Werte rc_input_right_y und rc_input_right_x werden wie in den Kommentaren angegeben durch eine ISR von einem Empfänger aufgenommen. Das klappt auch so wie es soll, aber irgendwie fährt er immer nur vorwärts, bzw landet immer an der Stelle wo es heisst vorwärts fahren und wenn er auf der Stelle drehen soll dreht er sich auch nuch nach rechts.
Werd mir das morgen nochmal anschaun. Evtl sehe ich dann klarer.

SlyD
18.09.2008, 16:11
Hui - nun das Programm ist doch recht lang und da gibt es viele Ecken woran es liegen könnte... Da musst Du mal ein paar zusätzliche Ausgaben reinmachen wie die Variablen so gesetzt sind (mit writeInteger) an verschiedenen Stellen und dann genau nachvollziehen wohin er verzweigt ist und mit welchen Werten...

Oder alternativ mit was kleinerem anfangen und das Programm Schritt für Schritt aufbauen und zwischendrin immer wieder testen ob es bis dahin schonmal klappt...
Umgekehrt geht es auch - teile aus dem Programm erstmal wieder rausnehmen und dann schritt für schritt testen und wieder mit reinnehmen.

MfG,
SlyD

vogel0815
18.09.2008, 16:34
Das mit den Ausgaben hab ich gemacht, aber irgendwie rennt er dann immer wieder an die gleiche Stelle.
Werd da dann wohl mal hingehen und das Stück für Stück duchexerzieren.

Wenn das dann klapt mach ich mich dran das I2C Slave programm zu bearbeiten. Denn die Basis soll eigentlich etwas selbstständig machen, is jemand sagt er will das Ding per Fernsteuerung steuern.

Und ich mach das doch Schritt für Schritt.
Schritt 1: Testprogramme durchprobieren
Schritt 2: Eigene Idee einfallen lassen
Schritt 3: Diese Idee mit allen Mitteln durchdrücken bis sie klappt
Schritt 4: Ergebnis bewundern
Schritt 5: Wieder alles demontieren und eine neue Idee suchen

*g*

vogel0815
19.09.2008, 15:36
Ich schon wieder mit freudiger Botschaft.

Hab in dem Programm nun diese if Abfragen wie "if ( dir_cruising == dir_cruising_high )" alle so ersetzt das die Variable dir_cruising nun auf true oder false oder 0 gesetzt wird und dadurch die abfragen etwas anders sind. Nun klappt das auch wunderbar.

*lustig sein Roboterli in der Gegend herum steuer* :D
*freu*

Nun kommt die Änderung des I2C Slave Programms in der Basis dran.

Mensch ich bin stolz wie sonst wa das des Ding nu so fährt wie es soll.

vogel0815
24.09.2008, 12:06
Schau Dir mal

void task_commandProcessor(void)

an.
Da einfach nen neues Kommando hinzufügen (neuen case) in dem halt irgendwas gemacht wird active = param1 z.B.
Der Aufruf geht dann genauso wie bei CMD_SETLEDS.

MfG,
SlyD


Hallöle genau daran scheiter ich grad.
Evtl hab ich was übersehen.

Ich hab zwei neue CMD's definiert

#define CMD_REMOTE_ON 13
#define CMD_REMOTE_OFF 14

sowohl im M32 als auch in der Base.

im task_commandProcessor der Base (gibt es ja nur da) hab ich au noch 2 neue Fälle eingebaut:


case CMD_REMOTE_ON:
remote_control=true;
break;
case CMD_REMOTE_OFF:
remote_control=false;
break;

die Variable remote_control hab ich au noch definiert.

Im Hauptprogramm des M32 setze ich diese Varible dann mit


I2CTWI_transmitByte(I2C_RP6_BASE_ADR, CMD_REMOTE_ON);
bzw
I2CTWI_transmitByte(I2C_RP6_BASE_ADR, CMD_REMOTE_OFF);

und in der Base wird die mittels einer if-abfrage
if ( ( remote_control == false) ) {}
else {}
verwendet.

Nur irgendwie klappt das nicht so wie es soll.
Er rennt immer in die if-Abfrage rein als ob remote_control immer auf false wär.

Die I2C Adresse der Base ist auch in beiden Programmen gleich.

vogel0815
26.09.2008, 16:42
Hat keiner ne Idee?

Habs auch mal noch probiert mit
I2CTWI_transmit2Bytes(I2C_RP6_BASE_ADR, 0, CMD_REMOTE_ON);

Was auch immer dieses 0 sein soll, wird in manchen anderen Programmen genutzt.

Dreh mich hier grad auf der Stelle.

SlyD
26.09.2008, 17:16
Die 0 gibt das Register an in das geschrieben werden soll.
0 ist das Kommando Register. 1 bis 6 sind Register für Parameter.
(kann man natürlich noch erweitern bei Bedarf und auch direkt beschreibbare Register könnte man einführen)

Die 0 ist also absolut notwendig, sonst klappt es definitiv nicht.

Ich habe gerade keine Zeit das zu testen, was passiert wenn Du einfach mal
transmit3... (anstatt 2) verwendest?
(so kannst Du nebenbei auch die Variable beliebig beschreiben indem Du
remote_control = param1 schreibst... dann funktioniert das wie z.B. bei setLEDs)

MfG,
SlyD

vogel0815
26.09.2008, 19:16
Vielen Dank, genau das war es.
Nun funktioniert wirklich alles so wie es soll :D

fulltime
12.01.2012, 15:00
Hab jetzt mal bei der M32-Platine die LDRs benötigt. Beim compilieren kommt immer die Meldung, dass er getLightSensors() nicht kennt. Den Befehl getAllSensors kennt er aber. Da ich nur die Sensorendaten der LDRs brauche wie ich nicht die ganzen Sensordaten hochladen.