mardi 20 août 2019

Serialisation JSON, essayons d'en faire une librairie

Mon petit code de sérialisation en JSON du behavior tree m'a finalement donné l'intérêt de tester la création d'une librairie. J'ai donc commencé le projet JSONSerialWriter qui j'espère pourra devenir une librairie supportée par l'IDE sur plusieurs architectures. Il y a sûrement d'autre librairie JSON me direz-vous. Bin kin, y a en pas mal en fait et ArduinoJSON est excellente, mais elles sont toutes un peu trop gourmante en mémoire à mon goût. Comme la sérialisation de graph est assez verbose et que je veux utiliser le moins de RAM possible, tout spécialement sur les Uno/Nano/Micro,  je crois qu'il y a une niche pour ce projet. Il n'est pas exclus d'utiliser plus d'une librairie sdans un même projet aussi ( ici, ça ne sérialise, ça ne parse pas).

Mais sincèrement, le but est de se faire les dents à la création d'une librairie.

Que sont les prérequis pour être inclus dans le "library manager"?


Voici sommairement ce qui est nécessaire pour qu'une librarie soit incluse dans le manager de l'IDE d'Arduino.
  • Doit être héberger sur un site de gestion de source tel github, gitlab et bitbucket.
  • Doit avoir à la racine du repo les fichiers qui seront installer sous Arduino/librairies/[nomdelalibrairie]
  • Le fichier librairy,property doit être présent
  • La numéro de version est sous la forme major.minor.revision (semver)
  • Le fichier README.adoc doit décrire la librairie
  • Le fichier keywords doit définir les mots clés à "highliter" dans l'IDE
  • Le fichier .development ne doit pas être présent ( mais utile pour le dévelopment )
  • Le code source doit être accessible à partir de la racine, quoi que les dernières version supporte le répertoire /src
  • Les examples sont contenus dans le sous-répertoire /examples
  • Si supporté, utiliser le mécanisme de "release" pour spécifier les nouvelles versions
  • Écrire dans le forum d'Arduino pour annoncer la nouvelle librairie.

 Une fois la librairie inscrite, un sytème automatisé monitore le repo et mets à jours assez rapidement les nouvelles versions ( peut prendre quelques heures ).

Où trouver l'information complète pour le support du dévelopment de librairies



Fonctionnalités et utilisation de la librairie


Une seule classe est accessible via la libraire et c'est JSONSerialWriter. Les méthodes sont relativement évidentes dans leur fonctionnalité. Puisque c'est un sérializer qui écrit de manière synchrone dans le stream, l'ordre d'appel est important. C'est aussi à l'utilisateur de gérer la hiérarchie des objets sauvegardés. Par défaut, c'est l'objet Serial qui est assigné comme stream de sorti. Il est cependant possible d'assigner tout autre classe dérivant de Print pour la sérialisation.

Comme le but est d'être le moins gourmand en mémoire, la classe ne contient que trois booléens, un int et un pointeur vers le Print a utiliser. Très probable que plus tard dans le développement, le tout soit encore plus compact. Puisque les appels ne garde pas vraiment d'états ni de buffer, c'est tout aussi compact lors de l'exécution.


JSONSerialWriter writer;
writer.startWriter();
writer.writeValue( "temperature", 10 );
writer.writeValue( F("humidity"), 22.87f );
writer.writeValue( F("winddirection"), F("North"));
writer.closeWriter();

Le résultat èa la sorti sera:

{"temperature":10,"humidity":22.8700,"winddirection":"North"}


À noter que l'utliliation des string en flash F(str) est important pour sauvegarder de la mémoire.

Cédule de développement

Bien qu'il puisse y avoir pas mal de fonctionnalités utilitaires à cette librairie, j'espère faire un release rapidement. J'imagine qu'il est possible de sortir une version avant la 1.0.0 . Si c'est le cas, tant que le tout est fonctionnel, compilable sur AVR et megaAVR, ce sera parfait comme ça.

Dans les ajouts qui viendront par la suite, je prévois:

  • Support pour écrire directement dans le stream.
  • Permettre d'écrire la valeur de chaine de caractère en plusieurs appels.
  • Compiler pour les architecture sam et samd
  • Quelques méthodes utilitaires pour facilité la vie avec les arrays.
  • Optimisation 



jeudi 8 août 2019

JSON, Flask et "Quality of life" pour Arduino

J'essaie d'implémenter la gestion d'évènements et les utiliser comme déclencheur mais le tout devient un peu tannant de déboguer avec seulement un output texte et des nombres comme identifiant. J'ai donc décider de me faire une meilleure visualisation du Behavior Tree.

Pour y arriver, je veux:
  • Un sortie standardisée facile à décoder
  • Un système simple permettant de se connecter sur le port série et lire le contenu
  •  Du code portable et rapide a implémenter
Pour ce qui est de l'output, j'ai décider de le faire en JSON. Cependant, comme c'est un arbre et qu'il peut y avoir pas mal d'info a sérialiser, une librairie comme ArduinoJSON bien qu'excellente, nécessite de générer un "document" qui sera sérialisé. C'est trop gourmand, donc j'ai écrit un serialiseur "in place" qui envoit directement sur Serial l'information.

Pour le moment la classe de sérialisation est incluse dans le code de Behavior Tree mais je pourrais en faire une librairie simpliste qui j'imagine pourrait être utile à condition de permettre de spécifier le stream de sortie ( Wifi, BT, RF module y compris ) et d'y ajouter le support pour les chaines de caractères en progmem.

Ensuite, le projet python Flask permet de réaliser un petit site web dont des url permettent de se connecter, déconnecter et lire le port série. C'est encore en chantier mais c'est prometteur. Ce pourrait être pratique si configuré pour répondre autre que sur localhost et monitorer à distance ou sur appareil mobile sur le même réseau.

Comme c'est en Python ça n'utilise que Flask, pySerial, le code est relativement simple et surtout portable. Comme l'output série est déjà en JSON, c'est simple à "parser" et pourrait même être décoder côté client. Il me reste à faire une configuration pour l'affichage selon le type et ce sera déjà pas mal mieux que regarder le "serial monitor".

C'est encore un "work in progress", mais le code est dispo sur github

samedi 3 août 2019

Blackboard et Behavior Tree

Les noeuds n'ont pas vraiment de mémoire excepté les 2 octets qui sert de paramètre. Qui plus est, il difficile d'échanger des données entre les noeuds. Pour y arriver, le concept de "tableau noir" est implémenté. C'est un espace disponible pour tous les noeuds d'un arbre afin d'y laisser de l'information qui peut être lu et modifié par n'importer quel autre noeud. Ici, comme l'espace est limité, la clé est composée que d'un octet et le nombre d'espace dans le tableau doit lui aussi être limité. Seulement 2 octets peut être assigné comme valeur. Ici encore, un pool d'objet d'une taille immuable est définie et utilisé pour l'entièreté de l'exécution. Une valeur de 255 indique un espace libre dans le tableau, donc ne doit pas être utilisé comme clé.

Deux actions de behavior de base sont ajoutées, soit l'assignation et le retrait d'élément au tableau. Puisque seulement 2 octets sont disponible comme paramètre aux action, la valeur assignée est limité à un octet. Ce sont des actions utilitaires, les actions propriétaires pourront mieux utilisé l'espace.

Puisque l'espace est si limité, le blackboard n'est pas fait pour stocker l'ensemble du monde comme pourrait être fait dans une système plus performant. Un robot pourrait encoder les valeur des ses senseur dans une structure plus performante qui serait disponible lors de l'exécution de noeuds propriétaires. Cependant, c'est une structure généraliste qui est pratique.

La classe Blackboard est simple à utiliser. Les méthode set et get permettent l'assignation et l'accès aux valeurs disponible. La méthode releaseElement permet de retirer un élément précis et hasKey retourne si un l'élément existe dans le tableau. L'action SetBBValue aura le statut de SUCCESS si l'assignation réussi et  FAILURE s'il n'y a plus de place dans le tableau.

Prochaine étape, l'utilisation d'évènements pour déclencher l'exécution de sous-arbres.