Writi-Fi

Aus HRW FabLab MediaWiki
Wechseln zu: Navigation, Suche

Writi-Fi

Writi-Fi


Entwickler

Igor Pyshchyk, Dennis Krohmer, Pierre Pascal Pospiech

Programmiersprachen

Java Arduino

Entwicklungssoftware

Autodesk Fusion 360, Arduino IDE, Cura, Eclipse IDE

Eingesetzte Hardware

Ultimaker 2+, Tiertime UP Mini 2

Das Writi-Fi Produkt ermöglicht die einfache Bedienung einer Tastatur mit Hilfe von einfachen Handbewegungen. Um die Tastatureingaben zu bestätigen wird die Hand nach oben geneigt.


Manifest[Bearbeiten]

Das Ziel bestand darin ein einfaches System zu bauen, welches Personen, die keine Tastatur benutzen können, eine Alternative zu bieten. Dabei werden die Personen adressiert, die Schwierigkeiten haben präzise Tastatureingaben zu tätigen. Die verschiedenen Gründe, die den Nutzer davon abhalten sind irrelevant für unser System, solange er in der Lage ist seine Hand zu neigen. Ein großer Vorteil dieses Systems ist, dass die Verbindung zum Computer kabellos funktioniert.

Material[Bearbeiten]

Neben den selbstgedruckten 3D-Konstruktionen wurden folgende Materialen verwendet:

Materialliste
Bezeichnung Anzahl
ESP-32 1
Powerbank 1
Infrarot-Diode 1
Infrarot-Fotowiderstand 1
Jumper Kabel 4
Tennisarmband 1
Klettverschlusspunkte 2

Entwicklung[Bearbeiten]

Den ersten Überlegungen zufolge war gedacht, einen Arduino Nano zu verwenden. Dieser sollte dann mit einem Fotowiderstand die Lichtverhältnisse bestimmen und über eine Veränderung informieren.

Weil eine kabellose Verbindung unabdingbar für unser Produkt ist, war ein Bluetooth Modul notwendig, welches jedoch zu groß für die Befestigung auf dem Arm wäre. Jedoch waren wir soweit, dass wir einen ersten Prototypen entwickeln konnten, der wie folgt aussieht:

Prototyp - Arduino Nano

Zu sehen ist außerdem eine Klappe, die den Fotowiderstand verdecken würde, sobald der Nutzer die Hand neigt. Dadurch würde der Mikrocontroller eine Veränderung feststellen und ein Signal auslösen. Weil das Messen der Umgebungslicht relativ störanfällig ist (Unterschiedliche Raumbeleuchtung, Direkt Sonneneinstrahlung usw.), haben wir uns in den späteren Überlegung auf das Messen von Infrarotlicht geeinigt.

Nachdem wir auf die Nachteile der Benutzung eines Arduino Nano aufmerksam wurden, haben wir uns schlussendlich darauf geeinigt, einen ESP-32 zu verwenden. Mit diesem war es durch den verbauten WLAN-Chip sehr einfach eine kabellose Verbindung zum Computer herzustellen. Unter Beachtung des ergonomischen Aspekts haben wir uns Gedanken über ein Design für das Produkt gemacht und diese Überlegungen mithilfe eines Mockups verdeutlicht.

Mockup - ESP32

Als nächsten Schritt galt es die nötigen Komponenten richtig mit dem Mikrocontroller zu verkabeln. Dafür waren in unserem Fall 4 Jumper Kabel ausreichend. Zum Einschalten der IR Diode wird Strom eines Pins des esp32 mit einer Spannung von 3,3V verwendet. Angesichts der niedrigen Spannung ist hier kein Widerstand nötig, was sich gut auf den Platz und die Verkabelung im Case auswirkt. Eine Skizze der Verkabelung und die endgültige Verkabelung sind hier zu sehen.

Ausgehend von unserem Mockup haben wir ein Case entwickelt. In dieses Case sollen der Mikrocontroller, die Infrarot-Diode und der Infrarot-Fotowiderstand Platz finden. Um dies gewährleisten zu können wurde die Konstruktion groß genug bemessen. Außerdem sollten Schienen geschaffen werden für die einzelnen Komponenten. Das bedeutet, dass wir eine separate Halterung für den ESP32 konstruiert haben, die danach in das Case hineingeschoben wird. Außerdem bekamen auch die zwei angeschlossenen Elemente eine Halterung, welche in dem Case platziert wird.

Die nächste Herausforderung bestand darin, die gesamte Konstruktion auf dem Arm zu platzieren. Dieses Problem wurde von uns so gelöst, dass wir zwei Klettverschlusspunkte an die Unterseite des Case's geklebt haben, welche im Nachhinein an die zugehörigen Punkte, an einem Tennisarmband, fixiert werden.

3D-Modelle[Bearbeiten]

Mikrocontroller[Bearbeiten]

Der esp32 agiert als Server und erwartet einen Client, an den er dann ein Signal schicken kann. Auf der Client-Seite befindet sich ein Java-Programm, welches sich mit dem Server auf dem esp32 verbindet. Voraussetzung dafür ist, dass der Computer bereits mit dem WiFi Netzwerk des esp32 verbunden ist. Dies geschieht analog zum Verbinden mit einem WLAN-Router.


 #include <WiFi.h>
 #include <driver/adc.h>
 const int ledPin = 5;
 int differenzLast=0;//vorletzte gemessene Differenz zwischen IR-LED an/aus
 int differenz=0;    //   letzte gemessene Differenz zwischen IR-LED an/aus
 int previousOn=0;   //vorheriger Wert bei eingeschalteter LED
 int currentOn=0;    //neuer Wert bei eingeschalteter LED
 boolean bleibt=true;
 const char* ssid = "MKS";
 const char* password =  "server123";
 WiFiServer server(80);
 WiFiClient client;
 void setup(){
 pinMode (ledPin, OUTPUT);
 Serial.begin(115200);
 delay(1000); 
 // Connect to Wi-Fi network with SSID and password
 Serial.print("Setting AP (Access Point)…");
 
 // Remove the password parameter, if you want the AP (Access Point) to be open
 
 WiFi.softAP(ssid,password);
 delay(1000);
 IPAddress IP = WiFi.softAPIP();
 Serial.print("AP IP address: ");
 Serial.println(IP);

 server.begin();
 delay(1000);
 Serial.println("ESP32 Analog IN Test");
 }
 void loop(){
   if(!client) {
   client = server.available();
   if(client) {
     Serial.println("New Client."); 
   }
 }
   if(!client.connected()) {
     Serial.println("Client disconnected.");
     client.stop();
   }
   else {
 bleibt = false;
 // berechnen der Differenz zwischen letzter und vorletzter Differenzmessung
 // Differenzmessung ist das berechnen der Differenz der gemessenen Sensorwerte vor und nach einschalten der IR-LED
 int diffWert = differenz - differenzLast;                                  
 if(diffWert<0){
   diffWert=diffWert*(-1);
   }
   
 if(diffWert<15){
   //Serial.println("Bleibt");
   bleibt = true;
   }
   if(!bleibt && (previousOn<currentOn)){//
     Serial.println(diffWert);
     Serial.println("Change");
     client.println(1);
     delay(2000);
   }
   
 digitalWrite (ledPin, HIGH);  // turn on the LED
 delay(300);  
 int sensorValueOn = analogRead(32);//einlesen des Sensorwertes bei eingeschalteter IR-LED
 previousOn=currentOn;
 currentOn=sensorValueOn;


 Serial.println("IR an2");
 Serial.println(sensorValueOn);
 
 digitalWrite (ledPin, LOW);  // turn off the LED
 delay(200);
 int sensorValueOff= analogRead(32);//einlesen des Sensorwertes bei ausgeschalteter IR-LED
 Serial.println("IR aus");          
 Serial.println(sensorValueOff);
 differenzLast=differenz;
 differenz=sensorValueOn-sensorValueOff;// Differenz zwischen IR-LED an und IR-LED aus Sensorwerten
   }
 }

Java-Programm[Bearbeiten]

Hauptklasse[Bearbeiten]

Die Hauptklasse ist für die Verbindung mit dem esp32 und die Erstellung einer graphischen Oberfläche zuständig. Schickt der esp32 ein Signal in Form einer 1, so wird es hier empfangen und verarbeitet. Ein empfangenes Signal löst eine Eingabe aus. Für die Verbindung wird das Transmission Control Protocol verwendet.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class Main {
 public static MainSensor m;
 public static void main(String [] args) {
 //Socket client = new Socket("192.168.4.1", 80);
 Thread t = new Thread() {
 public void run() {
 
 try {
  Socket client = new Socket("192.168.4.1", 80);
  BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
  String fromEsp32;
  while((fromEsp32=reader.readLine())!=null) {
  //System.out.println(fromEsp32);
  if(m != null && fromEsp32.contains("1")) {
  //System.out.println("a");
  m.flick();
 }
 }}
 
 catch(Exception e) {
  e.printStackTrace();
  }
 }
 };
 
 t.start();
 Thread tm = new Thread() {
  public void run() {
  new MainSensor();
  }
 };
 tm.start();
 }
}

GUI-Klasse[Bearbeiten]

Die GUI-Klasse ist für die Darstellung einer graphischen Oberfläche zuständig. Um etwas einzugeben muss die entsprechende Zelle gewählt werden. Um eine Zelle auszuwählen wird zuerst die Spalte und danach die Zeile ausgewählt, in der sich die gewünschte Eingabe befindet. Für die Darstellung der Zellen mit den Eingabezeichen und einem Delete-Befehl wurden Buttons gewählt.

import javax.swing.JPanel;
import javax.swing.JFrame;

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; 
public class MainSensor extends JFrame  {

 JPanel p = new JPanel();
 Button buttons[][] = new Button[6][8];
 
 boolean stop=false;// wenn space gedrückt
 boolean spalte_zeile = true; // true wenn die spalte gewählt wird, false wenn zeile gewählt wird
 
 int rowCount = 0;// spalten Zähler
 
 int lineCount = 0;// zeilen Zähler
 
 String word = "";
 
 public static void main(String[] args) {
 new MainSensor();
 }
 
 public MainSensor() {
  super("Sensor");
  setSize(800,400);
  setResizable(false);
  setDefaultCloseOperation(EXIT_ON_CLOSE);
  
  p.setLayout(new GridLayout(6,8));
  
  for(int i =0; i<buttons.length;i++) {
   for(int j =0; j<buttons[0].length;j++) {
    buttons[i][j] = new Button("leer" );
    p.add(buttons[i][j]);
   }
  }
  
  int letter=0;
  for(int i = 0; i<buttons.length;i++) {
   for(int j = 0;j<buttons[0].length;j++) {
    if(i==0 || j==0) {
     //buttons[i][j] = new Button("leer" );
    }
    else if(i>0 && j>0) {
     if(letter<26) {
      //buttons[i][j] = new Button( Character.toString((char)(letter+65)) );
      buttons[i][j].setContent(Character.toString((char)(letter+65)));
      	
      //p.add(buttons[i][j]);
      letter++;
     }
    }
   }
  	
  }
  
  buttons[4][6].setContent("DELETE");
  
  add(p);
  
  Main.m = this;
  
  setVisible(true);
  
  
  while(true && stop==false) {
   if(spalte_zeile==true) {
    rowCount++;
    int spalte = (rowCount%7 )+1;
    buttons[0][spalte].setBackground(Color.BLUE);
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    buttons[0][spalte].setBackground(null);
    //rowCount++;
    			
   }
   
   if(spalte_zeile==false) {
    lineCount++;
    int zeile = (lineCount%5 )+1;
    buttons[zeile][0].setBackground(Color.BLUE);
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    buttons[zeile][0].setBackground(null);
    //lineCount++;
    			
   }
   		
  }
  		
 }
 
 public void flick() {
  stop=true; 
  
  if(spalte_zeile == true) {// spalte wurde gewählt
  spalte_zeile = false;
  }
  else if(spalte_zeile==false) {
   spalte_zeile=true;
   String btnText = buttons[(lineCount%5 )+1][(rowCount%7 )+1].getContent();
   
   //System.out.println((lineCount%5 )+1 );
   //System.out.println((rowCount%7 )+1);
   //System.out.println(buttons[(lineCount%5 )+1][(rowCount%7 )+1].getContent());
   if( ((lineCount%5 )+1==4)  && (rowCount%7 )+1 == 6) {
    word="";
   }
   else {
    word += btnText.replaceAll("leer", "");
    System.out.println(word);
   }
   
   rowCount = -1;
   lineCount=-1;				
  }
  stop=false;
 }
 
 	
}

Button-Klasse[Bearbeiten]

Die Button-Klasse erbt von der Klasse Java-Klasse JButton.

 import javax.swing.JButton;
 
 public class Button extends JButton{
 
  private String content ="";
  	
  public Button(String s) {
   content=s;
   this.setText(content);
   
  }
  public void setContent(String a) {
   content=a;
   this.setText(content);
  }
  public String getContent() {
   return content;
  }
 }