5. 🚧 Hardware trifft Software mit Processing
Synopsis: [ 🔗 https://processing.org] [🔗 Processing Cheat Sheet]
Einstieg mit Poti auslesen
Der Poti auf dem Expansion Board wird ausgelesen und als zwei Byte über die Serielle Schnittstelle verschickt.
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27 für 16 Zeichen und 2 Zeilen ein
void setup() {
lcd.begin(16, 2); // initialize the lcd
lcd.clear();
lcd.setBacklight(255);
lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
lcd.print("UART Poti");
Serial.begin(9600);
}
void loop() {
uint16_t potiVal = analogRead(PA0);
unsigned char byte_0 = potiVal & 0x00FF; // left Byte;
unsigned char byte_1 = (potiVal & 0xFF00) >> 8; // right Byte;
lcd.setCursor(0,1); // erstes Zeichen, zweite Zeile
lcd.printf("%X %X", byte_1, byte_0);
Serial.write(byte_1);
Serial.write(byte_0);
delay(1000);
}
Mit Processing werden die Daten empfangen und angezeigt
import processing.serial.*; //verwende die 'Serial' Library
Serial myPort; // Deklariere ein Object vom Typ 'Serial', mit dem Namen 'myPort'
//globale Variablen
int x = 0;
//stelle eine Verbindung zum Arduino/Mbed Controller her.
void setup() {
size(600,600); // Zeichenfläche
background(#FFFFFF); // Weisser Hintergrund
ellipseMode(CENTER); // Tentrum der Ellipse als Referenzpunkt
// Setup der Kommunikation über UART
// ======================================================
// Um den Namen der Schnittstelle herauszufinden, lassen wir uns von der Serial-Klasse zunächst
// eine Liste der Namen der am PC vorhandenen Ports geben ('Serial.list()')
// Den x'ten Eintrag aus dieser
//Liste bekommen wir mit 'Serial.list()[x-1]' (die indices fangen mit 0 an)
// Bei den meisten PCs ist der STM32/Arduino der letzte Port in der Liste.
// Deshalb ermitteln wir zunächst die Länge der Liste (Serial.list().length)
// und nehmen uns den letzten Namen aus der Liste heraus (Serial.list()[Serial.list().length-1])
String portName = Serial.list()[Serial.list().length-1]; // finde den Namen des letzten Serialports heraus.
println(portName); //print them to the user
int baudrate=9600; // Diese Baudrate muss mit der in eurem MBed/Arduino-Programm übereinstimmen.
// portName = "COM1"; // Feslegung auf Port COM1 sonst wird die erste Schnittstelle in der Liste verwendet.
myPort = new Serial(this, portName, baudrate); // Erzeuge ein Serial Objekt und stelle eine Verbindung her
}
//Lese Daten und gib sie in Processing aus
void draw() {
int int_16bit = 0;
while (myPort.available() > 0) { // wiederhole das folgende, solange (while) es neue Daten (myPort.available() > 0)gibt.
//char inByte = myPort.readChar(); // lese einen einzelnen Buchstaben von der Seriellen Schnittstelle
//int intByte = myPort.read();
//println(hex(inByte)); // gib den gelesenen Buchstaben im Fenster unter dem Code aus.
//if(inByte == '\n') println();
//print(intByte);
//int int_16bit = (myPort.readChar()<<8)+myPort.readChar();
//println(hex(int_16bit));
char hByte = myPort.readChar();
char lByte = myPort.readChar();
int_16bit = (hByte<<8) + lByte;
print("0x"+hex(int_16bit,4)+" "+int_16bit+" ");
println(int_16bit*(3.3/65535)+" V");
stroke(1);
//point(x,int_16bit/100);
fill(#EA0707);
ellipse(x,200-int_16bit/10,5,5);
x += 5;
if(x==width) {
x=0;
background(#FFFFFF);
}
}
}
Processing Sonar
Synopsis: [🔗 https://www.youtube.com/watch?v=uO3mTJZ2Vyc ]
Servo an Expansion Board anschließen, Ultraschallsensor an PA10 und PC9.
#include <Wire.h> // Wire Bibliothek einbinden
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd (0x27); // LCD-Adresse auf 0x27 für 16 Zeichen und 2 Zeilen ein
#include <Servo.h>
Servo myservo;
#define TRIGGER PA10 // Anschluss Ultraschall-Entfernungsmesser
#define ECHO PC9
void setup() {
lcd.begin(16, 2); // initialize the lcd
lcd.clear();
lcd.setBacklight(255);
lcd.setCursor(0,0); // erstes Zeichen, erste Zeile
lcd.print("Sonar Demo");
Serial.begin(115200);
pinMode(PC1,OUTPUT); // PC1 braucht +5V
digitalWrite(PC1,HIGH);
myservo.attach(PC0); // Servosignal an PC0 anschliessen
pinMode(TRIGGER, OUTPUT); // Trigger-Pin ist ein Ausgang
pinMode(ECHO, INPUT); // Echo-Pin ist ein Eingang
}
int minGrad = 0;
int maxGrad = 180;
int grad = 0;
bool nachRechts = true;
void loop() {
unsigned int mess;
digitalWrite(TRIGGER, HIGH); // Trigger-Pin high zum Start der Messung
delayMicroseconds(10); // 10 µs reichen
digitalWrite(TRIGGER, LOW); // Trigger-Pin low
mess = pulseIn(ECHO, HIGH,12000); // auf 12ms begrenzen für max 206cm
mess = mess/58; // näherungsweise Berechnung der cm
myservo.write(grad);
lcd.setCursor(0,1); // erstes Zeichen, zweite Zeile
lcd.printf("%3d %3d", mess, grad);
Serial.write(mess & 0xFF);
Serial.write(grad & 0xFF);
if (nachRechts) {
grad += 3;
if (grad > maxGrad) {
grad = maxGrad;
nachRechts = false;
}
}
else {
grad -= 3;
if (grad < minGrad) {
grad = minGrad;
nachRechts = true;
}
}
delay(100);
}
Mit Processing die Daten visualisieren
import processing.serial.*; // Serial-Bibliothek
import processing.sound.*; // Sound-Bibliothek
Serial meinPort; // serieller Port
SoundFile file; // Sounddatei
float radius = 500; // Setzt den Radius
boolean richtung = true; // Setzt die Richtung
int gradZahl = 0;
int entfernung = 0;
ArrayList<Linie> linien = new ArrayList<Linie>(); // Erstellt einen Array von Linien
int letzteAbspielzeit = 0;
void setup() {
serialPortEinrichten(); // Ruft die Funktion zum Einrichten des seriellen Ports auf
size (1000, 500); // Größe des Fensters
background(#050505); // Hintergrundfarbe
file = new SoundFile(this, "sound/sonarPing.mp3"); // Lädt die Sounddatei
}
void draw() {
datenLesenUndVerarbeiten(); // Ruft die Funktion zum Lesen und Verarbeiten der Daten auf
bildZeichnen(); // Ruft die Funktion zum Zeichnen des Bildes auf
}
// Funktion zum Einrichten des seriellen Ports
void serialPortEinrichten() {
String portName = Serial.list()[Serial.list().length-1]; // Holt den Portnamen
println(portName); // Zeigt den Portnamen an
int baudrate=115200; // Setzt die Baudrate
//portName = "COM3"; // Setzt den Portnamen falls nicht der erste in der Liste
meinPort = new Serial(this, portName, baudrate); // Öffnet den seriellen Port
}
// Funktion zum Lesen und Verarbeiten der Daten
void datenLesenUndVerarbeiten() {
while (meinPort.available() >= 2) { // Während Daten verfügbar sind
byte[] inBuffer = new byte[2]; // Erstellt einen Puffer
meinPort.readBytes(inBuffer); // Liest die Bytes
// Setzt die geteilten Werte wieder zusammen
entfernung = (int) (inBuffer[0] & 0xFF);
gradZahl = (int) (inBuffer[1] & 0xFF);
println("Entfernung: " + entfernung + ", Grad: " + gradZahl); // Zeigt die Entfernung und Gradzahl an
linien.add(new Linie(entfernung, gradZahl)); // Fügt eine neue Linie hinzu
// Wiederholt den sound je nach Abstand unterschiedlich
if (entfernung <= 50 && millis() - letzteAbspielzeit > 3000) {
file.play(); // Spielt die Datei ab
letzteAbspielzeit = millis(); // Aktualisiert die letzte Abspielzeit
}
else if (entfernung <= 30 && millis() - letzteAbspielzeit > 2000) {
file.play(); // Spielt die Datei ab
letzteAbspielzeit = millis(); // Aktualisiert die letzte Abspielzeit
}
else if (entfernung <= 10 && millis() - letzteAbspielzeit > 1000) {
file.play(); // Spielt die Datei ab
letzteAbspielzeit = millis(); // Aktualisiert die letzte Abspielzeit
}
}
}
// Funktion zum Zeichnen des Bildes
void bildZeichnen() {
size (1000, 500); // Größe des Fensters
background(#050505); // Hintergrundfarbe
halbkreiseZeichnen(); // Ruft die Funktion zum Zeichnen der Halbkreise auf
rasterZeichnen(); // Ruft die Funktion zum Zeichnen des Rasters auf
for (Linie l : linien) { // Für jede Linie in dem Array
l.linieZeichnen(); // Zeichnet die Linie
}
linien.removeIf(l -> l.istAnzeigedauerAbgelaufen()); // Entfernt abgelaufene Linien
textSize(20); // Textgröße
textAlign(CENTER, CENTER); // Textausrichtung
// Textfarbe je nach Entfernung
if (entfernung <= 50) {
fill(#FF0000); // Füllfarbe
text("Entfernung:\n" + entfernung + " cm", 50, 20); // Zeichnet den Text
}
else if (entfernung > 50) {
fill(#28BF00); // Füllfarbe
text("Entfernung:\n> 50 cm", 50, 20); // Zeichnet den Text
}
fill(#28BF00); // Füllfarbe
text("Winkelgrad:\n" + gradZahl + "°", width - 50, 20); // Zeichnet den Text
}
// Funktion zum Zeichnen der Halbkreise
void halbkreiseZeichnen() {
fill(#001504); // Füllfarbe
stroke(#218320); // Strichfarbe
strokeWeight(8); // Strichstärke
ellipse(500,500,1000,1000); // Zeichnet einen Kreis
fill(#28BF00); // Füllfarbe
ellipse(500,500,50,50); // Zeichnet einen Kreis
noFill(); // Keine Füllung
stroke(#218320); // Strichfarbe
strokeWeight(4); // Strichstärke
ellipse(500,500,200,200); // Zeichnet einen Kreis
noFill(); // Keine Füllung
stroke(#218320); // Strichfarbe
strokeWeight(5); // Strichstärke
ellipse(500,500,400,400); // Zeichnet einen Kreis
noFill(); // Keine Füllung
stroke(#218320); // Strichfarbe
strokeWeight(6); // Strichstärke
ellipse(500,500,600,600); // Zeichnet einen Kreis
noFill(); // Keine Füllung
stroke(#218320); // Strichfarbe
strokeWeight(7); // Strichstärke
ellipse(500,500,800,800); // Zeichnet einen Kreis
// Skalierung hinzufügen
textSize(12); // Textgröße
fill(#28BF00); // Füllfarbe
textAlign(CENTER, CENTER); // Textausrichtung
for (int i = 1; i <= 5; i++) {
text(i*10 + "cm", 500, 500 - i*100 + 10); // Zeichnet den Text
}
}
// Funktion zum Zeichnen des Rasters
void rasterZeichnen() {
noFill(); // Keine Füllung
stroke(#28BF00); // Strichfarbe
strokeWeight(0.2); // Strichstärke
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 5; j++) {
rect(i*100, j*100, 100, 100); // Zeichnet ein Rechteck
}
}
}
// Klasse Linie zum erzeugen einer Linie als Objekt
class Linie {
float entfernung;
int gradZahl;
int anzeigedauer = 180; // Setzt die Anzeigedauer
float x_Position;
float y_Position;
// Konstruktor
Linie(int entfernung, int gradZahl) {
this.entfernung = entfernung; // Setzt die Entfernung
this.gradZahl = gradZahl; // Setzt die Gradzahl
float rad = radians(gradZahl); // Berechnet den Winkel
this.x_Position = 500 + radius * cos(rad); // Berechnet die X-Position
this.y_Position = 500 - radius * sin(rad); // Berechnet die Y-Position
}
// Funktion zum Zeichnen der Linie
void linieZeichnen() {
float rad = radians(gradZahl); // Berechnet den Winkel
float skalierteEntfernung = map(entfernung, 0, 50, 0, 500); // Skaliert die Entfernung von 0 bis 50 auf 0 bis 500
skalierteEntfernung = min(skalierteEntfernung, radius); // Skaliert die Entfernung
float x_Linie = 500 + skalierteEntfernung * cos(rad); // Berechnet die X-Position der Linie
float y_Linie = 500 - skalierteEntfernung * sin(rad); // Berechnet die Y-Position der Linie
strokeWeight(5); // Setzt die Strichstärke
int transparenz = (int) map(anzeigedauer, 0, 360, 0, 255); // Berechnet die Transparenz
stroke(#28BF00, transparenz); // Strichfarbe und Transparenz
line(500, 500, x_Linie, y_Linie); // Zeichnet die Linie
if (entfernung <= 50) {
stroke(#FF0000, transparenz); // Strichfarbe und Transparenz
line(x_Linie, y_Linie, x_Position, y_Position); // Zeichnet die Linie
}
anzeigedauer--; // Verringert die Anzeigedauer
}
// Funktion zum Überprüfen, ob die Anzeigedauer abgelaufen ist
boolean istAnzeigedauerAbgelaufen() {
return anzeigedauer <= 0; // Gibt true zurück, wenn die Anzeigedauer abgelaufen ist
}
}