C++Guns – RoboBlog

24.07.2018

C++ Guns: Rolladensteuerung 1

Filed under: Allgemein — Tags: — Thomas @ 21:07

Hier habe ich ein kleines Projekt eines Freundes zur Steuerung eines Rolladens mittels Mikrocomputer, selbst gebastelte Elektronik und natürlich C++.

Die ganze Anlage wird über Textdateien gesteuert. So ist der Zustand des Rolladenmotor durch vier Relais in einer Datei mit Buchstaben kodiert. Das Programm soll nun die Status Datei einlesen, modifizieren und wieder raus schreiben.

Klein muss man anfangen, hier mal die erste Version.
Man kann natürlich immer weiter verbessern. Die ausführlichen Schleifen zum Beispiel verstecken. So verhindert man ein paar Index Fehler. Oder ein paar Sensoren mit einbeziehen die bei zu viel Sonne die Motoren aktivieren.

Hier ein Video der funktionierende Hard+Software

https://www.youtube.com/watch?v=wBCo-W7wVNA

#include <iostream>
#include <fstream>
#include <chrono>
#include <thread>
#include <array>

using namespace std;
using namespace std::chrono;

// Operator << ueberladen um einfach eine Zeitspanne auf der Konsole auszugeben
std::ostream& operator<<(std::ostream& s, std::chrono::duration<double> dur) {
    // Sekunden, Minuten u.s.w. sind im Standard definiert. Ein Tag leider nicht. Aber das ist kein Problem.
    // Ein Tag hat bekanntlich 24 Stunden. Und eine Stunde hat 3600 Sekunden.
    using day = std::chrono::duration<int64_t, std::ratio<24*3600>>;

    const auto days = std::chrono::duration_cast<day>(dur);
    dur -= days;
    if(days.count() > 0) s << days.count() << "d ";

    const auto HH = std::chrono::duration_cast<std::chrono::hours>(dur);
    dur -= HH;
    if(HH.count() > 0) s << HH.count() << "h ";

    const auto min = std::chrono::duration_cast<std::chrono::minutes>(dur);
    dur -= min;
    if(min.count() > 0) s << min.count() << "m ";

    const auto sec = std::chrono::duration_cast<std::chrono::seconds>(dur);
    dur -= sec;
    if(sec.count() > 0) s << sec.count() << "s ";

    const auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(dur);
    if(msec.count() > 0) s << msec.count() << "ms";

    return s;
}

// 4 Relais werden benutzt
static const int N = 4;
// Zeit bis das Relais von AN nach AUS wechselt
static const auto waittime = 10s;

// Ein Relais kann entweder an, oder aus sein. Dieser Sachverhalt laesst sich gut als strong typed enum ausdruecken.
enum class RelaisStatus{ AUS, AN };

// Operator << ueberladen um den Zustand eines Relais einfach auf der Konsole auszugeben
std::ostream& operator<<(std::ostream& s, const RelaisStatus& status) {
    switch(status) {
    // Entweder das Relais ist an...
    case RelaisStatus::AN: s << "AN"; break;
        // Oder es ist aus. Das ist auch der default Fall.
    default:
    case RelaisStatus::AUS: s << "AUS"; break;
    }

    return s;
}

// Lese die Statusdatei ein.
// Relais AN ist als "a" codiert. Alles anderes wird als "AUS" interpretiert.
auto read() {
    array<RelaisStatus,N> status{ RelaisStatus::AUS};
    ifstream ff;
    ff.open("datei.txt", ios::in);

    for(int i=0; i < N; ++i) {
        if(ff.eof()) {
            break;
        }
        string s;
        getline(ff, s);
        if(s == "a") {
            status[i] = RelaisStatus::AN;
        }
    }
    ff.close();

    return status;
}

// Schreibe Statusdatei.
// AN wird als der Buchstabe "a" kodiert. AUS als der Buchstabe "b"
void write(const array<RelaisStatus,N>& status) {
    fstream f;
    f.open("datei.txt", ios::out);
    for(int i=0; i < N; ++i) {
        if(status[i] == RelaisStatus::AN) {
            f << "a\n";
        } else {
            f << "b\n";
        }
    }
    f.close();
}

int main() {
    const auto start = system_clock::now();
    array<chrono::system_clock::time_point,N> warten;
    array<bool,N> aktiv{false};

    cout << "Default Wartezeit " << waittime << "\n";

    while(true) {
        cout << "Time " << system_clock::now()-start << "\n";
        array<RelaisStatus,N> status = read();

        // Wenn das Relais an geht, und nicht schon an war,
        // wird der Zeitpunkt ermittelt wann es wieder aus gehen soll
        for(int i=0; i < N; ++i) {
            cout << status[i] << " ";
            if(status[i] == RelaisStatus::AN and not aktiv[i]) {
                aktiv[i] = true;
                warten[i] = system_clock::now() + waittime;
            }
        }
        cout << "\n";
        // Fanzy Befehle um den Inhalt der Konsole zu loeschen
        //        cout << "\033[2J\033[1;1H";

        // Wenn der Zeitpunkt verstrichen ist wann das Relais aus gehen soll, Relais ausschalten.
        for(int i=0; i < N; ++i) {
            if(aktiv[i] and system_clock::now() >= warten[i]) {
                aktiv[i] = false;
                status[i] = RelaisStatus::AUS;
            }
        }

        write(status);

        // Program kurz pausieren um nicht zuviel CPU Last zu erzeugen
        this_thread::sleep_for(0.5s);
    }
    return 0;
}

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress