Forum: Mikrocontroller und Digitale Elektronik sensoren auswerten und fahren: Nebenläufigkeit?


von Erdnuckel (Gast)


Lesenswert?

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?

von Philipp (Gast)


Lesenswert?

externen schrittmotortreiber oder dc-motoren verwenden

von Uwe .. (uwegw)


Angehängte Dateien:

Lesenswert?

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.

von Erdnuckel (Gast)


Lesenswert?

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!

von Thomas (Gast)


Lesenswert?

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

von Flo (Gast)


Lesenswert?

Die Motorensteuerung kannste auch in einem Timerinterrupt laufen lassen, 
dann muss sich das Hauptprogramm darum nicht kümmern.

von Erdnuckel (Gast)


Lesenswert?

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_t entf=0;
9
10
ISR(ADC_vect)
11
{  
12
PORTC^=32;
13
_delay_ms(10);
14
ADCSRA |= (1<<ADSC); 
15
}
16
17
18
void init()
19
{  
20
  DDRD = 0xFF;      //Port D ist Ausgang
21
  DDRB = 0xFF;
22
  DDRC = (1 << DDC5);    //Port C ist Eingang, bis auf Pin 5
23
  ADMUX|=((1<<REFS0) | (0<<REFS1) | (1<<MUX0) | (0<<MUX1) | (0<<MUX2) | (0<<MUX3) | (1<<ADLAR));
24
  ADCSRA|=((1<<ADEN) | (1<<ADSC) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));
25
}
26
27
28
29
30
int main(void)
31
{  
32
  sei();
33
  init();
34
35
  while(1)
36
  {  
37
    
38
  }
39
  return 0;
40
}

von Erdnuckel (Gast)


Lesenswert?

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.

von Uwe .. (uwegw)


Lesenswert?

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.

von Thomas (Gast)


Lesenswert?

@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 ;-)

von Erdnuckel (Gast)


Lesenswert?

@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?

von MarioT (Gast)


Lesenswert?

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.

von Thomas S. (klegom)


Lesenswert?

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.

von Mar V. (marvol)


Lesenswert?

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

von Erdnuckel (Gast)


Lesenswert?

Danke nochmal für eure Hilfen und Beispiele! Im Moment klappt so alles. 
Ich denke ich bin jetzt auf einem guten Weg.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.