PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Robosapien V1 mit RP6 steuern!



Roboterarsch
23.02.2009, 18:16
Hallo zusammen,

möchte gerne mit dem RP6 meinen Robosapien V1 steuern.
Leider funktioniert es nicht unten mein Anweisungen. Den TimerInterupt habe ich in der RP6RobotBaselib auskommentiert. Vielleicht hat einer nen Tip!


#include "RP6RobotBaseLib.h"
uint16_t z;
uint8_t i;
uint8_t ir_command;
uint16_t Zeit;

void Delay_us(uint16_t Verzoegerung)
{
Zeit=0;
while(Zeit<=Verzoegerung);
}

void ir_code_833(void)
{
for(z=0; z<= 33;z++)
{
PORTD = (1<<PIND7);
Delay_us(13);
PORTD &= ~(1<<PIND7);
Delay_us(12);
}
}

void ir_code_6666(void)
{
for(z=0; z<= 266;z++)
{
PORTD = (1<<PIND7);
Delay_us(13);
PORTD &= ~(1<<PIND7);
Delay_us(12);
}
}

ISR (TIMER2_OVF_vect)
{
Zeit++;
}

int main(void)
{
initRobotBase();

TCCR2 = (1 << WGM21) | (0 << COM20) | (1 << CS20);
OCR2 = 0x08; // 0x66 = 78,4kHz @8MHz

// Initialize Timer Interrupts:
TIMSK = (1 << OCIE0); //| (1 << OCIE2); // Fixed: Timer2 Interrupt is turned
// off by default now! It is only active
// when ACS/IRCOMM are transmitting.
TIMSK |= (1 << OCIE2);

while(true)
{
ir_command=137; //Left Arm Up

ir_code_6666(); //ir-signal 6666us
for( i=1; i<= 8;i++)
{
if ((ir_command & 0x80)==0)
{
Delay_us(833);
ir_code_833();
}
else
{
Delay_us(3333);
ir_code_833();}
ir_command=ir_command << 1;
}
}
return(0);
}

radbruch
23.02.2009, 19:02
Hallo

Zuerst eine Warnung: Die IR-CommLED hängt über R6 (10Ohm) direkt an der Batteriespannung. Wenn Q5 nicht mit einem Trägertakt angesteuert wird kann die IRLED zerstört werden! Zum Testen wäre eine Ausgabe an eine StatusLED sicherer, wenns dann blickt kann man richtig loslegen.

Auf den ersten Blick scheint mir folgender Fehler vorzuliegen: Der Timer2 mit Prescaler 1 und OCR2=8 blockiert alles weil zwischen den Matches nur 8 Takte (!) Zeit bleiben. Das reicht nicht einmal aus um die ISR auszuführen:


ISR (TIMER2_OVF_vect)
{
1880: 1f 92 push r1
1882: 0f 92 push r0
1884: 0f b6 in r0, 0x3f ; 63
1886: 0f 92 push r0
1888: 11 24 eor r1, r1
188a: 8f 93 push r24
188c: 9f 93 push r25
Zeit++;
188e: 80 91 0c 01 lds r24, 0x010C
1892: 90 91 0d 01 lds r25, 0x010D
1896: 01 96 adiw r24, 0x01 ; 1
1898: 90 93 0d 01 sts 0x010D, r25
189c: 80 93 0c 01 sts 0x010C, r24
18a0: 9f 91 pop r25
18a2: 8f 91 pop r24
18a4: 0f 90 pop r0
18a6: 0f be out 0x3f, r0 ; 63
18a8: 0f 90 pop r0
18aa: 1f 90 pop r1
18ac: 18 95 reti

Nur zur Erinnerung: Ein Riskprozessor wie die ATMegas braucht mindestens einen Takt pro Befehl. Auch ohne den Sprung ist deine ISR einfach zu lang.

Ich habe dein Programm mit der Overflow-ISR für Timer2 übersetzt weil diese ISR von der RP6-Lib nicht verwendet wird (und ich deshalb die Comp-ISR nicht ausblenden muss). So kann man bequem den Timer2 in eigenen Anwendungen verwenden und bei Bedarf initialiert man den Timer einfach wieder mit den Lib-Parametern. Mein Setup für eine 100kHz-Servo-ISR sieht so aus:


// Initialize Timer2 - 100kHz für Servos mit Overflow-ISR
TCCR2 = (0 << WGM21) | (0 << COM20) | (1 << CS20); // Normal Mode, no prescaler
TCNT2 = -80; // alle 80 Takte ein Interrupt
TIMSK |= (1 << TOIE2); // Timer2 Overflow-Interrupt erlauben

Weil das Counterregister nach dem Überlauf mit 0 geladen wird muss man in der ISR selbst einen neuen Startwert setzen:

ISR (TIMER2_OVF_vect)
{
TCNT2 = -80; // alle 80 Takte ein Interrupt
...
}
Nach diesem Prinzip könnest du vermutlich auch deine Zeiten erzeugen. Anstelle der -80 müssen bei dir eben die an deine Zeiten angepassten Werte stehen.

Hast du Infomationen zum Protokoll des Robosapien?

Gruß

mic

Roboterarsch
23.02.2009, 19:56
Vielen Dank Radbruch!

Du könntest natürlich Recht haben.
Unten habe ich das Protokoll des Robosapiens aufgeführt.
Trägerfrequenz ist 39,2kHz.
Habe inzwischen noch einen erneuten Versuch unternommen und mein Programm ähnlich aufgebaut wie in der lib des RP6 zum senden von RC5-Signalen.

Timing based on 1/1200 second clock (~.833ms)
Signal is normally high (idle, no IR).
Start: signal goes low for 8/1200 sec.
Data bits: for each of 8 data bits, space encoded signal depending on bit value
Sends the most significant data bit first
If the data bit is 0: signal goes high for 1/1200 sec, and low for 1/1200 sec.
If the data bit is 1: signal goes high for 4/1200 sec, and low for 1/1200 sec.
BTW: The first bit (msb) is always 1 (valid codes are from $80 to $FF)

Carrier is 39,2 kHz




#include "RP6RobotBaseLib.h"


uint16_t Zaehler=0;
uint8_t i;
uint8_t ir_command=137;
uint8_t Aufgabe=0;
uint8_t Zeichen=0;

ISR (TIMER2_COMP_vect)

{
if(Aufgabe==0){
if(Zeichen==0){
Aufgabe=1;
Zaehler=0;}
if(Zeichen>0 && Zeichen<9){
Zaehler=0;
if ((ir_command & 0x80)==0){
Aufgabe=2;}
else{Aufgabe=3;}
ir_command=ir_command << 1;
Zeichen++;
}
if(Zeichen==9){
PORTD &= ~(1<<PIND7);
Zeichen=0;
ir_command=137;
Aufgabe=0;}

}
if(Aufgabe==1){
if(Zaehler<520){
PORTD ^= (1<<PIND7); //PORTD ^= (1<<PIND7);
Zaehler++;}
else{
Aufgabe=0;
Zeichen=1;}
}
if(Aufgabe==2){
if(Zaehler<65){
PORTD &= ~(1<<PIND7);} //PORTD &= ~(1<<PIND7);
else{
if(Zaehler<130){
PORTD ^= (1<<PIND7);} //PORTD ^= (1<<PIND7);
else{ Aufgabe=0;}
}
Zaehler++;
}

if(Aufgabe==3){

if(Zaehler<260){
PORTD &= ~(1<<PIND7);} //PORTD &= ~(1<<PIND7);
else{
if(Zaehler<325){
PORTD ^= (1<<PIND7);} //PORTD ^= (1<<PIND7);
else{ Aufgabe=0;}
}
Zaehler++;
}


}



int main(void)
{
initRobotBase();

TCCR2 = (1 << WGM21) | (0 << COM20) | (1 << CS20);
OCR2 = 0x66; // 0x66 = 78,4kHz @8MHz

// Initialize Timer Interrupts:
TIMSK = (1 << OCIE0); //| (1 << OCIE2); // Fixed: Timer2 Interrupt is turned
// off by default now! It is only active
// when ACS/IRCOMM are transmitting.
TIMSK |= (1 << OCIE2);


while(true)
{

}

return 0;
}

Pr0gm4n
25.02.2009, 17:32
Hi,

ich hab zwar keine Ahnung ob das überhaupt noch im Programm steht (*sry grade zu müde um mehr zu lesen :D*)
aber ganz oben iss mir dashier aufgefallen:



void Delay_us(uint16_t Verzoegerung)
{
Zeit=0;
while(Zeit<=Verzoegerung);
}


dabei iss aber, egal mit welchem parameter man die Funktion Delay_us aufruft dann sofort ewiger Stillstand

denn da Verzögerung nicht negativ sein kann (wies mit 0 iss weiss ich garned iss aber egal) MUSS sie immer >= 0 sein :D

das bedeutet soviel wie wenn du einfach while(1); hinschreibst


ich vermute das sollte eigentlich so aussehen:



void Delay_us(uint16_t Verzoegerung)
{
Zeit=0;
while(Zeit<=Verzoegerung)Zeit++;
}


ach ja, dabei sit aber noch zu beachten, dass die funktion nicht soviele us wartet wie verzögerung groß ist, die takte eines µCs sind soweit ich weiss noch kleiner...

da diese art von delay eh blockierend ist, kann man auch gleich die delay.h oder wie die genau heißt hernehmen...


LG Pr0gm4n

radbruch
25.02.2009, 18:23
Hallo

Es sollte eine möglichst genaue Verzögerung sein, deshalb wird die Variable "Zeit" in der Interrupt-Service-Routine incrementiert (vergrößert?):


ISR (TIMER2_OVF_vect)
{
Zeit++;
}

Wenn man das berücksichtigt hat die Zeile in Delay_us() wieder Sinn:

while(Zeit<=Verzoegerung);

Allerdings sollte man Zeit als volatile vereinbaren. Soweit ich weiß zwingt das den Kompiler die Variable im Ram zu halten und erst damit wird der wechselseitige Zugriff von ISR und Hauptprogramm auf die Variable möglich. Aber wirklich wissen tu ich nix:

volatile uint16_t Zeit;

Gruß

mic

Pr0gm4n
25.02.2009, 20:23
Hi,

also das mit volatile weiss ich ned so genau aber es sollte dann so ablaufen dass man zeit besser als globale variable deklariert (was er oben auch macht) und sie innerhalb der funktion Delay_us() initialisiert mit dem wert 0 (ihn zuweist)

das passt also doch alles, sry, hab mich vertan :D hab wie gesagt nich den nerv gehabt so müde nochmal soviel zu lesen :D jezt nach 3 stunden schlaf oder was des warn iss schon n bissl besser :D

das "incrementiert (vergrößert?)" deute ich so dass du nicht sicher bist?

inkrementieren heisst um eins erhöhen ja.


LG Pr0gm4n

Roboterarsch
26.02.2009, 16:21
Hallo Zusammen,

werde mal die Varaiable Zeit als volatile deklarieren, und noch nen Versuch machen.

Vielen Dank erst mal für die Unterstützung! Werde mich melden ob das Ding funzt.

Pr0gm4n
27.02.2009, 09:55
Hi,

also ich versteh zwar ned warum du das machen willst, denn mit deiner Lösung mit Zeit als globaler Variable funktioniert das 100%ig

wenn dann liegt der Fehler wo anders

LG Pr0gm4n

sechsrad
13.03.2009, 11:27
So ist das Timing.
Funktioniert bei mir tadellos.
Noch die Einstellungen für einen Atmega32 mit 8mhz bei mir :
DDRD|=(1<<PD5);
PORTB=0;
OCR1A=101;
TCCR1B=(1<<WGM12)|(1<<CS10);
TCCR1A=(1<<COM1A1);



void ir_command(uint8_t command)
{
uint8_t mask;

TCCR1A=(1<<COM1A0);
delay_us(6666);
TCCR1A=(1<<COM1A1);

for (mask=0x80; mask>0; mask=mask>>1 )
{
if ( command & mask )
{
delay_us(3333);
TCCR1A=(1<<COM1A0);
delay_us(833);
TCCR1A=(1<<COM1A1);
}
else
{
delay_us(833);
TCCR1A=(1<<COM1A0);
delay_us(833);
TCCR1A=(1<<COM1A1);
}
}
}


das sind die Befehle:


Red Commands:
=============
(Page P.7)
81 (129) - Right Arm Up
84 (132) - Right Arm Down
85 (133) - Right Arm In
82 (130) - Right Arm Out
83 (131) - Tilt Body Right

89 (137) - Left Arm Up
8C (140) - Left Arm down
8D (141) - Left Arm In
8A (138) - Left Arm Out
8B (139) - Tilt Body Left

(Page P.8)
80 (128) - Turn Right
88 (136) - Turn Left
86 (134) - Walk Forward
87 (135) - Walk Backward
8E (142) - Stop

92 (146) - Right Sensor Program
94 (148) - Sonic Sensor Program
93 (147) - Left Sensor Program
90 (144) - Master Command Program
91 (145) - Program Play

Green Commands:
===============
(Page P.9)
A1 (161) - Right Hand Thump
A4 (164) - Right Hand Pickup
A5 (165) - Lean Backward
A2 (162) - Right Hand Throw
A3 (163) - Sleep

A9 (169) - Left Hand Thump
Ac (172) - Left Hand Pickup
AD (173) - Lean Forward
AA (170) - Left Hand Throw
AB (171) - Listen

(Page P.10)
A0 (160) - Right Turn Step
A8 (168) - Left Turn Step
A6 (166) - Forward Step
A7 (167) - Backward Step
AE (174) - Reset

B2 (178) - Right Sensor Program Execute
B4 (180) - Sonic Sensor Program Execute
B3 (179) - Left Sensor Program Execute
B0 (176) - Master Command Program Execute
B1 (177) - Wake Up

Orange Commands:
================
(Page P.11)
C1 (193) - Right Hand Sweep
C4 (196) - High 5
C5 (197) - Right Hand Strike 1
C2 (194) - Burp
C3 (195) - Right Hand Strike 2

C9 (201) - Left Hand Sweep
CC (204) - Talk Back
CD (205) - Left Hand Strike 1
CA (202) - Whistle
CB (203) - Left Hand Strike 2

(Page P.12)
C0 (192) - Right Hand Strike 3
C8 (200) - Left Hand Strike 3
C6 (198) - Bulldozer
C7 (199) - Opps!
CE (206) - Roar

D2 (210) - Demo 1
D4 (212) - Dance
D3 (211) - Demo 2
D0 (208) - All Demo
D1 (209) - Power Off