Forum: Mikrocontroller und Digitale Elektronik Lichtsensor Servo steuern


von cube4 (Gast)


Lesenswert?

Hallo,

Ich habe zwei Lichtsensoren die über den ADC ausgelesen werden und je 
nachdem einen Servo steuern sollen.
Ich bräuchte ein paar Denkanstöße wie ich das realisieren könnte.

In einer Schleife ?

LinkerSensor == RechterSensor
(nichts tun bzw. Letzten PWM-Wert beibehalten)

Wenn LinkerSensor > RechterSensor
(Servo nach Links drehen bis LinkerSensor == RechterSensor)
aber wie könnte ich das umsetzen ? eine Schleife die meinen Letzten PWM 
Wert runterzählt bis wieder LinkerSensor == RechterSensor ?

oder gibt es da einfachere Methoden und ich denke wieder zu Kompliziert 
?

Danke

von Karl H. (kbuchegg)


Lesenswert?

cube4 schrieb:

> oder gibt es da einfachere Methoden und ich denke wieder zu Kompliziert
> ?

Die Grundidee ist nicht so falsch, aber die Usetzung ist viel zu 
kompliziert.
Du hast noch nicht verinnerlicht, dass dir die Hauptschleife, die jedes 
µC Programm hat, automatisch eine Art Zeittaktung deines Programms 
vorgibt, in die du dich am besten einklinkst, anstatt gegen sie zu 
arbeiten.

Jedes µC Programm sieht in etwa so aus
1
int main()
2
{
3
  Initialisierungen
4
5
  sei();
6
7
  while( 1 ) {
8
9
    Programmlogik
10
11
  }
12
}

Der Teil Programmlogik ist der interessante Teil. Deine Denkweise muss 
sein, dass sich die Programmlogik immer nur um Zeitpunkte kümmert. D.h. 
deine Programmlogik fragt sich: Was genau gibt es jetzt zu tun? Welche 
Ereignisse sind eingetreten? Welche Messwerte liegen vor? Welche 
Aktionen leiten sich daraus ab?
Und ein paar Myykrosekunden später beginnt die Hauptschliefe wieder von 
vorne und der ganze Prozess des "Was gibt es genau jetzt zu tun? etc. 
etc" beginnt wieder von vorne. Nur das eben jetzt ein etwas späterer 
Zeitpunkt vorliegt.


D.h. dein Programm baust du so auf
1
  ...
2
3
  while( 1 ) {
4
5
    Messung Links
6
    Messung Rechts
7
8
    if ( Messung Links < Messung Rechts )
9
      drehe Servo etwas nach links (zb PWM Wert--)
10
11
    else if ( Messung Links > Messung Rechts )
12
      drehe Servo etwas nach rechts (zb PWM Wert++)
13
14
    else
15
      stoppe Servo (zb PWM Wert nicht verändern)
16
  }

du musst dich von dieser "Ich drehe nach links bis die Werte gleich 
sind, und das Ganze am Besten in einer Schleife" - Denkweise lösen. Du 
hast bereits eine Schleife - deine Hauptschleife. Dein Programm ackert 
diese durch, viele tausend mal in der Sekunde. So schnell ist deine 
Hardware nicht, dass dein Programm den Punkt verpassen würde, an dem die 
beiden Messwerte gleich sind. Ganz im Gegenteil wird dein Programm eher 
sogar zu schnell sein, so dass du es bremsen musst, damit es den PWM 
Wert nicht viel zu schnell ändert, so dass das Servo nicht mitkommt.

>
> Danke

von cube4 (Gast)


Lesenswert?

Habe es jetzt mal so umgesetzt aber ich mache irgendwas mit meiner 
Funktion falsch, kann mich jemand aufklären ?
1
#include <avr/io.h>
2
#include "MrLCD.h"
3
#include <util/delay.h>
4
  
5
6
uint16_t LinkerSensor = 0;
7
uint16_t RechterSensor = 0;
8
uint16_t LetzterWert = 512;
9
10
void SensorenAuswerten(void);
11
12
  
13
int main(void)
14
{
15
  
16
  InitializeMrLCD(); //LCD initialisieren
17
18
  //ADC initialisieren
19
  
20
  ADCSRA = (1<<ADPS2) | (1<<ADEN); // Prescaler 16 | ADC-An 
21
  ADMUX  |= (1<<REFS0);        // AVCC als Referenz Kondensator bei AREF
22
  
23
  //PWM initialisieren
24
  
25
  DDRD |= 1<<PORTD4 ; // PD4 auf Ausgang
26
  TCCR1A |= 1<<WGM11| 1<<COM1B1 | 1<<COM1B0; // Fast PWM | PD4 Inverted
27
  TCCR1B |= 1<<WGM12 | 1<<WGM13 | 1<<CS10;  // Fast PWM  | Prescaler 1
28
  ICR1 = 19999;  // 20ms Period  
29
  //Send_A_StringToMrLCDwithLocation(1,1,"MUUUHHH!!!");
30
  
31
while (1)
32
{
33
  
34
  void SensorenAuswerten();
35
36
37
  if(LinkerSensor > RechterSensor) //Wenn LinkerSensor größer dann
38
  {  
39
    LetzterWert --; //LetzenWert verringern  
40
    OCR1A = LetzterWert; //Und an PWM ausgeben
41
  }
42
  
43
    else if(LinkerSensor < RechterSensor)  
44
  {  
45
    LetzterWert ++; //LetzenWert vergrößern  
46
    OCR1A = LetzterWert; //Und an PWM ausgeben
47
  }
48
  
49
    else if(LinkerSensor == RechterSensor) //Wenn gleich
50
51
  {
52
    OCR1A = LetzterWert; //dann nichts tun Letzten Wert behalten
53
  }
54
55
    
56
    
57
}
58
  
59
  
60
void SensorenAuswerten()
61
{
62
63
  //Linken Sensor auslesen
64
  
65
  ADMUX = 0x40; // REFS0 (AVCC) | PA0 lesen 
66
  ADCSRA |= (1<<ADSC);        //1. ADC PA0 auslesen Linker Sensor
67
  while (ADCSRA & (1<<ADSC) ) {}   //auf Abschluss der Konvertierung warten
68
  
69
  LinkerSensor = ADC;     //und in Variable übergeben
70
  
71
  Send_A_StringToMrLCDwithLocation(1,1,"Links:");
72
  Send_An_IntegerToMrLCD(7, 1, LinkerSensor,7); //Ergebnis an Display senden
73
74
  
75
  //Rechten Sensor auslesen
76
  
77
  ADMUX = 0x41; // REFS0 (AVCC) | PA1 lesen
78
  ADCSRA |= (1<<ADSC);       //2. ADC PA1 auslesen Rechter Sensor
79
  while (ADCSRA & (1<<ADSC) ) {}  //auf Abschluss der Konvertierung warten
80
  
81
  RechterSensor = ADC;   //und in Variable übergeben
82
  
83
  Send_A_StringToMrLCDwithLocation(1,2,"Rechts:");
84
  Send_An_IntegerToMrLCD(7, 2, RechterSensor,7); //Ergebnis an Display senden
85
86
}
87
88
}

von Karl H. (kbuchegg)


Lesenswert?

Das
1
while (1)
2
{
3
4
  void SensorenAuswerten();

ist kein Funktionsaufruf, sondern die Deklaration einer Funktion, von 
deren Argumentliste nichts bekannt ist und die nichts zurückliefert.

Das
1
while (1)
2
{
3
4
  SensorAuswerten();

wäre einer.

von cube4 (Gast)


Lesenswert?

So bekomme ich aber das Warning:

undefined reference to SensorAuswerten

von Karl H. (kbuchegg)


Lesenswert?

cube4 schrieb:
> So bekomme ich aber das Warning:
>
> undefined reference to SensorAuswerten


Wie heisst noch mal deine Funktion?

  SensorAuswerten   (also Einzahl)

oder

  SensorenAuswerten   (also mehrere Sensore_n_)

?

Deine Funktionsnamen solltest du schon kennen, selbst wenn ich mich in 
der Eile vertippe.

von cube4 (Gast)


Lesenswert?

Ne ich hab mich vertippt SensorenAuswerten, aber die Funktion heißt bei 
mir überall gleich und der Fehler kommt trotzdem ?

von Karl H. (kbuchegg)


Lesenswert?

Sie kann nicht überall gleich heißen, sonst würdest du den Fehler nicht 
kriegen. Irgendwo muss ein Tippfehler sein.

Nimm den Namen in den Copy&Paste Buffer und kopier ihn überall drüber. 
So ist sichergestellt, dass alle Schreibweisen überall gleich sind.

von MaWin (Gast)


Lesenswert?

Ein eindeutiges Argument warum man nichts in eine Funktion verpacken 
sollte wenn man ss sowieso nur ein Mal aufruft. Dann muss man auch nicht 
darauf achten, die Funktion vor der Verwendungsstelle zu definieren.
Du solltest deiner PWM noch Zeit geben, den Impuls auszugeben und die 
Wartezeit abzuwarten, bevor du schon wieder den PWM Wert änderst.

von Karl H. (kbuchegg)


Lesenswert?

MaWin schrieb:
> Ein eindeutiges Argument warum man nichts in eine Funktion verpacken
> sollte wenn man ss sowieso nur ein Mal aufruft.

(*)

Na ja.
Iregendwann muss er aber mal lernen, worauf er achten muss und wie 
Fehlermeldungen zu interpretieren sind.

> Dann muss man auch nicht
> darauf achten, die Funktion vor der Verwendungsstelle zu definieren.

Er braucht nur die Funktion vor main schieben und auf die Schreibweise 
achten.
Das Argument sollte eigentlich lauten: Ein eindeutiges Argument, warum 
man auf Funktionsnamen achten soll, die einem wenig Spielraum für 
Tippfehler geben ohne dass man es bemerkt.

> Du solltest deiner PWM noch Zeit geben, den Impuls auszugeben und die
> Wartezeit abzuwarten, bevor du schon wieder den PWM Wert änderst.

Das allerdings.



(*) mich regen Funktionsnamen wie Send_A_StringToMrLCDwithLocation viel 
mehr auf. Viel zu lang, viel zu kindisch.

von cube4 (Gast)


Lesenswert?

Hallo,

also an den Namen liegt es wirklich nicht hab es Kopiert, das mit den 
Namen
Send_A_StringToMrLCDwithLocation ist schon "besch.." ja :-) aber das hab 
ich von einer Seite die die ganzen Funktionen für mich wirklich gut 
verständlich rübergebracht hat, habe es erstmal so beibehalten.

Sei es wie es will, lass ich die Funktion weg und packe es so in die 
Schleife funktioniert es meiner Meinung nach recht gut, NUR meine PWM 
noch nicht also Servo bewegt sich nicht.

Werde das mit der Zeit mal einbauen und sehen.

von cube4 (Gast)


Lesenswert?

So habe es jetzt so gelöst funktioniert recht gut, obwohl nicht nötig, 
würde mich dennoch interessieren wie ich den Servo noch schneller machen 
könnte ?
Die In bzw. Dekrementierung erhöhen ?
1
#include <avr/io.h>
2
#include "MrLCD.h"
3
#include <util/delay.h>
4
  
5
6
uint16_t LinkerSensor = 0;
7
uint16_t RechterSensor = 0;
8
9
//void SensorenAuswerten(void);
10
11
  
12
int main(void)
13
{
14
  
15
  InitializeMrLCD(); //LCD initialisieren
16
17
  //ADC initialisieren
18
  
19
  ADCSRA = (1<<ADPS2) | (1<<ADEN); // Prescaler 16 | ADC-An 
20
  ADMUX  |= (1<<REFS0);        // AVCC als Referenz Kondensator bei AREF
21
  
22
  //PWM initialisieren
23
  
24
  DDRD |= 1<<PORTD4; // PD4 auf Ausgang
25
  TCCR1A |= 1<<WGM11| 1<<COM1B1 | 1<<COM1B0; // Fast PWM | PD4 Inverted
26
  TCCR1B |= 1<<WGM12 | 1<<WGM13 | 1<<CS10;  // Fast PWM  | Prescaler 1
27
  ICR1 = 19999;  // 20ms Period  
28
  
29
  uint16_t LetzterWert = ICR1 - 1500; //ServoPos = Mitte (18499)
30
31
  
32
while (1)
33
{
34
  
35
  //Linken Sensor auslesen
36
  
37
  ADMUX = 0x40; // REFS0 (AVCC) | PA0 lesen 
38
  ADCSRA |= (1<<ADSC);        //1. ADC PA0 auslesen Linker Sensor
39
  while (ADCSRA & (1<<ADSC) ) {}   //auf Abschluss der Konvertierung warten
40
  
41
  LinkerSensor = ADC;     //und in Variable übergeben
42
  
43
  Send_A_StringToMrLCDwithLocation(1,1,"Links:");
44
  Send_An_IntegerToMrLCD(7, 1, LinkerSensor,7); //Ergebnis an Display senden
45
46
  
47
  //Rechten Sensor auslesen
48
  
49
  ADMUX = 0x41; // REFS0 (AVCC) | PA1 lesen
50
  ADCSRA |= (1<<ADSC);       //2. ADC PA1 auslesen Rechter Sensor
51
  while (ADCSRA & (1<<ADSC) ) {}  //auf Abschluss der Konvertierung warten
52
  
53
  RechterSensor = ADC;   //und in Variable übergeben
54
  
55
  Send_A_StringToMrLCDwithLocation(1,2,"Rechts:");
56
  Send_An_IntegerToMrLCD(7, 2, RechterSensor,7); //Ergebnis an Display senden
57
  
58
  int16_t Differenz = LinkerSensor - RechterSensor;
59
60
61
  if(Differenz > 50) //Wenn Differenz größer als +50 
62
  {  
63
    LetzterWert  --; //LetzenWert verringern  z.B 18499 --; = 18498
64
    OCR1B = LetzterWert; //Und an PWM ausgeben
65
    
66
  }
67
  
68
    else if(Differenz < -50) //Wenn Differenz kleiner als -50  
69
  {  
70
    LetzterWert ++; //LetzenWert vergrößern  
71
    OCR1B = LetzterWert; //Und an PWM ausgeben
72
  }
73
  
74
    else  //ansonsten 
75
76
  {
77
    OCR1B = LetzterWert; //dann nichts tun Letzten Wert behalten
78
  }
79
80
    
81
    
82
}
83
  
84
  
85
86
87
  
88
89
90
}

von Mikesch (Gast)


Lesenswert?

Hi

Manchmal kommt man auch auf Ideen für Programme indem man sich eine 
Analogschaltung anschaut, die den selben Zweck erfüllt.

http://www.electronicsplanet.ch/Schaltun/servoson/servosonnennachfuehrung.html

Gruss
Mikesch

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.