Startseite Skripte für das Wintersemester 2018/19 Projekt „Citizen Science“ Arduino Grundlagen Photo-Resistor-Daten mit Web-Interface


Photo-Resistor-Daten mit Web-Interface

Falls man sich im gleichen Wlan-Netzt befindet: http://arduinopi.local/fotozelle/

Grundlegendes

Bei diesem Projekt ist der Arduino via USB-Kabel mit einem Raspberry Pi verbunden, auf dem Apache und PHP7 installiert ist.

Der Arduino zeichnet alle 5s einen Helligkeiswert auf und schickt diesen über das USB-Kabel an den Raspberry Pi. Via Python werden dort die vom Arduino empfangenen Helligkeitswerte in einer CSV-Datei gespeichert. Via p5.js wird die CSV-Datei ausgelesen und als Graph im Browser dargestellt.

Arduino-Hardware-Aufbau

Der Arduino-Hardware-Aufbau ist identisch mit dem vorherigen Aufbau („Photo-Resistor (Fotozelle)“)

Der Arduino-Code unterscheidet sich auch nicht groß, nur das Abfrage-Intervall wurde auf 5s verlängert!

Arduino

int fotozelle = A0; // Pin Zuweisung bei A0; Widerstand 10 kOhm

void setup() {
  pinMode(fotozelle, INPUT);
  Serial.begin(9600);
}

void loop() {
  int hell = analogRead(fotozelle); // Wert, den Fotozelle ausgibt, wird gelesen

  Serial.println(hell); // Ausgabe des Helligkeitswertes der Foto-Zelle

  // alle 5sek Messung, entsprechend Python-Script "fotozelle_csv_datei.py"
  delay(5000);
}

Das hier gezeigte Python-Script läuft auf dem Raspberry Pi und erzeugt die CSV-Datei "data_log.csv" und speichert diese an einer Stelle, an der p5.js einfach darauf zugreifen kann:

Python

#!/user/bin/env python

# speichert die CSV-Datei im Ordner "/var/www/html/fotozelle/"
# damit das geht, muss das Script mit "sudo" ausgefuehrt werden
# sudo python fotozelle_csv_datei_2.py

import os
import time 
from time import sleep
from datetime import datetime

import serial

# hier richtigen Serial-Port des Arduinos angeben!
port = "/dev/ttyACM0"

# pfad zum HTML-Ordner
pfadDatei = "/var/www/html/fotozelle/daten/data_log.csv"

# Geschwindigkeit muss identisch wie bei Arduino-Script sein!
s1 = serial.Serial(port,9600)
s1.flushInput()

file = open(pfadDatei, "a")

while True:
    if s1.inWaiting()>0:

        # formatierte Datum- und Zeit-Kombination
        now = datetime.now().strftime('%Y-%m-%d,%H:%M:%S')

        # gibt den Helligkeiswert jeweil in einer Zeile aus
        inputValue =s1.readline()

        # "\n" macht jeweils eine Leerzeile
        file.write(str(now)+","+inputValue+"\n")
        file.flush()

        # Script wartet 5 Sekunden, bis es sich wiederholt (entsprechend der Zeit im Arduino-Sketch
        time.sleep(5)

file.close()

Das oben gezeigte Python-Script erzeugt eine CSV-Datei "data_log.csv", die beispielsweise so aussehen könnte:

CSV-Datei (Ausschnitt)

2018-11-03,14:59:43,793

2018-11-03,14:59:48,815

2018-11-03,14:59:53,352

2018-11-03,14:59:58,46

2018-11-03,15:00:03,29

2018-11-03,15:00:08,794

2018-11-03,15:00:13,793

2018-11-03,15:00:18,810

Via p5.js wird diese CSV-Datei eingelesen und als Graph im Canvas einer Website dargestellt

p5.js

var aktuelleWerte;
var HelligkeitsPunkte = [];
var factor = 0.6; // um wieviel wird Skala und Wert skaliert
var breite = 20; // Breite der Säulen
var abstand = 5; // Abstand der Säulen
var rowCount = 0; // wieviele Datensätze sind vorhanden?
var x; // Position des senkrechtes Nullpunktes
var y; // Position des waagrechten Nullpunktes

function preload() {
  // alle 5 Sekunden Werte laden
  loadTable("daten/data_log.csv", tableFuellen);
}

function tableFuellen(data) {
  aktuelleWerte = data;
  // console.log(aktuelleWerte);
}

function setup() {
  var myCanvas = createCanvas(800, 658);
  myCanvas.parent("graph");

  x = 35;
  y = height - 20;

  textFont("roboto_condensedregular");

  textStyle(NORMAL);

  // Ausgabe der aktuellen Zeit
  zeitAngabe();

  // wieviele Datensätze befinden sich in der CSV-Datei?
  rowCount = aktuelleWerte.getRowCount();

  AnzeigeUeberCanvas();

  // wieviele Werte sollen dargestellt werden?
  var anzahl;
  if (rowCount >= 30) {
    anzahl = 30;
  } else {
    anzahl = rowCount;
  }

  noStroke();

  // Darstellung der Rechtecke mit den Helligkeitswerten
  // werden von rechts nach links dargestellt
  // der aktuellste Wert ist also recht, nach links geht es in die Vergangenheit
  for (var i = 0; i <= anzahl; i++) {
    var helligkeit = HelligkeitsPunkte[rowCount - i];

    // Rechtecke werden Stufenweise dunkler
    fill(255 - 8.5 * i, 0, 0);

    rect(
      width - 5 - (breite + abstand) * i,
      y,
      breite,
      helligkeit * -1 * factor
    );
  }

  // Zeichnen von Skala, senkrechter Beschriftung
  SkalaLinien();
}

function draw() {}

// Angaben zu Anzahl Datensätzen und letztem Wert oberhalb des Canvas
function AnzeigeUeberCanvas() {
  var ausgabe = "Datensätze: " + rowCount;
  document.getElementById("AnzahlDaten").innerHTML = ausgabe;

  for (var i = 0; i < rowCount; i++) {
    HelligkeitsPunkte[i] = aktuelleWerte.getNum(i, 2);
  }
  var letzterWert = HelligkeitsPunkte[rowCount - 1];
  var ausgabe = "letzter Wert: " + letzterWert;
  document.getElementById("letzterWert").innerHTML = ausgabe;
}

function zeitAngabe() {
  var a = new Date();
  var h = a.getHours();
  var m = a.getMinutes();
  var s = a.getSeconds();
  var tag = a.getDate();
  var mon = a.getMonth() + 1; //Monat fängt bei 0 an
  var jahr = a.getFullYear();

  var h = zahlenAuffuellen(h);
  var m = zahlenAuffuellen(m);
  var s = zahlenAuffuellen(s);

  akt_datum = tag + "." + mon + "." + jahr;

  akt_zeit = h + ":" + m + ":" + s;
  var ausgabe = "Aktualisiert am " + akt_datum + " um " + akt_zeit + " Uhr";

  document.getElementById("AktualisierungsDatum").innerHTML = ausgabe;
}

// wenn Stunden, Minuten, Sekunden nur einstellig sind
// werden diese mit einer Null aufgefüllt
function zahlenAuffuellen(ziffer) {
  if (ziffer < 10) {
    ziffer = "0" + ziffer;
  }
  return ziffer;
}

function SkalaLinien() {
  stroke(150);
  // X-Linie
  line(x, y, width, y);
  // Y-Linie
  line(x, 10, x, y + 5);

  // waagrechte SkalaLinien
  stroke(190);
  for (var i = 0; i <= 10; i++) {
    line(x - 3, y - i * 100 * factor, width, y - i * 100 * factor);
  }

  // Einstellungen für Beschriftung
  noStroke();
  fill(100);
  textSize(16);
  textAlign(RIGHT);

  // Beschriftung der Y-Achse
  for (var i = 0; i <= 10; i++) {
    var yBeschriftung = 100 * i;
    text(yBeschriftung, x - 5, y - yBeschriftung * factor + 5);
  }

  // Beschriftung der X-Achse
  textAlign(CENTER);

  for (var i = 0; i <= 29; i = i + 2) {
    var xBeschriftung = -5 * i + "s";
    // width - 5 - (breite + abstand) * i
    text(xBeschriftung, width - 20 - (breite + abstand) * i, y + 18);
  }
}