Problem mit Lichtschranke

Liebe Arduino Bastler,

ich beginne gerade damit mich als frisch gebackener Physiklehrer für Arduino zu interessieren. Ich bastle seit Tagen an einer Laser-Lichtschranke zur Geschwindigkeitsmessung und komme an einem entscheidenden Punkt nicht weiter.

Ich habe ein zweizeiliges LCD-Display, Fotodioden GL5539 und Laserdioden (5V).

So sieht aktuell mein Code aus:

#include <LiquidCrystal.h> //LCD-Bibliothek laden

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); 

int LS1= A0; // "LS1" steht für "Lichtschranke1"
long sensorWert1= 0;// Sensorwert der LS1
int LS2= A1; // Lichtschranke2
long sensorWert2= 0; // Sensorwert der LS2
int a= 10000; // Abstand zwischen LS1 und LS2

int zeit1 = 0; // Zeitpunkt durchschritt LS1
int zeit2 = 0; // Zeitpunkt durchschritt LS2
int zeit3 = 0; // Zeitdiffernez zwischen LS1 und LS2
int v = 0; // Geschwindigkeit

void setup() 
{
lcd.begin(16, 2); //16 Zeichen in 2 Zeilen.
}

void loop() 
{
lcd.setCursor(0, 0);
sensorWert1 = analogRead(LS1);


if (sensorWert1 <= 500)
{zeit1 = millis();}

sensorWert2 = analogRead(A1);

if (sensorWert2 <= 500)
{zeit2 = millis();}

zeit3=(zeit2-zeit1);

if (zeit3 <=0)
{
lcd.print ("Geschwindigkeit:");}

else
{

lcd.setCursor(0, 1);
v=(a/zeit3);
lcd.print(v);
}

}

Das Ergebnis sollte in der Einheit (m/s) sein. Leider funktioniert die Rechnung irgendwie nicht. Es müsste eine Kommazahl mit zwei Nachkommastellen angezeigt werden…

Ich vermute, es liegt irgendwie an den Variablen.

Schau Dir mal die Variablentypen an, die es gibt. Tipp: Fließkommazahlen haben Kommastellen.

Gruß Tommy

Hallo - um Nachkommastellen zu sehen, muss eine Variable vom typ "float" genommen werden. Int steht nur für Ganzzahlen. Ihre Variable "v" für die Geschwindigkeit muss also vom Typ "float" sein!

float v;  // Variable für die Geschwindigleit
 ...

v = float(a) / zeit3;
lcd.print(v);

int zeit1 = millis(); ist das größere Problem !

millis() liefert einen Datentyp unsigned long ( 32 bit ) Mit einem int bist du auf 32 Sekunden (seit Reset) beschränkt.

Ihr seit ja schneller als die Polizei erlaubt :slight_smile:

Ich habe jetzt “float” als Variable genommen, schon funktioniert es! Vielen Dank!

Mit einem int bist du auf 32 Sekunden (seit Reset) beschränkt.

Ich habe jetzt "float" als Variable genommen, schon funktioniert es!

Offenbar sind die Zeitintervalle kurz genug, oder die ausgeworfenen Werte suggerieren einfach nur "korrekte" Werte, weil sie mit Nachkommastellen angezeigt werden.

sYros2k:
ich beginne gerade damit mich als frisch gebackener Physiklehrer für Arduino zu interessieren.

Ich hätte da mal eine Frage zur Raumzeit … kennst Du Dich damit aus?

Erstmal Arduino, das muß ja besonders gut werden, da die Schüler wohl gleich die richtigen Sachen lernen sollen, oder? Ich lege den Anspruch also besonders hoch!

Die IDE hat mit t eine automatische Formatierung, die der Übersicht hilft. Überflüssige Leerzeilen zerreißen ein Programm, vor else eher verwirrend.

LC-Displays gibt es mit I2C-Adapter, auch nachträglich, das spart Pins.

Konstante Werte wie Pinnummern sollten auch in Konstanten gespeichert werden. Zeiten sind unsigned long. Der Typ int ist selten sinnvoll, mal ein Vorschlag, über den man im Detail noch nachdenken müßte:

const byte LS1 = A0; // "LS1" steht für "Lichtschranke1"
uint16_t sensorWert1 = 0; // Sensorwert der LS1
const byte LS2 = A1; // Lichtschranke2
uint16_t sensorWert2 = 0; // Sensorwert der LS2
const uint16_t a = 10000; // Abstand zwischen LS1 und LS2

uint32_t zeit1 = 0; // Zeitpunkt durchschritt LS1
uint32_t zeit2 = 0; // Zeitpunkt durchschritt LS2
uint32_t zeit3 = 0; // Zeitdiffernez zwischen LS1 und LS2
float v = 0; // Geschwindigkeit

Eine Lichtschranke macht an/aus, sollte daher digital ausgewertet werden, also digitalRead().

Berechnungen erfolgen als Standard in int: 3 / 2 ergibt die Ganzzahl 1. Man kann das natürlich steuern: 3 / 2.0 ergibt die Fließkommazahl 1,5. Fallstrick: Auch wenn die Zahl links vom Komma vom Typ float ist, wird die Berechnung rechts vom Komma mit int durchgeführt. Das kann man steuern mit der Floatkonstanten 1.0:

const uint16_t a = 10000;
uint32_t zeit3;
...
    v = (1.0 * a / zeit3);

Oder

const float a = 10000;
uint32_t zeit3;
...
    v = (a / zeit3);

Andere Möglichkeiten wurden schon gezeigt.

Die Genauigkeit von float ist begrenzt, hängt auch von der Hardware (UNO?) ab.

Hast Du auch die zeit1 bis zeit3 also die 'int zeit1' ... 'int zeit3' in 'unsigned long zeit1' ... 'unsigned long zeit3' geändert? Sonst bekommst Du da früher oder später Probleme mit.

LG Stefan

Hi

Da Du gerade mit Arduino anfängst, hast Du noch nicht so lange damit zu tun. Selber benutze ich als Datentypen nicht die Arduino-namen (int, long, long long, unsigned), sondern uint16_t Das u steht für unsigned - also vorzeichenlos (nur Zahlen >=0) - ohne u signed = +/- halber Wertebereich int Ganzzahl ... keine Komma 16 die Breite in Bit, Wertebereich 2^16 _t ... irgend ein Überbleibsel aus grauer Vorzeit

Das ist auf JEDEM µC genau so groß, wie Du Das angegeben hast. Ein INT ist auf dem Arduino 16 Bit breit, auf einem ARM mehr!! Spätestens, wenn Du den Kram zwischen den verschiedenen µCs tauschen willst, kanns Probleme geben.

So, muß abbrechen ... Essen wartet :)

MfG

Float Zahlen haben nur 6-7 significante Stellen. Das kann knapp werden. Bei millis() bietet sich sowieso an die Zeit in millisekunden zu messen und dann in Sekunden und Hunderstel zu berechnen und dann bei der Ausgabe ein Komma dazwischen zu hängen.

Grüße Uwe

uwefed: Float Zahlen haen nur 6-7 significante Stellen. Das kann knapp werden. Bei millis() bietet sich sowieso an die Zeit in millisekunden zu messen und dann in Sekunden und Hunderstel zu berechnen und dann bei der Ausgabe ein Komma dazwischen zu hängen.

Grüße Uwe

Hallo, er wollte letzlich die Geschwindigkeit berechnen in m/s da wird er ohne einen float nicht hinkommen. Zeitmessung in ms ist ok.

Gruß Heinz

Ich danke euch für die vielen Hinweise. Ich habe versucht einiges davon umzusetzen:

#include <LiquidCrystal.h> //LCD-Bibliothek laden

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const byte LS1 = A0; // "LS1" steht für "Lichtschranke1"
uint16_t sensorWert1 = 0; // Sensorwert der LS1
const byte LS2 = A1; // Lichtschranke2
uint16_t sensorWert2 = 0; // Sensorwert der LS2
const float a = 150; // Abstand zwischen LS1 und LS2 (in mm)

uint32_t zeit1 = 0; // Zeitpunkt durchschritt LS1
uint32_t zeit2 = 0; // Zeitpunkt durchschritt LS2
uint32_t zeit3 = 0; // Zeitdifferenz zwischen LS1 und LS2
float v = 0;

void setup()
{
  lcd.begin(16, 2); //16 Zeichen in 2 Zeilen.
}

void loop()
{
  lcd.setCursor(0, 0);
  sensorWert1 = analogRead(LS1);


  if (sensorWert1 <= 500)
  {
    zeit1 = millis();
  }

  sensorWert2 = analogRead(LS2);

  if (sensorWert2 <= 500)
  {
    zeit2 = millis();
  }

  zeit3 = (zeit2 - zeit1);

  if (zeit3 <= 0)
  {
    lcd.print ("Geschwindigkeit:");
  }

  else
  {

    lcd.setCursor(0, 1);
    v = ((a) / zeit3);
    lcd.print(v);
    lcd.setCursor(7, 1);
    lcd.print("m/s");
  }

}

Wenn ich jedoch von analogRead zu digitalRead wechsle, dann springt die Anzeige nur noch von 150 auf 75 und zurück…

Die inzwischen gemessenen Geschwindigkeiten entsprechen den Erwartungen. Ich lasse Glasmurmeln durch die Lichtschranken fahren und kann ja mit der Stoppuhr zumindest ansatzweise die Werte überprüfen. Nur bei sehr hohen Geschwindigkeiten tritt noch ein Fehler auf, es erscheint ein viel zu kleiner Wert.

agmue:
Ich hätte da mal eine Frage zur Raumzeit … kennst Du Dich damit aus?

Die Genauigkeit von float ist begrenzt, hängt auch von der Hardware (UNO?) ab.

Ich bin Lehrer für die Sekundarstufe 1 - alles was in Richtung Raumzeit geht, weiß ich nur durch mein privat motiviertes Interesse an Physik - was möchtest du denn da wissen?

Ich habe einen Arduino von Funduino (UNO R3).

Hallo,

so richtig weiter gekommen bist Du ja noch nicht. Das könnte damit zusammen hängen das du nicht mit den Flanken der Lichtschranken arbeitest. Zudem könnte das mit dem lesen der Analogen Werte etwas "wackelig" sein. Wichtig ist auch das Du einen eindeutigen Status des Zustandes hast ob die Messung gerade läuft oder nicht. Zudem kann es sein das die ständige Bearbeitung des Displays dazu führen das es ungenau wird. Eventuell macht man das auch nur alle 200ms einmal, dann ist die Wahsceinlichkeit des Unglücksfalles kleiner. ;)

ich hab Dir mal eine Lösung gebastelt. Allerdings hab ich dazu Taster verwendet, sollte aber egal sein. Lichtschranken benötigen in der Regel keinen PULLUP Widerstand. Natürlich gibt es wie immer viele Wege nach Rom. Anzeige erfolgt nur wenn die Messung beendet ist. Wenn Du dein Display alle 200 ms aktualisieren willst nimmst Du einenTakt den du wieder von millis() ableitest und rufst damit die functoin auf wenn die Messung läuft und dann noch einmal wie jetzt wenn sie beendet wird.

Du must jetzt noch prüfen wie Deine Schichtschranken schalten. Also wenn die Lichtschranke belegt (unterbrochen) ist, ob dann der Eingang H oder L ist. Entsprechend must Du das dann invertieren oder eben nicht.

Heinz

/*
 * Hardware UNO mit zwei Tastern 
 * Taster schalten gegen 0V
 */

const byte startpin = 3;// Pin festlegen
const byte stoppin = 4;
uint32_t startzeit;
uint32_t messzeit;// Messergebniss in ms 

bool startflag, startLS; // status Variable 
bool stopflag, stopLS;

float distance = 1000.0; // Messtrecke in mm
float V;  // Geschwindigkeit in m/s

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(startpin, INPUT_PULLUP); // interner PULLUP aktiv
  pinMode(stoppin, INPUT_PULLUP);
  // pinmode(startpin,INPUT);// interner PULUP nicht aktiv
}


void loop() {

  startLS = !digitalRead(startpin); //Pin einlesen und invertieren
  //startLS =digitalRead(startpin); // Pin einlesen nicht invertieren
  stopLS = !digitalRead(stoppin);

  if (startLS && !startflag) { // Abfrage start
    Serial.println("start");
    startflag = true;     // Flanke erkannt Messung läuft
    stopflag = false;     // reset stop Flanke
    startzeit = millis(); // startzeit setzen
  }

  if (stopLS && startflag && !stopflag) { // Abfrage Stop 
    Serial.println("stop");
    stopflag = true;// Flanke erkannt
    messzeit = millis() - startzeit;  // Messzeit berechnen
    V = distance / messzeit;          // Geschw. rechnen
    display();// zur Anzeige
    startflag = false;// wieder bereit für neuen start

  }
}

void display() {
  Serial.println("---------------");
  Serial.print("Messzeit ms \t"); Serial.println(messzeit);
  Serial.print("Geschw. m/s \t"); Serial.println(V, 4);

}

Vielen Dank für die weiteren Hinweise. Ich habe versucht das ganze umzusetzen. Auch wenn ich nicht alles ganz nachvollziehen konnte, funktioniert die Sache nun sauber.

Hier ist der Code:

#include <LiquidCrystal.h> //LCD-Bibliothek laden

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const byte LS1 = A0; // "LS1" steht für "Lichtschranke1"
uint16_t sensorWert1 = 0; // Sensorwert der LS1
const byte LS2 = A1; // Lichtschranke2
uint16_t sensorWert2 = 0; // Sensorwert der LS2
const float a = 150; // Abstand zwischen LS1 und LS2 (in mm)

uint32_t zeit1 = 0; // Zeitpunkt durchschritt LS1
uint32_t zeit2 = 0; // Zeitpunkt durchschritt LS2
uint32_t zeit3 = 0; // Zeitdifferenz zwischen LS1 und LS2
float v = 0;

bool startflag, startLS;
bool stopflag, stopLS;


void setup()
{
  lcd.begin(16, 2); //16 Zeichen in 2 Zeilen.
  pinMode (LS1, INPUT_PULLUP); // interner PULLUP ist aktiv
  pinMode (LS2, INPUT_PULLUP);
  pinMode (LS1, INPUT);
}

void loop()
{
  lcd.setCursor(0, 0);
  startLS = !digitalRead(LS1);
  stopLS = !digitalRead(LS2);

  if (startLS && !startflag) {
    lcd.print("Start");
    startflag = true;
    stopflag = false;
    zeit1 = millis();
  }
  if (stopLS && startflag && !stopflag) {
    stopflag = true;
    zeit3 = (millis() - zeit1);

    v = (a / zeit3);
    lcd.print(v);
    lcd.print("m/s");
    startflag = false;

  }
}

Für mich ist dieser Teil des Projekts beendet, es funktioniert :slight_smile: Ich habe bereits ein neues Thema aufgemacht, in dem ich Hilfe für Teil 2 des Projektes brauche.

Hallo,

Schön daß es jetzt klappt. Allerdings hast du die beiden Lichtschranken anscheinen immer noch an den Analog pins A0,A1 angeschlossen. Kannst du so lassen wenn du willst, ist aber eigendlich verschenkt
Mit einem Abstand von 150mm kann das Ergebniss so nicht stimmen denke ich, kann aber sein das ich was übersehen habe.
Heinz

Fotodioden GL5539

Die GL5539 ist ein Fotowiderstand (LDR) und somit ungeeignet Für eine schnelle messung eweil er zu träge ist. Du brauchst einen Fototransistor oder wenn ganz genau und schnell eine Fotodiode. Eventuell zusätzliche Elektronik.

Grüße Uwe