Archiv verlassen und diese Seite im Standarddesign anzeigen : Anschluss von Infrarotsensoren
proevofreak
10.01.2009, 19:23
Hallo, ich werde meinen RP6 demnächst mit 2 Infrarotsensoren, wie sie ja bereits einfach vorhanden sind, ausstatten.
Dazu habe ich mir gerade den Schaltplan des RP6 angeschaut.
Leider ist mir so einiges unklar, was den Anschluss und die Programmierung betrifft
Kann mir jemand vielleicht mal grob in worten schildern wie man eine Hindernisserkennung mit 2 sendern und einem empfänger programmieren muss?
gruß
RP6conrad
11.01.2009, 21:08
Das ACS-system von der RP6 functioniert anhand einer IR-empfanger die nur reagiert auf eine IR-signal das moduliert ist mit 36 kHz. Nur wen dieses Signal den Empfanger trefft, wird das weitergegeven an der Mega32. Die IR-Leds Links und Rechts senden exact auf diese 36 kHz, aber erst gibt der Linker Diode ein Anzahl von Pulsen, und dan der Rechter Diode. Da das alles von Mega32 gesteuert werd, ist das dan auch klar auf welche Sendesignalen die Empfanger reagiert.
Das programmieren von eine zweite ACS-system geht, aber ist nicht so einfach. Zum Empfanger brauch men am besten eine Interrupteingang (nicht mehr Forhanden bei RP6 gelaube ich). Zum Senden zwei freie Ports. Aufgepasst : max 20 mA/port !! Siehe auch die Lib von RP6 an. Das ist recht komplieziert, da auch der RC5 Code decodiert werd in diese Functionen (ACS). Ohne RC5 ist das einfacher machbar.
proevofreak
11.01.2009, 22:54
also, hab ich das jetzt richtig verstanden?
es sendet zuerst die linke sendediode ir und dann die rechte und immer so weiter?
und links wäre dann zum beispiel ein hindernis, wenn der ir- empfänger während dem senden der linken sendediode ir- strahlung empfangen würde.
wenn ich das baue ist das bisherige ir eh ausgeschaltet weil ich es nur zur teilerkennung für meinen greifer brauche. das von dir geschilderte problem existiert also da drum nicht.
die ir- sender sind beim rp6 so unverständlich angeschlossen.
kann ich das eine ende einer sendediode einfach jeweils an einen eigenen mikrocontrollerausgang anschließen und die anderen enden masse?
müsste doch eigentlich funktionieren, oder?
gruß
gruß
RP6conrad
12.01.2009, 19:10
Frage 1 und 2 : ja,richtig verstanden.
Frage 3 :
Nein. Minimal braucht du eine Wiederstand von ca 250 ohm in serien mit der IR-sende diode. Ansonst ueberschreitet die Strom 20 mA und geht die Ausgang von µ kaputt.
Zweitens sollst du auch eine Art von Modulation verwenden, ansonst reagiert der Empfanger auch auf "Fremdlicht" wie Sonneschein.
Eine einfachere Alternative sond die Sharp GP2 IR Sensoren : Kannst du einfach anschliessen an ADC0/ADC1 und geben ihnen dan auch die Abstand von Hinderniss !! Auch die Farbe von Hinderniss hat dan kaum Einfluss mehr. Diese Sensoren kosten ca 12 €.
hi! ich kann dir nur die IR-Sensoren von Sharp empfehlen. Ich hab schon mit mehreren GP2D12 gearbeitet, die muss man mithilfe des ADCs auslesen. Diese Teile haben eine super Auflösung, und du bekommst zwischen 10 und 80cm fast centimetergenaue Abstände raus. Die Sensoren gibt es auch mit I2C-Ausgang, wenn du ADCs sparen willst, mit der I2C-Version hab ich allerdings noch nie was gemacht..
Der Anschaffungspreis ist recht hoch, aber im Gegensatz zum Eigenbau musst du dir selbst keine Sorgen über Modulation und Messung machen..
proevofreak
14.01.2009, 17:26
danke für eure vorschläge,
ich werde mir die sharpsensoren aber trotzdem nicht anschaffen.
ich will ja schließlich selber richtig c programmieren lernen, und drum werd ich das ganze mit 2 sendedioden ld271 und dem entsprechendem 16 khz empfänger programmieren.
hat nicht nur den vorteil, dass es günstiger ist, sondern auch noch den vorteil, dass ich daraus mehr lerne als mit fertigen sensoren.
der rp6 ist in meinen augen eh ein lernroboter.
viel zu schade, um ihn nur für ein projekt zu erweitern und dann immer so belassen.
gruß
proevofreak
15.01.2009, 17:53
für die ansteuerung von den ir- sendedioden muss ich ja ein 16khz signal erzeugen.
wenn ich das in der anleitung richtig gelesen habe besitzt der sleep- timer die kleinste auflösung.
aber auch mit diesem timer lässt sich so kein 16 khz signal erzeugen.
muss ich dass dann mit rechenanweisungen machen?
zu erklärung: ich weiß, dass es bereits ein fertiges makro in der rp6 lib gibt, aber auf das will ich nicht zurückgreifen, weil ich die ansteuerung selber programmieren will.
gruß
RP6conrad
15.01.2009, 20:37
OK. Stichwort hier sind die hardwaretimer von der µ. Der MEGA32 hat 3 solche Timer (counter), 2*8 bit und 1*16 bit. Diese Timer konnen hoch oder unterzahlen auf eine bestimmte Teilfrequenz von der hauptakt. So mit der Haupttakt von 8 MHz kansst du zahlen an 8MHz oder ein teilfactor davon (prescaler). Mit hilfe von bestimmte register (OCR) konnen dan bei bestimmte ergebnissen etwas getan wirden. Sage mal diesen 8 bit counter lauft mit ein prescaler von 8. Dan ist seine Frequenz 1 MHz. In 1 mS zaehlt er dan hoch bis 1000.... Leiter gibt nur 8 bit, nach 255 fangt das wieder von 0 an... Lassen wir mal bei Zahlerwert 200 eine Ausgang toggle (wechseln von Zustand) und der Zaehler zuruck auf 0 setzen. Dan schaltet diese Ausgang mit 5000 Hz !! Zahler rucksetzen bei 50 gibt dan schon 20000 Hz.
Leiter sind alle 3 Timer bei den RP6 schon genutzt für : PWM Motoren, ACS - RC5 Functionen, Stopwatches und Timer Functionen.
Aber du muss sicher mal die RP6lib ansehen. Das nutzen von diese Timer ist nicht so gans einfach. Bestimmte Register mussen richtig gesetzt werden, interrupts sub routines (ISR) mussen programmiert werden. Aber mit Hilfe von das gut documentierte Lib von RP6, und das datasheet von der ATMega32 ist das zu verstehen.
proevofreak
12.12.2009, 22:56
so, nach längerer abstinenz in diesem thread mache ich mich meinen rp6 nun mit einem ir kollissionssensor ausgestattet.
siehe hier:
http://img37.imageshack.us/img37/2290/1001323p.th.jpg (http://img37.imageshack.us/i/1001323p.jpg/)
empfänger und sender sind die selben wie bei der RP6 Base.
die 36 KHz möchte ich über den freien Timer 1 auf der M32 mittels CTC modus erzeugen.
dazu hab ich die controllib.c folgendermaßen abgeändert:
TCCR1B = (0 << ICNC1)
| (0 << ICES1)
| (0 << WGM13)
| (1 << WGM12)
| (0 << CS12)
| (0 << CS11)
| (1 << CS10);
OCR1A = 221;
// Timer 2 - used for beeper:
TCCR2 = 0;
OCR2 = 0xFF;
// Enable timer interrupts:
TIMSK = (1 << OCIE0)|(1<<OCIE1A);
sei();
mein programmcode dazu sieht bisher so aus:
#include "RP6ControlLib.h"
uint8_t a;
ISR(TIMER1_COMPA_vect)
{
PORTD ^= PD5;
writeString_P("\Interrupt Timer1 Compare");
}
void infrarotempfang(void)
{if (PINC & PC3)
{
a++;}
if (a >100)
{writeString_P("\Infrarot empfangen");
startStopwatch1();}
if (getStopwatch1() >1000)
{setStopwatch1(0);}
}
int main(void)
{initRP6Control();
DDRD |= PD5; //PD5 als Ausgang
DDRC &=~ PC3; //PC3 als Eingang
while(true)
{
infrarotempfang();
}
return 0;
}
obwohl ich mittlerweile das datenblatt der M32 genau seziert habe, löst mein timer 1 immer noch keinen interrupt aus. die einstellungen hab ich genauestens überprüft.
kann es sein, dass der interrupt irgendwo an anderer stelle in der controllib blockiert wird?
gruß
radbruch
13.12.2009, 00:36
Hallo
Ich bin im Moment zu faul dein Timersetup nachzuprüfen, weil ich die Bedeutung der einzelnen Bits im TCCR1B-Register nicht auswendig kenne. Hier wäre es sehr hilfreich, wenn du dazu ein paar Kommentare einfügen würdest...
Was mir aber sofort aufgefallen ist: Du setzt bzw. prüfst die Pins der Ports nicht richtig. Die Basis bildet die Definitionen in der entsprechenden io.h-Datei, für den Mega32 auf dem M32 befinden sich die in der Datei iom32.h im avr-Pfad. Hier der entsprechende Abschnitt für Port C/D:
/* PORTC */
#define PC7 7
#define PC6 6
#define PC5 5
#define PC4 4
#define PC3 3
#define PC2 2
#define PC1 1
#define PC0 0
/* DDRC */
#define DDC7 7
#define DDC6 6
#define DDC5 5
#define DDC4 4
#define DDC3 3
#define DDC2 2
#define DDC1 1
#define DDC0 0
/* PINC */
#define PINC7 7
#define PINC6 6
#define PINC5 5
#define PINC4 4
#define PINC3 3
#define PINC2 2
#define PINC1 1
#define PINC0 0
/*
PD7 = OC2
PD6 = ICP
PD5 = OC1A
PD4 = OC1B
PD3 = INT1
PD2 = INT0
PD1 = TXD
PD0 = RXD
*/
/* PORTD */
#define PD7 7
#define PD6 6
#define PD5 5
#define PD4 4
#define PD3 3
#define PD2 2
#define PD1 1
#define PD0 0
Wenn du auf einen bestimmten Pin eines Ports mit DDRx, PORTx oder PINx zugreifen willst, musst du dazu die Wertigkeit des Pins verwenden und nicht seine Nummer! PC3 ist z.B. das dritte Bit (Zählung startet bei 0!) mit dem Wert 2^3 oder 8. Um diesen Pin einzulesen muss die Abfrage deshalb so aussehen:
if(PINC & 8)...
Deshalb verwendet man hier die Bitschieberei um das richtige Bit anzusprechen. (1<<PC3) schreibt die 1 ganz rechts in das Byte und schiebt es dann 3 mal nach links. Das ergibt genau die 8:
if(PINC & (1<<PC3))...
Das gilt dann auch hier:
PORTD ^= (1<<PD5);
DDRD |= (1<<PD5); //PD5 als Ausgang
DDRC &=~ (1<<PC3); //PC3 als Eingang
Hier habe ich das kapiert:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=295604#295604
Vielleicht löst das dann schon dein Problem.
Gruß
mic
proevofreak
13.12.2009, 12:11
danke radbruch für deinen vorschlag mit den bits, hab ich wohl irgendwie total vergessen, dass man das so machen muss.
jetzt ändert sich immerhin schon mal die spannung an meiner ir sendediode.
im standby betrieb beträgt diese an der diode etwa 1V. im betrieb sinkt diese nun auf 0,6 V.
was allerdings auch sehr komisch ist, ist die tatsache, dass das writeString_P("\Interrupt Timer1 Compare");, welches in jedem interrupt angezeigt werden sollte, während des laufenden programms nie erscheint und nur beim beenden des programmes einmal im terminal angezeigt wird.
ist das normal?
außerdem empfängt mein ir- empfänger keine ir- signale. als vorwiderstand für den ir- sender habe ich einen 100 ohm widerstand eingelötet.
der ir- empfänger habe ich wie im schaltplan des rp6Base angeschlossen.
gibt es vielleicht irgendeine möglichkeit z.b. über den rp6loader zu sehen, ob ein ausgang gepulst wird, bzw. ob ein interrupt ausgelöst wird?
mfg andi
proevofreak
13.12.2009, 12:31
ich bins nochmal,
heut ist wohl nicht mein tag. ich habe bei den writeString(...) das \n am ende vergessen. nun habe ich das korrigiert und jetzt kann ich im terminal sehen, dass mein interrupt funktioniert.
nur empfängt mein ir empfänger immer noch keine ir- singale.
an was kann das liegen?
mfg
radbruch
13.12.2009, 12:52
Hallo
Das Timersetup erscheint mir in Ordnung (kleines Lob für die 72kHz;)
Mit einer Digicm oder einem Fotohandy sollte man die glimmende IR-Led erkennen können. Eine noch einfacherer Methode wäre eine sichtbare Led in der ISR mitzutakten (oder einfach nur einzuschalten um zu testen, ob die ISR überhaupt aufgerufen wird):
ISR(TIMER1_COMPA_vect)
{
PORTD ^= PD5;
sichtbareLed ^= sichtbareLed;
}
btw. schaltet der IR-Empfänger seinen Ausgang auf low wenn er etwas empfängt.
Gruß
mic
proevofreak
27.12.2009, 22:34
so, jetzt habe ich meine ganze isr nochmal überarbeitet. in einem anderen internetforum habe ich gelesen, dass das agc des ir- empfängers zu macht, es dauerhaft ir- impulse empfängt. kann mir jemand ähnliches bestätigen?
darum habe ich jetzt die isr abgeändert, und eine zyklische pulspause eingefügt.
wenn ich nun mit einer handykamera die ir- led beobachte, kann ich ein blinken erkennen. d.h. die ansteuerung der ir- led funktioniert so weit.
nur leider empfängt mein ir- empfänger immer noch keine ir- signale.
letztens habe ich mit einem alten oszi (weiß leider nicht ob es korrekt funktioniert) die pulsfrequenz ir signale gemessen (vor der abänderung des programms auf pulpausen). da habe ich eine pulsfrequenz von 72Hz gemessen. also genau um den faktor 1000 die falsche.
darum die frage, ob vielleicht jemand mal meine timereinstellung überprüfen kann:
// Timer 1 erweiterung
TCCR1B = (0 << ICNC1)
| (0 << ICES1)
| (0 << WGM13)
| (1 << WGM12)
| (0 << CS12)
| (0 << CS11)
| (1 << CS10);
OCR1A = 221;
// Timer 2 - used for beeper:
TCCR2 = 0;
OCR2 = 0xFF;
// Enable timer interrupts:
TIMSK = (1 << OCIE0)|(1<<OCIE1A);
sei();
mein abgeändertes programm:
#include "RP6ControlLib.h"
uint8_t a;
uint8_t interruptcounter;
ISR(TIMER1_COMPA_vect)
{interruptcounter++;
if(interruptcounter <51)
{PORTD ^= (1<<PD5);
writeString_P("Interrupt Timer1 Compare\n");}
if(interruptcounter > 50)
{writeString_P("Interrupt Pause\n");}
if(interruptcounter > 80)
{interruptcounter =0;}
}
void infrarotempfang(void)
{if (PINC & (1<<PC3))
{
a++;
}
if (a >100)
{writeString_P("Infrarot empfangen\n");
startStopwatch1();}
if (getStopwatch1() >1000)
{setStopwatch1(0);}
}
int main(void)
{initRP6Control();
DDRD |= (1<<PD5); //PD5 als Ausgang
DDRC &=~ (1<<PC3); //PC3 als Eingang
while(true)
{
infrarotempfang();
}
return 0;
}
bin um jede hilfe dankbar.
mfg andi
proevofreak
29.12.2009, 17:06
so, nach weitereim rumtüfteln bin ich nun zu dem entschluss gekommen, dass irgendetwas an meiner timereinstellung nicht passen kann.
bei folgendem programm müsste die ir- pulspause nach meiner berechnung 690µs betragen. wenn ich das programm aber teste beträgt sie geschätzt nur etwa 0,1s.
irgendwie habe ich langsam das gefühl, dass mein oszi mit den 72Hz doch richtig misst und mein timer um den faktor 1000 falsch eingestellt ist...
hier die timereinstellung:
// Timer 1 erweiterung
TCCR1B = (0 << ICNC1)
| (0 << ICES1)
| (0 << WGM13)
| (1 << WGM12)
| (0 << CS12)
| (0 << CS11)
| (1 << CS10);
OCR1A = 221;
// Timer 2 - used for beeper:
TCCR2 = 0;
OCR2 = 0xFF;
// Enable timer interrupts:
TIMSK = (1 << OCIE0)|(1<<OCIE1A);
sei();
mein programm:
#include "RP6ControlLib.h"
uint8_t a;
uint8_t interruptcounter;
ISR(TIMER1_COMPA_vect)
{interruptcounter++;
if(interruptcounter <50)
{PORTD ^= (1<<PD5);
writeString_P("Interrupt Timer1 Compare\n");}
if(interruptcounter > 50 && interruptcounter <101)
{writeString_P("Interrupt Pause\n");}
if(interruptcounter > 100)
{interruptcounter =0;}
}
void infrarotempfang(void)
{if (PINC & (1<<PC3))
{
a++;
}
if (a >100)
{writeString_P("Infrarot empfangen\n");
startStopwatch1();}
if (getStopwatch1() >1000)
{setStopwatch1(0);}
}
int main(void)
{initRP6Control();
DDRD |= (1<<PD5); //PD5 als Ausgang
DDRC &=~ (1<<PC3); //PC3 als Eingang
while(true)
{
infrarotempfang();
}
return 0;
}
was meint ihr dazu?
weiß langsam nicht mehr weiter....
mfg andi
proevofreak
03.01.2010, 17:10
so, jetzt habe ich mich nochmal über die infrarotsensorik schlau gemacht. aber ich scheiter immer noch an einem grundlegenden problem. und zwar erkennt die M32 irgendwie nicht meinen port PC3 als eingang.
das dürfte auch das problem sein, warum sie keinen infrarotempfang meldet.
ich komm mir richtig blöd vor das zu fragen, weil ich nicht das erste mal einen port als eingang verwende. aber ich habe gerade +5Volt auf meinen eingang PC3 gebrückt und dieser aber scheinbar nichts registriert.
scheinbar steh ich gerade extrem auf der leitung. hier das programm:
#include "RP6ControlLib.h"
uint8_t a;
uint8_t interruptcounter;
ISR(TIMER1_COMPA_vect)
{interruptcounter++;
if(interruptcounter <21)
{PORTD ^= (1<<PD5);
writeString_P("Interrupt Timer1 Compare\n");}
if(interruptcounter > 20 && interruptcounter <41)
{writeString_P("Interrupt Pause\n");}
if(interruptcounter == 41)
{interruptcounter =0;}
}
void infrarotempfang(void)
{if (PINC & (1<<3))
{writeString_P("eingang PC3 high\n");
a++;
}
if (a >100)
{writeString_P("Infrarot empfangen\n");
startStopwatch1();}
if (getStopwatch1() >1000)
{setStopwatch1(0);}
}
int main(void)
{initRP6Control();
DDRD |= (1<<PD5); //PD5 als Ausgang
DDRC &=~ (1<<3); //PC3 als Eingang
while(true)
{
infrarotempfang();
}
return 0;
}
was ist hier falsch? ich glaub ich versteh die welt nicht mehr....
mfg andi
proevofreak
05.02.2010, 17:55
so, die semesterferien machen es möglich. nun ist mein ir kollissionsumbau fertig und funktioniert auch.
allerdings habe ich meine schaltung noch einmal ein wenig abgeändert um eine höhere reichweite zu erreichen. nun jetzt steuere ich die ir led über einen transistor, wessen basis über einen 1K widerstand mit meinem µc ausgang verbunden ist. den kollektor habe ich über ein 500 ohm poti mit VDD verbunden. so kann ich die reichweite einstellen. die ir led hängt nun ohne weiteren widerstand an emitter und masse.
konkret schaut das ganze nun so aus:
http://img211.imageshack.us/img211/4489/1001329f.jpg
damit erreiche ich nun eine maximal reichweite von gut 20cm.
nun möchte ich mit dieser sensorik ein inrarotradar bauen. d.h. ich möchte die sensorik mittels eines servos ständig langsam drehen und dadurch die nähere umgebung des roboters abzuscannen und so hindernissen ausweichen.
nun ist es so, dass ich ja die ir sensorik über den timer 1 der M32 ansteuere und für die servoansteuerung dirks servolib verwenden möchte.
da aber dirks servolib für die M32 schon den timer1 belegt, würde ich gerne den servo über die base ansteuern, d.h. mit dirks servobaselib.
nun meine frage: kann ich mit einem programm auf der M32 gleichzeitig mein ir system ansteuern und gleichzeitig einen servo, welcher an der base angeschlossen ist?
oder muss ich für den servo das RP6_Slave programm noch erweitern und dann zusätzlich mit einem programm auf der M32 das ir ansteuern?
wie ist es am leichtesten so etwas zu realisieren?
mfg andi
Hallo andi,
wenn du willst, kannst du auch meine Servo Lib für die M32 nehmen.
Du kannst in der Lib F_TIMER1 auf die Frequenz ändern, die du für deinen IR-Empfang brauchst (bei 72 kHz müßte F_TIMER1 = 72000 gesetzt werden, OCR1A wird dann automatisch 28 ).
Deinen IR-Empfang könntest du dann in die ISR einklinken. Die neuen Servo-Grenzwerte kannst du ohne Probleme ausrechnen (siehe die Header-Datei der Lib!). Die Auflösung der Servo-Schritte ist mit der geringeren Timer1-Frequenz natürlich nicht mehr so groß,- müßte aber reichen.
Gruß Dirk
proevofreak
05.02.2010, 22:01
gute idee dirk,
das ist dann wohl auch die einfachste lösung. allerdings errechne ich für den OCR1A einen wert von 26,77 bei einem abgeänderten wert von 72000 für F_TIMER1.
das ist wahrscheinlich auch der grund, warum du dem µc den OCR1A mit der formel berechnen lässt, und nicht gleich 19 hineinschreibst.
bis gerade eben habe ich gedacht, dass der µc für den wert des OCR1A nur gerade werte zulässt.
dann muss ich jetzt ja eigentlich nur noch neue werte für die impulslängen der servopulse ausrechnen und die dann in der lib abändern.
klasse idee \:D/
dann muss ich jetzt ja eigentlich nur noch neue werte für die impulslängen der servopulse ausrechnen und die dann in der lib abändern.
Ja, exakt.
Für LEFT_TOUCH würde ich mit 50 anfangen zu testen, für RIGHT_TOUCH mit 116.
Gruß Dirk
proevofreak
06.02.2010, 11:51
also dirk, jetzt habe ich mich mal an das abändern deiner servolib für die M32 gemacht.
als erstes war mein ziel, dass mein ir system nach wie vor funktioniert, nach dem ich es in deine isr eingebunden habe.
allerdings habe ich da festgestellt, dass in task_SERVO() dein interrupt aus- und eingeschaltet wird.
darum habe ich das abschalten aus der lib rausgeworfen, damit der Interrupt immer ausgelöst wird und mein ir system dauerhaft arbeitet.
darum habe ich deinen wert der PULS_REPETITION auf 20 abgeändert und das mSleep(3) im demoprogramm weggelassen.
mein IR system arbeitet nun wieder so wie früher.
dann habe ich die werte von LEFT_TOUCH auf 50 und RIGHT_TOUCH auf 116 abgeändert.
anschließend habe ich an PC4 noch einen Servo zum testen angeschlossen.
das ganze schaut nun so aus:
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> RP6 CONTROL
* ----------------------------------------------------------------------------
* ------------------------ [c]2008 - Dirk ------------------------------------
* ************************************************** **************************
* File: RP6ControlServoLib.h
* Version: 1.0
* Target: RP6 CONTROL - ATMEGA32 @16.00MHz
* Author(s): Dirk
* ************************************************** **************************
* Description:
* This is the RP6ControlServoLib header file.
* You have to include this file, if you want to use the library
* RP6ControlServoLib.c in your own projects.
*
* ************************************************** **************************
* THE CHANGELOG CAN BE FOUND AT THE END OF THIS FILE!
* ************************************************** **************************
*/
/************************************************** ***************************/
// Includes:
#include "RP6ControlLib.h" // The RP6 Control Library.
// Always needs to be included!
/************************************************** ***************************/
// Defines:
// Servo constants:
#define SERVO1 0b00000001
#define SERVO2 0b00000010
#define SERVO3 0b00000100
#define SERVO4 0b00001000
#define SERVO5 0b00010000
#define SERVO6 0b00100000
#define SERVO7 0b01000000
// Servo movement limits (depending on servo type):
// Standard servos need an impulse every 20ms (50Hz). This impulse must have
// a length of 1ms (0.7 .. 1ms) to move the servo lever to the left touch
// and a length of 2ms (2 .. 2.3ms) for moving it to the right touch. In the
// middle position the servo needs an impulse length of 1.5ms (1.3 .. 1.6ms).
// If you want to modify the following constants for a certain servo type,
// you must adapt the LEFT_TOUCH constant first (values ~70 .. 100 = ~0.7 ..
// 1ms at 100kHz) by using a servo position value (servoX_position) of zero.
// After that you have two "screws" to adjust the servo movement limits:
// First you may change the RIGHT_TOUCH constant. If you choose a higher
// value than 255, you will use 16-bit values. Higher values mean a longer
// impulse length, but longer impulses than 2.3ms do not make sense.
// Second you may alter the Timer 1 frequency constant (F_TIMER1).
// A higher frequency leads to smaller steps of the servo movement. This of
// course reduces the impulse length and may be compensated again by a higher
// RIGHT_TOUCH constant. As a possible range of Timer 1 frequency values you
// may use 50kHz (20us) .. 105.263kHz (9.5us).
// HINT: If you alter F_TIMER1, you'll have to adapt LEFT_TOUCH and
// RIGHT_TOUCH again as you can see in the following table!
// Steps -> 9.5 10 12.5 15 17.5 20 [us]
// ------------------------------------------------------------------
// LEFT_TOUCH 74 71 57 47 41 35
// RIGHT_TOUCH 169 162 129 107 92 80
// F_TIMER1 105263 100000 80000 66667 57143 50000 [Hz]
#define LEFT_TOUCH 50 // Left servo touch abgeändert
#define RIGHT_TOUCH 116 // Right servo touch abgeändert
#define MIDDLE_POSITION (RIGHT_TOUCH / 2) // Middle position (~1.5ms)
#define PULSE_REPETITION 20 // Pulse repetition freq. (~50Hz)
#define F_TIMER1 72000 // abgeändert auf 72khz
// Servo ports:
#define SERVO1_PULSE_ON (PORTC |= IO_PC2) // PC2
#define SERVO1_PULSE_OFF (PORTC &= ~IO_PC2)
#define SERVO2_PULSE_ON (PORTC |= IO_PC3) // PC3
#define SERVO2_PULSE_OFF (PORTC &= ~IO_PC3)
#define SERVO3_PULSE_ON (PORTC |= IO_PC4) // PC4
#define SERVO3_PULSE_OFF (PORTC &= ~IO_PC4)
#define SERVO4_PULSE_ON (PORTC |= IO_PC5) // PC5
#define SERVO4_PULSE_OFF (PORTC &= ~IO_PC5)
#define SERVO5_PULSE_ON (PORTC |= IO_PC6) // PC6
#define SERVO5_PULSE_OFF (PORTC &= ~IO_PC6)
#define SERVO6_PULSE_ON (PORTC |= IO_PC7) // PC7
#define SERVO6_PULSE_OFF (PORTC &= ~IO_PC7)
#define SERVO7_PULSE_ON (PORTD |= IO_PD5) // PD5
#define SERVO7_PULSE_OFF (PORTD &= ~IO_PD5)
// -----------------------------------------------------------
// Other possible ports for connecting servos to RP6Control:
//#define SERVOx_PULSE_ON (PORTA |= ADC6) // PA6
//#define SERVOx_PULSE_OFF (PORTA &= ~ADC6)
//#define SERVOx_PULSE_ON (PORTA |= ADC7) // PA7
//#define SERVOx_PULSE_OFF (PORTA &= ~ADC7)
// -----------------------------------------------------------
/************************************************** ***************************/
// Variables:
uint16_t servo1_position; // Servo 1 position [0..RIGHT_TOUCH]
uint16_t servo2_position; // Servo 2 position [0..RIGHT_TOUCH]
uint16_t servo3_position; // Servo 3 position [0..RIGHT_TOUCH]
uint16_t servo4_position; // Servo 4 position [0..RIGHT_TOUCH]
uint16_t servo5_position; // Servo 5 position [0..RIGHT_TOUCH]
uint16_t servo6_position; // Servo 6 position [0..RIGHT_TOUCH]
uint16_t servo7_position; // Servo 7 position [0..RIGHT_TOUCH]
/************************************************** ***************************/
// Functions:
void initSERVO(uint8_t servos);
void startSERVO(void);
void stopSERVO(void);
void pulseSERVO(void);
void task_SERVO(void);
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 31.12.2008 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
// EOF
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> RP6 CONTROL
* ----------------------------------------------------------------------------
* ------------------------ [c]2008 - Dirk ------------------------------------
* ************************************************** **************************
* File: RP6ControlServoLib.c
* Version: 1.0
* Target: RP6 CONTROL - ATMEGA32 @16.00MHz
* Author(s): Dirk
* ************************************************** **************************
* Description:
* This is my simple RP6 Control Servo Library for up to 8 Servos.
*
* COMMENT: It is a good idea to use a separate power supply for the servos!
*
* Servo connections:
* SERVO1 -> I/O Pin 7 (IO_PC2) SERVO5 -> I/O Pin 4 (IO_PC6)
* SERVO2 -> I/O Pin 5 (IO_PC3) SERVO6 -> I/O Pin 1 (IO_PC7)
* SERVO3 -> I/O Pin 6 (IO_PC4) SERVO7 -> I/O Pin 9 (IO_PD5)
* SERVO4 -> I/O Pin 3 (IO_PC5)
*
* ************************************************** **************************
* ATTENTION: Stopwatch 1 is used for the servo task! Please do
* not use this stopwatch elsewhere in your program!
*
* ************************************************** **************************
* THE CHANGELOG CAN BE FOUND AT THE END OF THIS FILE!
* ************************************************** **************************
*/
/************************************************** ***************************/
// Includes:
#include "RP6ControlServoLib.h"
/************************************************** ***************************/
// Variables:
uint8_t usedservos;
uint8_t servo_on = FALSE;
uint8_t interruptcounter; //abgeändert
uint16_t impulselength1 = 0;
uint16_t impulselength2 = 0;
uint16_t impulselength3 = 0;
uint16_t impulselength4 = 0;
uint16_t impulselength5 = 0;
uint16_t impulselength6 = 0;
uint16_t impulselength7 = 0;
volatile uint16_t intcounter = 0;
/************************************************** ***************************/
// Functions:
/**
* INIT SERVO
*
* Call this once before using the servo function.
* Timer 1 is configured to work in "Clear Timer On
* Compare Match Mode" (CTC). So no PWM is generated!
* The timer runs on a fixed frequency (100kHz).
*
* Input: servos -> Used servos
* Examples:
* - initSERVO(SERVO1 | SERVO2) -> Use only servos 1 and 2
* - initSERVO(SERVO1 | SERVO6) -> Use only servos 1 and 6
* - initSERVO(SERVO1 | SERVO2 | SERVO8) -> Use servos 1, 2 and 8
*
*/
void initSERVO(uint8_t servos)
{
usedservos = servos; // Save used servos
impulselength1 = 0;
impulselength2 = 0;
impulselength3 = 0;
impulselength4 = 0;
impulselength5 = 0;
impulselength6 = 0;
impulselength7 = 0;
if (servos & SERVO1) {DDRC |= IO_PC2; PORTC &= ~IO_PC2;}
if (servos & SERVO2) {DDRC |= IO_PC3; PORTC &= ~IO_PC3;}
if (servos & SERVO3) {DDRC |= IO_PC4; PORTC &= ~IO_PC4;}
if (servos & SERVO4) {DDRC |= IO_PC5; PORTC &= ~IO_PC5;}
if (servos & SERVO5) {DDRC |= IO_PC6; PORTC &= ~IO_PC6;}
if (servos & SERVO6) {DDRC |= IO_PC7; PORTC &= ~IO_PC7;}
if (servos & SERVO7) {DDRD |= IO_PD5; PORTD &= ~IO_PD5;}
// -----------------------------------------------------------
// Other possible ports for connecting servos to RP6Control:
// if (servos & SERVOx) {DDRA |= ADC6; PORTA &= ~ADC6;}
// if (servos & SERVOx) {DDRA |= ADC7; PORTA &= ~ADC7;}
// -----------------------------------------------------------
cli();
// Timer 1: Normal port operation, mode 4 (CTC), clk/8
TCCR1A = (0 << COM1A1)
| (0 << COM1A0)
| (0 << COM1B1)
| (0 << COM1B0)
| (0 << FOC1A)
| (0 << FOC1B)
| (0 << WGM11)
| (0 << WGM10);
TCCR1B = (0 << ICNC1)
| (0 << ICES1)
| (0 << WGM13)
| (1 << WGM12)
| (0 << CS12)
| (1 << CS11)
| (0 << CS10);
OCR1A = ((F_CPU/8/F_TIMER1)-1); // abgeändert auf 26,777
// ------------------------------------------------------
// Possible OCR1A values (F_CPU = 16000000):
// OCR1A = 2000000 / F_TIMER1 - 1 // F_TIMER1 (Steps)
// OCR1A = 18; // 105263Hz (9.5us)
// OCR1A = 19; // 100000Hz (10us)
// OCR1A = 24; // 80000Hz (12.5us)
// OCR1A = 29; // 66667Hz (15us)
// OCR1A = 34; // 57143Hz (17.5us)
// OCR1A = 39; // 50000Hz (20us)
// ------------------------------------------------------
// Enable output compare A match interrupts:
startSERVO();
sei();
startStopwatch1(); // Needed for 20ms pulse repetition
}
/**
* START SERVO
*
* If the servo function was stopped with the
* function stopSERVO() before, it can be
* started again with this function.
*
*/
void startSERVO(void)
{
TIMSK |= (1 << OCIE1A);
servo_on = TRUE;
}
/**
* STOP SERVO
*
* The servo function uses a certain amount of the
* processor's calculating time. If the servos are
* not moving for a while, the Timer 1 interrupt
* can be stopped with this function.
*
*/
void stopSERVO(void)
{
TIMSK &= ~(1 << OCIE1A);
servo_on = FALSE;
}
/**
* PULSE SERVO
*
* This is the servo pulse generation. This function
* must be called every 20ms (pulse repetition).
*
* position = 0 : Left touch
* position = RIGHT_TOUCH : Right touch
* position = MIDDLE_POSITION : Middle position
*
* ! Please make sure in your main program, that the !
* ! servo position values (servoX_position) don't !
* ! exceed RIGHT_TOUCH!!! !
*
* COMMENT: The pulses are only started here!
* The pulses end in the Timer 1 ISR!
*
*/
void pulseSERVO(void)
{
if (servo_on) {
intcounter = RIGHT_TOUCH; // Avoid interference of Timer 1 ISR!
// (Only necessary, if pulseSERVO() is called
// from outside of this library!)
if (usedservos & SERVO1) {
SERVO1_PULSE_ON; impulselength1 = LEFT_TOUCH + servo1_position;}
if (usedservos & SERVO2) {
SERVO2_PULSE_ON; impulselength2 = LEFT_TOUCH + servo2_position;}
if (usedservos & SERVO3) {
SERVO3_PULSE_ON; impulselength3 = LEFT_TOUCH + servo3_position;}
if (usedservos & SERVO4) {
SERVO4_PULSE_ON; impulselength4 = LEFT_TOUCH + servo4_position;}
if (usedservos & SERVO5) {
SERVO5_PULSE_ON; impulselength5 = LEFT_TOUCH + servo5_position;}
if (usedservos & SERVO6) {
SERVO6_PULSE_ON; impulselength6 = LEFT_TOUCH + servo6_position;}
if (usedservos & SERVO7) {
SERVO7_PULSE_ON; impulselength7 = LEFT_TOUCH + servo7_position;}
intcounter = 0;
}
}
/**
* TIMER1 ISR
*
* In this ISR the servo pulses are finished, if the
* correct pulse length of each servo is reached.
*
*/
ISR (TIMER1_COMPA_vect)
{interruptcounter++; //abgeändert
if(interruptcounter <21)
{DDRD |= (1<<PD5); //PD5 als Ausgang
PORTD ^= (1<<PD5);
}
if(interruptcounter > 20 && interruptcounter <41)
{DDRD &=~ (1<<PD5);
}
if(interruptcounter == 41)
{interruptcounter =0;}
intcounter++;
if (intcounter == impulselength1) {SERVO1_PULSE_OFF;}
if (intcounter == impulselength2) {SERVO2_PULSE_OFF;}
if (intcounter == impulselength3) {SERVO3_PULSE_OFF;}
if (intcounter == impulselength4) {SERVO4_PULSE_OFF;}
if (intcounter == impulselength5) {SERVO5_PULSE_OFF;}
if (intcounter == impulselength6) {SERVO6_PULSE_OFF;}
if (intcounter == impulselength7) {SERVO7_PULSE_OFF;}
}
/**
* SERVO TASK
*
* This is the servo task. The task performes the pulse repetition
* with the help of a stopwatch.
* At the next call of the servo task (earliest about 3ms after the
* last servo pulse generation) the compare A match interrupt will
* be disabled to reduce the interrupt load. It will be enabled
* again after the next pulseSERVO() function call.
*
*/
void task_SERVO(void)
{
if (getStopwatch1() > PULSE_REPETITION) { // Pulse every ~20ms
pulseSERVO(); // Servo pulse generation
setStopwatch1(0);
}
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 31.12.2008 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
// EOF
mein demoprogramm:
// Uncommented Version of RP6ControlServo.c
// ------------------------------------------------------------------------------------------
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
//Servo 1 => PC2
//Servo 2 => PC3
//Servo 3=> PC4
//Servo 4=> PC5
//Servo 5=> PC6
uint16_t a;
uint8_t b;
void infrarotempfang(void)
{if(b==0)
{
if (!(PINC & (1<<PC3)))
{writeString_P("Infrarotempfang ein\n");
writeStringLCD("a=:");
writeString("a=:");
writeInteger(a,DEC);
writeIntegerLCD(a, DEC);
writeChar('\n');
a++; //infrarot empfangen
}}
}
void RP6_Bewegung(void)
{if(a<50)
{changeDirection(BWD);
moveAtSpeed(50,50); //Roboter fährt
}
if(a==50)
{moveAtSpeed(0,0);
startStopwatch2();
b=1;
}
if (getStopwatch2() >0 && getStopwatch2()<2000)
{moveAtSpeed(0,0);
}
if (getStopwatch2()>2000)
{a=0;
b=0;
stopStopwatch2();
setStopwatch2(0);
writeString_P("stopwatch auf 0\n");}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = LEFT_TOUCH;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 30;
writeString_P("servo position 30\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() ==3000)
{stopStopwatch3();
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
int main(void)
{
initRP6Control();
I2CTWI_initMaster(100);
DDRC &=~ (1<<PC3); //PC3 als Eingang infrarotempfänger
a=0; // a anfangs auf 0 setzen
b=0;
initSERVO(SERVO3);
startStopwatch3();
while(true)
{infrarotempfang();
RP6_Bewegung();
servoansteuerung();
task_SERVO();
}
return 0;
}
irgendwas größeres muss aber immer noch falsch sein, denn seit ich das initSERVO(SERVO3) im Demoprogramm habe geht das programm nach dem einschalten sofort wieder in den standby modus, d.h. es lässt sich gar nicht mehr richtig starten.
vielleicht kannst du mir sagen, was ich noch falsch gemacht habe, mit deiner servolib bist du ja bestens vertraut.
danke auf jeden fall schon mal im voraus.
mfg andi
Hallo proevofreak,
ich habe nicht das ganze Programm angesehen.
Wichtig ist auf jeden Fall, die Variable interruptcounter anders zu deklarieren:
volatile uint8_t interruptcounter; //abgeändert
Die task_SERVO muss wahrscheinlich auch öfter aufgerufen werden, weil deine Unterprogramme doch viel Zeit brauchen, bis die Hauptschleife wieder dran kommt.
Gruß Dirk
proevofreak
09.02.2010, 16:16
danke dirk für deine hilfe,
jetzt hab ich das mit dem volatile noch abgeändert und jetzt funktioniert alles.
das zuletzt gepostete problem, dass das programm gar nicht erst startet lag allerdings an etwas anderem, nämlich an dem, dass die akkuspannung nur noch 4,8V betrug.
wenn alles ferig ist, werde ich noch mit bildern und ein video posten.
mfg
proevofreak
15.02.2010, 16:00
so, mein problem mit der gleichzeitigen servosteuerung und ir- empfang habe ich ja nun gelöst.
da ich aber das ir antikollissionssystem als makro in dirks servolib (M32) einbinden will, bin ich heute auf ein neues problem gestoßen.
und zwar habe ich mein bisheriges ir programm überwiegend unverändert in dirks servolib eingebunden.
dazu habe ich in die header datei void infrarotkollission(void) eingefügt.
das infrarotkollission() programm habe ich in die .c datei eingefügt und dazu noch
uint16_t ir_counter; //abgeändert
uint8_t ir_hindernis;
uint8_t ir_erweiterung;
eingefügt:
/* ************************************************** **************************
* _______________________
* \| RP6 ROBOT SYSTEM |/
* \_-_-_-_-_-_-_-_-_-_/ >>> RP6 CONTROL
* ----------------------------------------------------------------------------
* ------------------------ [c]2008 - Dirk ------------------------------------
* ************************************************** **************************
* File: RP6ControlServoLib.c
* Version: 1.0
* Target: RP6 CONTROL - ATMEGA32 @16.00MHz
* Author(s): Dirk
* ************************************************** **************************
* Description:
* This is my simple RP6 Control Servo Library for up to 8 Servos.
*
* COMMENT: It is a good idea to use a separate power supply for the servos!
*
* Servo connections:
* SERVO1 -> I/O Pin 7 (IO_PC2) SERVO5 -> I/O Pin 4 (IO_PC6)
* SERVO2 -> I/O Pin 5 (IO_PC3) SERVO6 -> I/O Pin 1 (IO_PC7)
* SERVO3 -> I/O Pin 6 (IO_PC4) SERVO7 -> I/O Pin 9 (IO_PD5)
* SERVO4 -> I/O Pin 3 (IO_PC5)
*
* ************************************************** **************************
* ATTENTION: Stopwatch 1 is used for the servo task! Please do
* not use this stopwatch elsewhere in your program!
*
* ************************************************** **************************
* THE CHANGELOG CAN BE FOUND AT THE END OF THIS FILE!
* ************************************************** **************************
*/
/************************************************** ***************************/
// Includes:
#include "RP6ControlServoLib.h"
/************************************************** ***************************/
// Variables:
uint8_t usedservos;
uint8_t servo_on = FALSE;
uint16_t impulselength1 = 0;
uint16_t impulselength2 = 0;
uint16_t impulselength3 = 0;
uint16_t impulselength4 = 0;
uint16_t impulselength5 = 0;
uint16_t impulselength6 = 0;
uint16_t impulselength7 = 0;
uint16_t ir_counter; //abgeändert
uint8_t ir_hindernis;
uint8_t ir_erweiterung;
volatile uint8_t interruptcounter; //abgeändert
volatile uint16_t intcounter = 0;
/************************************************** ***************************/
// Functions:
/**
* INIT SERVO
*
* Call this once before using the servo function.
* Timer 1 is configured to work in "Clear Timer On
* Compare Match Mode" (CTC). So no PWM is generated!
* The timer runs on a fixed frequency (100kHz).
*
* Input: servos -> Used servos
* Examples:
* - initSERVO(SERVO1 | SERVO2) -> Use only servos 1 and 2
* - initSERVO(SERVO1 | SERVO6) -> Use only servos 1 and 6
* - initSERVO(SERVO1 | SERVO2 | SERVO8) -> Use servos 1, 2 and 8
*
*/
void initSERVO(uint8_t servos)
{
usedservos = servos; // Save used servos
impulselength1 = 0;
impulselength2 = 0;
impulselength3 = 0;
impulselength4 = 0;
impulselength5 = 0;
impulselength6 = 0;
impulselength7 = 0;
if (servos & SERVO1) {DDRC |= IO_PC2; PORTC &= ~IO_PC2;}
if (servos & SERVO2) {DDRC |= IO_PC3; PORTC &= ~IO_PC3;}
if (servos & SERVO3) {DDRC |= IO_PC4; PORTC &= ~IO_PC4;}
if (servos & SERVO4) {DDRC |= IO_PC5; PORTC &= ~IO_PC5;}
if (servos & SERVO5) {DDRC |= IO_PC6; PORTC &= ~IO_PC6;}
if (servos & SERVO6) {DDRC |= IO_PC7; PORTC &= ~IO_PC7;}
if (servos & SERVO7) {DDRD |= IO_PD5; PORTD &= ~IO_PD5;}
// -----------------------------------------------------------
// Other possible ports for connecting servos to RP6Control:
// if (servos & SERVOx) {DDRA |= ADC6; PORTA &= ~ADC6;}
// if (servos & SERVOx) {DDRA |= ADC7; PORTA &= ~ADC7;}
// -----------------------------------------------------------
cli();
// Timer 1: Normal port operation, mode 4 (CTC), clk/8
TCCR1A = (0 << COM1A1)
| (0 << COM1A0)
| (0 << COM1B1)
| (0 << COM1B0)
| (0 << FOC1A)
| (0 << FOC1B)
| (0 << WGM11)
| (0 << WGM10);
TCCR1B = (0 << ICNC1)
| (0 << ICES1)
| (0 << WGM13)
| (1 << WGM12)
| (0 << CS12)
| (1 << CS11)
| (0 << CS10);
OCR1A = ((F_CPU/8/F_TIMER1)-1); // abgeändert auf 26,777
// ------------------------------------------------------
// Possible OCR1A values (F_CPU = 16000000):
// OCR1A = 2000000 / F_TIMER1 - 1 // F_TIMER1 (Steps)
// OCR1A = 18; // 105263Hz (9.5us)
// OCR1A = 19; // 100000Hz (10us)
// OCR1A = 24; // 80000Hz (12.5us)
// OCR1A = 29; // 66667Hz (15us)
// OCR1A = 34; // 57143Hz (17.5us)
// OCR1A = 39; // 50000Hz (20us)
// ------------------------------------------------------
// Enable output compare A match interrupts:
startSERVO();
sei();
startStopwatch1(); // Needed for 20ms pulse repetition
}
/**
* START SERVO
*
* If the servo function was stopped with the
* function stopSERVO() before, it can be
* started again with this function.
*
*/
void startSERVO(void)
{
TIMSK |= (1 << OCIE1A);
servo_on = TRUE;
}
/**
* STOP SERVO
*
* The servo function uses a certain amount of the
* processor's calculating time. If the servos are
* not moving for a while, the Timer 1 interrupt
* can be stopped with this function.
*
*/
void stopSERVO(void)
{
TIMSK &= ~(1 << OCIE1A);
servo_on = FALSE;
}
/**
* PULSE SERVO
*
* This is the servo pulse generation. This function
* must be called every 20ms (pulse repetition).
*
* position = 0 : Left touch
* position = RIGHT_TOUCH : Right touch
* position = MIDDLE_POSITION : Middle position
*
* ! Please make sure in your main program, that the !
* ! servo position values (servoX_position) don't !
* ! exceed RIGHT_TOUCH!!! !
*
* COMMENT: The pulses are only started here!
* The pulses end in the Timer 1 ISR!
*
*/
void pulseSERVO(void)
{
if (servo_on) {
intcounter = RIGHT_TOUCH; // Avoid interference of Timer 1 ISR!
// (Only necessary, if pulseSERVO() is called
// from outside of this library!)
if (usedservos & SERVO1) {
SERVO1_PULSE_ON; impulselength1 = LEFT_TOUCH + servo1_position;}
if (usedservos & SERVO2) {
SERVO2_PULSE_ON; impulselength2 = LEFT_TOUCH + servo2_position;}
if (usedservos & SERVO3) {
SERVO3_PULSE_ON; impulselength3 = LEFT_TOUCH + servo3_position;}
if (usedservos & SERVO4) {
SERVO4_PULSE_ON; impulselength4 = LEFT_TOUCH + servo4_position;}
if (usedservos & SERVO5) {
SERVO5_PULSE_ON; impulselength5 = LEFT_TOUCH + servo5_position;}
if (usedservos & SERVO6) {
SERVO6_PULSE_ON; impulselength6 = LEFT_TOUCH + servo6_position;}
if (usedservos & SERVO7) {
SERVO7_PULSE_ON; impulselength7 = LEFT_TOUCH + servo7_position;}
intcounter = 0;
}
}
/**
* TIMER1 ISR
*
* In this ISR the servo pulses are finished, if the
* correct pulse length of each servo is reached.
*
*/
ISR (TIMER1_COMPA_vect)
{interruptcounter++; //abgeändert
if(interruptcounter <21)
{DDRD |= (1<<PD5); //PD5 als Ausgang
PORTD ^= (1<<PD5);
}
if(interruptcounter > 20 && interruptcounter <41)
{DDRD &=~ (1<<PD5);
}
if(interruptcounter == 41)
{interruptcounter =0;}
intcounter++;
if (intcounter == impulselength1) {SERVO1_PULSE_OFF;}
if (intcounter == impulselength2) {SERVO2_PULSE_OFF;}
if (intcounter == impulselength3) {SERVO3_PULSE_OFF;}
if (intcounter == impulselength4) {SERVO4_PULSE_OFF;}
if (intcounter == impulselength5) {SERVO5_PULSE_OFF;}
if (intcounter == impulselength6) {SERVO6_PULSE_OFF;}
if (intcounter == impulselength7) {SERVO7_PULSE_OFF;}
}
/**
* SERVO TASK
*
* This is the servo task. The task performes the pulse repetition
* with the help of a stopwatch.
* At the next call of the servo task (earliest about 3ms after the
* last servo pulse generation) the compare A match interrupt will
* be disabled to reduce the interrupt load. It will be enabled
* again after the next pulseSERVO() function call.
*
*/
void task_SERVO(void)
{
if (getStopwatch1() > PULSE_REPETITION) { // Pulse every ~20ms
pulseSERVO(); // Servo pulse generation
setStopwatch1(0);
}
}
void infrarotkollission(void)
{DDRC &=~ (1<<PC3); //PC3 als Eingang infrarotempfänger
if(ir_erweiterung ==0)
{
if (!(PINC & (1<<PC3)))
{writeString_P("Infrarotempfang ein\n");
writeStringLCD("ir_counter=:");
writeString("ir_counter=:");
writeInteger(ir_counter,DEC);
writeIntegerLCD(ir_counter, DEC);
writeChar('\n');
ir_counter++; //infrarot empfangen
}
}
if (ir_counter ==50)
{ir_hindernis = true;
ir_erweiterung = 1;
startStopwatch8();}
if (getStopwatch8()>1000)
{ir_counter =0;
ir_erweiterung =0;
ir_hindernis = false;
stopStopwatch8();
setStopwatch8(0);}
}
/************************************************** ****************************
* Additional info
* ************************************************** **************************
* Changelog:
* - v. 1.0 (initial release) 31.12.2008 by Dirk
*
* ************************************************** **************************
*/
/************************************************** ***************************/
// EOF
und in meinem demoprogramm das ganze aufgerufen:
// Uncommented Version of RP6ControlServo.c
// ------------------------------------------------------------------------------------------
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
//Servo 1 => PC2
//Servo 2 => PC3
//Servo 3=> PC4
//Servo 4=> PC5
//Servo 5=> PC6
void RP6_Bewegung(void)
{if (ir_hindernis)
{writeString_P("objekt erkannt\n");}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 40;
writeString_P("servo position 40\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = 80;}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{servo3_position = 80;}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{servo3_position = 40;}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
int main(void)
{
initRP6Control();
I2CTWI_initMaster(100);
initSERVO(SERVO3);
startStopwatch3();
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
RP6_Bewegung();
}
return 0;
}
nun bringt der compiler aber folgende fehlermeldung:
In file included from IR_Radar.c:7:
../../RP6Lib/RP6common/RP6I2CmasterTWI.h: In function 'inrarotkollission':
../../RP6Lib/RP6common/RP6I2CmasterTWI.h:37: warning: empty declaration
../../RP6Lib/RP6common/RP6I2CmasterTWI.h:45: error: storage class specified for parameter 'TWI_statusReg'
../../RP6Lib/RP6common/RP6I2CmasterTWI.h:47: error: storage class specified for parameter 'i2c_req_adr'
../../RP6Lib/RP6common/RP6I2CmasterTWI.h:48: error: storage class specified for parameter 'TWI_operation'
In file included from IR_Radar.c:8:
RP6Control_I2CMasterLib.h:126: error: storage class specified for parameter 'mleft_speed'
RP6Control_I2CMasterLib.h:127: error: storage class specified for parameter 'mright_speed'
RP6Control_I2CMasterLib.h:130: error: storage class specified for parameter 'mleft_dist'
RP6Control_I2CMasterLib.h:131: error: storage class specified for parameter 'mright_dist'
RP6Control_I2CMasterLib.h:134: error: storage class specified for parameter 'mleft_des_speed'
RP6Control_I2CMasterLib.h:135: error: storage class specified for parameter 'mright_des_speed'
RP6Control_I2CMasterLib.h:138: error: storage class specified for parameter 'mleft_power'
RP6Control_I2CMasterLib.h:139: error: storage class specified for parameter 'mright_power'
RP6Control_I2CMasterLib.h:184: error: storage class specified for parameter 'bumper_left'
RP6Control_I2CMasterLib.h:185: error: storage class specified for parameter 'bumper_right'
RP6Control_I2CMasterLib.h:187: error: storage class specified for parameter 'obstacle_left'
RP6Control_I2CMasterLib.h:188: error: storage class specified for parameter 'obstacle_right'
RP6Control_I2CMasterLib.h:192: error: storage class specified for parameter 'adcBat'
RP6Control_I2CMasterLib.h:193: error: storage class specified for parameter 'adcMotorCurrentLeft'
RP6Control_I2CMasterLib.h:194: error: storage class specified for parameter 'adcMotorCurrentRight'
RP6Control_I2CMasterLib.h:195: error: storage class specified for parameter 'adcLSL'
RP6Control_I2CMasterLib.h:196: error: storage class specified for parameter 'adcLSR'
RP6Control_I2CMasterLib.h:197: error: storage class specified for parameter 'adc0'
RP6Control_I2CMasterLib.h:198: error: storage class specified for parameter 'adc1'
RP6Control_I2CMasterLib.h:210: error: storage class specified for parameter 'RC5data_t'
RP6Control_I2CMasterLib.h:215: warning: parameter names (without types) in function declaration
IR_Radar.c:21: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
IR_Radar.c:33: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
IR_Radar.c:67: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
IR_Radar.c:88: error: old-style parameter declarations in prototyped function definition
IR_Radar.c:87: error: expected '{' at end of input
make.exe: *** [IR_Radar.o] Error 1
> Process Exit Code: 2
> Time Taken: 00:01
leider kann ich mit dieser fehlermeldung nicht all zu viel anfangen, da sie etliche meldungen bringt, die mir komplett fremd sind und dazu sehr viele fehlermeldungen in der I2C_Masterlib bringt, obwohl ich diese gar nicht verändert habe.
kann mir jemand sagen, was ich genau beim lib abändern falsch gemacht habe?
leider habe ich bisher noch nie großartig eine lib abgeändert und stehe darum ziemlich auf der leitung :-&
mfg
proevofreak
15.02.2010, 16:38
so, also den großen fehler hab ich nun gefunden. in der headerdatei habe ich hinter infrarotkollission() das ; vergessen.
aber irgendwas passt immer noch nicht. jetzt bringt der compiler folgende fehlermeldung:
R_Radar.c: In function 'RP6_Bewegung':
IR_Radar.c:21: error: 'ir_hindernis' undeclared (first use in this function)
IR_Radar.c:21: error: (Each undeclared identifier is reported only once
IR_Radar.c:21: error: for each function it appears in.)
make.exe: *** [IR_Radar.o] Error 1
das heißt, dass er mein ir_hindernis noch nicht findet. kann mir jemand sagen, ob ich das mit ir_hindernis = true bzw. ir_hindernis = false in der .c datei der servolib und das
if (ir_hindernis)
{writeString_P("objekt erkannt\n");}
so machen darf?
ich muss zugeben, dass ich es mir in der original robotBaseLib abgeschaut habe, und bisher noch nicht so 100%ig genau verstanden habe, was es damit auf sich hat.
mfg andi
RP6conrad
15.02.2010, 18:02
ir_hindernis ist eine globale variabele. Dazu muss du das auch declareren mit "extern uint8_t ir_hindernis". Stichwort ist hier extern. So weiss der compiler das es hier um eine globale variabele geht.
Moglicherweise muss du auch noch in der .h datei diese variabele eintragen. Siehe auch nach bestehende globale variabele die mit "extern" declariert werden.
proevofreak
15.02.2010, 18:48
also jetzt hab ich es mal mit dem extern ausprobiert. aber auch nachdem ich extern uint8_t ir_hindernis in der header und in der .c datei eingefügt habe, kommt immer noch die gleiche fehlermeldung wie vorher.
das heißt das problem muss irgendwo anders liegen.
mfg
proevofreak
16.02.2010, 14:51
so, jetzt habe ich mir nochmal genau angeschaut, wie das mit dem obstacle_left() bzw obstacle_right() auf der base programmiert ist.
dabei konnte ich folgendes finden:
in der .h lib:
void task_ACS(void);
die ACS funktion wird also hier auch aus der .h lib aufgerufen.
das habe ich bei mir mit void infrarotkollission(void); in dirks servolib.h gemacht, also genau gleich wie hier gemacht.
in der .c lib:
uint8_t obstacle_left;
uint8_t obstacle_right;
die variablen werden hier auch nicht als externe variablen deklariert.
also wie bei mir in servolib.c
dann das demoprogramm (Example_04_ACS):
// Uncommented Version of RP6Base_Stopwatches.c
// written by Dominik S. Herwald
// ------------------------------------------------------------------------------------------
// Another uncommented version - this time of RP6Base_ACS.c.
// ------------------------------------------------------------------------------------------
#include "RP6RobotBaseLib.h"
void acsStateChanged(void)
{
writeString_P("ACS state changed L: ");
if(obstacle_left)
writeChar('o');
else
writeChar(' ');
writeString_P(" | R: ");
if(obstacle_right)
writeChar('o');
else
writeChar(' ');
if(obstacle_right && obstacle_left)
writeString_P(" MIDDLE!");
writeChar('\n');
if(obstacle_left && obstacle_right)
statusLEDs.byte = 0b100100;
else
statusLEDs.byte = 0b000000;
statusLEDs.LED5 = obstacle_left;
statusLEDs.LED4 = (!obstacle_left);
statusLEDs.LED2 = obstacle_right;
statusLEDs.LED1 = (!obstacle_right);
updateStatusLEDs();
}
void bumpersStateChanged(void)
{
writeString_P("Bumpers state changed! BPL: ");
if(bumper_left)
writeChar('o');
else
writeChar(' ');
writeString_P(" | BPR: ");
if(bumper_right)
writeChar('o');
else
writeChar(' ');
writeChar('\n');
}
int main(void)
{
initRobotBase();
writeString_P("\nRP6 ACS - Testprogram\n");
writeString_P("_____________________\n\n");
setLEDs(0b111111);
mSleep(1000);
setLEDs(0b001001);
ACS_setStateChangedHandler(acsStateChanged);
BUMPERS_setStateChangedHandler(bumpersStateChanged );
powerON();
setACSPwrMed();
while(true)
{
task_RP6System();
}
return 0;
}
hier mein demoprogramm zum aufrufen meiner neuen acs funktion zum vergleich:
// Uncommented Version of RP6ControlServo.c
// ------------------------------------------------------------------------------------------
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
//Servo 1 => PC2
//Servo 2 => PC3
//Servo 3=> PC4
//Servo 4=> PC5
//Servo 5=> PC6
void RP6_Bewegung(void)
{if (ir_hindernis)
{writeString_P("objekt erkannt\n");}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 40;
writeString_P("servo position 40\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = 80;}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{servo3_position = 80;}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{servo3_position = 40;}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
int main(void)
{
initRP6Control();
I2CTWI_initMaster(100);
initSERVO(SERVO3);
startStopwatch3();
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
RP6_Bewegung();
}
return 0;
}
da ich keinen grundlegenden unterschied zwischen meiner programmiervariante und der von der base feststellen kann, bei mir aber immer noch die fehlermeldung
-------- begin --------
avr-gcc (WinAVR 20090313) 4.3.2
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compiling: IR_Radar.c
avr-gcc -c -mmcu=atmega32 -I. -gdwarf-2 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=IR_Radar.lst -I../../RP6Lib -I../../RP6Lib/RP6control -I../../RP6Lib/RP6common -std=gnu99 -MD -MP -MF .dep/IR_Radar.o.d IR_Radar.c -o IR_Radar.o
IR_Radar.c: In function 'RP6_Bewegung':
IR_Radar.c:21: error: 'ir_hindernis' undeclared (first use in this function)
IR_Radar.c:21: error: (Each undeclared identifier is reported only once
IR_Radar.c:21: error: for each function it appears in.)
make.exe: *** [IR_Radar.o] Error 1
> Process Exit Code: 2
> Time Taken: 00:05
kommt, hoffe ich nun, dass mir jemand aus dem forum helfen kann.
mfg andi
ir_hindernis <<- wird nirgends in RP6ControlServo.c oder in einem der Header deklariert. Wurde oben ja schon gesagt.
Und nachdem Du nen Header geändert hast immer einmal make clean ausführen zur Sicherheit soweit ich mich erinnere übernimmt der Compiler sonst Änderungen nicht.
MfG,
SlyD
proevofreak
19.02.2010, 16:59
so, nach ein wenig rumprobieren funktioniert die erweiterung nun.
allerdings funktioniert es nur, wenn man ir_hindernis in der header datei mit uint8_t ir_hindernis und in der .c datei mit extern uint8_t ir_hindernis deklariert.
wenn ich die variable, beide male mit extern deklariere bringt der compiler eine fehlermeldung.
danke auf jeden fall für eure hilfe
proevofreak
21.02.2010, 18:36
hallo, bei meinem ir radar projekt stehe ich gerade bei der rotate funktion ein wenig auf dem schlauch und brauche hilfe.
interessant ist eigentlich nur der folgende kurze programmauszug:
void RP6_Bewegung(void)
{if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3();
writeString_P("ir ende gleich false\n");}
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{rotate(50,RIGHT,90,true);
ir_ende= true;
}
if ((getStopwatch3() >1000 && getStopwatch3() <2000)||(getStopwatch3()>5000 && getStopwatch3() <6000))
{rotate(50,RIGHT,45,true);
ir_ende= true;
}
if (ir_ende)
{startStopwatch3();
writeString_P("ir ende gleich true\n");}
}}
mein ziel ist, dass nachdem die rotate- funktionen ausgeführt wurden die variable ir_ende auf true gesetzt wird.
nachdem ich die anleitung genauer untersucht habe, bin ich zum entschluss gekommen, dass das eigentlich mit der variable true am ende der rotate- funktion funktionieren müsste.
aber leider ist es jetzt so, dass nach dem ausführen der rotate- funktionen nichts mehr geschieht und die variable ir_ende nicht auf true gesetzt wird.
mit den parametern BLOCKING und false habe ich es auch schon erfolglos probiert.
wer kann mir weiterhelfen?
mfg andi
RP6conrad
21.02.2010, 18:59
Der trick ist das du eine move oder rotate auftrag nur einmal aufruft, aber nicht mit "blocking". Der auftrag wird dan automatisch weiter ausgefuhrt und ihre main program kan sich um andere Sachen bekummern. Ende von Auftrag wird dan in main abgefragt mit ismovementcomplete(). Eine kleines codeschnipsel (nicht einfach kopieren, da ich da gans fiele Sachen in die lib geandert habe):
void sharp_rotate(void) //elke 40 mS samplen tijdens 360° draai
{
if (state==1) {reset_odometrie();rotate(10,10,360,LEFT,0);state+ +;}
if (state==2) if (getStopwatch2()>40)
{
setStopwatch2(0);
adc0 = 0.3*adc0+0.7*readADC(ADC_0);
adc1 = 0.3*adc1+0.7*readADC(ADC_1);
adc2 = 0.3*adc2+0.7*readADC(ADC_2);
adc3 = 0.3*adc3+0.7*readADC(ADC_3);
int16_t sharp0= Sharp_LR(adc0);//omzetten naar afstand in mm
int16_t sharp1= Sharp_MR(adc1);
int16_t sharp2= Sharp_MR(adc2);
int16_t sharp3= Sharp_LR(adc3);
writeInteger((e_compass/E_COMPASS_RESOLUTION), DEC);writeString_P(" ");
writeInteger(sharp0, DEC);writeString_P(" ");
writeInteger(sharp3, DEC);writeString_P(" ");
writeInteger(sharp1, DEC);writeString_P(" ");
writeInteger(sharp2, DEC);writeString_P(" ");
writeChar('\n');
}
if (state==3) {program=0;state=1;}
if (isMovementComplete()&(state!=0)) state++;
}
proevofreak
21.02.2010, 19:29
danke für die schnelle antwort. jetzt hab ich es mal so abgeändert:
void RP6_Bewegung(void)
{if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3();
writeString_P("ir ende gleich false\n");}
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{rotate(50,RIGHT,90,true);
}
if ((getStopwatch3() >1000 && getStopwatch3() <2000)||(getStopwatch3()>5000 && getStopwatch3() <6000))
{rotate(50,RIGHT,45,true);
}
if (isMovementComplete())
{ir_ende= true;}
if (ir_ende)
{startStopwatch3();
writeString_P("ir ende gleich true\n");}
}}
aber das ergebnis ist das gleiche wie vorher. der rp6 führt die rotate bewegung korrekt bis zum ende aus aber die ir_ende variable wird nicht auf true gesetzt.
was ist noch falsch?
mfg
proevofreak
21.02.2010, 20:46
so, jetzt habe ich mir mal etwas genauer das RP6_Move_04_FSM2 beispielprogramm angeschaut.
bei diesem wird die move- funktionen ja in switch cases abgearbeitet. nach diesem vorbild habe ich jetzt auch mein programm abgeändert.
hier der ausschnitt:
void RP6_Bewegung(void)
{if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3();
writeString_P("ir ende gleich false\n");}
else {startStopwatch3();}
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{move_state= 0;
}
if ((getStopwatch3() >1000 && getStopwatch3() <2000)||(getStopwatch3()>5000 && getStopwatch3() <6000))
{move_state=1;
}
switch(move_state)
{case 0:
rotate(50,RIGHT,90,NON_BLOCKING);
move_state= 2;
break;
case 1:
rotate(50,RIGHT,45,NON_BLOCKING);
move_state= 2;
break;
case 2:
if(isMovementComplete())
{ir_ende= true;
startStopwatch3();
writeString_P("ir ende gleich true\n");
}
break;
}}}
obwohl ich meiner meinng nach nach dem gleichem schema wie in diesem beispielprogramm programmiert habe, funktioniert es nicht im beispielprogramm.
ich habe nun das problem, dass der rp6 sich ständigt dreht, d.h. er dreht nicht eine bestimmte gradzahl sondern er dreht sich permanent auf der stelle.
außerdem wird ir_ende= true immer noch nicht gesetzt.
woran liegt das?
mfg
proevofreak
24.02.2010, 10:48
jetzt hab ich mal nochmal alles genau überarbeitet und mit dem beispielprogramm verglichen. aber ich kann einfach keinen unterschied der programmiervariante bzw. fehler finden.
kann mir denn niemand helfen?
danke schon mal im voraus
Habe grad mal fix drübergeschaut.
Das hier
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{move_state= 0;
}
wird immer ausgeführt!
Damit wird der Teil hier:
case 0:
rotate(50,RIGHT,90,NON_BLOCKING);
move_state= 2;
break;
auch dauernd ausgeführt denn das move_state=2 hat solange keinen Effekt wie die Stopwatch3 nicht bei 1000 angekommen ist.
ir_ende ist wohl zu beginn false also wird ständig das hier:
if (!(ir_ende))
{stopStopwatch3();
writeString_P("ir ende gleich false\n");}
aufgerufen. Also läuft die Stopwatch3 nicht.
--> RP6 dreht dauerhaft.
Formatier den Code in Zukunft mal übersichtlicher dann sieht man sowas auch leichter ;)
MfG,
SlyD
proevofreak
24.02.2010, 16:23
@Slyd: wenn ich deinen post richtig verstanden habe, war mein ursprüngliches problem, dass in meinem programm move_state immer = 0 war und dadurch case 1 erst gar nicht ausgeführt wird.
Aus diesem grund habe ich jetzt noch einmal alles abgeändert und auch ein paar kommentare hinzugefügt.
zum besseren verständnis hier noch meine dazugehörige liberweiterung:
void infrarotkollission(void)
{DDRC &=~ (1<<PC3); //PC3 als Eingang infrarotempfänger
if(ir_erweiterung ==0)
{
if (!(PINC & (1<<PC3)))
{writeString_P("Infrarotempfang ein\n");
writeStringLCD("ir_counter=:");
writeString("ir_counter=:");
writeInteger(ir_counter,DEC);
writeIntegerLCD(ir_counter, DEC);
writeChar('\n');
ir_ende = false;
ir_counter++; //infrarot empfangen
}
}
if (ir_counter ==50)
{ir_hindernis = true;
ir_erweiterung = 1;
}
if (ir_ende)
{ir_counter =0;
ir_erweiterung =0;
ir_hindernis = false;
}
}
und hier jetzt mein komplettes abgeändertes demoprogramm:
// Uncommented Version of RP6ControlServo.c
// ------------------------------------------------------------------------------------------
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
//Servo 1 => PC2
//Servo 2 => PC3
//Servo 3=> PC4
//Servo 4=> PC5
//Servo 5=> PC6
uint8_t move_state = 0; // Wenn nichts anderes zugewiesen ist, ist move_state =0
void RP6_Bewegung(void)
{if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3(); //stopwatch3 anhalten wenn ir erkannt wird und damit servobewegung anhalten
writeString_P("ir ende gleich false\n");}
{switch(move_state)
{case 0:
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{rotate(50,RIGHT,90,NON_BLOCKING); //um 90 grad rotieren
move_state= 1;} // move_state den wert 1 zuweisen
break;
case 1:
if(isMovementComplete())
{ir_ende= true; //ir_ende=true, wenn bewegung abgeschlossen
startStopwatch3(); //stopwatch3 wieder starten und servo wieder starten
writeString_P("ir ende gleich true\n");
}
break;
}
}}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 20;
writeString_P("servo position 40\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = 90;}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{servo3_position = 90;}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{servo3_position = 20;}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
int main(void)
{
initRP6Control();
I2CTWI_initMaster(100);
initSERVO(SERVO3);
startStopwatch3();
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
RP6_Bewegung();
}
return 0;
}
das alte problem, dass das programm in der case 0 ständig "hängen" bleibt müsste ich jetzt eigentlich behoben habe. der RP6 dreht sich jetzt auf jeden fall schon mal 90 grad und bleibt dann stehen.
was allerdings immer noch nicht geht, ist dass das programm nach der rotationsbewegung in die case 1 geht und dann mit startStopwatch3() die servobewegung wieder startet.
hat jemand vielleicht auf dieses phänomen eine erklärung?
Formatier den Code in Zukunft mal übersichtlicher dann sieht man sowas auch leichter ;)
MfG,
SlyD
ich gelobe in zukunkt besserung O:)
proevofreak
26.02.2010, 11:48
so, jetzt hab ich mal zur besseren veranschaulichung ein kleines video hochgeladen:
http://www.youtube.com/watch?v=Wi1J1KOA0Gc
das alte problem besteht aber nach wie vor. nachdem ein hindernis erkannt wird, stoppt die servobewegung und der RP6 dreht um 90 grad und bleibt dann stehen (kann man im video ganz gut sehen).
allerdings sollte anschließend mein programm (liberweiterung und programm im letzten post) in case 1 springen und da dann servobewegung und infrarotempfang wieder starten.
das programm springt auch in case 1(hab ich gerade mit einer textmeldung getestet) aber irgendwie wird isMovementComplete() nie true und damit werden auch die damit verbundenen funktionen (startStopwatch3(), ir_ende= true;) nicht ausgelöst.
ich habe trotz langem suchens immer noch keine erklärung dafür gefunden aber dafür ist das forum ja auch da, um für solche probleme antworten zu bekommen O:).
mfg andi
RP6conrad
26.02.2010, 20:26
Ihre void RP6_Bewegung(void) fangt an mit
{if (ir_hindernis)
Das bedeutet naturlich auch das (ir_hindernis) immer TRUE sein muss um die weitere ablauf zu bearbeiten. Ist das auch so ?
Du muss absolut die layout so machen, das es klar ist welche {} zusammen horen. Auf das ende von diese function stehen 4 } nacheinander, und mir ist es nicht klar was bei was gehort.
proevofreak
26.02.2010, 21:42
Ihre void RP6_Bewegung(void) fangt an mit
{if (ir_hindernis)
Das bedeutet naturlich auch das (ir_hindernis) immer TRUE sein muss um die weitere ablauf zu bearbeiten. Ist das auch so ?
ir_hindernis ist solange TRUE bis ir_ende gleich TRUE wird, also die ganze zeit.
siehe hier:
void infrarotkollission(void)
{DDRC &=~ (1<<PC3); //PC3 als Eingang infrarotempfänger
if(ir_erweiterung ==0)
{
if (!(PINC & (1<<PC3)))
{writeString_P("Infrarotempfang ein\n");
writeStringLCD("ir_counter=:");
writeString("ir_counter=:");
writeInteger(ir_counter,DEC);
writeIntegerLCD(ir_counter, DEC);
writeChar('\n');
ir_ende = false;
ir_counter++; //infrarot empfangen
}
}
if (ir_counter ==50)
{ir_hindernis = true;
ir_erweiterung = 1;
}
if (ir_ende)
{ir_counter =0;
ir_erweiterung =0;
ir_hindernis = false;
}
}
Du muss absolut die layout so machen, das es klar ist welche {} zusammen horen. Auf das ende von diese function stehen 4 } nacheinander, und mir ist es nicht klar was bei was gehort.
hier habe ich das demoprogramm noch mal sorgfältig überarbeitet:
// Uncommented Version of RP6ControlServo.c
// ------------------------------------------------------------------------------------------
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
//Servo 1 => PC2
//Servo 2 => PC3
//Servo 3=> PC4
//Servo 4=> PC5
//Servo 5=> PC6
uint8_t move_state = 0; // Wenn nichts anderes zugewiesen ist, ist move_state =0
void RP6_Bewegung(void)
{if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3(); //stopwatch3 anhalten wenn ir erkannt wird und damit servobewegung anhalten
writeString_P("ir ende gleich false\n");
}
{switch(move_state)
{case 0:
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{rotate(50,RIGHT,90,NON_BLOCKING); //um 90 grad rotieren
move_state= 1; // move_state den wert 1 zuweisen
}
break;
case 1:
if(isMovementComplete())
{ir_ende= true; //ir_ende=true, wenn bewegung abgeschlossen
startStopwatch3(); //stopwatch3 starten => servo wieder drehen
writeString_P("ir ende gleich true\n");
}
break;
}
}
}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 20;
writeString_P("servo position 40\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = 90;}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{servo3_position = 90;}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{servo3_position = 20;}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
int main(void)
{
initRP6Control();
I2CTWI_initMaster(100);
initSERVO(SERVO3);
startStopwatch3();
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
RP6_Bewegung();
}
return 0;
}
mfg andi
radbruch
26.02.2010, 23:37
Hallo
Ich war mal so frei und habe den Code nach meinen Gewohnheiten formatiert:
void infrarotkollission(void)
{
DDRC &=~ (1<<PC3); // PC3 als Eingang infrarotempfänger
if(ir_erweiterung == 0)
{
if (!(PINC & (1<<PC3)))
{
writeString_P("Infrarotempfang ein\n");
writeStringLCD("ir_counter=:");
writeString("ir_counter=:");
writeInteger(ir_counter,DEC);
writeIntegerLCD(ir_counter, DEC);
writeChar('\n');
ir_ende = false;
ir_counter++; // infrarot empfangen
}
}
if (ir_counter == 50)
{
ir_hindernis = true;
ir_erweiterung = 1;
}
if (ir_ende)
{
ir_counter = 0;
ir_erweiterung = 0;
ir_hindernis = false;
}
}
// IR-Radar von proevofreak 26.2.2010
// von radbruch formatierter Code
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
// Servo 1 => PC2
// Servo 2 => PC3
// Servo 3 => PC4
// Servo 4 => PC5
// Servo 5 => PC6
uint8_t move_state = 0; // Wenn nichts anderes zugewiesen ist, ist move_state =0
void RP6_Bewegung(void)
{
if (ir_hindernis)
{
if (!(ir_ende))
{
stopStopwatch3(); // stopwatch3 anhalten wenn ir erkannt wird und damit servobewegung anhalten
writeString_P("ir ende gleich false\n");
}
switch(move_state)
{
case 0:
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{
rotate(50,RIGHT,90,NON_BLOCKING); // um 90 grad rotieren
move_state= 1; // move_state den wert 1 zuweisen
}
break;
case 1:
if(isMovementComplete())
{
ir_ende= true; // ir_ende=true, wenn bewegung abgeschlossen
startStopwatch3(); // stopwatch3 starten => servo wieder drehen
writeString_P("ir ende gleich true\n");
}
break;
}
}
}
void servoansteuerung(void)
{
if (getStopwatch3() <1000)
{
servo3_position = 0;
writeString_P("LEFT Touch\n");
}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{
servo3_position = 20;
writeString_P("servo position 40\n");
}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{
servo3_position = 90;
}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{
servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");
}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{
servo3_position = 90;
}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{
servo3_position = 20;
}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{
servo3_position = 0;
writeString_P("LEFT Touch\n");
}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");
}
}
int main(void)
{
initRP6Control();
I2CTWI_initMaster(100);
initSERVO(SERVO3);
startStopwatch3();
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
RP6_Bewegung();
}
return 0;
}(Weder kompiliert noch überprüft oder getestet)
Gruß
mic
proevofreak
27.02.2010, 11:49
Hallo
Ich war mal so frei und habe den Code nach meinen Gewohnheiten formatiert:
ist ja nett, dass du meinen code sauber umformatierst (jetzt weiß ich glaube ich auch was man unter sauberer formatierung versteht) aber leider löst das auch nicht mein bestehendes problem.
mein eigentliches problem liegt ja nicht in der unübersichtlichen programmierung, sondern vielmehr daran, dass in case1 isMovementComplete() nie true wird, obwohl der rp6 korrekt rotiert.
wenn mir da jemand weiterhelfen würde und mir sagen würde was ich anders programmieren muss, wäre ich richtig dankbar.
mfg andi
Du rufst nirgendwo task_RP6System(); auf.
Jedenfalls sehe ichs nicht...
Das MUSS unbedingt in die Endlosschleife in der Main rein!
MfG,
SlyD
proevofreak
27.02.2010, 17:28
Du rufst nirgendwo task_RP6System(); auf.
Jedenfalls sehe ichs nicht...
Das MUSS unbedingt in die Endlosschleife in der Main rein!
MfG,
SlyD
bist du dir sicher? ich verwende für mein programm ja die M32 und nicht die Base.
also in den beispielprogrammen der M32 (z.b. in RP6Control_06_I2CMaster) rotiert der RP6 auch, ohne dass task_RP6System(); aufgerufen wird.
mfg
Ach sorry - hab ich nicht drauf geachtet.
Ändert aber prinzipiell nix dran das ein ähnlicher Aufruf fehlt :D
Hier musst Du halt
task_checkINT0();
task_I2CTWI();
aufrufen - wie soll der Controller auf dem Erweiterungsmodul sonst mitbekommen das der andere Controller auf dem Mainboard seinen Status geändert hat (also mit rotieren fertig ist)?
Das muss ja über den I2C Bus übertragen werden - das regelt die task_I2CTWI... und die andere Funktion wird gebraucht um zu prüfen ob der Controller auf dem Mainboard die Interrupt Leitung gesetzt hat (also neue Daten vorhanden sind).
Du musst auch noch die entsprechenden Handler setzen damit die Funktion checkRP6Status aus der RP6Control Master Lib aufgerufen wird und die Register aktualisiert.
Schau Dir die M32 Beispielprogramme nochmal an da wird das genau beschrieben!
MfG,
SlyD
proevofreak
27.02.2010, 17:52
oh danke, ja daran könnte es liegen. hab nur bisher gedacht, dass da schon alles passt, weil ich schon mal die M32 als Master mit gleichzeitiger fahrfunktion (allerdings damals mit moveAtSpeed()) verwendet habe, und damals nichts weiter aufgerufen habe und trotzdem alles funktioniert hat.
aber gut dass du jetzt darauf hingewiesen hast, dann werd ich jetzt die ganze I2C funktionen und Beispielprogramme erst mal nochmal gründlich anschauen und dann in meinem programm ergänzen.
danke nochmal
proevofreak
02.03.2010, 14:41
so, nach wirklich stundenlangem durcharbeiten der I²C lib, der beispielprogramme mit I²C und dem durchlesen der anleitung der base und der M32 habe ich mein programm jetzt nochmal abgeändert:
// Uncommented Version of RP6ControlServo.c
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
uint8_t move_state = 0; // Wenn nicht anders zugewiesen,move_state=0
void motionControlStateChanged(void)
{ if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3(); //stopwatch3 anhalten wenn ir erkannt wird und damit servobewegung anhalten
writeString_P("stopStopwatch3\n");}
switch(move_state)
{case 0:
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{rotate(50,RIGHT,90,NON_BLOCKING); //um 90 grad rotieren wenn hindernis erkennt wird und stopwatch3 <1000 oder >6000 ist
move_state= 1; // move_state den wert 1 zuweisen
}
break;
case 1:
if(isMovementComplete())
{ir_ende= true; //ir_ende=true, wenn bewegung abgeschlossen
startStopwatch3(); //stopwatch3 wieder starten und servo wieder starten
writeString_P("stopwatch3 starten\n");
}
break;
}
}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 20;
writeString_P("servo position 40\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = 90;}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{servo3_position = 90;}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{servo3_position = 20;}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
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');
}
int main(void)
{
initRP6Control();
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_ROTATE, true);
MOTIONCONTROL_setStateChangedHandler(motionControl StateChanged);
initSERVO(SERVO3);
startStopwatch3();
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
task_checkINT0();
task_I2CTWI();
}
return 0;
}
jetzt ist es so, dass das programm zwar fehlerfrei kompiliert wird, wenn ich es aber laufen lasse, springt es sofort nach dem start wieder in den standby- modus (hoffe die bezeichnung ist so richtig) und im terminal erscheint folgende meldung:
[READY]
LEFT Touch
I2C ERROR - TWI STATE: 0x20
LEFT Touch
LEFT Touch
LEFT Touch
LEFT Touch
LEFT Touch
LEFT Touâ
[RP6BOOT]
offensichtlich ist im programm noch irgendetwas in verbindung mit I²C falsch.
grundsätzlich kann ich nicht behaupten, dass ich die I²C lib bzw. funktionen trotz gründlichem durcharbeitens wirklich 100%ig verstanden habe, da sie doch aus sehr vielen verschiedenen teilen bestehen.
um so mehr bin ich auf eure hilfe hier angewiesen.
mfg andi
proevofreak
04.03.2010, 19:23
kann mir denn wirklich niemand sagen was noch fehlt bzw. falsch ist?
mfg andi
proevofreak
06.03.2010, 14:52
so, jetzt hab ich threads zu diesem thema und die beispielprogramme untersucht, so dass ich mein programm jetzt nach dem vorbild de RP6Control_09_Move beispielprogramm abgeändert habe:
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
uint8_t move_state = 0; // Wenn nichts anderes zugewiesen ist, ist move_state =0
void motionControlStateChanged(void)
{ if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3(); //stopwatch3 anhalten wenn ir erkannt wird und damit servobewegung anhalten
writeString_P("stopStopwatch3\n");}
switch(move_state)
{case 0:
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{rotate(50,RIGHT,90,NON_BLOCKING); //um 90 grad rotieren wenn hindernis erkennt wird und stopwatch3 <1000 oder >6000 ist
move_state= 1; // move_state den wert 1 zuweisen
}
break;
case 1:
if(isMovementComplete())
{ir_ende= true; //ir_ende=true, wenn bewegung abgeschlossen
startStopwatch3(); //stopwatch3 wieder starten und servo wieder starten
writeString_P("stopwatch3 starten\n");
}
break;
}
}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 20;
writeString_P("servo position 40\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = 90;}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{servo3_position = 90;}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{servo3_position = 20;}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
void watchDogRequest(void)
{
static uint8_t heartbeat2 = false;
if(heartbeat2)
{
clearPosLCD(0, 14, 1);
heartbeat2 = false;
}
else
{
setCursorPosLCD(0, 14);
writeStringLCD_P("#");
heartbeat2 = true;
}
}
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');
}
int main(void)
{
initRP6Control();
WDT_setRequestHandler(watchDogRequest);
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, true);
initSERVO(SERVO3);
startStopwatch3();
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
task_checkINT0();
task_I2CTWI();
}
return 0;
}
das ergebnis ist aber leider immer noch das selbe wie vorher. der das programm läuft nur einen sekundenbruchteil und der mikrocontroller springt dann in den standby modus zurück.
im terminal erscheint diese meldung:
I2C ERROR - TWI STATE: 0x20
I2C ERROR - TWI STATE: 0x20
LEFT Touch
I2C ERROR - TWI STATE: 0x20
LEFT Touch
LEFT Touch
LEFT Touch
LEFT Touch
LEFT Touch
LEFT Touc
ich kann mir vorstellen, dass ich vielleicht dem ein oder anderen in diesem forum mit meinem problem auf die nerven gehe, aber da ich die ganzen I²C funktionen noch überhaupt nicht kapiere und mittlerweile mit allen möglichen programmschnipsel aus beispielprogrammen erfolglos hantiert habe, bin ich halt auf eure hilfe angewiesen.
danke schon mal im voraus für eure mühen mir zu helfen.
mfg andi
deaktivier erstmal den Watchdog und Request (WDT und WDT_RQ auf false!).
Dann zusätzlich brauchst Du eine Pause von mind. 500ms am Anfang des Programms direkt nach der initialisierung da eine kleine Pause auch in dem Base Programm drin ist vorher reagiert das nicht daher auch wahrscheinlich die 0x20 Fehler am Anfang.
Für den Rest hab ich nun aber leider keine Zeit - sorry ;)
MfG,
SlyD
proevofreak
09.03.2010, 21:00
danke SlyD für die hilfe. jetzt hab ich mal alles so abgeändert wie du gesagt hast:
#include "RP6ControlLib.h"
#include "RP6ControlServoLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_I2CMasterLib.h"
uint8_t move_state = 0; // Wenn nichts anderes zugewiesen ist, ist move_state =0
void motionControlStateChanged(void)
{ if (ir_hindernis)
{
if (!(ir_ende))
{stopStopwatch3(); //stopwatch3 anhalten wenn ir erkannt wird und damit servobewegung anhalten
writeString_P("stopStopwatch3\n");}
switch(move_state)
{case 0:
if (getStopwatch3() <1000 || getStopwatch3() >6000)
{rotate(50,RIGHT,90,NON_BLOCKING); //um 90 grad rotieren wenn hindernis erkennt wird und stopwatch3 <1000 oder >6000 ist
move_state= 1; // move_state den wert 1 zuweisen
}
break;
case 1:
if(isMovementComplete())
{ir_ende= true; //ir_ende=true, wenn bewegung abgeschlossen
startStopwatch3(); //stopwatch3 wieder starten und servo wieder starten
writeString_P("stopwatch3 starten\n");
}
break;
}
}
}
void servoansteuerung(void)
{if (getStopwatch3() <1000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >1000 && getStopwatch3() <2000)
{servo3_position = 20;
writeString_P("servo position 40\n");}
if (getStopwatch3() >2000 && getStopwatch3() <3000)
{servo3_position = 90;}
if (getStopwatch3() >3000 && getStopwatch3() <4000)
{servo3_position = RIGHT_TOUCH;
writeString_P("Servo Right touch\n");}
if (getStopwatch3() >4000 && getStopwatch3() <5000)
{servo3_position = 90;}
if (getStopwatch3() >5000 && getStopwatch3() <6000)
{servo3_position = 20;}
if (getStopwatch3() >6000 && getStopwatch3() <7000)
{servo3_position = 0;
writeString_P("LEFT Touch\n");}
if (getStopwatch3() >7000)
{
setStopwatch3(0);
writeString_P("stopwatch3 auf 0 zurück\n");}
}
void watchDogRequest(void)
{
static uint8_t heartbeat2 = false;
if(heartbeat2)
{
clearPosLCD(0, 14, 1);
heartbeat2 = false;
}
else
{
setCursorPosLCD(0, 14);
writeStringLCD_P("#");
heartbeat2 = true;
}
}
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');
}
int main(void)
{
initRP6Control();
initSERVO(SERVO3);
startStopwatch3();
I2CTWI_initMaster(100);
WDT_setRequestHandler(watchDogRequest);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
mSleep(1500);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, false);
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, false);
while(true)
{
servoansteuerung();
task_SERVO();
infrarotkollission();
task_checkINT0();
task_I2CTWI();
}
return 0;
}
jetzt hab ich zumindest die meldung mit dem I²C error weg bekommen. allerdings springt mein programm auf dem mikrocontroller nach wie vor nach der abgelaufenen wartezeit (bei mir jetzt 1,5 sekunden) wieder in den standbymodus.
es muss also nach wie irgendetwas in meinen I²C funktionen falsch sein.
wer kann mir weiterhelfen?
mfg andi
proevofreak
16.03.2010, 14:04
so, da ich die letzten tage immer noch nicht mit meinem i2c problem weitergekommen bin, habe ich jetzt mal im forum nach einem thread gesucht, der ein ähnliches problem (fahren mit RP6 mit M32 als Master) behandelt.
leider konnte ich aber nichts finden, was mir wirklich entscheidend weitergeholfen hat. meiner meinung nach muss noch irgendetwas bei der verwendung von I²C nicht stimmen.
da ich auf der Base das ganz normale I2C_Slave_Programm unverändert verwende, muss der fehler wohl in meinem programm auf der M32 liegen.
wer kann mir weiterhelfen?
das programm ist immer noch das selbe wie in meinem vorherigen post. leider ist es das erste mal, dass ich den I²C Bus so richtig verwende aber einem erfahrenem I2C Benutzer müsste doch eigentlich der fehler auffallen.
ich bedanke mich schon mal im voraus für eure mühen mir zu helfen.
mfg andi
Reduzier das Programm doch mal auf ein MINIMUM - also alles raus!
Dann Schritt für Schritt wieder einbauen und immer wieder testen zwischendurch.
Weitere Ausgaben einfügen damit man genau sieht was das Programm macht.
> aber einem erfahrenem I2C Benutzer müsste doch eigentlich
> der fehler auffallen.
Schon möglich, habe aber zu wenig Zeit mir jede Zeile einzeln anzuschauen.
;)
MfG,
SlyD
PS:
Die Beispielprogramme laufen aber wie sie sollen, ja?
Sonst kopier einfach nochmal den Code vom letzten! Beispielprogramm (erst da ist die I2C Lib vollständig ) und lösch alles raus was Du nicht brauchst.
proevofreak
21.03.2010, 17:05
@SlyD: Ja, die I2C Beispielprogramm auf der M32 laufen alle einwandfrei. Jetzt hab ich mal deinen Rat befolgt und habe das letzte! Beispielprogramm (RP6Control_10_Move2) komplett zerpflückt.
das ergebnis ist leider sehr ernüchternd: obwohl ich seit gestern abend mit so gut wie nichts anderem beschäftigt war und jede menge probiert habe. ein problem ist mit unter auch, dass ich einzelne programmteile in diesem Beispielprogramm nicht richtig verstehe:
Was hat es zum Beispiel genau damit auf sich?:
typedef struct {
uint8_t speed_left; // left speed (is used for rotation and
// move distance commands - if these commands are
// active, speed_right is ignored!)
uint8_t speed_right; // right speed
unsigned dir:2; // direction (FWD, BWD, LEFT, RIGHT)
unsigned move:1; // move flag
unsigned rotate:1; // rotate flag
uint16_t move_value; // move value is used for distance and angle values
uint8_t state; // state of the behaviour
} behaviour_command_t;
ich vermute das hängt irgendwie damit zusammen, aber wie?
behaviour_command_t STOP = {0, 0, FWD, false, false, 0, IDLE};
behaviour_command_t cruise = {CRUISE_SPEED_FWD, CRUISE_SPEED_FWD, FWD,
false, false, 0, MOVE_FORWARDS};
behaviour_command_t escape = {0, 0, FWD, false, false, 0, IDLE};
behaviour_command_t avoid = {0, 0, FWD, false, false, 0, IDLE};
behaviour_command_t waitForStart = {0, 0, FWD,
false, false, 0, PREPARE};
warum darf man das so schreiben:
escape.move = true; //Warum kann man das hier so "escape.move" schreiben?
escape.rotate = true; //Hier das selbe, habe das noch nie gesehen
was hat es hier mit den zeichen * und -> auf sich?
void moveCommand(behaviour_command_t * cmd)
{
if(cmd->move_value > 0) // move or rotate?
{
if(cmd->rotate)
rotate(cmd->speed_left, cmd->dir, cmd->move_value, false);
da ich aus diesen programmteilen bisher nicht wirklich schlau geworden bin, habe ich jetzt einmal den großteil aus dem programm geworfen. zur erklärung: vorerst ist erstmal nur mein ziel, dass sich der RP6 dreht.
das programm schaut dann so aus:
#include "RP6ControlLib.h" // The RP6 Control Library.
// Always needs to be included!
#include "RP6I2CmasterTWI.h" // I2C Master Library
/************************************************** ***************************/
/************************************************** ***************************/
// Include our new "RP6 Control I2C Master library":
#include "RP6Control_I2CMasterLib.h"
/************************************************** ***************************/
void RP6_Bewegung(void)
{if (getStopwatch3() >3000)
{rotate(50,FWD,90,false);}
}
/**
* Timed Watchdog display - the other heartbeat function
* does not work in this example as we use blocked moving functions here.
*/
void watchDogRequest(void)
{
static uint8_t heartbeat2 = false;
if(heartbeat2)
{
clearPosLCD(1, 14, 1);
heartbeat2 = false;
}
else
{
setCursorPosLCD(1, 14);
writeStringLCD_P("#");
heartbeat2 = true;
}
}
/************************************************** ***************************/
// I2C Requests:
/**
* The I2C_requestedDataReady Event Handler
*/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}
/************************************************** ***************************/
// I2C Error handler
/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}
/************************************************** ***************************/
// Main function - The program starts here:
int main(void)
{
initRP6Control();
initLCD();
writeString_P("\n\nRP6 CONTROL M32 I2C Master Example Program!\n");
writeString_P("\nMoving...\n");
// ---------------------------------------
WDT_setRequestHandler(watchDogRequest);
// ---------------------------------------
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
sound(180,80,25);
sound(220,80,25);
setLEDs(0b1111);
showScreenLCD("################", "################");
mSleep(500);
showScreenLCD("I2C-Master", "Behaviours");
mSleep(1000);
setLEDs(0b0000);
// ---------------------------------------
// Setup ACS power:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
// Enable Watchdog for Interrupt requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
// Enable timed watchdog requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, true);
startStopwatch1();
startStopwatch2();
startStopwatch3();
showScreenLCD("Active Behaviour", "");
while(true)
{
task_checkINT0();
task_I2CTWI();
RP6_Bewegung();
}
return 0;
}
auch wenn ich bisher keine erklärung dafür finde, tut das programm bisher gar nichts. nicht einmal die textmeldungen im main teil werden im terminal ausgegeben.
zur erinnerung: das original Beispielprogramm (RP6_Control_Move2) lief einwandfrei also kann man einen I2C defekt ausschließen.
bin für jede hilfe dankbar
mfg andi
Hi,
> Was hat es zum Beispiel genau damit auf sich?:
Das ist eine "struct" die hier als Typ deklariert wird (kann man dann wie z.B. uint16_t verwenden - nur hat diese "Variable" dann eben mehrere "untervariablen" um es einfach auszudrücken)
Die * -> Zeichen: Lies Dir mal das Kapitel Pointer in einem x beliebigen C Tutorial durch.
> tut das programm bisher gar nichts.
Also da ich mir das nicht vorstellen konnte habe ich es gerade mal selbst getestet - es funktioniert bei mir (auch wenn er nicht rotiert sondern geradeaus fährt und nicht anhält aber das liegt am rotate(...FWD...) und der art wie die Stopwatch benutzt wird... :) ).
Hast Du die Beispielprogramme mal SELBST COMPILIERT?
Funktionieren die dann immer noch?
Falls nicht dann baut Dein Compiler scheinbar mist (Version?) - installier den mal neu und nimm am besten eine andere Version - ÄLTER ist meistens besser.
Der AVR-GCC Compiler wird mit der Zeit leider nicht unbedingt besser und es können auch mal Bugs drin sein...
MfG,
SlyD
proevofreak
21.03.2010, 19:41
danke SlyD für deine Hilfe. also, das beispielprogramm funktioniert noch, wenn ich es selber kompiliert habe. habe es gerade getestet.
habe mir aber trotzdem winavr deinstalliert und eine neue version (aus dem jahr 2006) installiert. das ergebnis ist aber das selbe wie vorher. das beispielprogramm funktioniert nach dem kompilieren immer noch, aber mein testprogramm macht nach dem starten gar nichts (keine textmeldung, kein fahren).
etwas anderes ist mir jetzt aber noch aufgefallen, muss aber nicht unbedingt etwas damit zu tun haben. wenn ich das beispielprogramm laufen lasse und ein hindernis über die bumper oder acs simulieren bleibt der RP6 auf einmal stehen und macht gar nichts mehr. egal ob ich einen taster drücke, ein hindernis simuliere oder sonst irgendwas der RP6 macht nichts mehr (das war auch schon vor der neuinstallation von winavr).
auf der M32 leuchten dann LED2 und LED3 dauerhaft, auf der Base blinken SL2, SL3, SL5 und SL6.
ist das normal? schaut irgendwie nach einer störmeldung aus.
mfg andi
Na 2006er ist dann doch etwas extrem alt.
Ich meinte eher so 2007 / 2008.
Nimm z.B. mal 20080610 mit der hab ich es hier auf dem notebook gerade getestet und damit hat es problemlos funktioniert.
Sicher das Du die richtigen Hexfiles hochlädst wenn Du es neu kompiliert hast?
(schau mal aufs Datum/Uhrzeit der dateien ob die wirklich verändert wurden)
> Blinkende LEDs:
Verwendest Du Akkus oder Batterien?
Voll aufgeladen?
Läuft der Selftest fehlerfrei durch?
MfG,
SlyD
proevofreak
31.03.2010, 22:03
tut mir leid SlyD, dass ich mich erst jetzt wieder melde aber ich hatte in letzter zeit einfach keine zeit für den RP6.
mittlerweile habe ich die version 20080610 von winavr installiert. kompilieren lassen sich alle programme fehlerfrei. es werden auch neue hexfiles erzeugt (habe es über datum/uhrzeit getestet). aber irgendwas stimmt nach wie vor nicht.
mein testprogramm tut nach wie vor nichts, also der RP6 fährt nicht wie bei dir.
noch etwas anderes unerklärliches ist mir aufgefallen. und zwar erzeugt das winavr beim Example_10_Move2 beispielprogramm nur beim RP6Control_10_Move2_fast beispielprogramm beim kompilieren ein neues hexfile. beim RP6Control_10_Move2 geschieht dagegen gar nichts. auch nachdem ich das bereits bestehende hexfile gelöscht habe, konnte ich beim kompilieren kein neues hexfile erzeugen.
an was kann das liegen?
mfg andi
_|Alex|_
01.04.2010, 09:05
Schonmal an einem anderen PC Probiert?
proevofreak
02.04.2010, 19:59
@_|Alex|_ : nein das hab ich noch nicht. kommt aber eigentlich auch nicht in frage, da ich keinen zweiten besitze.
nachdem ich heute gefühlte 10 mal winavr neuinstalliert habe, bin ich immer noch nicht weitergekommen. hexfiles werden bei meinem testprogramm auf jeden fall neue erzeugt. darum denke ich, dass das problem nicht an einem falsch funktionierenden winavr liegt. um so mehr verwundert es mich, dass das programm bei mir und SlyD auf dem RP6 unterschiedlich funktioniert.
vielleicht kann ja noch jemand anderes mein testprogramm bei mir auf der M32 testen und schauen was es bei ihm macht:
#include "RP6ControlLib.h" // The RP6 Control Library.
// Always needs to be included!
#include "RP6I2CmasterTWI.h" // I2C Master Library
/************************************************** ***************************/
/************************************************** ***************************/
// Include our new "RP6 Control I2C Master library":
#include "RP6Control_I2CMasterLib.h"
/************************************************** ***************************/
void RP6_Bewegung(void)
{if (getStopwatch3() >3000)
{rotate(50,FWD,90,false);}
}
/**
* Timed Watchdog display - the other heartbeat function
* does not work in this example as we use blocked moving functions here.
*/
void watchDogRequest(void)
{
static uint8_t heartbeat2 = false;
if(heartbeat2)
{
clearPosLCD(1, 14, 1);
heartbeat2 = false;
}
else
{
setCursorPosLCD(1, 14);
writeStringLCD_P("#");
heartbeat2 = true;
}
}
/************************************************** ***************************/
// I2C Requests:
/**
* The I2C_requestedDataReady Event Handler
*/
void I2C_requestedDataReady(uint8_t dataRequestID)
{
checkRP6Status(dataRequestID);
}
/************************************************** ***************************/
// I2C Error handler
/**
* This function gets called automatically if there was an I2C Error like
* the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
*/
void I2C_transmissionError(uint8_t errorState)
{
writeString_P("\nI2C ERROR - TWI STATE: 0x");
writeInteger(errorState, HEX);
writeChar('\n');
}
/************************************************** ***************************/
// Main function - The program starts here:
int main(void)
{
initRP6Control();
initLCD();
writeString_P("\n\nRP6 CONTROL M32 I2C Master Example Program!\n");
writeString_P("\nMoving...\n");
// ---------------------------------------
WDT_setRequestHandler(watchDogRequest);
// ---------------------------------------
I2CTWI_initMaster(100);
I2CTWI_setRequestedDataReadyHandler(I2C_requestedD ataReady);
I2CTWI_setTransmissionErrorHandler(I2C_transmissio nError);
sound(180,80,25);
sound(220,80,25);
setLEDs(0b1111);
showScreenLCD("################", "################");
mSleep(500);
showScreenLCD("I2C-Master", "Behaviours");
mSleep(1000);
setLEDs(0b0000);
// ---------------------------------------
// Setup ACS power:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_ACS_POWER, ACS_PWR_MED);
// Enable Watchdog for Interrupt requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT, true);
// Enable timed watchdog requests:
I2CTWI_transmit3Bytes(I2C_RP6_BASE_ADR, 0, CMD_SET_WDT_RQ, true);
startStopwatch1();
startStopwatch2();
startStopwatch3();
showScreenLCD("Active Behaviour", "");
while(true)
{
task_checkINT0();
task_I2CTWI();
RP6_Bewegung();
}
return 0;
}
die hexdatei hat bei mir 19KB speicherplatz.
wär echt dankbar, wenn das mal jemand bei sich selber ausprobieren würde. das würde die problemsuche erhelblich erleichtern.
mfg andi
Hallo,
tja - compilier doch mal das Selftest programm (bitte nochmal das komplette Zip Archiv neu von der RP6 Website herunterladen evtl. ist da ja was falsch über die Leitung gekommen... ) und poste die KOMPLETTE compilerausgabe hier.
Vielleicht sieht man ja worans hapert.
Ach und wenn die Programme sich alle nicht übersetzen lassen ist definitiv was am Compiler/Linker "defekt" denn es funktioniert ja sonst bei allen anderen ;)
Schick mir dann bitte auch noch das ggf. erzeugte Hexfile per PM - kann zwar nicht garantieren das ich was daran erkenne aber würde mich interessieren.
Poste von deinem eigenen Programm besser mal die CRC16 Checksumme die der RP6Loader im Hexviewer anzeigt.
Welches Betriebssystem verwendest Du eigentlich?
MfG,
SlyD
proevofreak
02.04.2010, 21:25
hier ist die compilerausgabe, beim übersetzen des selftest_M32 programms (ich hoffe du meinst das hier):
> "make.exe" all
-------- begin --------
avr-gcc (WinAVR 20080610) 4.3.0
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compiling: RP6Control_SELFTEST.c
avr-gcc -c -mmcu=atmega32 -I. -gdwarf-2 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=RP6Control_SELFTEST.lst -I../../RP6Lib -I../../RP6Lib/RP6control -I../../RP6Lib/RP6common -std=gnu99 -MD -MP -MF .dep/RP6Control_SELFTEST.o.d RP6Control_SELFTEST.c -o RP6Control_SELFTEST.o
Linking: RP6Control_SELFTEST.elf
avr-gcc -mmcu=atmega32 -I. -gdwarf-2 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=RP6Control_SELFTEST.o -I../../RP6Lib -I../../RP6Lib/RP6control -I../../RP6Lib/RP6common -std=gnu99 -MD -MP -MF .dep/RP6Control_SELFTEST.elf.d RP6Control_SELFTEST.o ../../RP6Lib/RP6control/RP6ControlLib.o ../../RP6Lib/RP6common/RP6uart.o ../../RP6Lib/RP6common/RP6I2CmasterTWI.o --output RP6Control_SELFTEST.elf -Wl,-Map=RP6Control_SELFTEST.map,--cref -lm
Creating load file for Flash: RP6Control_SELFTEST.hex
avr-objcopy -O ihex -R .eeprom RP6Control_SELFTEST.elf RP6Control_SELFTEST.hex
Creating Extended Listing: RP6Control_SELFTEST.lss
avr-objdump -h -S RP6Control_SELFTEST.elf > RP6Control_SELFTEST.lss
Creating Symbol Table: RP6Control_SELFTEST.sym
avr-nm -n RP6Control_SELFTEST.elf > RP6Control_SELFTEST.sym
Size after:
AVR Memory Usage
----------------
Device: atmega32
Program: 7368 bytes (22.5% Full)
(.text + .data + .bootloader)
Data: 203 bytes (9.9% Full)
(.data + .bss + .noinit)
-------- end --------
> Process Exit Code: 0
aber ich glaube du hast mich falsch verstanden. das kompilieren sämtlicher programme funktioniert fehlerfrei, zumindest spuckt der compiler keine fehlermeldung aus.
ich programmiere ja auch schon länger mit dem RP6 und da hab ich bisher auch noch nie probleme mit dem compilieren gehabt.
das komplette hexfile schick ich dir per PM.
mfg andi
Bei mir erzeugt der Compiler definitiv was anderes.
Das Hexfile von Dir ist größer, bei mir erzeugt er nur 6608 Bytes bei Dir 6632.
Die Compilerversion ist aber identisch also sollte das nicht sein.
Also nochmal - welches Betriebssystem und hast Du in letzter Zeit *irgendwas* am System geändert?
proevofreak
03.04.2010, 14:38
danke SlyD für deine hilfe,
also ich verwende windows xp als betriebssystem. ich tüftel schon öfter mal am pc rum und da kann es schon sein, dass ich etwas verstellt habe, was jetzt das compiler programm behindert.
ich werd jetzt einfach mal ne systemwiederherstellung machen und dann das ganze nochmal probieren.
hoffentlich lässt sich das problem so beheben.
mfg andi
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.