Pyboard.py

Note

Ce module est le même que celui que l'on installe lors de la configuration de Geany par exemple, mais son usage est beaucoup plus polyvalent que simplement l'utilisation avec Geany.

Pour comprendre

Pyboard.py est un utilitaire qui permet d'interagir avec micropython à partir d'un interpréteur ou d'un code Python tournant sur le poste principal. Il s'agit donc d'un outil particulièrement intéressant, notamment dès lors que l'on envisage de réaliser des interfaces, etc.

Avec Pyboard, on va ainsi pouvoir, à partir d'un code Python envoyer vers la carte micropython :

  • une simple instruction
  • un code complet
  • accèder au système de fichier de la carte micropython

Noter que l'on peut aussi utiliser pyboard.py de 2 façons :

  • soit en mode interpréteur, ce qui revient à un mode "ligne de commande"
  • soit au sein d'un code python, comme un module

Un outil polyvalent !

Au contraire de ce que son nom laisse à penser, Pyboard.py, est un utilitaire qui fonctionne avec n'importe quelle carte Micropython et çà c'est une bonne nouvelle ! Yes !

Télécharger pyboard.py

Pyboard.py est un simple script Python 3 qui se télécharge et se placera dans le répertoire à partir duquel on veut communiquer avec la carte micropython, typiquement le répertoire où se trouvent les codes que l'on veut envoyer.

La dernière version est ici sur Github ou

Dépendances

La seule dépendance de pyboard.py est le module serial :

sudo apt-get install python3-serial

Dans le terminal sur ordinateur

Ne vous trompez pas et comprenez bien !

On exécute ce qui suit SUR LE POSTE QUI COMMUNIQUE AVEC LA CARTE MICROPYTHON ! (et pas dans l'interpréteur REPL de micropython) En clair, les commandes sont à saisir dans un terminal système sans lancer l'outil de communication série habituel tel que screen au préalable.

Commencer par se placer dans le répertoire où on a placé le fichier pyboard.py et ouvrir un terminal à cet emplacement (clic droit > "ouvrir un terminal ici" sous XFCE)

Afficher l'aide

Ensuite saisir la commande :

python3 pyboard.py --help

Ce qui affiche l'aide :

usage: pyboard.py [-h] [-d DEVICE] [-b BAUDRATE] [-u USER] [-p PASSWORD]
                  [-c COMMAND] [-w WAIT] [--follow | --no-follow] [-f]
                  [files [files ...]]

Run scripts on the pyboard.

positional arguments:
  files                 input files

optional arguments:
  -h, --help            show this help message and exit
  -d DEVICE, --device DEVICE
                        the serial device or the IP address of the pyboard
  -b BAUDRATE, --baudrate BAUDRATE
                        the baud rate of the serial device
  -u USER, --user USER  the telnet login username
  -p PASSWORD, --password PASSWORD
                        the telnet login password
  -c COMMAND, --command COMMAND
                        program passed in as string
  -w WAIT, --wait WAIT  seconds to wait for USB connected board to become
                        available
  --follow              follow the output after running the scripts [default
                        if no scripts given]
  --no-follow           Do not follow the output after running the scripts.
  -f, --filesystem      perform a filesystem action: cp local :device | cp
                        :device local | cat path | ls [path] | rm path | mkdir
                        path | rmdir path

On constate d'entrée de jeu que l'on dispose de pas mal de possibilités et c'est donc un outil "couteau suisse" pour la communication entre le Python du poste principal et micropython de la carte. Noter notamment les commandes permettant d'accéder au système de fichier de la carte micropython.

Forme alternative de la commande

On peut également utiliser une commande de la forme :

pyboard.py --help

ou encore :

./pyboard.py --help

Il faut par contre rendre au préalable le script exécutable ce qui se fait soit graphiquement ( clic droit sur le fichier > propriétés > onglet permissions > cocher "Autoriser exécution" ) ou bien avec la ligne de commande suivante :

chmod +x pyboard.py

Voyons à présent quelques exemples concrets :

Envoyer une commande à micropython

Pour envoyer une commande à micropython et recevoir la réponse, on fera :

python3 pyboard.py --device /dev/ttyACM0 -c 'print(1+1)'

où :

  • --device /port/serie : indique le port série à utiliser. Adapter le chemin à celui utilisé par la carte. Si on a un doute, vérifier avec ls /dev/ttyACM* par exemple.
  • -c 'instruction' : entre guillemets, la commande Python à passer à micropython

Ce qui donne ici :

2

Remarquer donc que pyboard.py intercepte par défaut la réponse de la carte. Ceci peut être désactivé avec le paramètre --no-follow (voir la sortie de --help )

Réaliser des opérations sur le système de fichiers de la carte avec Pyboard.py

On peut réaliser des opérations sur le système de fichier de la carte avec Pyboard.

Pour charger en RAM un fichier local :

python3 pyboard.py --device '/dev/ttyACM0' "fichier.py"

Note

La commande de configuration de Geany est celle-ci légèrement adaptée :

python3 pyboard.py --device '/dev/ttyACM0' "%f"

Note

On peut ajouter --no-follow à la commande pour éviter les blocages

Pour copier un fichier local vers le fichier main.py de la carte :

python3 pyboard.py --device /dev/ttyACM0 -f cp gpio_out_led_timer.py :main.py

Noter qu'ici, on fait "d'une pierre 2 coups" en copiant sur la carte et en renommant simultanément le fichier

Note

Les chemins correspondant à la carte microPython lorsqu'ils sont appelés depuis Pyboard.py sont précédés d'un : Le : représente la racine de la Flash de la carte.

A noter que l'on peut facilement réaliser de la sorte quelques opérations simples :

Afficher le contenu du fichier boot.py

python3 pyboard.py --device /dev/ttyACM0 -f cat :boot.py

Lister le contenu de la Flash :

python3 pyboard.py --device /dev/ttyACM0 -f ls :

Ce qui donne par exemple :

         304 main.py
        2721 pybcdc.inf
         528 README.txt
         302 boot.py
       13474 upyduino.py
           7 test.txt
           0 test/
        7255 lcd_api.py
        3091 pyb_i2c_lcd.py

Si on souhaite copier localement un fichier de la carte, on fera :

python3 pyboard.py --device /dev/ttyUSB0 -f cp :boot.py boot.py

Pour copier le contenu d'un répertoire, on fera :

python3 pyboard.py --device /dev/ttyUSB0 -f cp picoweb/* :/lib/picoweb/

Effacer un fichier sur la carte :

python3 pyboard.py --device /dev/ttyACM0 -f rm :trans.py

Utiliser micropython depuis un interpréteur Python

Ne vous trompez pas et comprenez bien !

Ici on va communiquer avec micropython depuis un interpréteur Python sur le "poste fixe" auquel la carte micropython est connectée. Soyez bien conscient que l'interpréteur ici n'est pas l'interpréteur REPL de micropython mais l'interpréteur Python du système.

A présent, nous allons voir comment interagir avec micropython depuis un interpréteur Python sur le poste fixe. Pour éviter la confusion, je vous conseille de lancer Ipython par exemple, ce qui vous montrera clairement la différence d'avec screen utilisé dans le terminal.

Placez-vous dans le répertoire où se trouve pyboard.py, ouvrez un terminal dans ce répertoire (clic droit > ouvrir un terminal ici sous XFCE) et lancer la console Jupyter, ce qui se fait avec :

jupyter-qtconsole

ce qui donne :

Une fois fait, on va saisir successivement :

import pyboard # importe le script pyboard.py

pyb=pyboard.Pyboard('/dev/ttyACM0', 115200) # definit un objet Pyboard correspondant à la carte

pyb.enter_raw_repl() # bascule en mode repl_raw permettant l'envoi / réception de bytes depuis micropython 

#------- a partir de ce moment on peut envoyer des commandes et interagir avec micropython  - tout est placé en RAM --------

pyb.exec('print(1+1)')
# b'2\r\n'

ret=pyb.exec('print(1+1)') 
# aucun affichage

print(ret)
# b'2\r\n'

print(ret.decode()) # pour afficher en str
# 2

# chargement d'un code depuis poste fixe
file=open("test.py",'r') # ouverture fichier
code=file.read() # lecture fichier
file.close() # fermeture fichier
ret=pyb.exec(code) # exécution du fichier

pyb.exec('hello()') # appel d'une fonction présente dans le code précédent
#b'Micropython OK !\r\n' # on récupère sa sortie !


# chargement d'un code présent sur la carte micropython
ret=pyb.exec("""from upyduino import *
millis()
digitalWrite(1,0)
""")

# saisie d'un code en multilignes 
ret=pyb.exec("""import pyb
pyb.LED(4).on()
""")

#--- sortie du mode d'interaction directe - conseillé / obligatoire ?

pyb.exit_raw_repl() # sortie du mode repl_raw

On peut pousser le bouchon un peu plus loin même avec Jupyter qui permet les affichages graphiques. Soit un petit code micropython intégrant une fonction de mesure analogique :

import pyb

rvar=pyb.ADC(pyb.Pin('X1'))


def getData(nb=1): # fonction d'acquisition des données

    for i in range(nb):
        mesure=rvar.read()
        print(mesure)

Ensuite, on fait une acquisistion de 1000 mesures que l'on affiche sous forme graphique :

pyb.enter_raw_repl()

file=open("test_adc_2.py", 'r')
code=file.read()
file.close()
ret=pyb.exec(code)
ret=pyb.exec("getData(1000)")

data=ret.decode()

import io
buf=io.StringIO(data)
lines=buf.readlines()

%pylab inline

x=arange(len(lines))
y=[ int(value) for value in lines ]

plot(x,y)

# pyb.exit_raw_repl() 

Ce qui donne :

Trucs et astuces

Si on souhaite transférer un code dans la RAM de la Pyboard, on utilisera la commande :

python3 pyboard.py --device '/dev/ttyACM0' "file.py"

A noter que si on utilise cette commande dans Geany, on remplaçant file.py par "%f", on obtient l'équivalent du "téléverser" de Arduino :

python3 pyboard.py --device '/dev/ttyACM3' "%f"

Si on souhaite transférer un code sur la carte Micropython (dans la mémoire Flash) et que l'on veut de plus faire un Reset dans la foulée, on fera :

python3 pyboard.py --device /dev/ttyACM3 -f cp file.py :main.py && python3 pyboard.py --device /dev/ttyACM3 -c 'machine.reset()' --no-follow

Ne fonctionne pas avec machine.soft_reset() mais Ok avec machine.reset()

A noter que si on utilise cette commande dans Geany, on remplaçant file.py par "%f", on obtient l'équivalent du "téléverser" de Arduino :

python3 pyboard.py --device /dev/ttyACM3 -f cp "%f" :main.py && python3 pyboard.py --device /dev/ttyACM3 -c 'machine.reset()' --no-follow

C'est cadeau !

Cette dernière commande m'a demandé un peu de recherche, quelques essais et de "jugeote" pour l'obtenir, mais elle fonctionne à merveille et est une excellente façon de simplfier l'utilisation d'une carte Micropython, "façon Arduino".

Alternative pour utilisation de Pyboard depuis un script Python

Dans la mesure où il est facile de réaliser toute une série d'opération facilement avec Pyboard en ligne de commande, on peut vouloir simplement garder le bénéfice çà et appeler Pyboard en ligne de commande depuis le code Python lui-même.

Ce qui donne par exemple :

Copie d'un fichier

import subprocess
pathThisApp=os.getcwd()+"/"

# python3 pyboard.py --device $1 -f cp $2 :main.py # commande pour copier dans main.py
cmd=['python3', pathThisApp+'pyboard.py', '--device', '/dev/ttyUSB0' , '-f', 'cp', 'test.py', ':test.py', '--no-follow']
# cmd=['python3', 'pyboard.py', '--device', '/dev/ttyUSB0' , '-f', 'cp', 'test.py', ':test.py', '--no-follow']

p=subprocess.run(cmd)

Ensuite, on peut vérifier, toujours depuis le même terminal que la copie s'est bien déroulée :

import pyboard
pyb=pyboard.Pyboard('/dev/ttyUSB0', 115200)
pyb.enter_raw_repl()
ret=pyb.exec("""import os
print(os.listdir())
""")

print(ret)

pyb.exit_raw_repl() 

Lister les fichiers de la carte :

import subprocess

cmd=['python3', 'pyboard.py', '--device', '/dev/ttyACM0' , '-f', 'ls', ':']
p=subprocess.run(cmd)
out=subprocess.check_output(cmd)
out
Out[8]: b'         195 gpio_blink_onboard_timer.py\r\n         195 main.py\r\n        7097 neoSPI.py\r\nls :\n'
out.decode()
Out[10]: '         195 gpio_blink_onboard_timer.py\r\n         195 main.py\r\n        7097 neoSPI.py\r\nls :\n'
lines=out.decode().split('\n')
lines
Out[12]: 
['         195 gpio_blink_onboard_timer.py\r',
 '         195 main.py\r',
 '        7097 neoSPI.py\r',
 'ls :',
 '']
 ```

## Un script bash pour automatiser la copie d'un code Micropython sur la carte

Cerise sur le gâteau, voici un petit script d'automatisation du upload d'un fichier *.py vers main.py en passant en paramètre au script la cible au format `/dev/ttyACM0` et le nom du fichier. 

```bash
#!/bin/bash
# Transfert d'un fichier *.py vers main.py sur la carte Micropython
#le fichier pyboard.py doit se trouver dans le répertoire du script

echo "Le fichier à uploader vers la carte $1"
echo "est $2"

echo "Copie du fichier vers main.py :"
python3 pyboard.py --device $1 -f cp $2 :main.py

echo "Reboot de la carte."
python3 pyboard.py --device $1 -c 'machine.reset()' --no-follow

echo "Upload OK !"

exit 0;

# commande type :  ./upload.sh /dev/ttyACM3 gpio_blink_onboard_timer.py

A enregistrer dans le répertoire de vos fichiers Micropython sous le nom upload.sh par exemple et à rendre exécutable avec :

chmod +x upload.sh

Ensuite, on appelle la commande avec :

./upload.sh /dev/ttyACM3 programme.py

Et aussi

A noter que si on veut extraire l'exception renvoyée par Pyboard, on fera :

           try : 
                ret=self.pyb.exec(code) 
                ret=ret.decode() # bytes en str

            except Exception as e:

                #print(dir(e))
                ret=e.args[2].decode() # extraction de la réponse

                print(ret)
                # forme ('exception', b'', b'Traceback (most recent call last):\r\n  File "<stdin>", line 1, in <module>\r\nNameError: name \'a\' isn\'t defined\r\n')

                ret=str(e)

L'exception renvoie 3 args et le dernier est le message, d'où index 2

Gui pour Pyboard ?

Une petite GUI PyQt5 serait intéressante avec éditeur syntaxique Python et des boutons différents pour charger en RAM ou charger sur la carte.

Liens utiles