PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RP6 fernsteuern



I♥ROBOTIC
11.04.2011, 20:07
Hallo RN,

ich hab radbruchs videos gesehen, in denen er seinen RP6 ferngesteuert hat. ich hab seine programme ausprobiert aber bei mir funktionieren die iwie nicht (empfänger ist richtig angeschlossen).. also hab ich mir gedacht, versuche ich selbst ein programm zu schreiben. erst mal eins zum auslesen der "Servopostitionen"

Hier das Programm:

#include "RP6ControlLib.h"

uint16_t speed=0;
uint16_t dir=0;
uint16_t speedcount=0;
uint16_t dircount=0;

ISR(TIMER1_COMPA_vect)
{
if (PINA & ADC5)
{
speedcount++;
}
else
{
if (speedcount > 0)
{
speed=speedcount;
}
speedcount=0;
}


if (PINA & ADC3)
{
dircount++;
}
else
{
if (dircount > 0)
{
dir=dircount;
}
dircount=0;
}
}
void initRC(void)
{
TCCR1A = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR1A |= (0 << COM00) | (0 << COM01); // ohne OCR-Pin
TCCR1A |= (0 << CS02) | (1 << CS01) | (0 << CS00); // prescaler /8
TIMSK |= (1 << OCIE1A); // Interrupt ein
OCR1A = 9; // 100kHz?
}

int main(void)
{
initRP6Control();
initLCD();
initRC();

while(1)
{
writeInteger(speed, DEC);
writeString("\t\t");
writeInteger(dir, DEC);
writeString("\n");
}
return 0;
}

Es soll nur messen wie lange die Ports high sind und das dann ausgeben, aber irgendwie bekomm ich immer nur 0en raus...

mein empfänger bekommt strom, denn wenn ich testweise eine servo dranhänge bewegt er sich einwandfrei.

ich hoffe ihr könnt mir helfen den Fehler zu finden, denn ich hab keine lust mich morgen auch nochmal den ganzen Tag hinzusetzen..

könnte es sein dass es an der Timerinitaliesierung liegt ?? die hab ich nämlich nicht selbst geschrieben (kenn mich mit dem Bitschubsen nicht aus), die ist noch von Radbruchs Programm...

radbruch
11.04.2011, 20:30
Versuche es mal so:


volatile uint16_t speed=0;
volatile uint16_t dir=0;
volatile uint16_t speedcount=0;
volatile uint16_t dircount=0;

Läuft das m32 nicht mit 16MHz? Dann sollte OCR1A mit 20 geladen werden um einen 100kHz-Takt zu erreichen. Aber eigentlich ist der absolute Messwert der Impulslänge ja nicht wichtig, es funktioniert auch so.

Vorsicht bei 16-Bit-Werten. Sie könnten während der Ausgabe von der ISR verändert werden:

uint16_t speed1, dir1;
while(1)
{
cli(); // Interrupts verbieten
speed1=speed;
dir1=dir;
sei(); // Interrupts wieder zulassen
writeInteger(speed1, DEC);
writeString("\t\t");
writeInteger(dir1, DEC);
writeString("\n");
mSleep(100);
}


Gruß

mic

I&amp;#9829;ROBOTIC
11.04.2011, 20:36
danke für die schnelle Antwort, aber leider bringts nichts... ich bekomm im Terminal nur Nullen ausgegeben

radbruch
11.04.2011, 21:45
Also ich war mal so frei und habe für dich ins Datenblatt des Mega32 geschaut:

COM00/COM01 heißen beim Timer1 für KanalA COM1A0 und COM1A1 und müssen gelöscht sein für keine Ansteuerung des OCR-Pins, entsprechendes gilt für CS00-02. WGM00/WGM01 heißen WGM10/WGM11 und weil der Timer1 mehr Modi hat braucht man für CTC (Mode4) zusätzlich noch WGM12/13. Außerdem besitzt der Timer1 zwei Controllregister, das Setup (ungetestet) wäre also etwa so:

void initRC(void)
{
TCCR1A = (0 << WGM11) | (0<<< WGM10) | (0 << COM1A0) | (0 << COM1A1); // CTC-Mode4, ohne OCR-Pin
TCCR1B = (0 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); // CTC und prescaler /8
TIMSK |= (1 << OCIE1A); // Interrupt ein
OCR1A = 20; // 100kHz?
}

I&amp;#9829;ROBOTIC
12.04.2011, 14:55
Danke für die Mühe allerdings bekomm ich eine Fehlermeldung:


RC.c:40: error: expected expression before '<' token

Z.40 ist die erst der Initialisierung:


TCCR1A = (0 << WGM11) | (0<<< WGM10) | (0 << COM1A0) | (0 << COM1A1);

Fabian E.
12.04.2011, 15:03
Naja, da ist eben ein "<" zu viel...

I&amp;#9829;ROBOTIC
12.04.2011, 15:08
ach danke :D ich hab immer nur am anfang geschaut :D

auch danke an Radbruch für die Mühe sich das Datenblatt extra anzusehen.... es funktioniert jetzt einwandfrei ;)

radbruch
12.04.2011, 15:41
Naja, da ist eben ein "<" zu viel...Entschuldigung. Trotz ordentlicher Formatierung ist mir das nicht aufgefallen. Naja, niemand ist perfekt. Schön, dass es nun funzt :)

Das aktuelle funktionierende Programm würde mich noch interessieren...

Fabian E.
12.04.2011, 16:25
Entschuldigung. Trotz ordentlicher Formatierung ist mir das nicht aufgefallen. Naja, niemand ist perfekt. Schön, dass es nun funzt :)

Das aktuelle funktionierende Programm würde mich noch interessieren...

Kann ja mal passieren ;)

I&amp;#9829;ROBOTIC
13.04.2011, 12:57
Hier das Bisherige Programm:


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

void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}

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

volatile uint16_t speed=0;
volatile uint16_t dir=0;
volatile uint16_t speedcount=0;
volatile uint16_t dircount=0;

ISR(TIMER1_COMPA_vect)
{
if (PINA & ADC5)
{
speedcount++;
}
else
{
if (speedcount > 0)
{
speed=speedcount;
}
speedcount=0;
}


if (PINA & ADC3)
{
dircount++;
}
else
{
if (dircount > 0)
{
dir=dircount;
}
dircount=0;
}
}

void initRC(void)
{
TCCR1A = (0 << WGM11) | (0 << WGM10) | (0 << COM1A0) | (0 << COM1A1); // CTC-Mode4, ohne OCR-Pin
TCCR1B = (0 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); // CTC und prescaler /8
TIMSK |= (1 << OCIE1A); // Interrupt ein
OCR1A = 20; // 100kHz?

DDRA &= ~ADC5;
PORTA &= ~ADC5;
DDRA &= ~ADC3;
PORTA &= ~ADC3;
}



int main(void)
{
initRP6Control();
initLCD();
initRC();

mSleep(500);

I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

uint16_t speed1, dir1;

while(1)
{
cli(); // Interrupts verbieten
speed1=speed;
dir1=dir;
sei(); // Interrupts wieder zulassen

rc_pwr=0;
rc_dir=0;

if (dir1<130) { rc_dir=150-dir1; changeDirection(LEFT); writeInteger(dir1, DEC); writeString("\t\t");}
if (dir1>180) { rc_dir=dir1-110; changeDirection(RIGHT); writeInteger(dir1, DEC); writeString("\t\t");}
if (speed1<150) { rc_pwr=150-speed1; changeDirection(FWD); writeInteger(speed1, DEC); writeString("\n");}
if (speed1>160) { rc_pwr=speed1-110; changeDirection(BWD); writeInteger(speed1, DEC); writeString("\n");}
rc_pwr*=3;
if (rc_pwr)
{
if (dir1<150) moveAtSpeed(rc_pwr-rc_dir,rc_pwr+rc_dir);
else if (dir1>160) moveAtSpeed(rc_pwr+rc_dir,rc_pwr-rc_dir);
else moveAtSpeed(rc_pwr,rc_pwr);
}
else
{
moveAtSpeed(rc_dir*3, rc_dir*3);
}

task_checkINT0();
task_I2CTWI();
}
return 0;
}

allerdings haut das mit dem fahren noch nicht richtig hin... wenn die fernbedienung ein ist bekomm ich unendlich errors ausgegeben (0x20) was ja soviel ich weiß heist das die Base nicht antwortet
wenn die fernbedienung aus ist bekomm ich Nullen (logisch, da der empfänger keinen impuls sendet) und nach einer zeit reseted die M32, und der RP6 fängt an zu fahren....
oder der ganze rp6 hängt sich auf, so dass ich nicht mal mehr das programm beenden kann

hab ich einen fehler im prog oda so ?? ich kann mir das nämlich nicht erklären


[EDIT] GROSSES PROBLEM !!!!

irgendwas stimmt mit meinem RP6 nicht, der rp6 loader kann nicht verbinden (ziel reagiert nicht) und danach wird auf dem lcd nur noch die 1 zeile angezeigt, und nach 2 oder 3 maligem ein und ausschalten zeigt es garnichts mehr an (leuchtet nur noch blau) und die roten status leds der base blinken, und das verheist soviel ich weis nichts gutes

ich lade mal die akkus auf (vll liegt es an denen, denn das lcd ist, sofern es etwas anzeigt, sehr schwach) danach sehen wir mal weiter

[EDIT2]

aus welchem grund auch immer geht mein rp6 auch wieder aber ich bekomm unendlich errors raus (zwischendrin auch eine weile lang servowerte) aber nach ein paar sek kommen nur noch errors und dann hängt sich der rp6 auf ... wisst ihr wo der hacken steckt ?

SlyD
13.04.2011, 16:40
> und die roten status leds der base blinken

Alle?
Dann sind wahrscheinlich die Akkus zu schwach / leer.

I&amp;#9829;ROBOTIC
13.04.2011, 21:06
ja blinken alle, hab ich mir schon gedacht werd sie über nacht mal aufladen

I&amp;#9829;ROBOTIC
15.04.2011, 22:46
also, nachdem ich die Batterien aufgeladen hab, hab ich das Programm nochmal getestet, und es lief (bis auf das Problem, dass ich die Encoder wieder mal einstellen muss) einwandfrei ! (sofern man das bei dermasen verstellten encodern sagen konnte) da ich zu faul war, den ganzen RP6 zu zerlegen, nur um die dinger einzustellen, hab ich mir gedacht, füge ich der RP6Control_I2CMasterLib.c die funktion setMotorPower hinzu. (die ist ja auf der base im slaveprogramm verfügbar, man kann sie nur nicht durch das M32 aufrufen. ich hab also in der der RP6Control_I2CMasterLib.c das hier hinzugefügt:


void setMotorPower(uint8_t PWR_left, uint8_t PWR_right)
{
I2CTWI_transmit4Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_MOTOR_PWR, PWR_left, PWR_right );
while(I2CTWI_isBusy() || TWI_operation != I2CTWI_NO_OPERATION) task_I2CTWI();
}

In der RP6Control_I2CMasterLib.h das hier:


#define CMD_SET_MOTOR_PWR 13

und im slaveprog für die base hab ich natürlich in die task_commandProcessor() das hinzugefügt:


case CMD_SET_MOTOR_PWR: setMotorPower(param1,param2); break;

und natürlich auch die definition von CMD_SET_MOTOR_PWR

aber wenn ich mein Programm nun starte, bekomme ich nur Errors raus :(

hat jemand ne idee was ich falsch gemacht, bzw. vergessen haben könnte ??

Dirk
16.04.2011, 19:42
@I&.......,

beim Original Slave-Programm für die Base (RP6Base_I2CSlave.c) ist bei mir keine Funktion "setMotorPower" enthalten.

Wie sieht die bei dir denn aus?

I&amp;#9829;ROBOTIC
16.04.2011, 19:57
bei mir war sie auch nicht enthalten aber in dern RP6BaseLib gibt es sie und die wird ja im base slave prog verwendet.. naja mir ist jetzt aufgefallen dass ich das slave prog zwar geändert aber nicht neu compiliert hab !!(ich vergess oft die hälfte) das wollte ich jetzt machen, bekomme allerdings den fehler, dass IRCOMM nicht definiert wurde... was eig iwie nicht sein kann denn das habe ich nicht nachgetragen, das stand schon so drinnen....

ach ja IRCOMM wird hier verwendet:

void task_MasterTimeout(void)
{
if(status.watchDogTimer)
{
if( getStopwatch2() > 3000) // 3 seconds timeout for the master to react on
{ // our interrupt events - if he does not react, we
// stop all operations!
cli(); // clear global interrupt bit!
PORTD &= ~IRCOMM;
setACSPwrOff();
OCR1AL = 0;
OCR1BL = 0;
TCCR1A = 0;
powerOFF();
writeString_P("\n\n##### EMERGENCY SHUTDOWN #####\n");
writeString_P("##### ALL OPERATIONS STOPPED TO PREVENT ANY DAMAGE! #####\n\n");
writeString_P("The Master Controller did not respond to the interrupt requests\n");
writeString_P("within the defined timeout! Maybe he's locked up!\n");
writeString_P("\nThe Robot needs to be resetted now.\n\n");
while(true) // Rest In Peace
{
setLEDs(0b100010);
uint8_t dly;
for(dly = 10; dly; dly--)
delayCycles(32768);
setLEDs(0b010100);
for(dly = 10; dly; dly--)
delayCycles(32768);
}
}
else if(getStopwatch3() > 250)
{
status.wdtRequest = true;
signalInterrupt();
setStopwatch3(0);
}
}
}

weiß jemand wie man dieses problem lösen kann ?? denn dan glaube und hoffe ich, dürfte das programm laufen


EDIT:

könnte man die rot markierte zeile vll durch dies hier ersetzen:

PORTD &= ~(1<<PIND7)

so wirdn nämlich in der BaseLib der IRCOMM port abgeschaltet

radbruch
16.04.2011, 20:35
Hallo


Wegen eines übereifrigen RP6-Besitzers wurde die Definition von IRCOMM in RP6BaseLib.h geändert:

/************************************************** ***************************/
// IRCOMM pin:

// ### WARNING!
//
// #define IRCOMM (1 << PIND7) // Output
//
// ### DO NOT USE THIS PIN BY YOURSELF!
// ONLY LET THE INTERRUPT ROUTINE OF THE LIBRARY
// CONTROL THIS PIN!
// The IR LEDs must be controlled by a modulated
// signal with minimal 5kHz or higher
// modulation frequency!
// Nominal modulation frequency is 36kHz!
// YOU MAY DAMAGE THE IRCOMM IF YOU USE IT
// IN ANY OTHER WAY!

// Only use this macro to make sure IRCOMM is
// turned off:
#define IRCOMM_OFF() PORTD &= ~(1 << PIND7);


Besser als der direkte Zugriff ist deshalb IRCOMM_OFF();

https://www.roboternetz.de/community/showthread.php?29313-gel%F6st-Einfache-IR-Kommunikation-f%FCr-den-RP6&p=280380&viewfull=1#post280380

Gruß

mic

I&amp;#9829;ROBOTIC
16.04.2011, 21:03
ich hab jetzt and die stelle IRCOMM_OFF() eingetragen und nun ließ sich das Programm auch kompilieren und mein RP6 fährt auch, allerding nicht ganz so wie gewünscht:

1. wen man gas gibt (egal ob vor- oder rückwärts) er fährt hin und wieder mal rückwärts, dann aber mal doch wieder vorwärts.....
2. ich muss nach jeder drehung oder fahrt 2 oder 3 sekunden warten, weil der rp6 sonst die vorherige bewegung fortführt (also wenn ich nach rechts drehe, und dan plötzlich rückwärts gasgebe dreht er weiter...

ich hab mir das ehrlich gesagt leichter vorgestellt -.-

hier mein Programm bisher:

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

uint8_t frequenz=0;
uint8_t furz=0;

void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}

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

if(getStopwatch1() > 1)
{
if(frequenz == 255)
{
furz=1;
}

else if(frequenz == 0)
{
furz=0;
}

if(furz){frequenz--;}
else{frequenz++;}

setBeeperPitch(frequenz);
setStopwatch1(0);
}
}

volatile uint16_t speed=0;
volatile uint16_t dir=0;
volatile uint16_t speedcount=0;
volatile uint16_t dircount=0;

ISR(TIMER1_COMPA_vect)
{
if (PINA & ADC5)
{
speedcount++;
}
else
{
if (speedcount > 0)
{
speed=speedcount;
}
speedcount=0;
}


if (PINA & ADC3)
{
dircount++;
}
else
{
if (dircount > 0)
{
dir=dircount;
}
dircount=0;
}
}

void initRC(void)
{
TCCR1A = (0 << WGM11) | (0 << WGM10) | (0 << COM1A0) | (0 << COM1A1); // CTC-Mode4, ohne OCR-Pin
TCCR1B = (0 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10); // CTC und prescaler /8
TIMSK |= (1 << OCIE1A); // Interrupt ein
OCR1A = 20; // 100kHz?

DDRA &= ~ADC5;
PORTA &= ~ADC5;
DDRA &= ~ADC3;
PORTA &= ~ADC3;
}



int main(void)
{
initRP6Control();
initLCD();
initRC();

startStopwatch1();

mSleep(1000);

I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);

uint16_t speed1, dir1;

while(1)
{
cli(); // Interrupts verbieten
speed1=speed;
dir1=dir;
sei(); // Interrupts wieder zulassen

rc_pwr=0;
rc_dir=0;

if (dir1<140) { rc_dir=150; changeDirection(LEFT); writeInteger(dir1, DEC); writeString("\t\t");}
if (dir1>170) { rc_dir=150; changeDirection(RIGHT); writeInteger(dir1, DEC); writeString("\t\t");}
if (speed1<150) { rc_pwr=speed1+50; changeDirection(BWD); writeInteger(speed1, DEC); writeString("\n");}
if (speed1>160) { rc_pwr=speed1-50; changeDirection(FWD); writeInteger(speed1, DEC); writeString("\n");}
rc_pwr*=3;
if (rc_pwr)
{
if (dir1<150) setMotorPower(rc_pwr-rc_dir,rc_pwr+rc_dir);
else if (dir1>160) setMotorPower(rc_pwr+rc_dir,rc_pwr-rc_dir);
else setMotorPower(rc_pwr,rc_pwr);
}
else
{
setMotorPower(rc_dir, rc_dir);
}

task_checkINT0();
task_I2CTWI();
}
return 0;
}

RolfD
17.04.2011, 19:42
Das der RP6 nicht zuverlässig zu steuern ist, liegt an der I2C Kommuniaktion.
LG Rolf

I&amp;#9829;ROBOTIC
19.04.2011, 22:05
mein programm läuft jetzt einwandfrei und ich kann auch ohne probleme herumfahren :D

danke an alle die mir geholfen haben :D