Archiv der Kategorie: Programmiersprache

Den ESP8266 schlafen legen

Sensorknoten sollen möglichst lange und unabhängig arbeiten können. Dennoch benötigen sie Strom, um mit der vorhandenen Energie möglichst effizient umgehen zu können, hat der ESP8266 und andere Controller die Möglichkeit in den Tiefschlaf zu gehen. Das schöne ist er kann sich nach fast beliebiger Zeit selbst wieder aufwecken. Ein Nachteil beim ESP8266 ist das er maximal 71 Minuten schlafen kann.

In diesem Beitrag wird gezeigt wie der ESP einschafen kann und auch wieder aufwacht.

Bauteile

1x ESP8266 Node Lua V2
1x Pinheaderkabel (Buchse : Buchse)

Schaltungsaufbau

(Von Quelle geklaut)nodemcu-deep-sleep.png

Der Reset wird hierbei mit dem GPIO 16 (Pin D0) verbunden.

So sieht es bei mir in der Realität aus

Testprogramm

 


void setup() {
  Serial.begin(115200);
  Serial.setTimeout(2000);

  // Wait for serial to initialize.
  while(!Serial) { }
  
  Serial.println("I'm awake.");

  Serial.println("Schlafe 20 Sekunden ");
  ESP.deepSleep(20e6); // 20e6 = 20 microseconds

}

void loop() {
  // nichts zu tun

}

Der ganze Spuk passiert durch eine Zeile Code (hier rot makiert).

… und das kommt bei mir auf der Konsole an:

Man kann gut am Textschrummel erkennen, dass der ESP alle 20 Sekunden neu startet.

Weiterführende Projekte

Quellen

https://www.losant.com/blog/making-the-esp8266-low-powered-with-deep-sleep

MQTT Protokoll + Versuchsaufbau

Ich bin im Netz auf den Begriff MQTT gestossen und fand den Ansatz dahinter richtig gut. Deshalb habe ich mir mal einen kleinen Versuchsaufbau gegönnt, den ich im folgenden beschieben habe.

Vorab ein paar Details zu MQTT

Infos zu MQTT

Allgemeines

MQTT regelt die Kommunikation zwischen Datenquellen und Datensenken mittels eines Brokers.

Datenquelle

Quellen für Daten können ganz unterschiedliche Geräte sein, eines haben sie jedoch alle gemeinsam, sie können Netzwerkverbindungen aufbauen um Ihre Daten weiter zu geben und sie haben was, was sie mitteilen wollen.

In der IoT können dies Sensor-Knoten sein, welche ihre Daten an einen oder mehrere Empfänger senden wollen.  Die Liste der möglichen Daten ist hierbei nahe unendlich. Beispiele sind Temperaturwerte, Schaltzustände,  Helligkeitswerte usw.

Die Quelle meldet sich an einem (oder mehreren Brokern?) an. Ihre Daten sendet sie so lange bis diese vom Broker quittiert wurden.

Datensenken (Interessenten)

Senken für Daten sind bei MQTT die sog. Interessenten. Diese möchten bestimmte Informationen von Quellen erhalten und diese dann Auswerten (Berechnung) oder einfach nur Präsentieren (Bildschirmanzeige). Beispiele sind Handy Apps, eine Lampe die wissen will wann sie eingeschaltet wird usw.

Broker

Der Broker dient als Bindeglied zwischen den Quellen und den Senken. Er hat die Aufgabe, Daten von Quellen zu sammeln und diese an die Interessenten weiter zu reichen.  Eine Auswertung/ Aufbereitung der Daten ist ihm nicht gestattet, jedoch darf er die Daten zwischenspeichern, um zum Beispiel neuen Interessenten mit dem zuletzt empfangenen oder auch mit historischen Werten zu versorgen.

Die Idee hinter dem Protokoll ist, dass Leistungsschwache Sensorknoten nur eine Verbindung mit einem Broker (Empfänger Server) aufbauen und nur an diesen senden sie ihre Daten. Der leistungstärkere Broker verteilt die Informationen dann an die Interessenten.

Ein kleines Projekt

Ich habe ein kleines Projekt aufgesetzt, mit einem Sensorknoten als Quelle, einem Broker auf einem Raspberry Pi und meinem Handy als Senke.

Quelle

  • Board Node MCU ESP8266
  • Temperatursensor DHT11
  • Bibliothek pubsubclient

Der genaue Aufbau ist in einem anderen Beitrag bereits beschrieben, weshalb ich mich hier nur auf die MQTT basierten Fakten stürze.

http://fambach.net/dht10-mit-esp8266/

Die Bibliothek installieren:

Hier ist der nach MQTT angepasste Quellcode:

ESP8266TempSensorMQTT

Bitte die Netzwerkdaten und die Brokerdaten an eure Topologie anpassen. Achtung der DHT Sensor benötigt auch eine Bibliothek wie im gelinkten Beitrag beschrieben.

Broker

Raspberry nach belieben aufsetzten oder so wie hier:

http://fambach.net/raspberry-pi-zero-w-headless-installation/

Auf dem Pi dann die Mosquitto software installieren.

Software Download

Link: http://mosquitto.org/download

Die letzte Version holen, der Link kann von der obigen Seite kopiert werden. Die aktuelle Version kann mit wget direkt auf den PI geholt werden:

sudo wget <direkter link zum paket>

in meinem Fall war das

sudo wget http://mosquitto.org/files/source/mosquitto-1.5.tar.gz

Installation

Benötigte libs installieren mit

sudo apt-get install libwrap0-dev libcurl4-openssl-dev libmysqlclient-dev libssl-dev apt-get install uuid-dev 

Paket auspacken:

tar zxf ./mosquitto-1.5.tar.gz

In den ausgepackten Ordner springen und mosquitto …

cd mosquitto-1.5/

… bauen und Installieren …

make
sudo make install
sudo ldconfig

… noch starten

Den ESP8266 starten und die erste Verbindung sollte klappen:

Senke

Ich verwende mein Handy als Senke und einen MQTT Empfänger APP. Ich habe ein paar probiert, bin dann aber erstmal mal bei „IoT MQTT Panel“ hängen geblieben, weil sie auf Anhieb funtkionierte und auch Platzhalter unterstüzt.

Hier der Link

Folgende Einstellungen habe ich vorgenommen, ihr müsst diese natürlich an eure Applikation und Netzwerktopoligie anpassen.

Erstmal eine neue Verbindung erstellen mit den Verbindungsdaten des Mosquitto Servers.

Die Neue Verbindung öffnen

Fazit

Solch ein MQTT Projekt ist in wenigen Stunden aufgebaut und macht Spaß. Dabei hat es noch großes Potential, denn man kann leicht mehrere Knoten mit einem standard Server verbinden und sich die Daten z.B. auf dem Handy anzeigen lassen.

Quellen

https://de.wikipedia.org/wiki/MQTT

Java Client Phao

MQTT Git-hub Community Wiki
https://github.com/mqtt/mqtt.github.io/wiki

Github Seite mit MQTT libs
https://github.com/mqtt/mqtt.github.io/wiki/libraries

Lib für ESP8266 und Andere
https://github.com/knolleary/pubsubclient

Mosquitto Broker Konfigurationhilfe

Quick Guide to The Mosquitto.conf File With Examples

MQTT best practice

MQTT Essentials Part 5: MQTT Topics & Best Practices

 

ESP32 Arduino Gui einrichten mit Git

Wie immer gibt es im Netz zahlreiche Informationen, wie die Arduino Gui zu konfigurieren ist. Deshalb fasse ich mich an dieser Stelle sehr kurz, für detailiertere Informationen sei auf die unten verlinkten Quellen verwiesen.

Repository Clonen

Es gibt ein Git Paket zur Einrichtung der GUI für den ESP 32. (Link zu GIT GUI)

Git Gui starten und „Clone Existing Repositiory“ wählen.

Die Quelle für die ESP 32 Sources ist:

https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series.git

dort gibt es auch zusätzliche Infos.

Das Ziel ist das Arduino Projektverzeichnis, in meinem Fall unter MyDocuments/Arduino.

Mit Bestätigung der Eingabe über den Clone Button, erscheint das folgende Bild und alle Dateien werden aus Git extrahiert.

Danach muss man im Verzeichnis ..\Arduino\hardware\heltec\esp32\tools noch das Programm get.exe ausführen und in der Console mit Enter starten.

Erfolgsbestätigung

Arduino Gui neu starten,  tauchen die ESP 32 Einträge in der Board-Liste auf war die Installation erstmal erfolgreich.

Ob auch alles wirklich funktioniert kann mit einen der Beispielprogramme verifiziert werden. Einfach auswählen, übersetzen und auf den ESP 32 übertragen. (Vorher das richtige Board auswählen)

Probleme

Arduino Gui – falsches Installationsverzeichnis gewählt

Ich hatte das falsche Verzeichnis für meine Arduino Gui angegeben .

Zur Lösung des Problems kann der komplette esp32 Ordner in das richtige Verzeichnis unter hardware kopieren werden.

Keine Beispielprogramme für den ESP32 ?!

Zuerst muss das ESP32 Board ausgewählt werden, dann sind auch die entsprechenden Beispielprogramme vorhanden.

Projekte

ESP32 WiFi Lora 433

Quellen

https://github.com/espressif/arduino-esp32/blob/master/docs/arduino-ide/windows.md

https://github.com/Heltec-Aaron-Lee/WiFi_Kit_series#instructions

Arduino Uno + WiFi

Hier geht es um einen Chinaimport und nicht um den offiziellen Uno WiFi. Die Platine hat einen vollständigen Ardunio Uno mit Atmega Prozessor und einen ESP8266 Chip on board. Über Dipschalter, kann jeweils der Uno mit dem USB, der ESP mit dem USB oder der ESP mit dem UNO verbunden werden.

Für den Betrieb kann eine externe Wlan-Antenne angeschlossen werden. Es sind zusätzlich ESP-Pins herausgeführt, die Beschaltung steht auf der Rückseite.

Daten

Name Uno + Wifi  
Anzahl/CPU
2 / ATmega328P + ESP 8266
Takt (MHz)16 / 80
Kerne1
Digital IOs / Pins14 / 4
Analog inputs6 / ?
PWM6 / ?
SPI1
Flash Speicher 32 KB / 8 MB
SRam (KB)2 / 128
EEPROM (KB)1 / -
WiFi- /2,4 GHz 802.11 b/g/n
Verschlüsselung- / WEB / WPA2 / TKIP /AES
Bluetooth-
UART1 / 1
I2C1 / 1
Ethernet- / -
Video-
Sound-
USB1 Micro
Betriebsspannung [V]5
Eingangsspannung7 - 12
Strom (mA) / Standby (mA)< 500
Größe l x b x h68,6 x 53,3
Gewicht [g]>25

Ansichten

Frontansicht mit den Verbindern für Erweiterungsplatinen, dem Stromanschluss, USB-Anschluss und einem  Resettaster. Zusätzlich zu den normalen Achlüssen befindet sich noch weitere für den ESP8266,  ein Antennenanschluss und ein Dip-Schalter zur Einstellung der seriellen Schnittstelle an Bord.

Hier ein paar technische Daten und die Pinbelegung der nach aussen geführten ESP Pins.

 

Jumper Einstellungen

DIP

Programmierumgebung

UNO

Dipschalter 3,4 auf ON Rest auf OFF

ESP8266

Dipschalter 5,6,7 auf ON Rest auf OFF. Sollte das programmieren nicht beginne ist ein Reset de des Boards nötig. Das spielen mit der Reset Methode brachte hier leider keine Besserung.

Test Programme

ESP8266 Durchreiche

Das folgende Programm reicht alles was auf dem seriellen Port eingeht an den verbundenen Server weiter und alles was über das  Netz rein kommt wieder auf den seriellen Port. Das Listing ist etwas lang weil ich die Netzwerkkommunikation aus einem anderen Projekt übernommen habe, deshalb hier nur die gelinkte Datei.

UARTEcho.ino

Alles Wichtige passiert in der loop Funktion. Die Daten für den Accesspoint und den Server müssen entsprechend angepasst werden.

Nachträglich habe ich auch Code von Arduino in den Beispielen der GUI gefunden. Die Datei heisst Wifi2Serial.ino.

Uno Echo

Das Testprogramm des Uno’s ist gleichfalls trivial. Es schreibt alles was er über den seriellen Port empfängt wieder auf diesen zurück.

String buf = "";

void setup(){
  Serial.begin(9600);
  while(!Serial){ delay(1);}
  buf.reserve(200);
  Serial.println("UNO started");
}

int ib = 0;
void loop(){
  while (Serial.available()){
    delay(4); // allow buffer to fill
    ib = Serial.read();
    buf += ((char)ib);

    if(((char)ib)== '\n' || buf.length()== 200){
        Serial.print("Echo: ");
        Serial.print(buf);
        buf = "";
    }
  }
}

SerialEcho.ino

Testen

Zum testen kann mein Socket-Tool verwendet werden.

Java Socket Konsolen Server

Dipschalter1,2 auf ON, der Rest auf OFF.

Die Socket Console starten.

Im Feld neben den „send“ Knopf kann ein Text eingegeben werden. Mit Betätigung des „send“ Knopfes, wird der Text an den Client geschickt. Wenn alles geklappt hat, kommt der Text mit einem „Echo: “ davor zurück.

Durch die Testausgaben des ESP auf den seriellen Port, kommen ein paar mehr Echos zurück als eingegeben wurden. Auch fehlt nach der Serververbindung der „New Line“- Befehl. Weshalb erst der 2. eingegeben Text gut sichtbar ist. Für einen ersten Test des Boards reicht es jedoch aus.

Quellen

https://github.com/jandrassy/UnoWiFiDevEdSerial1#writing-sketches-for-esp8266

https://github.com/esp8266/Arduino/issues/3004

https://community.blynk.cc/t/uno-wifi-r3-atmega328p-esp8266-board-32mb-memory-usb-ttl-ch340g-compatible-for/21564

https://github.com/gmag11/FirmataMaster

https://www.arduino.cc/reference/en/language/functions/communication/serial/

Arduino – HC-SR04 Entfernungsmesser

Ansteuerung des HC-SR04 Ultraschall-Entfernungsmesser mit Hilfe des Arduino UNO.

Grundlagen

SR-04

Aufbau

Schaltung

(Ich habe nachträglich noch die Pins von 0/1 auf 2/3 geändert weil an 0/1 noch der ISP hängt).

Testprogramm

Hier ein kleines Testprogramm. Es filtert zu kleine und zu große Werte heraus und ermöglicht die Mittelwertbildung über ein definiertes intervall.

// *************************************************
// SR04 Ultrasonic Distance Sensor
// time to distance conversion is
// divide by 2 (both ways to the obstical and back)
// divide by sonic constant 29.1
#define TRIGGER_PIN   3
#define ECHO_PIN      2    
#define SC_MM         5.82
#define SC_CM         58.2

#define MAX_DUR       300 * 58.2 // ~3m in dur 
#define MIN_DUR       2 * 58.2 // ~2cm in dur
#define TO_SMALL      -1
#define TO_BIG        -2
#define INT_TO_SMALL  -3


/** get duration */
long getDur(int interval){
  if(interval < 1) return -3;
  long dur=0;
  
  for(int i = 0; i < interval; i++ ){
    // init sensor
    digitalWrite(TRIGGER_PIN, LOW);
    delayMicroseconds(3);
    noInterrupts();  
  
    // start 10 us pulse
    digitalWrite(TRIGGER_PIN, HIGH); 
    delayMicroseconds(10);
    digitalWrite(TRIGGER_PIN, LOW);
    
    dur += pulseIn(ECHO_PIN, HIGH); // determine the time
    interrupts();
    
  }

  dur /= interval;
  if(dur > MAX_DUR ) { return TO_BIG;}
 // else if (dur < MIN_DUR){ return TO_SMALL;}
  return dur;
}
 
void initDist(){ pinMode(TRIGGER_PIN, OUTPUT); pinMode(ECHO_PIN, INPUT);}

/** get the distance in centi meter*/
double getDistCM(long dur){ return (dur / SC_CM);}

/** get the distance in milli meter*/
long getDistMM(long dur) { return (dur / SC_MM);}
// *************************************************

void setup(){
  Serial.begin(9600); 
  while(!Serial){delay(1);} // wait until the serial is ok (only for Leonardo)
  initDist();
}

void loop (){
  
  Serial.print("Current distance is: "); 
  long dur = getDur(5);
  if(dur > 0) Serial.println(getDistCM(dur));
  else if( dur == TO_BIG) Serial.println("TO FAR");
  else if( dur == TO_SMALL) Serial.println("TO NEAR");
  delay(1000); // wait a second
}

SR04Test.ino

Hier könnte jetzt noch der Median angewendet werden um Ausreisser heraus zu nehmen.

In der Praxis bietet es sich wahrscheinlich an die Millimeter weg zu kürzen und nur den Zentimeterwerte, die wesentlich geringeren Schwankungen unterliegen, zu verwenden.

Output

Quellen

http://www.mikrocontroller-elektronik.de/ultraschallsensor-hc-sr04/

 

 

Java – IP Fernbedienung

Zweck des Ganzen ist eine Fernbedienung für meine Roboter.

Da alle Roboter (zumindest die fortschrittlicheren) über eine Netzwerkverbindung verfügen, möchte ich eine kleine App entwickeln, die per Konfiguration Telegramme an einen bestimmten Empfänger versenden kann.

Erster Wurf

Im ersten Schritt soll die Fernbedienung nur aus einem Tastenfeld bestehen. Der Benutzer kann die Anzahl Zeilen und Spalten bestimmen und die Knöpfe einzeln konfigurieren. Dies sollte ausreichen eine einfache Fernsteuerung zu erstellen.

Std. Layout 3 x 3 Felder
Konfigurierte Version des 3×3 Std. Layouts.

 

 

Java Socket Konsolen Server

Die Java Socket Konsole öffnet einen Server auf einem definierten Port. Der Port kann beim Start mit übergeben werden. Wird kein Port angegeben ist der standard Port 2021.  Alles was an diesen Port gesendet wird, erscheint als zeilenbasierte Ausgabe in einem Fenster.

Das Programm ermöglicht genau eine Verbindung.  Über die Textbox am Fuß des Dialogs und den „send“ Knopf kann Text an den verbundenen Client gesendet werden.

Vorausetzung

Java Version >= 7 muss installiert sein
Wurde bis jetzt nur unter Win 10 getestet

Starten

Die Datei kann einfach per Mouse-Doppelkick gestartet werde.

Ein starten über die die Konsole, um den Port mit zu geben, sieht wie folgt aus.

Der Port kann direkt hinter dem Dateinamen angegeben werden.

Ausgabe

Dateien

Jar Archiv

SocketConsole

Sourcen (Eclipse Projekt)

net.fambach.net.socket.console.zip

Probleme

Bei Problemen Mail an mich anfrage(at)fambach.net

Quellen

http://openbook.rheinwerk-verlag.de/javainsel9/javainsel_21_006.htm

https://docs.oracle.com/javase/7/docs/api/java/net/Socket.html

https://docs.oracle.com/javase/tutorial/networking/sockets/index.html

https://javabeginners.de/Netzwerk/Socketverbindung.php

DHT10 mit ESP8266

Ansteuerung eines DHT10 Sensors über den ESP8266

Grundlagen

Feuchtigkeitsmesser DHT11

Aufbau

Testprogramm

#include "DHT.h" //DHT Bibliothek laden

#define DHTPIN 5        // Pin auf dem ESP8266
#define DHTTYPE DHT11   // Typ des Sensors

DHT dht(DHTPIN, DHTTYPE); // Eine Instanz des Sensors erstellen

void setup() {
  Serial.begin(9600); 
  dht.begin(); //DHT11 Sensor starten
}

void loop() {
  
  delay(2000); //Zwei Sekunden Vorlaufzeit bis zur Messung (der Sensor ist etwas träge)

  float wett = dht.readHumidity(); //die Luftfeuchtigkeit auslesen
  float temp = dht.readTemperature();//die Temperatur auslesen 
  Serial.print("Luftfeuchtigkeit: "); //Im seriellen Monitor den Text und 
  Serial.print(wett); //die Dazugehörigen Werte anzeigen
  Serial.print(" % \t");
  Serial.print("Temperatur: ");
  Serial.print(temp);
  Serial.println(" Grad Celsius");

}

Output

Arduino – DHT11 Feuchtigkeitsmesser

Ansteuerung eines DHT10 Sensors über den Ardunio Uno.

Grundlagen

Feuchtigkeitsmesser DHT11

Aufbau

Beschaltung

Testprogramm

#include "DHT.h" //DHT Bibliothek laden

#define DHTPIN 2        // Pin auf dem Arduino
#define DHTTYPE DHT11   // Typ des Sensors

DHT dht(DHTPIN, DHTTYPE); // Eine Instanz des Sensors erstellen

void setup() {
  Serial.begin(9600); 
  dht.begin(); //DHT11 Sensor starten
}

void loop() {
  
  delay(2000); //Zwei Sekunden Vorlaufzeit bis zur Messung (der Sensor ist etwas träge)

  float wett = dht.readHumidity(); //die Luftfeuchtigkeit auslesen
  float temp = dht.readTemperature();//die Temperatur auslesen 
  Serial.print("Luftfeuchtigkeit: "); //Im seriellen Monitor den Text und 
  Serial.print(wett); //die Dazugehörigen Werte anzeigen
  Serial.print(" % \t");
  Serial.print("Temperatur: ");
  Serial.print(temp);
  Serial.println(" Grad Celsius");

}

Output

Raspberry PI + Servo

Ansteuerung eines Servos mit dem Raspberry PI 3.
Hierbei geht es nur um die grundlegende Technik, der Einsatz könnte beispielsweise ein Mobiler Roboter sein.

Der Servo soll hierbei über den Software PWM angesteuert werden um die Hardwar PWMs für andere Funktionen frei zu halten.

Zusätzlich soll der Servo nicht wie üblich über Integer Werte gesteuert werden sondern über eine Gradzahl im Bezug zur Mittelstellung des Servos.

Das unten stehende Bild zeigt was hiermit gemeint ist.

Auf die eigentliche Funktionsweise eines Servos gehe ich hier nicht ein, dies kann bei Bedarf bei http://rn-wissen.de/wiki/index.php/Servos oder anderen Websites nachgelesen werden.

Benötigte Hardware

  • PI3 (oder älter bitte auf die richtigen Pins achten)
  • Standard-Servo
  • Diverse Kabel ( Vorgefertigte Pin-Header Kabel)

Aufbau der Schaltung

Die Ansteuerung des Servos geschieht in meinem Fall über GPIO 27. Die Spannungsversorgung liefert der PI. Für größere Servos müsste evtl. auf eine externe Spannungsversorgung zurückgegriffen werden.

(Die GPIOs gelten nur in Verbindung mit pi4j und wirePi)

 

Software

Als Entwicklungsumgebung verwende ich BlueJ auf dem PI selbst. Hiermit habe ich die folgenden Klassen erstellt.


Code

Ein Erster Test

Ein guter Anfang ist immer den im Internet gefundenen Code eine Main Funktion zu packen, um zu schauen ob überhaupt was klappt. Dies habe ich in Form der FirstTest Klasse getan. Sie fährt alle Positionen des Servos ab. Die Funktionalität ist hier nicht gekapselt.

import com.pi4j.wiringpi.SoftPwm;

public class FirstTest
{
    static int max = 27;
    static int min = 4;
    static int pin = 27;

    static void setMin(int min){
        FirstTest.min = min;
    }

    static void setMax(int max){
        FirstTest.max = max;
    }

    public static void main(String[] args) throws InterruptedException {

        // initialize wiringPi library
        com.pi4j.wiringpi.Gpio.wiringPiSetup();

        // create soft-pwm pins (min=0 ; max=100)
        SoftPwm.softPwmCreate(pin, 0, 200);

        int j = 0;
        // continuous loop
        while (j < 10) {
            // fade LED to fully ON
            for (int i = min; i <= max; i++) {
                SoftPwm.softPwmWrite(pin, i);
                Thread.sleep(100);
            }

            // fade LED to fully OFF
            for (int i = max; i >= min; i--) {
                SoftPwm.softPwmWrite(pin, i);
                Thread.sleep(100);
            }
            j++;
        }

        // make sure to stop software PWM driver/thread if you done with it.
        //
        SoftPwm.softPwmStop(1);
    }
}

Gekapselter Code

Als nächsten Schritt habe ich den Code aus dem ersten Test genommen und ihn mit ein paar Änderungen in eine Klasse gepackt. Hierbei habe ich auch die Umrechnung von absoluten Werten in Grad implementiert. Für den Test der Klasse habe ich wiederum eine Main-Klasse erstellt die alles mal aufruft.

Servo-Klasse

Klasse zur Steuerung des Servos. Die zwei wichtigsten Methoden sind:

  • setPos – Setzen der Position, Wertebereich von posMin bis posMax wobei (posMax-posMin+1)  die Mittelstellung ist.
  • setDeg – Diese Methode projeziert die angegebene Gradzahl auf die möglichen Positionen (aktuell sehr ungenau 🙁 )
import com.pi4j.wiringpi.SoftPwm;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.RaspiPin;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioPin;

/**
 * Control class for servo motors
 * @author Stefan Fambach (With help of many others)
 * @version 0.1
 * 
 * This class can either set position by values between posMin and posMax
 * or it can caluculate the position by an angle where degMin <= angle <= degMax
 * 
 * No warranty free for use see GPL v3.
 */
public class Servo
{
    Pin pin;

    int degMin = -90;
    int degMax = 90;

    int posMin = 4; // to have a center
    int posMax = 25;
    int pos = -1;

    /**
     * range between min and max degree
     */
    double degDelta = degMax - degMin;

    /**
     * range between min and max position
     */
    double posDelta = posMax - posMin;

    /**
     * multiplier for degree to pos calculation
     */
    double multiplier = posDelta/degDelta;

    /**
     * Time in ms to wait after new position is set
     */
    int timeout = 1000;

    /**
     * Default constructor, default pin is GPIO_27
     */
    public Servo(){
        this(RaspiPin.GPIO_27);
    }

    /**
     * Constructor for objects of class Servo
     */
    public Servo(Pin controlPin) 
    {
        this.pin = controlPin;
        // initialize wiringPi library
        com.pi4j.wiringpi.Gpio.wiringPiSetup();

        // create soft-pwm pins (min=0 ; max=100)
        SoftPwm.softPwmCreate(this.pin.getAddress(), 0, 200);

        moveCenter();

    }

    /** 
     * set position in degree, only 20 positions are possible, each step will be calculated
     */
    boolean setDeg(int deg) throws Exception {
        if(deg > degMax){
            throw new Exception( "Entered deg: "+ deg + "is greater maxDeg "+degMax);
        }

        if(deg < degMin){
            throw new Exception( "Entered deg: "+ deg + "is smaller maxDeg "+degMin);            
        }

        if(deg < 0){
            deg = (-degMin)+ deg;
        }else{
            deg -= degMin;
        }

        return setPos((int) (deg * multiplier));
    }

    /** 
     * set position posMin - posMax (default 0-21)
     */
    public boolean setPos(int pos)throws Exception{
        if(pos < 0 ){
            throw new Exception (pos + " Pos to small (<0) ");
        }

        if(pos > posMax ){
            throw new Exception (pos + " Pos to big > "+posMax+")");
        }
        if(pos != this.pos){
            this.pos = pos;
            SoftPwm.softPwmWrite(pin.getAddress(), posMin + pos);
            sleep(timeout);
            SoftPwm.softPwmWrite(pin.getAddress(), 0);
            return true;
        }
        return false;
    }

    /** 
     * set Servo to center position
     */
    public void moveCenter(){
        try{
            setPos((posMax-posMin+1)/2);
        } catch (Exception ex){
            // will hopefully never happen
        }
    }

    /** 
     * set Servo to min position
     */
    public void moveToMinPos(){
        try{
            setPos(0);
        } catch (Exception ex){
            // will hopefully never happen
        }
    }

    /** 
     * set Servo to max position
     */
    public void moveToMaxPos(){
        try{
            setPos(posMax-posMin);
        } catch (Exception ex){
            // will hopefully never happen
        }
    }

    public int getPos(){
        return this.pos;
    }

    public int getDegMin(){
        return degMin;
    }

    public int getDegMax(){
        return degMax;
    }

    public void setDegMin(int min){
        this.degMin = min;
        calculateVariables();
    }

    public void getDegMax(int max){
        this.degMax = max;
        calculateVariables();
    }

    public void setPosMin(int min){
        this.posMin = min;
        calculateVariables();
    }

    public void setPosMax(int max){
        this.posMax = max;
        calculateVariables();
    }

    public int getPosMin(){
        return  this.posMin;
    }

    public int getPosMax(){
        return  this.posMax;
    }

    /**
     * calculate the ranges for deg and pos 
     * as well as the multiplier for degree positioning of the servo
     */
    private void calculateVariables(){
        degDelta = degMax - degMin;
        posDelta = posMax - posMin;
        multiplier = posDelta/degDelta;
    }

    private void sleep(int msec){
        try
        {
            Thread.sleep(msec);
        }
        catch ( InterruptedException e)
        {
        }
    }

    public void release(){
        SoftPwm.softPwmStop(pin.getAddress());
        GpioController gpio = GpioFactory.getInstance();
        gpio.unprovisionPin(new GpioPin[]{gpio.getProvisionedPin(pin)});


    }
}

Test-Klasse

Klasse mit Main-Methode zum Testen der Servo-Klasse. In der Main-Methode werden alle Positionen abgefahren wobei die Positionierung über den Winkel relativ zur 0 Position erfolgt.

import com.pi4j.io.gpio.RaspiPin;


public class TestServo
{

    public static void main(String args[]){

        // Create the range sensor
        Servo servo = new Servo(RaspiPin.GPIO_27); 

        int j = 0;

        do {
            System.out.println("***** Start degree test from left to right *****");     

            int curPos = servo.getDegMin()-1;
            // from left to right
            for(int i = servo.getDegMin(); i < servo.getDegMax(); i++){
                try{
                    servo.setDeg(i);
                }catch(Exception e){
                    System.out.println(e.getMessage());
                }
                int cpos = servo.getPos();
                if(cpos > curPos){
                    curPos = cpos;
                    System.out.print("\n "+curPos+" : ");
                }

                System.out.print(i+" , ");

            }

            System.out.println("***** Start degree test from right to left *****");  
            curPos = servo.getDegMax() + 1;
            // from left to right
            for(int i = servo.getDegMax(); i > servo.getDegMin(); i--){
                try{
                    servo.setDeg(i);
                }catch(Exception e){
                    System.out.println(e.getMessage());
                }
                int cpos = servo.getPos();
                if(cpos < curPos){
                    curPos = cpos;
                    System.out.print("\n "+curPos+" : ");
                }
                System.out.print(i+" , ");

            }
            j++;
        } while (j < 5);

        servo.release();
    }
}

Tips

Das Positionieren über die PI4j Lib ist sehr ungenau für die 180° Bewegungsspielraum des Servos stehen gerade mal rund 20 (+-2) Positionen zur Verfügung. Das sind rund 9° pro Position.  Evtl. sollte man vorher testen welche Positionen für den Aktuellen Zweck am besten geeignet sind. Sollte der genaue Winkel wichtig sein, ist es besser diesen vorab zu messen als ihn über die setDeg Methode berechnen zu lassen.

Es gibt noch weitere Lib’s (Servoblast, … ) die evtl genauer sind, man könnte auch überlegen die Programmiersprache zu wechseln und dann den Ensprechenden Code über das Nativ-Interface anzusprechen. Als nächsten Versuch klingt Servoblast ersteinmal vielversprechend.

Weitere Schritte

PWM in Thread

Ich habe versucht den Software PWM innerhalb eines Threads laufen zu lassen, jedoch ohne Erfolg. Der Servo weigert sich zu funktionieren.  Über die Ursache hierfür bin ich mir noch im unklaren. Ich nehme allerdings an, dass hierdurch der Timer zerschossen wird.

ServoBlast

Nach diversen Tests mit unterschiedlichen Frequenzen habe ich mich entschlossen ServoBlaster od.  besser die PI variante (PiBits) zu verwenden. Die Installation gestaltet sich einfach wie folgt.

# holen der sourcen
wget https://github.com/richardghirst/PiBits/zipball/master

#umbenennen
mv master pibits.zip

#entpacken
unzip pibits.zip

#bauen
cd richardghirst-PiBits-96014c8/ServoBlaster/user
sudo make install 

#ändern des timeout von 2000 auf 500#
sudo nano /etc/init.d/servoblaster 

#eine reboot ist nicht unbedingt erforderlich 
sudo reboot

#ein starten reicht aus 
sudo /etc/init.d/servoblaster start

Programmierbeispiel

An dieser Stelle sollte nun eigentlich ein Code-Beispiel mit ServoBlast folgen. Da ich aktuell aber die Arbeiten am PI eingestellt  habe und mit dem ESP8266 und ESP32 unterwegs bin, sei auf die folgenden Links verwiesen:

https://github.com/richardghirst/PiBits/tree/master/ServoBlaster

http://www.leenabot.com/en/Servo-Motor-driver/

 

Problembehandlung

Exec Funktioniert nicht

Wenn die exec Funktion von Java nix macht ist hier ein guter Link zum Bugfixing.

http://www.javaworld.com/article/2071275/core-java/when-runtime-exec—won-t.html

Probleme mit println

Weiterhin könnte es helfen nicht die println Methode zu verwenden, sondern die print. Da zumindest mein PI den Abschluss der Zeile nicht richtig interpretieren konnte. print( „5=100\n“) hat jedoch funktioniert.

https://github.com/richardghirst/PiBits/tree/master/ServoBlaster

http://www.leenabot.com/en/Servo-Motor-driver/

Quellen

http://razzpisampler.oreilly.com/ch05.html
https://github.com/Pi4J/pi4j/blob/master/pi4j-example/src/main/java/MaestroServoExample.java
https://www.bluej.org/raspberrypi/ServoMotor.html
https://phyks.me/2015/05/controlling-servomotors-on-a-raspberry-pi.html
http://rn-wissen.de/wiki/index.php/Servos
https://github.com/richardghirst/PiBits/tree/master/ServoBlaster
https://github.com/BioMachinesLab/drones/wiki/Installing-Servoblaster

Raspberry Pi Servo Motor Steuerung

Between 0 and 1 – PWM with Raspberry Pi

 


Anhang

Pin-Belegung