[Python] event triggeren op timecode video? - example code

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
Voor een installatie die ik aan het bouwen ben moet ik een relais laten schakelen op een aantal exacte momenten in een video die afgespeeld wordt.
Gebruik hiervoor een RPi in combinatie met een 5V relais. De code om de relais te laten schakelen heb ik al werkend. De code om de video af te spelen ook, gebruik makend van python-omxplayer-wrapper.
Nu alleen nog die 2 combineren. Heb een stukje voorbeeld code gevonden waarmee het werkend te krijgen zou moeten zijn, maar loop vast op 'events'. Met feitelijk 0 Python ervaring is het lastig debuggen...

Dit is de betreffende code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from omxplayer import OMXPlayer
from time import sleep
from pathlib import Path

#/* Setup the player as shown in omxplayer-wrapper examples : */
path = Path('Videos/myvideo.m4v')
player = OMXPlayer(path, args=['--no-osd', '--blank'])
player.pause()
sleep(5)
player.play()

#/* Make a query to position() inside infinite loop : */
while (1):
    position = player.position() * 1000
#    /* Event timecodes values are stored in "events" */
    for event in events.values():
        if position - 20 <= event['tc'] and position + 20 >= event['tc']:
#            /* Put your code here */
            print("This is where the first GPIO should be triggered")
player.quit()


Bij het uitvoeren van deze code begint de video prima te spelen, maar krijg ik als foutmelding terug:
code:
1
2
3
4
Traceback (most recent call last):
  File "./bm_test.py", line 21, in <module>
    for event in events.values():
NameError: name 'events' is not defined


De vraag is nu, hoe/waar definiëer ik deze 'events'?
Heb ik hier extra software voor nodig, zoals https://pypi.org/project/Events/ en misschien https://pypi.org/project/timecode/ of is het een kwestie van wat extra code kloppen?

Relevante software en hardware die ik gebruik:
Hardware: Raspberry Pi 2b
Software: Raspbian, Python 3, python-omxplayer-wrapper (https://python-omxplayer-wrapper.readthedocs.io/en/latest/)

Uiteraard heb ik al de foutmelding gegoogle'd, maar werd daar niet veel wijzer uit.
Wel heb ik om te testen even
code:
1
event = "30"

toegevoegd om te kijken wat er zou gebeuren. De foutmelding verandert dan naar deze:

code:
1
2
3
4
Traceback (most recent call last):
  File "./bm_test.py", line 22, in <module>
    for event in event.values():
AttributeError: 'str' object has no attribute 'values'


Ook daar op googlen levert me geen antwoord op waar ik echt iets mee kan. Van wat ik begrijp / denk te begrijpen is dat ik niet simpelweg
code:
1
event = "30"
kan gebruiken maar dat ik een lijst met 'values' moet gaan definiëren. Maar hoe moeten die er dan uitzien?

EDIT: heb nog een paar variaties geprobeerd, met wisselende uitkomsten.
Poging 1:
code:
1
2
3
event = {
    'tc': 30
    }

Resultaat 1:
code:
1
2
3
4
 Traceback (most recent call last):
  File "./bm_test.py", line 27, in <module>
    if position - 20 <= event['tc'] and position + 20 >= event['tc']:
TypeError: 'int' object has no attribute '__getitem__'


Poging 2:
code:
1
event = [30, 60]

Resultaat 2:
code:
1
2
3
4
Traceback (most recent call last):
  File "./bm_test.py", line 26, in <module>
    for event in event.values():
AttributeError: 'list' object has no attribute 'values'

Zit ik in de goede richting of sla ik de plank helemaal mis?

[ Voor 11% gewijzigd door iGadget op 15-10-2020 15:24 . Reden: nog een aantal pogingen gedaan, resultaat toegevoegd ]

"I'll just use my Go-Go-Gadget handbook!"

Alle reacties


Acties:
  • 0 Henk 'm!

  • ValHallASW
  • Registratie: Februari 2003
  • Niet online
Wat je code -- als ik het goed begrijp, ook op basis van https://stackoverflow.com...mps-during-video-playback -- zou moeten doen is het volgende:
  • Speel de video
  • Terwijl de video speelt:
    • Bekijk de huidige timestamp
    • Check of de huidige timestamp in de buurt is van een event, en zo ja, trigger een ander stukje code
    • Herhaal
Dus:
code:
1
2
3
4
5
while (1):  # terwijl de video speelt.... maar in dit geval: herhaal voorgoed
    position = player.position() * 1000      # bekijk de huidige timestamp (https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/#OMXPlayer.position specificeert dat .position() secondes teruggeeft, dus position is nu in ms)
    for event in events.values():   # bekijk alle events
        if position - 20 <= event['tc'] and position + 20 >= event['tc']:  # check of de tijd van het event tussen [position-20, position+20] ligt -- in ms!
        print("This is where the first GPIO should be triggered")   # doe iets


Het helpt als je je code versimpelt tot een enkel event, en bovendien de timestamps in eerste instantie niet opslaat maar gewoon hardcoded. Je krijgt dan zoiets:

code:
1
2
3
4
while (1):  # terwijl de video speelt.... maar in dit geval: herhaal voorgoed
    position = player.position() * 1000      # bekijk de huidige timestamp (https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/#OMXPlayer.position specificeert dat .position() secondes teruggeeft, dus position is nu in ms)
    if position - 20 <= 12000 and position + 20 >= 12000:  # check of we op 12s +/- 20ms zitten
            print("This is where the first GPIO should be triggered")   # doe iets


Je kunt dan zelf op basis van de python-kennis die je al hebt dat uitbreiden tot meerdere events.

Houd er wel rekening mee dat dit een énorm inefficiente manier is: je CPU zal in een 'busy loop' wachten tot het event er is. Je kunt beter met een time.sleep() ongeveer de goede tijd wachten en dán op de specifieke timecode wachten. Maar het is een begin!

Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
Dank voor je reactie, @ValHallASW :)
ValHallASW schreef op vrijdag 16 oktober 2020 @ 08:42:
Wat je code -- als ik het goed begrijp, ook op basis van https://stackoverflow.com...mps-during-video-playback -- zou moeten doen is het volgende:
Haha daar had ik de code snippet idd vandaan, nice catch :)
  • Speel de video
  • Terwijl de video speelt:
    • Bekijk de huidige timestamp
    • Check of de huidige timestamp in de buurt is van een event, en zo ja, trigger een ander stukje code
    • Herhaal
Juist, zover was ik ook (na lang pielen, haha).
Dus:
code:
1
2
3
4
5
while (1):  # terwijl de video speelt.... maar in dit geval: herhaal voorgoed
    position = player.position() * 1000      # bekijk de huidige timestamp (https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/#OMXPlayer.position specificeert dat .position() secondes teruggeeft, dus position is nu in ms)
    for event in events.values():   # bekijk alle events
        if position - 20 <= event['tc'] and position + 20 >= event['tc']:  # check of de tijd van het event tussen [position-20, position+20] ligt -- in ms!
        print("This is where the first GPIO should be triggered")   # doe iets
Ah, en ik maar denken dat die * 1000 er juist voor zorgde dat de boel terug ging naar secondes ipv ms. Maar het is dus andersom? Hoe werkt dat dan, stel de video is op seconde 10, player.position() geeft 10 terug, dat doe je * 1000, heb je 10000. Maar aangezien player.position() een integer is, zal er toch geen verandering plaatsvinden tot 11, waarna de boel in 1x ophoogt tot 11000? Hoe krijg je dan sub-second precisie?
Het helpt als je je code versimpelt tot een enkel event, en bovendien de timestamps in eerste instantie niet opslaat maar gewoon hardcoded. Je krijgt dan zoiets:

code:
1
2
3
4
while (1):  # terwijl de video speelt.... maar in dit geval: herhaal voorgoed
    position = player.position() * 1000      # bekijk de huidige timestamp (https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/#OMXPlayer.position specificeert dat .position() secondes teruggeeft, dus position is nu in ms)
    if position - 20 <= 12000 and position + 20 >= 12000:  # check of we op 12s +/- 20ms zitten
            print("This is where the first GPIO should be triggered")   # doe iets
Top, ga ik proberen.
Je kunt dan zelf op basis van de python-kennis die je al hebt dat uitbreiden tot meerdere events.

Houd er wel rekening mee dat dit een énorm inefficiente manier is: je CPU zal in een 'busy loop' wachten tot het event er is. Je kunt beter met een time.sleep() ongeveer de goede tijd wachten en dán op de specifieke timecode wachten. Maar het is een begin!
Dat is goed om in gedachten te houden idd. Mochten er playback / performance issues ontstaan dan is dit het eerste waar ik naar ga kijken.

"I'll just use my Go-Go-Gadget handbook!"


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:54

Janoz

Moderator Devschuur®

!litemod

Bedenk trouwens ook dat je huidige code een window van 40ms heeft waarin wordt getriggered. Het kan heel goed gebeuren dat een trigger helemaal niet af gaat of meerdere keren. Daar houdt je huidige implementatie helemaal geen rekening mee.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
Janoz schreef op vrijdag 16 oktober 2020 @ 12:11:
Bedenk trouwens ook dat je huidige code een window van 40ms heeft waarin wordt getriggered. Het kan heel goed gebeuren dat een trigger helemaal niet af gaat of meerdere keren. Daar houdt je huidige implementatie helemaal geen rekening mee.
Ah dat is ook een goede om in de gaten te houden idd. Viel me al op dat bij de eerste test de trigger 2x af ging, maar ik dacht dat dat kwam omdat de code -20 *en* +20 ms aanhoudt. Maar dat zou dus zomaar een andere reden kunnen hebben? En hoe zou ik dit moeten afvangen?

"I'll just use my Go-Go-Gadget handbook!"


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:54

Janoz

Moderator Devschuur®

!litemod

Als je echt wilt weten wat er gebeurt dan zou je ook de waarde van position kunnen afdrukken in elke lus. Dan is beter te zien wat er gebeurt. Daarnaast houdt hij niet +20 *en* -20 aan. De test is eigenlijk:

Zodra position tussen 11980 en 12020 ligt ga ik iets doen.

Als je dat netjes op wilt lossen zal je bijvoorbeeld bij moeten houden welke events al afgespeeld zijn.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
Janoz schreef op vrijdag 16 oktober 2020 @ 12:57:
Als je echt wilt weten wat er gebeurt dan zou je ook de waarde van position kunnen afdrukken in elke lus. Dan is beter te zien wat er gebeurt. Daarnaast houdt hij niet +20 *en* -20 aan. De test is eigenlijk:

Zodra position tussen 11980 en 12020 ligt ga ik iets doen.

Als je dat netjes op wilt lossen zal je bijvoorbeeld bij moeten houden welke events al afgespeeld zijn.
Dat is nog even een paar bruggen te ver vrees ik.
Eerst maar even geprobeerd om de huidige player.position() weer te laten geven... #fail
code:
1
2
3
position_1 = player.position() #voordat we posities in ms op het scherm toveren, eerst maar 'default
      while (position_1 <60): #Zolang de teller onder de 60 secs blijft
      print(position_1) #Laat zien waar je bent

Output:
code:
1
2
3
4
5
6
7
-0.174797
-0.174797
-0.174797
-0.174797
-0.174797
-0.174797
....tot in het oneindige

Wat ik niet snap:
1. Waarom gaat de speler niet verder? Kennelijk kan ik mijn voorwaarde niet op deze manier in 'while' kwijt, maar waarom eigenlijk niet?
2. Waarom begint de teller onder de 0?
3. Als .position() een integer teruggeeft, waarom krijg ik dan toch een getal achter de komma?
Vragen, vragen...

"I'll just use my Go-Go-Gadget handbook!"


Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10:54

Janoz

Moderator Devschuur®

!litemod

Dat komt omdat 'while' een lus is. Waarschijnlijk bedoel je daar een test, daarvoor gebruik je 'if'.

Wat je code nu doet is:

Zolang position_1 kleiner is dan 60 moet je die waarde blijven afdrukken. Hij zal dus in het oneindige de regeltjes 2 en 3 (uit dat stukje codevoorbeeld) blijven uitvoeren.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Acties:
  • 0 Henk 'm!

  • ydderf
  • Registratie: December 2017
  • Laatst online: 16:26
Indien jou stukje code, alle code is, zul je de eerste regel ook in de while loop moeten opnemen. Op die manier wordt de variabele position_1 ook elke keer ge-update. In jou code wordt deze na het (eenmalig) uitvoeren van regel 1 niet ge-update . Ofwel je while loop blijft altijd waar.

Indien je stukje code nog in een grotere while loop zit, kun je beter de while voor een IF vervangen, zoals Janoz al aangaf.

Soms gaat het niet zoals het moet, maar moet het maar zoals het gaat


Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
@Janoz & @ydderf , dank voor jullie antwoorden. Ik denk dat ik zojuist zowaar een werkend stukje code heb geproduceerd :D
Voor debug-doeleinden heb ik nu dit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
event1_done = 0 # Het eerste event is nog niet geweest.

while (1):  # terwijl de video speelt.... maar in dit geval: herhaal voorgoed
    position_1 = player.position() # deze gaan we weergeven, dus niet *1000
    position = player.position() * 1000      # bekijk de huidige timestamp (https://python-omxplayer-wrapper.readthedocs.io/en/latest/_modules/omxplayer/player/#OMXPlayer.position specificeert dat .position() secondes teruggeeft, dus position is nu in ms)
    if position_1 < 120: # Zolang de teller onder de 2 mins blijft
            print(position_1) # laat zien waar je bent
    if position - 20 <= 12000 and position + 20 >= 12000:  # check of we op 12s +/- 20ms zitten
            if event1_done == 1: # even kijken of we het event al een keer gehad hebben
                print("no double triggers please")
            else: # is het event nog niet geweest, dan door
                print("We're @ 12 secs. This is where the first GPIO should be triggered")   # doe iets
                event1_done = 1 # event is geweest, dus zetten we de flag
    if position_1 > 20: # als we genoeg hebben gezien, voor testdoeleinden na 20 secs
        break     # stop de loop
player.quit()

En het lijkt te werken! Vanaf hier kan ik verder bouwen, super bedankt! _/-\o_

"I'll just use my Go-Go-Gadget handbook!"


Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 11-09 20:27

Matis

Rubber Rocket

Dit gaat dus niet werken zoals je wilt. Immers position zal alleen in stappen van 1000 ophogen.

Je gaat nooit de subseconde (in ms) nauwkeurigheid krijgen.

Misschien kun je _position_us() functie gebruiken en die dan delen door 1000. Dan krijg je ms nauwkeurigheid afgeleid van de microseconden.

[ Voor 30% gewijzigd door Matis op 17-10-2020 09:53 ]

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • +2 Henk 'm!

  • ValHallASW
  • Registratie: Februari 2003
  • Niet online
De documentatie klopt niet wat betreft het return type: .position() retourneert _position_us() / (1000. * 1000.), en dus gewoon een float. (https://github.com/willpr.../omxplayer/player.py#L421)

[ Voor 31% gewijzigd door ValHallASW op 17-10-2020 10:57 ]


Acties:
  • +1 Henk 'm!

  • ydderf
  • Registratie: December 2017
  • Laatst online: 16:26
Matis schreef op zaterdag 17 oktober 2020 @ 09:49:
Dit gaat dus niet werken zoals je wilt. Immers position zal alleen in stappen van 1000 ophogen.

Je gaat nooit de subseconde (in ms) nauwkeurigheid krijgen.

Misschien kun je _position_us() functie gebruiken en die dan delen door 1000. Dan krijg je ms nauwkeurigheid afgeleid van de microseconden.
Als de documentatie klopt en de functie een int returnt, dan heb je zeker gelijk mbt de nauwkeurigheid.
Maar ik denk dat de functie een float returnt zoals ValHallASW opmerkt. Ook als ik de debug print waardes zie, neig ik ook naar een bug in de documentatie.
Dus dan heeft deze wel de milliseconden nauwkeurigheid.

@iGadget mooi dat je voor je zelf zoveel commentaar in de code toevoegt. Tenminste ik vind dat als hobby programmeur fijn werken.

Waar je nog aan zou kunnen denken in je code:
-indien de totale duur van de film korter dan de 20 sec is, blijf je altijd in de loop. Ik zag in de documentatie dat je ook de duration kunt afvragen.
-je hebt nu een while(1) en in de loop een break. Je zou ook een conditie in de while kunnen zetten. While(position is kleiner dan 20 sec)
-je roept 2x de player.position aan en werkt met secondes en milliseconden door elkaar. De dubbele aanroep kan extra cyclustijd kosten en ook resulteren dat je met twee verschillende tijden werkt in 1 loop. (Al zal dat bij jou allemaal geen issu zijn)
-voor de duidelijkheid zou je position en position_1 kunnen hernoemen naar position_sec en position_msec. Dan leest het wat makkelijker.

Ps, hopelijk beschouw bovenstaande als opbouwende feedback

Soms gaat het niet zoals het moet, maar moet het maar zoals het gaat


Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
Na een paar dagen drukte eindelijk weer tijd gehad om hier mee verder te gaan. Dank @Matis , @ValHallASW en @ydderf voor de behulpzame antwoorden!
mooi dat je voor je zelf zoveel commentaar in de code toevoegt. Tenminste ik vind dat als hobby programmeur fijn werken.
Idd, 1 van de weinige dingen die ik heb onthouden van de blauwe maandag C++ lessen die ik in een vorig leven heb gehad, haha. Probeer dit echt aan te houden want ik ken mezelf - als dit project af is en ik hier een tijd niet naar kijk dan weet ik straks bij god niet meer wat de code doet of waarom ik het daar heb neergezet.
indien de totale duur van de film korter dan de 20 sec is, blijf je altijd in de loop. Ik zag in de documentatie dat je ook de duration kunt afvragen.
Klopt, dat heb ik voor nu gedaan omdat ik anders bij iedere testrun het hele freakin' filmpje moet afkijken. De uiteindelijke filmpjes staan vast dus ik weet precies hoe lang ieder filmpje duurt. Maar mocht ik deze code ooit in een 'wider scope' gaan gebruiken dan komt
code:
1
player.duration()
zeker van pas.
Inmiddels ben ik trouwens zover dat ik OMXplayer direct kan laten skippen naar het punt in de video waar de 'actie' begint, dat scheelt al een hoop :)
je hebt nu een while(1) en in de loop een break. Je zou ook een conditie in de while kunnen zetten. While(position is kleiner dan 20 sec)
Goeie. Heb de code nu aangepast naar
code:
1
while (status == "Playing")
gebruik makend van
code:
1
status = player.playback_status()
, maar ik ga ook eens kijken of ik het op jouw manier voor elkaar kan krijgen. Maar dan wordt het dus voor ieder event een losse while loop? En is dat dan beter / efficiënter dan alles in die ene while loop proberen te doen?
Bovendien - hoe zou ik dit werkend moeten krijgen? Want
code:
1
position_sec = player.position()
staat *in* de while loop en is daarvoor dus nog niet bekend. Heb tijdens een vorige test dit buiten de while loop proberen te krijgen (zie een aantal reacties hierboven) maar dat faalde jammerlijk.
je roept 2x de player.position aan en werkt met secondes en milliseconden door elkaar. De dubbele aanroep kan extra cyclustijd kosten en ook resulteren dat je met twee verschillende tijden werkt in 1 loop. (Al zal dat bij jou allemaal geen issu zijn)
Vooralsnog zie ik geen perfomance issue qua video playback. Wel merk ik dat de GPIO's niet werken in de while loop, daarover onder meer.
voor de duidelijkheid zou je position en position_1 kunnen hernoemen naar position_sec en position_msec. Dan leest het wat makkelijker.
Zeker duidelijker. Done, dank voor de tip!

De code ziet er nu als volgt uit en in theorie werkt het allemaal. Ik zie de juiste print messages verschijnen op de juiste tijdcodes, echter de GPIO code die erna volgt doet niks - het relais reageert niet. Dezelfde code doet het wel buiten de while loop. Wat doe ik fout?
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import RPi.GPIO as GPIO # zorg dat we met de RPi GPIO's kunnen werken
GPIO.setmode(GPIO.BOARD) # zet de pinout mode op 'board', zodat de fysieke pin overeenkomt met het getal dat we uitsturen

GPIO.setup(5,GPIO.OUT) # maak pin5 een GPIO output
GPIO.output(5,GPIO.HIGH) # zet pin5 in status 'hoog' (= lamp aan bij ons relais)

from omxplayer import OMXPlayer # nodig om OMXplayer aan te kunnen sturen
from time import sleep # nodig om pauzes in te kunnen lassen in de code
from pathlib import Path # nodig om het juiste videobestand aan te kunnen roepen

path = Path('Videos/testvideo.m4v') # De video
player = OMXPlayer(path, args=['--no-osd', '--blank', '-o', 'both']) # geen OSD, zwarte achtergrond, ook analoog audio uit

status = player.playback_status() # zo kunnen we zien of OMXplayer speelt, in pauze staat of gestopt is
player.pause()
print("sleeping 2 secs...")
print("GPIO 5 naar LOW") # even het relais testen
GPIO.output(5,GPIO.LOW) # lampje uit
sleep(2)
print("GPIO 5 naar HIGH") # doettut?
GPIO.output(5,GPIO.HIGH) # lampje aan
sleep(2)
print("...and play.")
player.play()
sleep(0.3) # De video begint in het zwart, da's niet mooi. Stukje vooruit.
print("Hebben we beeld?")
player.pause() # Nu wachten tot de video gestart wordt.
# TODO code voor button trigger hier
sleep(2) # tot de button trigger er is, 2 secs pauze placeholder
player.play()
sleep(3) # voor de testfase, 3 secs laten spelen, kijken of de boel werkt
player.pause() # eerst op pauze, anders werkt seek niet betrouwbaar
player.seek(120) # voor de testfase, meteen door naar 2 minuten
player.play()
print("Start!")

event1_done = 0 # Het eerste event is nog niet geweest.
event2_done = 0 # Het tweede event is ook nog niet geweest.

while (status == "Playing"):  # terwijl de video speelt.... 
    position_sec = player.position() # deze om weer te geven in de console
    position_ms = player.position() * 1000      # bekijk de huidige timestamp
    GPIO.setmode(GPIO.BOARD) # zonder deze code op deze plek weet Python ineens niet meer welke pinout mode we ook alweer gezet hadden en faalt
    GPIO.setup(5,GPIO.OUT) # zonder deze code op deze plek weet Python ineens niet meer in welke mode we pin 5 ook alweer gezet hadden en faalt
    if position_sec < 180: # Zolang de teller onder de 3 mins blijft
            print(position_sec) # laat zien waar je bent
    if position_ms - 20 <= 137600 and position_ms + 20 >= 137600:  # check of we op 137,6s +/- 20ms zitten
            if event1_done == 1: # kijk of we niet al eerder getriggerd zijn
                print("no double triggers please")
            else:
                GPIO.output(5,GPIO.LOW) # lampje uit
                print("Lampje uit")
                event1_done = 1 # we zijn klaar en dat slaan we op zodat we niet nogmaals getriggerd kunnen worden
    if position_ms - 20 <= 139200 and position_ms + 20 >= 139200:
            if event2_done == 1:
                print("no double triggers please")
            else:
                GPIO.output(5,GPIO.HIGH)
                print("Lampje aan")
                event2_done = 1
    if position_sec > 147: # voor de testfase zijn we na 00:02:27 wel klaar.
        GPIO.cleanup() # geef de GPIO's weer vrij
        break # stop de loop                

player.quit() # stop OMXplayer

Zou het kunnen dat door de while loop de GPIO's continu worden ingesteld en dat het daarom niet werkt? If so, hoe vang ik dit af? Want zonder de 'instel-code' in de while loop lijdt Python ineens aan Alzheimer en heeft geen idee meer dat ik de boel aan het begin van de code allang goed had gezet...

"I'll just use my Go-Go-Gadget handbook!"


Acties:
  • 0 Henk 'm!

  • ydderf
  • Registratie: December 2017
  • Laatst online: 16:26
iGadget schreef op vrijdag 23 oktober 2020 @ 14:12:
Heb de code nu aangepast naar
code:
1
while (status == "Playing")
gebruik makend van
code:
1
status = player.playback_status()
, maar ik ga ook eens kijken of ik het op jouw manier voor elkaar kan krijgen. Maar dan wordt het dus voor ieder event een losse while loop? En is dat dan beter / efficiënter dan alles in die ene while loop proberen te doen?
Ik bedoelde het zoals jij gemaakt hebt, met 1 while loop.

Python:
1
2
3
4
5
while (position_sec < 147 && player.is_playing):  # terwijl de video speelt.... 
    position_sec = player.position() # deze om weer te geven in de console
    position_ms = position_sec * 1000      # bekijk de huidige 

Gpio.cleanup()

Ik had dan alleen het bovenstaande in gedachten. Dan kan jou laatste if conditie weg. Ik vermoed dat jou “status” op dit moment nooit veranderd omdat deze nergens wordt ge-update in de while loop.

Mbt tot de gpio heb ik geen ervaring. Maar voor mijn gevoel zou je de setup maar 1x hoeven te doen. En daarna lijkt me dat je ze gewoon in de while loop kunt schrijven. Ik zou juist eerder verwachten dat de setup in de while loop problemen geeft....

Soms gaat het niet zoals het moet, maar moet het maar zoals het gaat


Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
@ydderf ok, heb jouw suggestie even uitgeprobeerd, maar dan krijg ik dit:
code:
1
2
3
4
File "omx_test.py", line 95
    while (position_sec < 147 && player.is_playing):  # terwijl de video speelt.... 
                               ^
SyntaxError: invalid syntax

Haal ik de 2e & weg, dan krijg ik dit:
code:
1
2
3
4
Traceback (most recent call last):
  File "omx_test.py", line 95, in <module>
    while (position_sec < 147 & player.is_playing):  # terwijl de video speelt.... 
NameError: name 'position_sec' is not defined

Precies wat ik al vermoedde - je kan position_sec niet aanroepen voordat deze gedefiniëerd is. En definiëer je 'm buiten de while loop, dan krijg ik dit:
code:
1
2
3
4
Traceback (most recent call last):
  File "omx_test.py", line 95, in <module>
    while (position_sec < 147 & player.is_playing):  # terwijl de video speelt.... 
TypeError: unsupported operand type(s) for &: 'int' and 'instancemethod'

Bovendien krijg ik, als ik position_sec buiten de while loop definiëer, slecht één waarde terug als ik 'm opvraag, namelijk de waarde die position_sec had op het moment dat 'ie gedefiniëerd werd.
Eigenlijk zou ik misschien meerdere while loops (threads?) moeten hebben die los van elkaar kunnen werken... of denk ik nou te moeilijk?

[ Voor 14% gewijzigd door iGadget op 23-10-2020 23:37 . Reden: meer info toegevoegd ]

"I'll just use my Go-Go-Gadget handbook!"


Acties:
  • 0 Henk 'm!

  • ydderf
  • Registratie: December 2017
  • Laatst online: 16:26
Sorry, daar ging ik dan net ff een stapje te snel.
Je zult inderdaad position_sec voor de while loop een keer moeten initialiseren. Je kunt hem een standaard waarde geven, bijvoorbeeld nul, zodat hij altijd een keer je loop in loopt. Of de actuele positie een keer uitlezen.
Daarna moet je hem inderdaad ook in de while loop blijven updaten.

Python:
1
2
3
4
5
6
position_sec = player.position()
while (position_sec < 147 & player.is_playing): # terwijl de video speelt....  
    position_sec = player.position() # deze om weer te geven in de console 
    position_ms = position_sec * 1000 # bekijk de huidige 

Gpio.cleanup()


Voor mijn gevoel heb je maar 1 while loop nodig. Wanneer je je programma functioneel beschrijft, krijg je zoiets:
code:
1
2
3
4
5
6
7
-test relais
-laad juiste film in player
-spoel door naar x tijd
-zolang de film nog speelt en nog niet voorbij y tijd is:
      -check voor events en activeer output 

-geef io vrij


Dan heb je maar 1x een loop (zolang de film speelt....)

Soms gaat het niet zoals het moet, maar moet het maar zoals het gaat


Acties:
  • 0 Henk 'm!

  • iGadget
  • Registratie: Januari 2000
  • Laatst online: 06-07 11:46
ydderf schreef op zaterdag 24 oktober 2020 @ 10:10:
Sorry, daar ging ik dan net ff een stapje te snel.
No worries :)
Of de actuele positie een keer uitlezen.
Dat is wat er gebeurt als ik 'm definiëer ook, toch?
Daarna moet je hem inderdaad ook in de while loop blijven updaten.
En èn dus. Duidelijk!
Python:
1
2
3
4
5
6
position_sec = player.position()
while (position_sec < 147 & player.is_playing): # terwijl de video speelt....  
    position_sec = player.position() # deze om weer te geven in de console 
    position_ms = position_sec * 1000 # bekijk de huidige 

Gpio.cleanup()
Ok, dit gaat ws. werken, en daarmee heb ik dus die laatste if statement niet meer nodig en ook geen break? Nice!
Voor mijn gevoel heb je maar 1 while loop nodig. Wanneer je je programma functioneel beschrijft, krijg je zoiets:
code:
1
2
3
4
5
6
7
-test relais
-laad juiste film in player
-spoel door naar x tijd
-zolang de film nog speelt en nog niet voorbij y tijd is:
      -check voor events en activeer output 

-geef io vrij


Dan heb je maar 1x een loop (zolang de film speelt....)
Dat is precies zoals ik 'm in gedachten had idd, met nog een button trigger erbij, maar dat is voor later zorg. Eerst uitvinden waarom de GPIO's niet getriggered worden.
Ik vermoed dat dit idd met die setup in de while loop te maken heeft. Maar hoe doe ik dit erbuiten? Kennelijk hanteren while loops hun eigen regels en worden (sommige) global zaken niet meegenomen...

"I'll just use my Go-Go-Gadget handbook!"


Acties:
  • 0 Henk 'm!

  • ydderf
  • Registratie: December 2017
  • Laatst online: 16:26
Ik zou niet verwachten dat de while loop iets raars doet met je GPIO. Maar zoals gezegd, heb ik daar geen ervaring mee. Het onderstaande zou ik eigenlijk verwachten.

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import RPi.GPIO as GPIO # zorg dat we met de RPi GPIO's kunnen werken
GPIO.setmode(GPIO.BOARD) # zet de pinout mode op 'board', zodat de fysieke pin overeenkomt met het getal dat we uitsturen

GPIO.setup(5,GPIO.OUT) # maak pin5 een GPIO output
GPIO.output(5,GPIO.HIGH) # zet pin5 in status 'hoog' (= lamp aan bij ons relais)

from omxplayer import OMXPlayer # nodig om OMXplayer aan te kunnen sturen
from time import sleep # nodig om pauzes in te kunnen lassen in de code
from pathlib import Path # nodig om het juiste videobestand aan te kunnen roepen

path = Path('Videos/testvideo.m4v') # De video
player = OMXPlayer(path, args=['--no-osd', '--blank', '-o', 'both']) # geen OSD, zwarte achtergrond, ook analoog audio uit

#wat andere test enz.
player.play()
print("Start!")

event1_done = 0 # Het eerste event is nog niet geweest.
event2_done = 0 # Het tweede event is ook nog niet geweest.

position_sec = player.position()
while (position_sec < 147 & player.is_playing):  
    position_sec = player.position() # deze om weer te geven in de console
    position_ms = position_sec     # bekijk de huidige timestamp
    print(position_sec) # laat zien waar je bent

    if position_ms - 20 <= 137600 and position_ms + 20 >= 137600:  # check of we op 137,6s +/- 20ms zitten
            if event1_done == 1: # kijk of we niet al eerder getriggerd zijn
                print("no double triggers please")
            else:
                GPIO.output(5,GPIO.LOW) # lampje uit
                print("Lampje uit")
                event1_done = 1 # we zijn klaar en dat slaan we op zodat we niet nogmaals getriggerd kunnen worden
    if position_ms - 20 <= 139200 and position_ms + 20 >= 139200:
            if event2_done == 1:
                print("no double triggers please")
            else:
                GPIO.output(5,GPIO.HIGH)
                print("Lampje aan")
                event2_done = 1


GPIO.cleanup() # geef de GPIO's weer vrij
player.quit() # stop OMXplayer


Als dat niet werkt, zou je nog via een tussengeheugen kunnen werken.

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
OutputGeheugen = true #begin met output hoog
while (position_sec < 147 & player.is_playing):  
    position_sec = player.position() # deze om weer te geven in de console
    position_ms = position_sec     # bekijk de huidige timestamp
    print(position_sec) # laat zien waar je bent

    if position_ms - 20 <= 137600 and position_ms + 20 >= 137600:  # check of we op 137,6s +/- 20ms zitten
            if event1_done == 1: # kijk of we niet al eerder getriggerd zijn
                print("no double triggers please")
            else:
                OutputGeheugen = false # lampje uit
                print("Lampje uit")
                event1_done = 1 # we zijn klaar en dat slaan we op zodat we niet nogmaals getriggerd kunnen worden
    if position_ms - 20 <= 139200 and position_ms + 20 >= 139200:
            if event2_done == 1:
                print("no double triggers please")
            else:
                OutputGeheugen = true
                print("Lampje aan")
                event2_done = 1

    GPIO.output(5,OutputGeheugen) #elke loop de output schrijven


En met jou huidige events, zou je het nog iets eenvoudiger kunnen maken. Je hebt eigenlijk maar 1 tijdgebied waar je wat schakeld. Maar dit werkt natuurlijk niet wanneer je straks nog meer events wilt maken voor deze uitgang.
Python:
1
2
3
4
5
6
7
8
9
while (position_sec < 147 & player.is_playing):  
    position_sec = player.position() # deze om weer te geven in de console
    position_ms = position_sec     # bekijk de huidige timestamp
    print(position_sec) # laat zien waar je bent

    if position_ms >= 137600 and position_ms <= 139200:  # check of we tussen 137,6s en139200:zitten
        GPIO.output(5,false) 
    else
        GPIO.output(5,true)

Soms gaat het niet zoals het moet, maar moet het maar zoals het gaat

Pagina: 1