{"id":873,"date":"2019-11-17T14:18:00","date_gmt":"2019-11-17T13:18:00","guid":{"rendered":"http:\/\/wollef.org\/?p=873"},"modified":"2019-11-17T14:18:00","modified_gmt":"2019-11-17T13:18:00","slug":"raspberry-cars-communication-avec-la-carte-gps-en-python","status":"publish","type":"post","link":"https:\/\/wollef.org\/blog\/raspberry-cars-communication-avec-la-carte-gps-en-python\/","title":{"rendered":"Raspberry Cars &#8211; Les Technos (1\/4) &#8211; Communication avec la carte GPS en Python"},"content":{"rendered":"\n<h1 class=\"wp-block-heading\"><a>La documentation de la carte<\/a><\/h1>\n\n\n\n<p>Avant de manipuler la carte, il faut examiner la\ndocumentation. Celle-ci est disponible sur le site de Waveshare&nbsp;: <a href=\"https:\/\/www.waveshare.com\/wiki\/GSM\/GPRS\/GNSS_HAT\">https:\/\/www.waveshare.com\/wiki\/GSM\/GPRS\/GNSS_HAT<\/a><\/p>\n\n\n\n<p>Le manuel PDF d\u00e9crit&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Les caract\u00e9ristiques techniques de la carte<\/li><li>Comment choisir le mode de connection&nbsp;: via\nle port USB soit via le port GPIO du Raspberry <\/li><li>Des exemples de programme python qui manipule la\ncarte, mais seulement pour la partie GSM (appels, SMS, etc) <\/li><\/ul>\n\n\n\n<h1 class=\"wp-block-heading\"><a>La configuration de la carte (mode USB)<\/a><\/h1>\n\n\n\n<p>J\u2019ai choisi le mode USB pour communiquer avec la carte car\nj\u2019ai besoin des ports GPIO pour connecter l\u2019\u00e9cran tactile (seulement pour la\npartie tactile, l\u2019affiche passe par le port HDMI).<\/p>\n\n\n\n<p>Pour que la carte fonctionne en mode USB, on doit positionner correctement les jumpers (des petits connecteurs jaunes qui peuvent \u00eatre fix\u00e9s de diff\u00e9rentes mani\u00e8res sur la carte).<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Jumpers configur\u00e9s en mode USB (le notre)<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2020\/01\/Sans-titre2-1.png\" alt=\"\" class=\"wp-image-877\"\/><\/figure>\n\n\n\n<ul class=\"wp-block-list\"><li>Jumpers configur\u00e9 pour utiliser le GPIO<\/li><\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2020\/01\/Sans-titre2.png\" alt=\"\" class=\"wp-image-876\"\/><\/figure>\n\n\n\n<h1 class=\"wp-block-heading\"><a>Identifier le port USB utilis\u00e9 par la carte<\/a><\/h1>\n\n\n\n<p>Pour savoir quel port USB est utilis\u00e9 par la carte, je dois taper la commande :<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ls \/dev\/ttyUSB*<\/code><\/pre>\n\n\n\n<p>Elle renvoi la liste des ports USB utilis\u00e9s, ici seul la carte GPS est connect\u00e9e et donc visible.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2020\/01\/Sans-titre3.png\" alt=\"\" class=\"wp-image-879\"\/><\/figure>\n\n\n\n<p>Ici, on voit que la carte est connect\u00e9e au port <strong>\/dev\/ttyUSB0<\/strong>.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\"><a>Exemple de programmation en Python et adaptation \u00e0 Python 3<\/a><\/h1>\n\n\n\n<p>En cherchant sur\nInternet, j\u2019ai r\u00e9cup\u00e9r\u00e9 un exemple de code Python permettant d\u2019\u00e9couter le\nsignal GPS de la carte en Python&nbsp;:<\/p>\n\n\n\n<p><a href=\"https:\/\/www.rhydolabz.com\/wiki\/?p=18639\">https:\/\/www.rhydolabz.com\/wiki\/?p=18639<\/a><\/p>\n\n\n\n<p>Mais la version de python utilis\u00e9e \u00e9tait la 2, j\u2019ai d\u00fb\nmodifier ce code pour la version 3&nbsp;:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>La syntaxe des instructions print(), avec les\nparenth\u00e8ses <\/li><li>La n\u00e9cessit\u00e9 d\u2019utiliser .encode(&#8216;ascii&#8217;) et\ndecode(&#8216;ascii&#8217;) pour les appels \u00e0 port.write et port.red (lecture \u00e9criture sur\nle port s\u00e9rie \/ USB <\/li><\/ul>\n\n\n\n<h1 class=\"wp-block-heading\"><a>Examen de l\u2019exemple\u00a0: lecture du flux de donn\u00e9es<\/a><\/h1>\n\n\n\n<p>Voici ce que donne l\u2019ex\u00e9cution du programme d\u2019exemple dans l\u2019IDE Python\u00a0:<br \/><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"http:\/\/wollef.org\/wp-content\/uploads\/2020\/01\/image.png\" alt=\"\" class=\"wp-image-874\"\/><\/figure>\n\n\n\n<p>Examinons la premi\u00e8re partie du code Python; le code est organis\u00e9 de la mani\u00e8re suivante\u00a0:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Cela commence par l\u2019importation des librairies\nn\u00e9cessaires&nbsp;: serial pour les lectures et \u00e9criture USB ( <strong>import\nserial<\/strong> )<\/li><li>L\u2019ouverture du port USB connect\u00e9 \u00e0 la carte <strong>port =\nserial.Serial(\u2026 <\/strong>Le port indiqu\u00e9 ( (<strong>&#8220;\/dev\/ttyUSB0<\/strong>) est\ncelui que nous avons trouv\u00e9 dans la partie pr\u00e9c\u00e9dente<\/li><li>Use s\u00e9rie de commandes AT (ce sont les textes \u00e0\nenvoyer \u00e0 la carte sur le port USB pour lui demander de travailler), Apr\u00e8s\nchaque envoi de commande, le programme lit la\nr\u00e9ponse, et <em>attend un dixi\u00e8me de seconde<\/em>.<ul><li>AT&nbsp;: elle renvoie OK comme r\u00e9ponse<\/li><\/ul><ul><li>AT+CGNSPWR=1&nbsp;: elle active le module GPS<\/li><\/ul><ul><li>AT+CGNSIPR=115200&nbsp;: elle configure la vitesse\nde transmission des sonn\u00e9es entre la carte et le Raspberry \u00e0 115200 bauds<\/li><\/ul><ul><li>AT+CGNSTST=1&nbsp;: elle demande \u00e0 la carte d\u2019\u00e9crire\nles donn\u00e9es GPS en continu vers le port USB, et donc vers le Raspberry<\/li><\/ul><ul><li>AT+CGNSINF&nbsp;: elle renvoie le statut de la carte<\/li><\/ul><\/li><li>Une boucle infinie qui<ul><li><strong>&nbsp;lit le flux\nd\u2019information envoy\u00e9 par la carte<\/strong><\/li><\/ul><ul><li><strong>L\u2019imprime dans la console<\/strong><\/li><\/ul><ul><li><em>Attend\nune demi seconde que d\u2019autres donn\u00e9es arrivent<\/em><\/li><\/ul><\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/python\n\nimport serial\nimport time\nfrom decimal import *\nfrom subprocess import call\n\ndef find(str, ch):\n    for i, ltr in enumerate(str):\n        if ltr == ch:\n            yield i\n\n# Enable Serial Communication\nport = serial.Serial(\"\/dev\/ttyUSB0\", baudrate=115200, timeout=1)\n# Transmitting AT Commands to the Modem\n# '\\r\\n' indicates the Enter key\n\nport.write(('AT'+'\\r\\n').encode('ascii'))\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\n\nport.write(('AT+CGNSPWR=1'+'\\r\\n').encode('ascii'))\n# to power the GPS\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nport.write(('AT+CGNSIPR=115200'+'\\r\\n').encode('ascii'))\n# Set the baud rate of GPS\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nport.write(('AT+CGNSTST=1'+'\\r\\n').encode('ascii'))\n# Send data received to UART\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nport.write(('AT+CGNSINF'+'\\r\\n').encode('ascii'))\n# Print the GPS information\nrcv = port.read(200).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nwhile True:\n    fd = port.read(200).decode('ascii')\n# Read the GPS data from UART\n    print (\"BLOC:\")\n    print(fd);\n    print(\"\")\n    time.sleep(.5)\n<\/code><\/pre>\n\n\n\n<p>Voici le\nr\u00e9sultat dans la console python durant l\u2019ex\u00e9cution&nbsp;:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Les premi\u00e8res interactions durant la configuration\u00a0:<\/li><\/ol>\n\n\n\n<pre class=\"wp-block-code\"><code>>>> %Run gps.py\nAT\nOK\nAT+CGNSPWR=1\nOK\nAT+CGNSIPR=115200\nOK\n+CGNSPWR: 1\nAT+CGNSTST=1\nOK\nAT+CGNSINF\n+CGNSINF: 0,,,,,,,,,,,,,,,,,,,,\n\nOK\n$PMTK011,MTKGPS*08\n$PMTK010,001*2E<\/code><\/pre>\n\n\n\n<ol class=\"wp-block-list\" start=\"2\"><li>Puis le flux de donn\u00e9es GPS commence \u00e0 s\u2019afficher par blocs\u00a0:<\/li><\/ol>\n\n\n\n<ul class=\"wp-block-list\" start=\"2\"><li>Les lignes de positions commencent par <strong>$GNRMC<\/strong>.<\/li><li>Initialement le GPS ne connait pas encore la position\u00a0: <strong>$GNRMC,235944.539,V,,,,,0.00<\/strong><\/li><li>Puis le GPS la connait et la fournit <strong>$GNRMC,114452.000,A,4936.683239,N,00609.052326,E,0.15,0.00,171119,,,A*7F<\/strong><\/li><li><strong>On sait que les lignes sont bonnes gr\u00e2ce \u00e0 l\u2019indicateur A ou V<\/strong>. Les bonnes lignes sont indiqu\u00e9es par A.<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>BLOC:\n$PMTK011,MTKGPS*08\n$PMTK010,002*2D\n$GNGGA,235944.539,,,,,0,0,,,M,,M,,*54\n$GPGSA,A,1,,,,,,,,,,,,,,,*1E\n$GLGSA,A,1,,,,,,,,,,,,,,,*02\n$GPGSV,1,1,00*79\n$GLGSV,1,1,00*65\n$GNRMC,235944.539,V,,,,,0.00\n\nBLOC:\n,0.00,050180,,,N*5D\n$GNVTG,0.00,T,,M,0.00,N,0.00,K,N*2C\n$GPACCURACY,9999000.0*08\n$GNGGA,235945.539,,,,,0,0,,,M,,M,,*55\n$GPGSA,A,1,,,,,,,,,,,,,,,*1E\n$GLGSA,A,1,,,,,,,,,,,,,,,*02\n$GPGSV,1,1,00*79\n\nBLOC:\n$GLGSV,1,1,00*65\n$GNRMC,235945.539,V,,,,,0.00,0.00,050180,,,N*5C\n$GNVTG,0.00,T,,M,0.00,N,0.00,K,N*2C\n$GPACCURACY,9999000.0*08\n$GNGGA,235946.538,,,,,0,0,,,M,,M,,*57\n$GPGSA,A,1,,,,,,,,,,,,,,,*1E\n\n..... quelques blocs plus tard .....\n\nBLOC:\n,00609.052326,E,1,5,1.90,299.486,M,47.677,M,,*47\n$GPGSA,A,3,07,22,19,09,,,,,,,,,2.09,1.90,0.88*07\n$GLGSA,A,3,76,,,,,,,,,,,,2.09,1.90,0.88*1C\n$GPGSV,2,1,07,09,86,226,33,37,31,160,,07,27,171,41,19,12\n\nBLOC:\n,234,29*78\n$GPGSV,2,2,07,22,10,112,32,03,,,43,23,,,18*40\n$GLGSV,1,1,01,76,31,112,33*55\n$GNRMC,114452.000,A,4936.683239,N,00609.052326,E,0.15,0.00,171119,,,A*7F\n$GNVTG,0.00,T,,M,0.15,N,0.27,K,A*22\n\nBLOC:\n\n$GPACCURACY,38.9*3A\n$GNGGA,114453.000,4936.683280,N,00609.052267,E,1,5,1.89,298.667,M,47.677,M,,*44\n$GPGSA,A,3,07,22,19,09,,,,,,,,,2.09,1.89,0.88*0F\n$GLGSA,A,3,76,,,,,,,,,,,,2.09,1.89,0.88*14\n$GP\n\nBLOC:\nGSV,2,1,07,09,86,226,33,37,31,160,,07,27,171,41,19,12,234,29*78\n$GPGSV,2,2,07,22,10,112,32,03,,,42,23,,,18*41\n$GLGSV,1,1,01,76,31,112,33*55\n$GNRMC,114453.000,A,4936.683280,N,00609.052267,E,0.22,0.0\n\nBLOC:\n0,171119,,,A*7C\n$GNVTG,0.00,T,,M,0.22,N,0.41,K,A*26\n$GPACCURACY,37.5*39\n$GNGGA,114454.000,4936.683205,N,00609.052184,E,1,5,1.89,299.035,M,47.677,M,,*40\n$GPGSA,A,3,07,22,19,09,,,,,,,,,2.09,1.89,0.8\n\n..... etc. .....<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\"><a>Examen de l\u2019exemple\u00a0: extraction des coordonn\u00e9es GPS<\/a><\/h1>\n\n\n\n<p>Le code du programme d\u2019exemple complet extrait dans la\nboucle infinie les coordonn\u00e9es GPS contenue dans les lignes <strong>$GNRMC.&nbsp; <\/strong>Voici\ncomment il fonctionne&nbsp;:<strong><\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Il commence de la m\u00eame mani\u00e8re par toutes les initialisations de la carte, <\/li><li>Puis, dans la boucle, le code d\u00e9compose le texte re\u00e7u\u00a0depuis la carte.<\/li><\/ul>\n\n\n\n<p>Cette boucle traite le code suivant :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Il rep\u00e8re les caract\u00e8res <strong>$GNRMC\u00a0<\/strong>, <\/li><li>Il d\u00e9tecte si la ligne est marqu\u00e9e avec un A, <\/li><li>Il v\u00e9rifie s\u2019il y a assez de caract\u00e8res apr\u00e8s le A qui ont \u00e9t\u00e9 re\u00e7u (au moins 50)<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>if '$GNRMC' in fd:        # To Extract Lattitude and\n        ps=fd.find('$GNRMC')        # Longitude\n        dif=len(fd)-ps\n        if dif > 50:<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>Il cherche dans le texte qui suit la prochaine virgule, et les deux sous cha\u00eenes Lon et Lat qui contiennent les coordonn\u00e9es<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>p=list(find(data, \",\"))\nlat=data&#91;(p&#91;2]+1):p&#91;3]]\nlon=data&#91;(p&#91;4]+1):p&#91;5]]<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li>Puis il convertit les valeurs en nombre exploitable et les imprime<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>s1=lat&#91;2:len(lat)]\ns1=Decimal(s1)\ns1=s1\/60\ns11=int(lat&#91;0:2])\ns1 = s11+s1\n\ns2=lon&#91;3:len(lon)]\ns2=Decimal(s2)\ns2=s2\/60\ns22=int(lon&#91;0:3])\ns2 = s22+s2\n\nprint (s1)\nprint (s2)<\/code><\/pre>\n\n\n\n<p>Voici le r\u00e9sultat affich\u00e9 dans la console<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$GNRMC,114603.000,A,4936.687012,N,00609.048559,E,0\n49.6114502\n6.150809316666666666666666667\n$GNRMC,114605.000,A,4936.687012,N,00609.048559,E,0\n49.6114502\n6.150809316666666666666666667\n$GNRMC,114606.000,A,4936.687012,N,00609.048559,E,0\n49.6114502\n6.150809316666666666666666667\n$GNRMC,114608.000,A,4936.687012,N,00609.048559,E,0\n49.6114502\n6.150809316666666666666666667<\/code><\/pre>\n\n\n\n<p>Et le code du programme complet<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/usr\/bin\/python\n\nimport serial\nimport time\nfrom decimal import *\nfrom subprocess import call\n\ndef find(str, ch):\n    for i, ltr in enumerate(str):\n        if ltr == ch:\n            yield i\n\n# Enable Serial Communication\nport = serial.Serial(\"\/dev\/ttyUSB0\", baudrate=115200, timeout=1)\n\n# Transmitting AT Commands to the Modem\n# '\\r\\n' indicates the Enter key\n\nport.write(('AT'+'\\r\\n').encode('ascii'))\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\n\nport.write(('AT+CGNSPWR=1'+'\\r\\n').encode('ascii'))\n# to power the GPS\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nport.write(('AT+CGNSIPR=115200'+'\\r\\n').encode('ascii'))\n# Set the baud rate of GPS\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nport.write(('AT+CGNSTST=1'+'\\r\\n').encode('ascii'))\n# Send data received to UART\nrcv = port.read(100).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nport.write(('AT+CGNSINF'+'\\r\\n').encode('ascii'))\n# Print the GPS information\nrcv = port.read(200).decode('ascii')\nprint (rcv)\ntime.sleep(.1)\n\nwhile True:\n    fd = port.read(200).decode('ascii')\n    time.sleep(.5)\n\n    if '$GNRMC' in fd:\n        ps=fd.find('$GNRMC')\n        dif=len(fd)-ps\n        if dif > 50:\n            data=fd&#91;ps:(ps+50)]\n            print (data)\n            ds=data.find('A')\n            if ds > 0 and ds &lt; 20:\n                p=list(find(data, \",\"))\n                lat=data&#91;(p&#91;2]+1):p&#91;3]]\n                lon=data&#91;(p&#91;4]+1):p&#91;5]]\n\n                s1=lat&#91;2:len(lat)]\n                s1=Decimal(s1)\n                s1=s1\/60\n                s11=int(lat&#91;0:2])\n                s1 = s11+s1\n\n                s2=lon&#91;3:len(lon)]\n                s2=Decimal(s2)\n                s2=s2\/60\n                s22=int(lon&#91;0:3])\n                s2 = s22+s2\n\n                print (s1)\n                print (s2)<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>La documentation de la carte Avant de manipuler la carte, il faut examiner la documentation. Celle-ci est disponible sur le site de Waveshare&nbsp;: https:\/\/www.waveshare.com\/wiki\/GSM\/GPRS\/GNSS_HAT Le manuel PDF d\u00e9crit&nbsp;: Les caract\u00e9ristiques techniques de la carte Comment choisir le mode de connection&nbsp;: via le port USB soit via le port GPIO du Raspberry Des exemples de programme <a class=\"read-more\" href=\"https:\/\/wollef.org\/blog\/raspberry-cars-communication-avec-la-carte-gps-en-python\/\">Continue Reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31,42,16,17],"tags":[],"class_list":["post-873","post","type-post","status-publish","format-standard","hentry","category-raspberry-cars","category-gps","category-python","category-raspberry-pi"],"_links":{"self":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/posts\/873","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/comments?post=873"}],"version-history":[{"count":0,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/posts\/873\/revisions"}],"wp:attachment":[{"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/media?parent=873"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/categories?post=873"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wollef.org\/blog\/wp-json\/wp\/v2\/tags?post=873"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}