Hallo!
Ich bastele an einem kleinem Fahzeug/Roboter.
Soll erst einmal fahren und Hindernissen ausweichen. Beides geht in die
tichtige Richtung, aaaber:
Ich verwende zur Steuerung einen ATMEGA8, Schrittmotoren und
GP2D12-Infrarotsensoren. Die brauchen ein paar ms um zu messen. In
dieser Zeit stoppen die Motoren natürlich bei sequentiellem
Programmablauf, da die Steuersignale nicht generiert werden.
Wie löst man solche Probleme üblicherweise? Kann man beim ATMEGA8 eine
Art Nebenläufigkeit erreichen?
Ich lasse bei meinem Roboter den ADC für die Infrarotsensoren im
Interrupt-Modus laufen. Dabei wird nach jeder abgeschlossenen Wandlung
die ISR aufgerufen. Dort wird dann das Ergebnis in einer globalen
Variable (aufpassen wegen atomarem Zugriff!) abgelegt und auf den
nächsten Kanal gewechselt. Im Hauptprogramm kann ich mir dann jederzeit
den neusten Wert aus der globalen Variable holen.
Uwe ... schrieb:
> Ich lasse bei meinem Roboter den ADC für die Infrarotsensoren im> Interrupt-Modus laufen. Dabei wird nach jeder abgeschlossenen Wandlung> die ISR aufgerufen. Dort wird dann das Ergebnis in einer globalen> Variable (aufpassen wegen atomarem Zugriff!) abgelegt und auf den> nächsten Kanal gewechselt. Im Hauptprogramm kann ich mir dann jederzeit> den neusten Wert aus der globalen Variable holen.
... und das wäre ja dann so etwas wie Nebenläufigkeit, oder?
Cool, das klingt gut. Ich werde mich da einlesen. Danke auch für den
Code!
Ich löse Nebenläufigkeiten in Mikrocontrollern, indem ich alle Aufgaben
in Zustandsautomaten programmiere, die strikt Message basierend
arbeiten. dadurch kriegt man Nebenläufigkeiten sehr gut in den Griff.
Siehe: http://consulting.astade.de/workshop.htm
Also ich versuche gerade die Lösung mit dem ADC Interrupt, bin aber
irgendwie nicht in der Lage dazu, trotz des guten Beispielcodes von
oben.
Um zu Überprüfen, ob der Interrupt ausgelöst wird, wollte ich eine LED
blinken lassen. Offenbar wird der Interrupt nicht ausgelöst. Wenn ich
das ADIE-Bit lösche, kann ich Messungen vornehmen. Seht ihr einen
Fehler?
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<util/delay.h>
4
#include<stdint.h>
5
#include"motor.h"
6
#define AUSWEICHENTFERNUNG 70
7
#define MESSUNGEN_ENTFERNUNG 3
8
uint8_tentf=0;
9
10
ISR(ADC_vect)
11
{
12
PORTC^=32;
13
_delay_ms(10);
14
ADCSRA|=(1<<ADSC);
15
}
16
17
18
voidinit()
19
{
20
DDRD=0xFF;//Port D ist Ausgang
21
DDRB=0xFF;
22
DDRC=(1<<DDC5);//Port C ist Eingang, bis auf Pin 5
Na gut ich nehm alles zurück. Es geht.
_delay_ms(10) war wohl ein bisschen wenig um das zu sehen.
Motoren laufen aber immer noch nicht ganz rund, wenn auch besser als
vorher.
Wenn du Nebenläufigkeit erreichen willst, darfst du kein _delay_ms()
verwenden! Es blockiert dir für die Verzögerungszeit den gesamten µC.
Wenn Wartezeiten von mehr als einigen µS nötig sind, dann sollten sie
über einen Timer realisiert werden.
Und der Tipp von Thomas ist auch gut. Ich löse selbst viel mit FSMs
(also Zustandsautomaten). Damit kann man komplett auf Pollingschleifen
verzichten, die dir ebenfalls die Nebenläufigkeit vermiesen würden. Das
benutze ich unter anderem für meine Ultraschallsensoren, bei denen es ja
bis zu 60ms dauert, bis das Ergebnis da ist. Statt hier einfach solange
zu warten, bis der Wert da ist, geht die FSM in einem Wartezustand. Bei
jedem Durchlauf der Hauptschleife wird geprüft, ob sich was getan hat.
Wenn ja, wird in den Zustand gewechselt, der den Wert einliest.
Ansonsten wird mit der nächsten Aufgabe (z.B. der Bearbeitung einer
anderen FSM) weitergemacht. Somit wird nie auf irgendein Ereignis
gewartet, und der µC ist nur mit "sinnvollen" Dingen beschäftigt.
@Erdnuckel
Für Dein Problem gibt es eigentlich nur 3 mögliche Lösungen:
1. Intelligenter Einsatz von Interrupt Routinen.
2. Ein Message Passing framework und alles in Zustandsmaschinen.
3. Ein Betriebssystem mit Multiprozessing und/oder Multithreading.
Da Punkt 3 wegen der Größe des Prozessors wohl ausscheidet, musst Du
Dich zwischen 1 und 2 entscheiden. Von 1 rate ich Dir ab, weil:
a) Interrupt Programmierung andere Schwierigkeiten aufwirft (Race
Condition)
b) Interrupt Programmierung fast "undebugbar" ist
c) Du innerhalb der Interrupt Routinen über kurz oder lang auch
"Zustände" brauchen wirst, die Du dann in irgendwelchen globalen
Variablen "versteckst" bis Du den Überblick völlig verloren hast.
Ein "Profi" kriegt das auch mit Interrupts hin. Aber wenn Du mit sowas
noch keine Erfahrung hast, dann stehen Dir viele frustrierende Wochen
bevor.
Für ein Projekt, wie Du es vorhast, kann ich Dir das Framework von
Astade nur wärmstens empfehlen. Gerade weil Du mit Deinen
Programierkünsten noch so am Anfang stehst und eine "Anleitung" zu gutem
Code bräuchtest.
Was Du gewinnst:
a) Keine Interrupts und damit keine Race Conditions
b) Das Trace Framework lässt Dich immer sehen, was Dein Code macht, Du
brauchst nicht mehr mit LEDs zu blinken.
c) Das Framework gibt Dir eine Struktur für Dein Programm vor. Das hilft
Dir am Anfang Ordnung zu halten.
Allerdings kostet es Dich auch was:
a) Du musst dich in das Tool "Astade" einarbeiten
Je nachdem, wie schnell Du bist, wird Dich das 3-5 Tage kosten (Oder Du
nimmst an dem angebotenen Workshop teil). Am Ende hast Du aber ein
mächtiges Werkzeug in der Hand.
Ein Beispiel: Auf meinem AtMega128 läuft ein Webserver der gleichzeitig
4 Verbindungen behandeln kann. Jede Verbindung kann viele verschiedene
Ereignisse haben (Verbindung aufbauen, anfrage, Antwort ..) und die
ganzen Fehlerbehandlungen und Timeouts die das braucht. Die Software hat
keine Interrupts und keine delay Anweisung. Und das beste: Sollte ich
jetzt noch gleichzeitig einen Schrittmotor steuern müssen, dann mache
ich einfach noch eine Maschine dazu ;-)
@Thomas:
Also erst mal danke für die Analyse! Es geht bei mir um ein
Hobby-Freizeitprojekt, also ist mein momentanes Ziel nicht mit Kanonen
auf Spatzen zu schießen. Dein Hinweis mit FSMs ist sehr interessant,
vorläufig werde ich aber versuchen mit Interrupts auszukommen, ggf weiß
ich ja dann, wie ich weitermachen kann.
Thomas schrieb:
> Gerade weil Du mit Deinen> Programierkünsten noch so am Anfang stehst und eine "Anleitung" zu gutem> Code bräuchtest.
Sehr interessant. Will ich gar nicht bestreiten. Jetzt interessiert mich
aber, was genau du meinst? Beziehst du dich auf meinen Codeschnipsel?
Ich wäre gespannt auf ein paar Beispiele.
Thomas schrieb:
> Allerdings kostet es Dich auch was:> a) Du musst dich in das Tool "Astade" einarbeiten>> Je nachdem, wie schnell Du bist, wird Dich das 3-5 Tage kosten (Oder Du> nimmst an dem angebotenen Workshop teil). Am Ende hast Du aber ein> mächtiges Werkzeug in der Hand.
Nimms mir nicht übel, aber kann es sein, dass du hier ein bisschen
Werbung für deinen Workshop machen möchtest?
Erdnuckel schrieb:
> Nimms mir nicht übel, aber kann es sein, dass du hier ein bisschen> Werbung für deinen Workshop machen möchtest?
kommt mir auch so vor. Erdnuckel Das brauchst Du aber auch nicht.
Erdnuckel schrieb:
> Also erst mal danke für die Analyse! Es geht bei mir um ein> Hobby-Freizeitprojekt, also ist mein momentanes Ziel nicht mit Kanonen> auf Spatzen zu schießen. Dein Hinweis mit FSMs ist sehr interessant,> vorläufig werde ich aber versuchen mit Interrupts auszukommen, ggf weiß> ich ja dann, wie ich weitermachen kann.
Wie Du meinst.
Erdnuckel schrieb:
> Sehr interessant. Will ich gar nicht bestreiten. Jetzt interessiert mich> aber, was genau du meinst? Beziehst du dich auf meinen Codeschnipsel?> Ich wäre gespannt auf ein paar Beispiele.
Bitte, ich wollte Dir nicht zu nahe treten. Nein es bezieht sich nicht
auf Deine Codeschnipsel. Aus Deiner Herangehensweise ans Projekt habe
ich das geschlossen. Nicht respektlos gemeint. Ich dachte einfach,
vermuten zu können, dass programmieren eher ein neues Feld für Dich ist
und Du sagst ja selbst, dass ich richtig geraten habe.
Erdnuckel schrieb:
> Nimms mir nicht übel, aber kann es sein, dass du hier ein bisschen> Werbung für deinen Workshop machen möchtest?
Nicht für den Workshop, aber für das Tool möchte ich werben.
Ich benutze es selbst, halte es für sehr gut und bin stolz darauf. Warum
sollte ich es dann nicht empfehlen, das ist schließlich der Sinn eines
Forums, das man Erfahrungen austauscht.
Das Tool ist Open Source, also kostenlos. Du siehst, ich will mich nicht
an Dir bereichern.
Vielleicht hätte ich mir die Bemerkung zum Workshop verkneifen sollen.
Die
dazu gehörende Website ist aber im Augenblick die einzige die ich habe,
wo speziell auf Mikrocontroller eingegangen wird.
Hallo Erdnuckel,
also ich habe ein sehr ähnliches Projekt, dabei hat der Roboter zwei
Schrittmotoren, zwei Sharp-Sensoren und noch ein Funkmodul. Das
Funkmodul überträgt die Roboterdaten nach Anfrage vom PC ca. alle 100
ms.
Am Anfang hatte ich auch das Problem, dass bei der Übertragung der Daten
die Schrittmotoren ruckelten, da das Empfangen in einem Interrupt war
und natürlich die Einstellung der Schrittmotorgeschwindigkeit in den
Timerinterrupts waren.
Lösung: Der Interrupt von dem Funkmodul blieb, aber die Schrittmotoren
liefen mit den Timer im CTC Mode ohne Interrupt. Sollte die
Geschwindigkeit geändert werden, so mußte ich lediglich die Register
OCR0 und OCR2 ändern, beides sind 8Bit-Counter (Umsetzung in einem
ATMega 32):
// Konfiguration vom PWM 0
DDRB |= (1<<PB3); // CLOCK
DDRC |= (1<<PC0); // DIR
DDRC |= (1<<PC1); // ENABLE
TCCR0 |= (1<<WGM01) | (1<<COM00); // CTC PWM
TCCR0 |= (1<<CS00) | (1<<CS02); // Prescaler 1024
TCNT0 = 0;
OCR0 = 20;
// Konfiguration für PWM 2
DDRD |= (1<<PD7); // CLOCK
DDRD |= (1<<PD6); // DIR
DDRB |= (1<<PD5); // ENABLE
TCCR2 |= (1<<WGM21) | (1<<COM20); // CTC PWM
TCCR2 |= (1<<CS20) | (1<<CS21) | (1<<CS22); // Prescaler 1024
TCNT2 = 0;
OCR2 = 20;
Das Auslesen der Sharp-Sensoren ließ ich einfach in der Main-Schleife,
genauso wie der Kommandointerpreter für das Funkmodul. Die Motoren
liefen sauber und die Kommunikation war schnell.
Auch das automatische Verfahren im Raum war bei mir nur ein asynchroner
Regelalgorithmus in der Main-Schleife gewesen, dies war absolut
ausreichend schnell, ich hatte sogar noch ein Delay eingefügt. Für
präzise Anwendungen muss hier sicherlich ein Timerinterrupt verwendet
werden.
Gruß
Marvol