RPI script automatisch starten

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
Ik ben bezig met een project voor android auto in een oudere auto, op basis van Bluewave OpenAuto.

Vraag in het kort:

Script automatisch starten om m.b.v. XDOtool van canbus stuurknoppen naar keystrokes te genereren in OpenAuto

Vraag in het lang:

Introductie
Ik heb geen kennis van linux. Resultaten tot nu toe is allemaal gebaseerd op voorbeelden, bestaande uitleg en trail en error. Ik begin lichtelijk het verschil te zien tussen power user en CHMOD rechten, maar echte kennis heb ik niet.

Het project:

Een ESP32 luistert naar de canbus van mijn auto:

1. auto in slaap modus of 'wakker': indien wakker: RPI aan (via relay voeding aanzetten). RPI gaat uit als auto in slaap modus gaat zodat de accu niet wordt leeg getrokken
2. indrukken stuurknoppen via canbus uitlezen en via seriele poort (tx/rx 0) naar GPIO input van RPI tekst sturen; bijvoorbeeld knop_links of knop_omhoog

De RPI ontvang via GPIO Serial0 de tekst van de ESP32 en mbv XDOtool wordt deze tekst omgezet in een keyboard press. Deze keyboard presses worden herkend door OpenAuto om de menu's te kunnen navigeren.

Het uitlezen van de canbus, het versturen van deze data naar de RPI en het omzetten naar een keystroke werkt, MITS ik het script met de hand start.

Hoe beste automatisch script starten in RPI?

De vraag is, hoe kan ik het beste het script automatisch starten nadat de RPI en OpenAuto gestart zijn?

Ik heb verschillende manieren geprobeerd, maar geen succes:

1. script in RC.local aanroepen: na reboot geen automatische start van het script
2. script in Crontab: na reboot geen automatische start van het script
3. In OpenAuto kunnen middels een configuratie bestand (Openauto_applications.ini) verscheidene apps automatisch gestart worden nadat OpenAuto gestart is.
Echter als ik mijn script toevoeg aan de .ini en het script start in Openauto dan crashed Openauto.

Een van de gebruikers op OpenAuto forum heeft in het verleden aangegeven dat je beter een bash script kunt starten vanuit OpenAuto welke vervolgens je eigen script aanroept.

Op basis van zijn voorbeeld heb ik geprobeerd dit te doen, maar OpenAuto crashed weer. Zie deze 2 linkjes:

https://bluewavestudio.io...ad.php?tid=2648&pid=14820
https://bluewavestudio.io/community/thread-2514.html

Ik snap zijn uitleg in grote lijnen, maar als ik zijn oplossing ombouw naar de mijne, dan krijg ik toch geen werkend resultaat.

Tot slot

Nu heb ik mijn vraag ook uiteengezet op het OpenAuto forum, maar ik heb sterk de indruk dat daar weinig uit gaat komen omdat meerdere mensen eenzelfde vraag hebben uitgezet zonder een constructief antwoord, althans bij mij werken de oplossingen niet.

Wellicht zijn de antwoorden bevredigend voor mensen met Linux kennis, maar ik ontbeer die helaas. Ik heb meerdere avonden zitten googlen en pielen met rechten, oplossingen etc, maar eigenlijk heb ik geen idee waar ik mee bezig ben.

Helaas is dit een discipline waar ik weinig van weet en waar ik helaas ook niet de focus op wil leggen. Ik ben namelijk zo dichtbij om dit project te voltooien, maar het kan toch niet zo moeilijk zijn omee script automatisch te starten?


Het maakt mij niet zoveel uit hoé ik het script automatisch start, maar wel dat hij automatisch start. Wat is jullie advies? Omdat mijn kennis gelimiteerd is zoek ik ook wat advies als het gaat om de juiste rechten, want na vele lezen lijkt het soms ook een probleem te zijn met rechten en volgorde van aanroepen van scripts etc.


Hierbij de code van mijn script:

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
import serial
import os
#import pyudev
import subprocess
#import _thread
import platform
import subprocess
import time


if __name__ == '__main__':
    ser = serial.Serial(port='/dev/serial0',baudrate=115200,timeout=1)
    ser.reset_input_buffer()
    

    while True:
        #ser.write(b'getCommands\n');
        line = ser.readline()
        print(line)
        if line==b'EVENT_SHUTDOWN\n':
            os.system('shutdown -h now')
        if line==b'EVENT_UP\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Up')
        if line==b'EVENT_DOWN\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Down')
        if line==b'EVENT_LEFT\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ 1')
        if line==b'EVENT_RIGHT\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ 2')
        if line==b'EVENT_ENTER\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Return')
        if line==b'EVENT_BACK\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ h')
        if line==b'EVENT_NEXT\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ n')
        if line==b'EVENT_PREVIOUS\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ v')
        if line==b'EVENT_ANSWER\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ p')
        if line==b'EVENT_HANGUP\n':
            os.system('export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ o')
    ser.close()


Hierbij de code van een bash file om indirect mijn eigen script aan te roepen:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
if (ps aux | grep event_monitor.py | grep -v grep > /dev/null)
  then
DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority xdotool search --desktop 0 --name "DashControl" windowactivate

  else

DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority python3 /home/pi/Scripts/event_monitor.py &
while [[ ! DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority wmctrl -l|grep DashControl ]] ; do
  true
done
DISPLAY=:0.0 XAUTHORITY=/home/pi/.Xauthority xdotool search --desktop 0 --name "DashControl" windowactivate

fi


hierbij voor de volledigheid de openauto_applications.ini (voor wat het waard is); autostart staat op false omdat Openauto sowieso niet wilt starten. Ik kan met de hand het script in de app zelf starten, maar dan crashed de sotware ook terug naar desktop

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
[Applications]
Count=5

[Application_0]
Name=YouTube
Path=/usr/bin/chromium-browser
IconPath=/home/pi/.openauto/icons/icon_youtube.svg
Arguments=--user-data-dir=/home/pi/.google-chrome/session/youtube --app=https://youtube.com --start-maximized
Autostart=false

[Application_1]
Name=Kodi
Path=/usr/local/kodi/bin/kodi
IconPath=/home/pi/.openauto/icons/icon_kodi.png
Arguments=
Autostart=false

[Application_2]
Name=Chromium
Path=/usr/bin/chromium-browser
IconPath=/home/pi/.openauto/icons/icon_chrome.svg
Arguments=--start-maximized
Autostart=false

[Application_3]
Name=Welle.io
Path=/usr/local/bin/welle-io-1
IconPath=/home/pi/.openauto/icons/icon_welleio.png
Arguments=--disable-splash
Autostart=false

[Application_4]
Name=DashControl
Path= /home/pi/Scripts/DashControl.sh
IconPath=/home/pi/.openauto/icons/icon_welleio.png
Arguments=
Autostart=false

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • Knielen
  • Registratie: December 2009
  • Laatst online: 17:13
Ik zou toch verwachten dat Crontab wel de juiste plek hiervoor is.

Hier een handige site met wat je kan checken en hoe je eventueel met een delay kan starten.

Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
Knielen schreef op dinsdag 24 oktober 2023 @ 17:44:
Ik zou toch verwachten dat Crontab wel de juiste plek hiervoor is.

Hier een handige site met wat je kan checken en hoe je eventueel met een delay kan starten.
Dank je wel, ik heb n.a.v. je reactie specifiek zitten googlen op Cron en Crontab.

Ik kwam daar o.a. achter dat het de voorkeur geniet om het volgende bovenaan mijn script te zetten:

code:
1
#!/usr/bin/python


Deze code is ervoor om het script geforceerd met Python uit te voeren? Ik zie dat ik dat mis in mijn script. Zou dit al het eerste probleem kunnen zijn, dat niet de juiste interpreter aangeroepen wordt?


Dit op basis van dit draadje met deze reactie:

https://stackoverflow.com...python-script-via-crontab
Put your script in a file foo.py starting with

#!/usr/bin/python

Then give execute permission to that script using

chmod a+x foo.py

and use the full path of your foo.py file in your crontab.

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • SA007
  • Registratie: Oktober 2002
  • Laatst online: 29-09 11:59

SA007

Moderator Tweaking
Dat is niet 'dat het de voorkeur geniet'
Dat is hoe je tegen de shell zegt met welke interpreter het uitgevoerd moet worden.

Waarschijnlijk wil je daat #!/usr/bin/python3 hebben ipv alleen python.
En je script met chmod +x scriptnaam uitvoerbaar maken.

Als het goed is kan je dan je script uitvoeren met ./scriptnaam als je in de map staat, als dat niet werkt gaat het uitvoeren via rc.local of crontab ook niet lukken.

Waarschijnlijk werkt het dan prima.

Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
SA007 schreef op woensdag 25 oktober 2023 @ 12:00:
Dat is niet 'dat het de voorkeur geniet'
Dat is hoe je tegen de shell zegt met welke interpreter het uitgevoerd moet worden.

Waarschijnlijk wil je daat #!/usr/bin/python3 hebben ipv alleen python.
En je script met chmod +x scriptnaam uitvoerbaar maken.

Als het goed is kan je dan je script uitvoeren met ./scriptnaam als je in de map staat, als dat niet werkt gaat het uitvoeren via rc.local of crontab ook niet lukken.

Waarschijnlijk werkt het dan prima.
Dank je wel, ik heb vanochtend e.e.a. zitten pielen op basis van Crontab en ik ben wat verder gekomen. Of eigenlijk het is opgelost, maar ik ben wel tegen een volgend probleem aangelopen waardoor het script soms crashed.

Allereerst de oplossing:

de shebang "#!/usr/bin/python" moet er zeker instaan. nu als ik ook handmatig de file dubbelklik gaat hij automatisch uitvoeren (zonder in Thonnie 'te draaien').

Tweedens moest ik in de crontab 'python' toevoegen.

M.a.w. mijn crontab regel is nu:

@reboot python /home/pi/Scripts/event_monitor.py


En uiteraard de juiste rechten voor event_monitor.py: chmod a+x /home/pi/Scripts/event_monitor.py

Maar nu loop ik tegen het volgende probleem aan waardoor het script soms crashed (met de hand starten of n.a.v. crontab):

Ik krijg soms een error dat de data onvolledig/leeg is die via Serial0 binnen komt. Het viel me al op dat soms alleen gedeeltes van de tekst 'event_right' binnen kwamen om na paar regels de juiste data weer te geven.

Als er een paar keer niet de juiste data binnenkomt crashed het script en zal dus ook niet op de achtergrond draaien. Soms crashed het script meteen en moet ik paar keer probreren te starten alvorens de data juist binnenkomt.

Ik heb getty uitgezet in CMD om zeker te weten dat die geen gebruik maakt van Serial0 via GPIO en ik heb in cmdline.txt gecontroleerd of daar de console geen gebruik maakt van Serial0. Dit lijkt niet het geval.

Als de data eenmaal goed binnenkomt dan blijft dat ook zo werken.

Het lijkt een initiele synchronisatie error tussen de het ontvangen van de data van de Arduino en de Raspberry Pi.

Dit is mijn test sketch voor arduino (na 1 seconde stuur 'event_left' en na 2 seconde stuur 'event_right').

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
#include "BluetoothSerial.h"
#include <HardwareSerial.h>

BluetoothSerial SerialBT;
HardwareSerial RTI(2);
HardwareSerial RPi(0);


void setup() {

  SerialBT.enableSSP();       //Turned on for Deconflicting
  SerialBT.begin("Volve");    //Turned on for Deconflicting
  SerialBT.setTimeout(100);   //Turned on for Deconflicting
  SerialBT.begin(9600);
  RPi.begin(9600);
  pinMode(GPIO_NUM_23, OUTPUT);
  digitalWrite(GPIO_NUM_23,HIGH);     

  // put your setup code here, to run once:

}

void loop() {

  RPi.print("EVENT_LEFT\n");
  SerialBT.println("EVENT_LEFT");
  delay(1000);
  RPi.print("EVENT_RIGHT\n");  
  SerialBT.println("EVENT_RIGHT");
  delay(2000);
  // put your main code here, to run repeatedly:

}


M.a.w. het starten van het script is opgelost, nu nog voorkomen dat het script crashed als de data gedeeltelijk/niet binnenkomt.

Ik heb geprobeerd de baudrate te verlagen, maar dat maakt geen verschil.

[ Voor 4% gewijzigd door Seesar op 25-10-2023 14:27 ]

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
Ik heb even verder zitten googlen en ik heb het idee dat er een initiele synchronisatie probleem is. Als een goede 'handshake' eenmaal tot stand is gekomen, dan is de data stabiel en correct.

Ik heb geen verstand van UART etc dus ik probeer e.e.a. uit te vogelen, maar ik kwam in een topic tegen dat de RPI 3 (die ik nu gebruik) geen parity bit ondersteunt op Serial0 (Serial 1 wordt actief gebruikt door bluetooth receiver & wifi).

Nu blijkt dat als data met een parity bit wordt doorgestuurd alles in de soep kan draaien omdat de parity bit als start bit aangezien kan worden?


Geen idee of dit van toepassing is in ijn geval en ik hoor graag of dit een realistisch is in mijn geval, ik de data die de ESP32 zodanig kan aanpassen dat er geen parity bit wordt gestuurd (geen super belangrijke data) of dat ik moet investeren in een RPI 4 (parity bit wordt wel ondersteunt in RPI 4 blijkbaar).


Update: nvt: default is 8n1 en ik heb niets anders in Arduino gezet; m.a.w. 8 bits, no parity en 1 stop bit.

We gaan verder zoeken waarom de handshake niet lukt.

Update 2!

het was een timeout probleem; timeout van 1 naar 30 gezet en nu draait het wel stabiel.


Zie dit draadje:

https://raspberrypi.stack...rect-data-using-mini-uart

[ Voor 12% gewijzigd door Seesar op 25-10-2023 16:42 ]

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
En dan nu de laatste vraag, want we zijn weer een stapje dichterbij gekomen!

Het probleem m.b.t. automatisch starten en de mismatch m.b.t. het opzetten van de seriele verbinding is opgelost, zie reacties hieronder.

Maar als laatste opgave waar ik niet uit komt is dat XDOtool elke key stroke tweemaal uitstuurt. Dit resulteert in 2 posities in menu wisselen telkens.

Ik heb bevestigd dat vanuit canbus (jitter gefilterd) via ESP32 slecht 1 maal een commando wordt gestuurd. Daarnaast met hiervoor genoemde test sketch (na 1s 'event_right' en na 2s 'event_left') er maar eenmaal het commando wordt gegeven. Dit wordt ook bevestigd met 'print(line)'.

M.a.w. het is de XDOtool aanroep/script die dubbel output.

Ik kom op internet heel vaak dezelfde reactie op verschillende fora tegen en komt er simpelweg op neer dat zowel de shell als terminal dezelfde keystroke genereren en outputten; ik denk dat ik dat grotendeels begrijp, maar totaaaaaaal niet hoe ik dat kan oplossen.

Ik begrijp ook dat de oplossing is om een -echo in mijn regel te zetten, maar ik heb daar een beetje mee lopen stoeien, maar waar ik dat ook neerzet, ik krijg dat niet gecomplieerd/getest.

Ik leun vooral op deze reactie en voorbeeld, maar omdat de situatie behoorlijk anders is, begrijp ik niet precies hoe ik die -echo moet verwerken om in mijn geval dit te laten werken:

https://superuser.com/que...n-twice-type-selection-of

zie voorbeeld antwoord:

code:
1
 fzf | (stty -F /dev/tty -echo; xargs -I{} xdotool type "{}"; stty -F /dev/tty echo)


Ik moet dus ergens in mijn code (of in elke aanroep van XDOtool) stty -F /dev/tty -echo aanroepen. Hoe doe ik dat in mijn code? Volledigheidshalve hierbij de snippet waarvan ik denk dat hij aangeroepen moet worden:

code:
1
2
if line==b'EVENT_UP\n':
            os.system('export DISPLAY=:0.0 && XAUTHORITY=/home/pi/.Xauthority && xdotool search --class autoapp key --window %@ Up')

[ Voor 13% gewijzigd door Seesar op 25-10-2023 19:50 ]

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • Sgrovert
  • Registratie: Mei 2004
  • Laatst online: 15:29
Ik zou binnen python lees erros negeren voor stabiliteit. Indien er nu een bitje omvalt heb je nog steeds kans op een crashen script.
code:
1
2
3
4
try:
    line = ser.readline()
except Exception as e:
    print(e)


Dit negeert alle leesfouten.
Netter is het om Ipv Exception de juiste errors in te vullen, maar ik weet nu niet welke errors read line kan geven

[ Voor 0% gewijzigd door Sgrovert op 25-10-2023 19:47 . Reden: Typo ]

Lost In Music


Acties:
  • 0 Henk 'm!

  • SA007
  • Registratie: Oktober 2002
  • Laatst online: 29-09 11:59

SA007

Moderator Tweaking
Denk dat dit even een schopje naar DEV krijgt, het heeft niet echt te maken met de rpi/esp32 maar met python software op een rpi, wat daar beter past.

Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
Klein schopje en bedankje voor verplaatsten topic @SA007 .

Ik loop er nog steeds stuk op waarom xdotool tweemaal een key press genereert. Of beter gezegd hoe ik dat kan voorkomen als het klopt dat de output ge-echoed wordt.

Ik las ook dat ik misschien beter i.p.v. os.system subprocess kan gebruiken, maar dan ben ik al helemaal het spoor bijster wat de syntax is.

De voorbeelden die ik kan vinden geven geen overzicht hoe ik een juiste windows selecteer (de actieve %@) en ik weet sowieso niet of dit wel de oplossing is.

Ik denk dat ik op een of andere manier de echo moet uitzetten, maar hoe bouw ik deze in de opdracht? Ik dnek dat ik de oplossing heb, maar niet hoe ik die implementeer.

Iemand die iets meer weet?

@Sgrovert; dank je wel. Ik heb het geimplementeerd, maar het scritp start dan niet omdat hij meteen in de error gaat. De eerste paar uitlezingen zijn nog steeds scrambled en daarna volgt de juiste informatie.

M.a.w. de timeout is meer ene hele rauwe manier, meer als pleister dan oplossing bij de bron

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • Sgrovert
  • Registratie: Mei 2004
  • Laatst online: 15:29
code:
1
2
3
4
5
try:
    line = ser.readline()
except Exception as e:
    print(e) 
    continue


Ik zal van de week eens op mijn gemak naar je script kijken. Zat vorige keer en nu op mijn mobiel en dat geeft toch geen fijn overzicht van de code.

Als je continue in de catch zet, scipt de code de rest van de while loop En gaat hij naar de volgende iteratie.
Als hij dan nog crashed, zou je de stack trace willen posten? Dan kijk ik er wel even naar

Lost In Music


Acties:
  • 0 Henk 'm!

  • Douweegbertje
  • Registratie: Mei 2008
  • Laatst online: 15:04

Douweegbertje

Wat kinderachtig.. godverdomme

Ik was begonnen met het begin en had de rest nog niet gelezen. Ik wilde je dit geven: https://www.makeuseof.com...ch-programs-raspberry-pi/

De crontab is naar mijn inziens _niet_ de plek om een service/script te starten. Daarnaast is iets als systemd wat praktischer in de zin dat 'ie je 'service' ook weer zal starten als deze voor wat voor reden niet meer draait.

Uiteraard is het wel praktisch om zo nu en dan je logs te bekijken of je spul ook herstart, want dan heb je misschien een bug en dat is het dat wel waard om te fixen.


M.b.t je huidige vraag; het zou voor mij althans veel meer helpen om minder details te geven en concreter input/output(verwachting) te geven. Wellicht ben ik dat, maar ik zou zo even niet weten waar je nu precies naar op zoek bent. Dus een simpele abstractie (sandbox), zodat het zonder alle overige context te debuggen/testen valt bijvoorbeeld.

Acties:
  • 0 Henk 'm!

  • Sgrovert
  • Registratie: Mei 2004
  • Laatst online: 15:29
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
66
67
68
import serial
import os
import time

commands = {'EVENT_SHUTDOWN': 'shutdown -h now',
            'EVENT_UP': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Up',
            'EVENT_DOWN': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Down',
            'EVENT_LEFT': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ 1',
            'EVENT_RIGHT': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ 2',
            'EVENT_ENTER': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Return',
            'EVENT_BACK': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ h',
            'EVENT_NEXT': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ n',
            'EVENT_PREVIOUS': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ v',
            'EVENT_ANSWER': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ p',
            'EVENT_HANGUP': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ o',
            }


def run_command(line):
    try:
        os.system(commands[line])
    except KeyError:
        print(f"command '{line}' not found")


class PerformAction:
    """
    Keep track of the last action. If the same action is performed twice in a timespan shorter than debounce time, the second command is ignored.
    """
    def __init__(self, debounce_time=0.1):
        self.debounce_time = debounce_time
        self.previous = ''
        self.time = 0

    def is_bounce(self, line: str):
        """
        True if the same command is repeated within debounce_time
        :param line:
        :return: True if bounce is detected
        """
        if time.time() - self.time < self.debounce_time:
            return line == self.previous

        return False

    def parse_serial_line(self, line: str):
        if self.is_bounce(line):
            print(f"{line} is bounce")
            return

        run_command(line)


def run_listner(debounce_time):
    perform_action = PerformAction(debounce_time)
    with serial.Serial(port='/dev/serial0', baudrate=115200, timeout=1) as ser:
        while True:
            raw = str(ser.readline())
            for line in raw.splitlines():
                perform_action.parse_serial_line(line.strip())


if __name__ == '__main__':
    while True:
        try:
            run_listner(0.1)
        except Exception as e:
            print(f"Error : {e}")


Dit is wat ik er van zou maken met de informatie die ik nu heb.


commands is een dictionary met de commando's die je wilt uitvoeren.
run_command voert een commando uit en print een message als hij het commando niet kent
Seesar schreef op donderdag 26 oktober 2023 @ 20:13:
Ik loop er nog steeds stuk op waarom xdotool tweemaal een key press genereert. Of beter gezegd hoe ik dat kan voorkomen als het klopt dat de output ge-echoed wordt.
De dubbele code is waarschijnlijk een electrische bounce van het indrukken van het knopje. Bij het indrukken of loslaten van een knopje word vaak meerdere malen contact gemaakt. Hierdoor genereeerd je arduino ook meerder messages.

In de performAction class heb ik hiervoor een oplossing gemaakt. De class vergelijkt het gegeven commando met het vorige command. Indien het commando hetzelfde is, en de tijd tussen de commando's korter dan de debounce time is, dan word het commando niet uigevoerd, maar geprint.
De debounce_time is in seconden. 0.1 is dus 100 ms. Je moet zelf even experimenteren wat een goede waarde voor jou hardware is.


Verder heb ik de serial code nog in een apparte functie gezet.

In de main staat de loop als eerste. Indien er een fout in de listener optreed, zal deze geprint worden, en in de volgende iteratie van de main loop word de listerner opnieuw gestart. Ik denk dat dit je crash probleem ook oplost.

Lost In Music


Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
Sgrovert schreef op vrijdag 27 oktober 2023 @ 17:27:
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
66
67
68
import serial
import os
import time

commands = {'EVENT_SHUTDOWN': 'shutdown -h now',
            'EVENT_UP': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Up',
            'EVENT_DOWN': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Down',
            'EVENT_LEFT': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ 1',
            'EVENT_RIGHT': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ 2',
            'EVENT_ENTER': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ Return',
            'EVENT_BACK': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ h',
            'EVENT_NEXT': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ n',
            'EVENT_PREVIOUS': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ v',
            'EVENT_ANSWER': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ p',
            'EVENT_HANGUP': 'export DISPLAY=:0.0 && xdotool search --class autoapp key --window %@ o',
            }


def run_command(line):
    try:
        os.system(commands[line])
    except KeyError:
        print(f"command '{line}' not found")


class PerformAction:
    """
    Keep track of the last action. If the same action is performed twice in a timespan shorter than debounce time, the second command is ignored.
    """
    def __init__(self, debounce_time=0.1):
        self.debounce_time = debounce_time
        self.previous = ''
        self.time = 0

    def is_bounce(self, line: str):
        """
        True if the same command is repeated within debounce_time
        :param line:
        :return: True if bounce is detected
        """
        if time.time() - self.time < self.debounce_time:
            return line == self.previous

        return False

    def parse_serial_line(self, line: str):
        if self.is_bounce(line):
            print(f"{line} is bounce")
            return

        run_command(line)


def run_listner(debounce_time):
    perform_action = PerformAction(debounce_time)
    with serial.Serial(port='/dev/serial0', baudrate=115200, timeout=1) as ser:
        while True:
            raw = str(ser.readline())
            for line in raw.splitlines():
                perform_action.parse_serial_line(line.strip())


if __name__ == '__main__':
    while True:
        try:
            run_listner(0.1)
        except Exception as e:
            print(f"Error : {e}")


Dit is wat ik er van zou maken met de informatie die ik nu heb.


commands is een dictionary met de commando's die je wilt uitvoeren.
run_command voert een commando uit en print een message als hij het commando niet kent


[...]


De dubbele code is waarschijnlijk een electrische bounce van het indrukken van het knopje. Bij het indrukken of loslaten van een knopje word vaak meerdere malen contact gemaakt. Hierdoor genereeerd je arduino ook meerder messages.

In de performAction class heb ik hiervoor een oplossing gemaakt. De class vergelijkt het gegeven commando met het vorige command. Indien het commando hetzelfde is, en de tijd tussen de commando's korter dan de debounce time is, dan word het commando niet uigevoerd, maar geprint.
De debounce_time is in seconden. 0.1 is dus 100 ms. Je moet zelf even experimenteren wat een goede waarde voor jou hardware is.


Verder heb ik de serial code nog in een apparte functie gezet.

In de main staat de loop als eerste. Indien er een fout in de listener optreed, zal deze geprint worden, en in de volgende iteratie van de main loop word de listerner opnieuw gestart. Ik denk dat dit je crash probleem ook oplost.
Ow super bedankt. Ik zit er nu moeilijk voor om uitgebreid te bekijken maar dank je wel voor de input.

Met dubbel, debouncung/anti jitter word al gefilterd in de esp als hij canbus uitleest. Daarnaast heb ik een test setup gemaakt waarbij de esp afwisselend 2 knoppen simuleert alsof hij wordt ingelezen via canbus. Maar in de test setup stuur de esp via UART 2 strings die elkaar afwisselen zonder daadwerkelijk de knoppen uit te lezen.


Ik kom er morgen op terug. Dan zal ik ook de log doen en een schemaatje uploaden wat input en output moet zijn van het project.

Dank jullie wel alvast

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
Ik heb zojuist me de code getest, maar nog steeds hetzelfde probleem m.b.t. dubbele output en dat de eerste paar waardes scrambled zijn.

Het was even pielen trouwens want ik moet een string met '\n' uitsturen wil de seriele poort de data weergeven, welke ik weer moet decoden in de RPI, dus ik heb het volgende toegevoegd tijdens readline:

code:
1
raw == str(ser.readline().decode('utf-8').rstrip())


Echter de 2 problemen blijven nog steeds:

1. eerste paar waarden na opstarten script zijn onvolledig; d.w.z. characters missen, maar geen rare tekens of characters die niet kloppen; dat is nog niet zo erg, want na paar keer uitlezen komt er een goede output en reageert het scriptje op de commando's
2. zoals helaas verwacht nog steeds dubbele output; menu verplaatst 2 maal een positie na 1 maal input met test programma.

In het kort het doel:

-Knop op stuurwiel indrukken
-Via canbus wordt een adres verstuurd die ik kan interpreteren met een ESP32: dat werkt (getest)
-ESP32 stuurt via een low level converter via GPIO 15 een string uit; dat mag ook een integer zijn. Zolang het commando/integer maar overeenkomt met een bepaalde knop op het stuurwiel
-Via GPIO15 (RXD) leest de RPI het commando uit. Dit commando moet dan vertaald worden naar een keystroke. Openauto is een stukje software dat automatishc start nadat de RPI is gestart en ondersteunt keyboard inputs zodat door het menu te navigeren is d.m.v. keystrokes.

Serial via GPIO is nodig omdat de RPI op een zelf gemaakte PCB gezet wordt en ik alle USB poorten nodig heb. Dit zou ook geen probleem moeten zijn.

Probleem 1: initiele startup script lees onvolledige string in (geen prioriteit, is heel lomp omheen te werken):

Ik denk dat er ergens nog steeds een console of een andere functie gebruik maakt van Serial0, ondanks

1. Login shell is uit (sudo raspi-config: optie 3 - 6: Shell 'no', Serial 'yes'
2. cmdline aangepast: sudo nano /boot/cmdline.txt: console=serial0,115200 verwijderd en opgeslagen
3. voor zover ik weet is het beste Serial0 aan te roepen en niet ttyS0

Probleem 2: keystroke wordt in een script m.b.v. xdotool tweemaal uitgestuurd.

Voor zover ik heb kunnen vinden online komt dat omdat zowel de bash (ik weet niet wat dat betekent) en xdotool het commando verwerken en vervolgens uitvoeren en waarschijnlijk is het beste om de Echo uit te zetten, maar hoe?

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • u_nix_we_all
  • Registratie: Augustus 2002
  • Niet online
Vwb die dubbele waardes, kijk nog eens naar je startscript. Als ik dat zo lees wordt er eerst gekeken of die event_monitor draait, zo ja (then) dan start je xdotool.
Als die niet draait (else) start je event_monitor.

Daarna wordt xdotool ongeacht de eerste if/then/else sowieso nogmaals gestart, maar dan kan hij dus 2x gestart zijn?

Edit: oh wacht die doet alleen een window actvate dus dat zal het wel niet zijn.

[ Voor 11% gewijzigd door u_nix_we_all op 28-10-2023 15:58 ]

You don't need a parachute to go skydiving. You need a parachute to go skydiving twice.


Acties:
  • 0 Henk 'm!

  • Sgrovert
  • Registratie: Mei 2004
  • Laatst online: 15:29
Zijn de dubbele waardes er altijd?
Kan het zijn dat je canbus een event + extra informatie stuurt?
Bv EVENT_UP on / EVENT_UP off . Indien je de extra informatie niet oppikt, kan het zijn dat indrukken en loslaten van een button as 2 events gezien worden.

Ook snap ik de esp32 niet helemaal in deze context. Word de esp alleen gebruikt om de canbus uit te lezen en om te zetten in een string? Of gebeurt er meer?

Als het alleen uitlezen is, overweeg dan om de raspberry rechtstreeks aan de canbus te hangen met een dedicated shield : https://www.tinytronics.n...us/can-bus-shield-mcp2515

Lost In Music


Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
u_nix_we_all schreef op zaterdag 28 oktober 2023 @ 15:39:
Vwb die dubbele waardes, kijk nog eens naar je startscript. Als ik dat zo lees wordt er eerst gekeken of die event_monitor draait, zo ja (then) dan start je xdotool.
Als die niet draait (else) start je event_monitor.

Daarna wordt xdotool ongeacht de eerste if/then/else sowieso nogmaals gestart, maar dan kan hij dus 2x gestart zijn?

Edit: oh wacht die doet alleen een window actvate dus dat zal het wel niet zijn.
Hmm, ik denk wel dat er zoiets gaande zou kunnen zijn.

het is namelijk echt uitgesloten dat de aanslag van het stuurwiel knop 2x ingedrukt wordt:

1. op dit moment run ik alleen een test sketch op de ESP32; dus niet aangesloten op de auto en SIMULEER ik dat de ESP een signaal krijgt en stuurt actief 1 maal een Event_left en eenmaal een Event_right uit elke 1seconde.

Werking hiervan is ook bevestigd door de feedback van print.line: er wordt maar eenmaal telkens een event geprint

2. op de ESP32 wordt al actief gefilterd: d.w.z. een knop moet ingedrukt zijn EN weer losgelaten voordat een tweede event aangemaakt kan worden. d.w.z. dat er dus actief gekeken wordt of de knop ingedrukt wordt.


3. welke knop ik ook indruk op het stuurwiel (het zijn er ongeveer 10); alle commando's worden 2x gegeven in openauto; niet soms, niet vaker, gewoon altijd 2x


overigens zit in de canbus controller al wat anti-jitter want de canbus commando's geassocieerd met desbetreffende knop komen ook 'schoon'binnen; d.w.z. dat er geen jitter canbus signalen verstuurd worden.

M.a.w. de focus moet echt liggen op het python script en de omgeving waarin deze gedraaid wordt.


Gekozen voor een ESP32 is omdat er nog wat meer dingen aangestuurd moeten worden (scherm omhoog/omlaag en starten van aantal andere dingen) op basis van canbus signalen en output signalen.

Mijn kennis van python is nagenoeg 0, mijn kennis van C (ESP32 dus) is zodanig dat ik dit soort dingen kan programeren.

Ik loop dus echt vast op het python/RPI aspect op dit moment en sta open voor alle input en ideeen!

[ Voor 4% gewijzigd door Seesar op 31-10-2023 16:20 ]

T60P Widescreen


Acties:
  • 0 Henk 'm!

  • Seesar
  • Registratie: September 2002
  • Laatst online: 06-06 13:42

Seesar

Icon thnx to l0c4lh0st

Topicstarter
Update;

vanmiddag met collega die blijkbaar veel met Python werkt even aan mijn hobby projectje gewerkt;

alle 2 de problemen zijn opgelost:

1. bij opstarten script eerste paar regels input via serial zijn scrambled:

i.p.v. een ser.reset_input_buffer() hebben we een ser.flush() erin gezet. Reset haalt het buffer niet leeg, een flush wel; nu komt er altijd de juiste info binnen, ook vanaf de start.

2. dubbele output van key-stroke. Na langzoeken en letterlijk trial en error door de code steeds meer uit te dunnen en tellers in te bouwen kwamen we erachter dat de volgende code voor een dubbele output zorgde:

code:
1
search --class autoapp key --window %@


Dit zorgt ervoor dat de key-stroke alleen in de app 'Autoapp' wordt gegenereerd. Verwijderen hiervan zorgt ervoor dat er in elk willekeurig actief window een keystroke wordt gegenereerd; dus ook in linux als je bijvoorbeeld in de editor zit.

Dit is in dit geval geen probleem; openauto start automatisch en loopt op de voorgrond. En als ik wil gaan editen, zorg ik er gewoon voor dat ik geen stuurwiel knoppen in druk!

N.a.v. dit ben ik gaan zoeken en toen kwam ik dit tegen (reactie van de developer van Openauto) in een verborgen/donker hoekje:
Try to not use search --class switch in xdotool command. As far as we know it will send key event to each window created by the application.

When Android Auto is launched, OpenAuto Pro creates new window for rendering the projection. Most probably xdotool sends key event to main OpenAuto Pro window and the one created by Android Auto. Rather than choosing receiver window by hand, try to send key event globally and let X11 do the dispatching job.
m.a.w. de key-stroke wordt idnerdaad 2 maal genereerd. Helaas ontbreekt deze informatie in de FAQ.

zie dit draadje:

https://bluewavestudio.io...-post-14791.html#pid14791

dit antwoord kon ik destijds niet vindne omdat de search op het forum heel slecht werkt en ik ook, toen, nog niet de juiste zoekwoorden had.

I.i.g toch bedankt voor de input allemaal en welliicht heeft iemand wat aan mijn antwoorden voor zijn/haar eigen projectje als leek zijnde.

[ Voor 7% gewijzigd door Seesar op 12-11-2023 20:39 ]

T60P Widescreen

Pagina: 1