Hallo zusammen
Lange nicht mehr hier gewesen... Und gleiche eine Frage, inwieweit Python als Taktgeber taugt, der die Taktfolge nach einer Uhr stellen kann und sehr exakt ist...
Konkret:
Ich brauche für einen Versuch einen Taktgenerator, der im ersten Step auf der Konsole einen Takt anzeigen kann, später sollte das dann einen Ausgang steuern. Auf mindestens zwei getrennten Rechnern. Das ganze ist leider etwas kompliziert. Die Taktfolge ist nicht symetrisch, sondern kann sowas sein wie:
(Start)
1000 ms ON
500 ms OFF
7000 ms ON
2000 ms OFF
5000 ms ON
2000 ms OFF
(ab hier zurück auf Start)
Der Steuerrechner hat eine Uhr, die per DCF77 oder NTP die genaue Zeit hat. Für den Test soll es NTP sein. Das ist sicher noch einfach. Das Problem kommt jetzt. Wenn der Taktgenerator startet, soll der Takt auf diesem einen Rechner genauso syncron laufen, wie auf jedem weiteren Rechner mit dem selben Programm. Wie die Blinklichter auf den Windparks, die per DCF syncron sind. Nur hier in diesem Fall ist der Takt komplexer als nur an und aus und so eine Abfolge der ON und OFFS kann auch mal länger sein... Die beiden und mehrere Rechner haben aber keine Verbindung, ausser die genaue Zeit... Die Abweichung des Taktes zwischen den Rechnern darf 30ms nicht überschreiten.
Kann Python so genau schalten, und kann der Takt auch nach langer Laufzeit des Programm noch syncron bleiben? Es ist sicher nicht damit getan, einen Zählen des Prozessor als Zeitbasis nach dem syncronen Start zu nehmen. Das würde sicher auseinander laufen. Es muss also der Zyklus einer Taktfolge alle paar Minuten neu an die Zeitbasis angelehnt werden, denke ich.
Lösbar, oder ein unsinniges Vorhaben.? Danke für Anregungen...
--
Rüdiger
Taktgeber, NTP Sync, syncroner Start
Wenn du die "wall clock" nimmst, was einfach time.time sein sollte, und die Rechner alle per synchron sind - dann ist das trivial. Es bietet sich an, die Rechner auf UTC zu konfigurieren (so hast du keine Umschaltung Sommer/Winterzeit), und spaeter dann per DCF muss man das eben auch entsprechend machen. Alles was du tun musst ist eine Epoche festlegen, ab der die Sequenz berechnet wird. Kann auch einfach die Unix-Epoche sein. Womit dann einfach
den Offset in die Sequenz bestimt. Und dann einfach warten.
Code: Alles auswählen
math.fmod(time.time(), <periode>)
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Epoche... Der berühmte 1.1.1970
Hört sich einfach an. Als weiss das Programm dann wo in der Abfolge es ist.?
Ja, das hatte ich vergessen. UTC ist die Zeit der Wahl.
Hört sich einfach an. Als weiss das Programm dann wo in der Abfolge es ist.?
Ja, das hatte ich vergessen. UTC ist die Zeit der Wahl.
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
OK, muss feststellen das meine ersten Gehversuche vor Jahren mit einem PI und ein paar GPIO mir hier nicht weiterhelfen. Die "periode" oben in spitzen Klammern ist diese Liste an ON und OFF Zeiten? Blätter gerade durch diverse Codebeispiele...
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Code: Alles auswählen
import math
import time
seconds = time.time()
print("Seconds since epoch =", seconds)
position = math.fmod(time.time(), 17500)
print(position)
nicht durch 17500 geteilt zu sein...

Code: Alles auswählen
$ python ./takt.py
('Seconds since epoch =', 1580840128.924031)
12628.924068
Ich habe dir ja auch gesagt, dass du die Summe deiner in Millisekunden angegebenen Intervalle in SEKUNDEN ausdruecken musst. Und natuerlich kommt der Wert als ein Modulo von 17500 bei raus - was sonst sollte denn 12628.924068 sein?
So berechnet man an/aus. Der Rest sollte nun wirklich ein Kinderspiel sein:
So berechnet man an/aus. Der Rest sollte nun wirklich ein Kinderspiel sein:
Code: Alles auswählen
import time
import math
import bisect
SEQUENCE = [
(1000, True),
(500, False),
(7000, True),
(2000, False),
(5000, True),
(2000, False),
]
PERIOD = sum(t for t, _ in SEQUENCE) / 1000.0 # in seconds
def main():
absolute_sequence = [0]
for ts, _ in SEQUENCE:
absolute_sequence.append(absolute_sequence[-1] + ts)
del absolute_sequence[0]
while True:
time.sleep(.1)
offset = int(math.fmod(time.time(), PERIOD) * 1000)
pos = bisect.bisect_left(absolute_sequence, offset)
print(offset, pos, SEQUENCE[pos][1])
if __name__ == '__main__':
main()
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Mist, zu doof. Hab ich ja selber vorgegeben.
Danke, ich probier mal damit rum...
Danke, ich probier mal damit rum...
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Tolle Sache. Hab das Programm in zwei getrennte Terminals nacheinander gestartet, und die True/False Zeilen laufen parallel hoch. OK, klar. Ist ja die selbe Zeitbasis. Aber wenn NTP und Co seinen Job machen, sollte das grundsätzlich gehen.
Und bzgl. weglaufen. Es wird immer wieder neu ausgerechnet.? Alle 100 ms...
Und bzgl. weglaufen. Es wird immer wieder neu ausgerechnet.? Alle 100 ms...
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Danke für die Unterstützung. Will das mal auf zwei Raspis laufen lassen und ne LED steuern. Das fällt dann mehr ins Auge, wenn das aus dem Takt läuft.
Schönen Abend noch...
Schönen Abend noch...
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Hab noch ne Frage bzgl. der LED...
Die Ansteuerung der LED ist kein Problem, wenn ich die jeweiligen Zeilen auskommentiere, geht die auch an bzw. aus. Aber die Abfrage, die parallel zu der Ausgabe True oder False die LED setzen soll, geht aber nicht.
Das wird einfach ignoriert.
Geht das so nicht innerhalb dieser Schleife?
Die Ansteuerung der LED ist kein Problem, wenn ich die jeweiligen Zeilen auskommentiere, geht die auch an bzw. aus. Aber die Abfrage, die parallel zu der Ausgabe True oder False die LED setzen soll, geht aber nicht.
Das wird einfach ignoriert.
Geht das so nicht innerhalb dieser Schleife?
Code: Alles auswählen
mport time
import math
import bisect
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setup(40, GPIO.OUT)
SEQUENCE = [
(1000, True),
(500, False),
(7000, True),
(2000, False),
(5000, True),
(2000, False),
]
PERIOD = sum(t for t, _ in SEQUENCE) / 1000.0 # in seconds
def main():
absolute_sequence = [0]
for ts, _ in SEQUENCE:
absolute_sequence.append(absolute_sequence[-1] + ts)
del absolute_sequence[0]
while True:
time.sleep(.1)
offset = int(math.fmod(time.time(), PERIOD) * 1000)
pos = bisect.bisect_left(absolute_sequence, offset)
print(offset, pos, SEQUENCE[pos][1])
if SEQUENCE == True:
GPIO.output(40, GPIO.HIGH)
else :
GPIO.output(40, GPIO.LOW)
if __name__ == '__main__':
main()
GPIO.cleanup()
Ich werde aus deiner Beschreibung des Problems nicht ganz schlau. Welche Zeile meinst du denn?
In der Zeile SEQUENCE == True prüfst du, ob das Objekt , das in den Namen "SEQUENCE" gebunden ist, den Wahrheitswert True hat. Das Objekt, dass du ein SEQUENCE gebunden hast, ist eine Liste. Ich bin mir ziemlich sicher, dass du das so nicht möchtest.
Edit: Und "in der Schleife" sehe ich auch keine Änderung zu deinem vorherigen Code.
In der Zeile SEQUENCE == True prüfst du, ob das Objekt , das in den Namen "SEQUENCE" gebunden ist, den Wahrheitswert True hat. Das Objekt, dass du ein SEQUENCE gebunden hast, ist eine Liste. Ich bin mir ziemlich sicher, dass du das so nicht möchtest.
Edit: Und "in der Schleife" sehe ich auch keine Änderung zu deinem vorherigen Code.
Zuletzt geändert von sparrow am Mittwoch 5. Februar 2020, 11:58, insgesamt 1-mal geändert.
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Ja, da hast Du Recht. In der Schleife wird immer ausgegeben, an welcher Stelle in dieser Sequenz die Berechnung rauskommt. Und im Falle von True soll der Ausgang auf High gehen, bzw. auf LOW bei False. Ich dachte ich kann die SEQUENCE als eine Art variable nehmen.!? War wohl Unsinn...
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
Der print Befehl gibt das ja periodisch aus. Endet damit die Schleife?
Sowas wie ein "Done" am Ende der Schleife gibt es bei Python wohl nicht...?!
Sowas wie ein "Done" am Ende der Schleife gibt es bei Python wohl nicht...?!
Es gibt ein ganz gutes Tutorial in der Python-Dokumentation, das einem die Grundlagen der Sprache recht gut vermittelt.
Da die Schleife endlos ist, endet sie nicht. Und wenn eine Schleife endlos laeuft, dann ist es auch irrelevant welcher Code danach steht - der wird ja nie ausgefuehrt(*). Der GPIO-Code muss IN die Schleife, und warum Code in einer Schleife ist, und warum nicht, ist absolute Grundlage in Python. Ein paar Stunden mit dem Tutorial das sparrow nennt wirst du dir goennen muessen.
(*)Ausnahmen sind Ausnahmen. Aber die kommen hier nicht vor.
(*)Ausnahmen sind Ausnahmen. Aber die kommen hier nicht vor.
-
- User
- Beiträge: 21
- Registriert: Montag 11. September 2017, 20:27
OK, schaue ich mir an.
Wie so oft, ist Zeit ein limitierender Faktor. Und ich hatte angenommen, das mein GPIO grundsätzlich laufen müsste, ich nur irgendwo ein Zeichen falsch gesetzt habe, oder so. Und dann neige ich dazu erstmal rumzuprobieren, was auch ab und zu klappt.
Aber eben nicht immer...
Wie so oft, ist Zeit ein limitierender Faktor. Und ich hatte angenommen, das mein GPIO grundsätzlich laufen müsste, ich nur irgendwo ein Zeichen falsch gesetzt habe, oder so. Und dann neige ich dazu erstmal rumzuprobieren, was auch ab und zu klappt.
Aber eben nicht immer...