vendredi 5 juillet 2019

PROGMEM et Behavior Tree, la suite

Puisque des parties de l'arbre pourront être désérialisées à la demande dans le projet de Behavior Tree pour Arduino, il est nécessaire d'avoir un mécanisme d'accès pour se facilité la vie. Dans mon cas, le type de noeud "proxy" à la comportement suivant:

  • Premier appel: désérialise selon une valeur en "data" le sous-arbre en tant qu'enfant.
  • En traitement, appel le traitement de l'enfant
  • Sur "Success" ou "Failure" de l'enfant, prend l'état et détruit le sous-arbre.

De cette manière, toute une partie de l'arbre n'existe pas en mémoire et n'est que présent que lors de son exécution. Comme l'élément "data" d'un noeud n'est un int, il est nécessaire de pouvoir adresser une liste de noeuds et d'en instancier au besoin.

Pour ce faire, j'ai créer la classe BehaviorBank qui permet de gérer une liste d'éléments et de répondre à la question de la taille sans devoir en parcourir le contenue. Pour le moment, l'implémentation de l'arbre et des classes utilitaire est faite de façon naïve sant me soucier de l'optimisation ou de la gestion d'erreur. La défition de la classe est la suivante:

 
class BehaviorBank
{
  int totalElements;
  const byte* behaviorIndexesSizes;
  const int* behaviorIndexes;
  const char* behaviorDatas;
public:
  void init( const byte* sizes, const int* indexes, const char* datas, int total );
  byte getNbrNodes( int idx );
  char* getDataPtr( int idx );
};
 

Ici, trois tableaux permettent de garder en mémoire Flash un ensemble de sous-arbre. L'indice dans le tableau et le nombre de noeud par sous-arbre permettent d'extraire selon un indice passé en paramère le pointeur vers les donnée. Le nombre d'indice total est passé en paramètre lors de l'inisialisation.

Les données sont présentement encoder comme suit:

const PROGMEM byte BBankSizes[] = {3, 3};
const PROGMEM int BBankIndexes[] = { 0, 12 };
const PROGMEM char BBankData[] = {1, 0, 0, 2, 20, 11, 0, 1, 20, 22, 
    0, 0, 1, 0, 0, 2, 20, 33, 0, 1, 20, 44, 0, 0};

 Et l'initialisation ressemble à:

BehaviorBank bBank;
bBank.init( BBankSizes, BBankIndexes, BBankData, 2 );

L'implémentation des méthode getNbrNodes et getDataPtr est la suivante:

byte BehaviorBank::getNbrNodes( int idx )
{
  byte ret = 0;
  if ( idx <= this->totalElements )
  {
    ret = pgm_read_byte_near( this->behaviorIndexesSizes + idx );
  }
  return ret;
}

char* BehaviorBank::getDataPtr( int idx )
{
   if ( idx <= this->totalElements )
  {
    int pos = pgm_read_word_near(this->behaviorIndexes + idx);
    return this->behaviorDatas + pos;
  }
  return NULL;
}

Ensuite, le code lors de la désérialisation dans le noeud "proxy" ayant accès à cette instance de BehaviorBank est:

if ( this->bBank.getNbrNodes(mePtr->data) <= this->b_tree.getFreeNodes() )
{
  char* behavSer = this->bBank.getDataPtr( mePtr->data );
  if ( this->b_tree.deserialize_flash( this->visitor.getIndex(), behavSer ) == false )
    return false;
} 

Il reste encore un peu de nettoyage dans mon projet avant de le partager mais il est maintenant fonctionniel avec un ensemble restreint d'éléments de test. Il me reste aussi à le faire compiler pour architecture SAMD en utilisant quelque directive de compilation.


Aucun commentaire:

Enregistrer un commentaire