Raspberry Pi – Python telnet script voor communicatie met Arduino
Dit is het python telnet script om te kunnen communiceren met een Arduino welke dit script geladen heeft.
Beste seriële communicatie?
Ik heb een poos lopen zoeken op internet wat het beste te gebruiken is voor Linux om via de seriële poort te communiceren!
Veelal word verwezen naar een “PhpSerial CLASS“!, dit werkt als een SHELL om het Linux STTY commando en werkt niet goed!
Naast dat je diverse STTY instellingen en toegangsrechten moet instellen (voor de dialout group) krijg ik het niet aan de praat via PHP.
Wat werkt dan wel?
Met Linux zit je al snel aan Python, Perl (en evt. C++) als je “low-level” met randapparatuur (COM poort) wilt werken…met PHP kan je niet rechtstreeks een COM poort aansturen;-)
Dus ik heb als oplossing een tussen layer (relay) bedacht met een Python script, welke op commandolijn argumenten werkt om de seriële data door te spelen!
Hoe werkt het “telnet” systeem?
Beide computers wachten op een hekje # om het einde van de data aan te geven, daarna wordt wat met het commando gedaan, hieronder een overzicht:
Raspberry Pi –> commando# –> Arduino –> gegevens# –> Raspberry Pi
Python ‘serial’ module:
Voordat je met python aan de slag gaat, moet je eerst de seriele module voor Python installeren, dit doe je met het commando:
sudo apt-get install python-serial
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Reading package lists... Done Building dependency tree Reading state information... Done Suggested packages: python-wxgtk2.8 python-wxgtk2.6 python-wxgtk The following NEW packages will be installed: python-serial 0 upgraded, 1 newly installed, 0 to remove and 1 not upgraded. Need to get 79.0 kB of archives. After this operation, 483 kB of additional disk space will be used. Get:1 http://mirrordirector.raspbian.org/raspbian/ wheezy/main python-serial all 2.5-2.1 [79.0 kB] Fetched 79.0 kB in 0s (189 kB/s) Selecting previously unselected package python-serial. (Reading database ... 69590 files and directories currently installed.) Unpacking python-serial (from .../python-serial_2.5-2.1_all.deb) ... Setting up python-serial (2.5-2.1) ... |
Ik heb na veel research op het internet en trial-and-error het “seriële relay” script klaar, het commando voor dit script werkt als volgt:
sudo python serialrelay.py [POORT] [COMMANDO] [VLAG]
POORT = De seriele poort USB0 of ACM0 (De seriele poort bij de Arduino NANO is /dev/ttyUSB0 en bij de UNO is het /dev/ttyACM0)
COMMANDO = Het commando voor de Arduino.
VLAG = Verwachten we gegevens terug van de Arduino?, dan blijf even luisteren voor data (als vlagdata kun je hier alles neerzetten, bijvoorbeeld een 1)
Een voorbeeld om de LED op de Arduino te schakelen: sudo python serialrelay.py USB0 aan
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 |
#!/usr/bin/python # Bibliotheek om commandolijn argumenten uit te lezen. (sys.argv[1]) import sys # Bibliotheek om data via een seriele lijn te verzenden. (ser.write) import serial # Voer dit uit als we 2 commando's of meer hebben. if (len(sys.argv)>2): # voeg /dev/tty to aan de 1e commandolijn (poort) en initialiseer de seriële poort naar de Arduino. poort = '/dev/tty' + sys.argv[1] ser = serial.Serial(poort, 9600, timeout=2) # Zet een hekje achter het commando, dit geeft het einde van het commando aan. commando = sys.argv[2] + '#' # Stuur commandolijn 2 door naar de Arduino. # Ps. string-escape is nodig anders kan je niet met hekjes (#) werken ser.write(commando.decode("string-escape")) # Als commandolijn 3 gevuld is verwachten we data terug van de Arduino, voer dan het volgende uit. if (len(sys.argv)>3): buffer = '' while True: # We plakken alle bytes die we ontvangen van de Arduino aan elkaar. buffer = buffer + ser.read() if '#' in buffer: # We hebben een hekje (#) ontvangen van de Arduino. (er komen geen gegevens meer) # Print de data welke ontvangen is van de Arduino minus het hekje #. print buffer[0:len(buffer)-1] # Beëindig het script! sys.exit() |
Probleem dat het script eindeloos blijft doorlopen
Probleem: Programma blijft eindeloos doorlopen (en kan er voor zorgen dat de Raspberry door de knieën gaat)
Ok, na wat tests blijken we een probleem te hebben, als we de vlag zetten voor het terugverwachten van data, en er komt niets terug van de Arduino (verkeerde commando of hardware problemen) dan blijft het python script eindeloop doorlopen en blijft wachten op ene hekje # vanaf de arduino (die er niet komt), zo kunnen dus veel python processen blijven hangen op de Raspberry, dat is niet handig!
Na wat speurwerk om een goede oplossing te vinden, heb ik gekozen voor “multiprocessing”, hiemee kun je een python child proces maken met een timer.
Met een timer op een functie, in dit geval genaamd: relay(), kun je python de child en “parent” laten sluiten na een tijdsinterval, je kan met de variabele scripttijd een aantal seconden zetten wanneer het python script moet eindigen.
Het script ziet er nu als volgt uit:
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 |
#!/usr/bin/python # Bibliotheek om commandolijn argumenten uit te lezen. (sys.argv[1]) import sys # Bibliotheek om data via een seriele lijn te verzenden. (ser.write) import serial # Bibliotheek om meerdere phyton processen te starten (multiprocessing.Process) import multiprocessing # Bibliotheek voor tijdfuncties. import time # De variabele in seconden voor het eindigen van het script. scripttijd = 2 # De functie waarin we de serialrelay code in hebben geplaatst. def relay(): # Voer dit uit als we 2 commando's of meer hebben. if (len(sys.argv)>2): # voeg /dev/tty to aan de 1e commandolijn (poort) en initialiseer de seriële poort naar de Arduino. poort = '/dev/tty' + sys.argv[1] ser = serial.Serial(poort, 9600, timeout=2) # Zet een hekje achter het commando, dit geeft het einde van het commando aan. commando = sys.argv[2] + '#' # Stuur commandolijn 2 door naar de Arduino. # Ps. string-escape is nodig anders kan je niet met hekjes (#) werken ser.write(commando.decode("string-escape")) # Als commandolijn 3 gevuld is verwachten we data terug van de Arduino, voer dan het volgende uit. if (len(sys.argv)>3): buffer = '' while True: # We plakken alle bytes die we ontvangen van de Arduino aan elkaar. buffer = buffer + ser.read() if '#' in buffer: # We hebben een hekje (#) ontvangen van de Arduino. (er komen geen gegevens meer) # Print de data welke ontvangen is van de Arduino minus het hekje #. print buffer[0:len(buffer)-1] # Beëindig het script! sys.exit() # Start de functie relay() als een child proces if __name__ == '__main__': p = multiprocessing.Process(target=relay) p.start() # Wacht een aantal seconden voordat het proces beëindigd wordt. p.join(scripttijd) if p.is_alive(): # Als het script nog actief is, beëindig het dan. p.terminate() p.join() |