Hors-série. De l’aléatoire. Partie 4.

A priori, je termine ici mon hors-série un peu technique, par cet article. 

Est-il intéressant d’intégrer de l’aléatoire dans nos séquences ? Si oui, comment l’intégrer ?

Spoiler : oui, c’est intéressant.

Découvrir de nouvelles configurations de fréquences « qui fonctionnent » au « hasard », se laisser surprendre par des enchainements étonnants, auxquels on aurait pas forcément pensé au départ… C’est intéressant pour pas mal de raisons, finalement ; pour des tests oui, en binôme, on peut facilement noter ce qui « fonctionne », mais peut-être pour des programmes complets aussi.

L’idée, c’est de laisser une marge au hasard, c’est de le contraindre, de le borner. C’est à priori nécessaire. Si on ne borne ni la durée des séquences ni les fréquences, on a toujours le risque de passer une bonne heure et demie sur une fréquence de 1 Hz en onde carrée avec un rapport de cycle de 50%, et, entre nous, ça ne risque pas d’être extraordinairement intéressant.

Il faut gérer le temps qu’on laisse à chaque séquence, et lancer une génération de nombres aléatoires, dans un intervalle défini précisément, pour envoyer ces nombres à une fonction qui va contrôler nos leds pendant cette séquence.

Il y a, bien entendu, un million de façon de procéder, du moins optimal au plus optimal, du plus sommaire au plus beau mathématiquement parlant.

Voici celle que j’ai choisie, ayant en tête quatre caractéristiques :
– cela doit fonctionner. Ça parait trivial, mais trouver le plus beau mathématiquement peut faire perdre un temps monumental au détriment de quelque chose de très simple : il faut que ça fonctionne, c’est ce que l’on attend.
– cela doit être assez simple (je débute !)
– cela doit être lisible et relativement clair
– cela doit communiquer avec un ordinateur, pour récupérer les informations qui nous intéressent (a minima, le programme doit nous envoyer la fréquence qui est en cours, avec son rapport de cycle – je ne travaille qu’en ondes carrées pour l’instant)

Mon point de départ se base sur les points suivants.

Sur un Arduino, random(min, max) va générer un nombre pseudo aléatoire qui aura pour borne inférieure (inclue) le nombre « min », et pour borne supérieure (exclue) le nombre « max ».

Si je tape random(1, 21), la fonction va donc me renvoyer un entier compris entre 1 et 20 inclus.

J’ai trouvé expérimentalement qu’une valeur de fréquence comprise entre 6 Hz et 21 Hz d’ondes carrées « fonctionne » plutôt bien (ça se discute, évidemment).

J’ai également trouvé qu’une valeur de rapport de cycle comprise entre 0.2 et 0.8 fonctionnait également.

Je vais donc créer une fonction qui va me générer tout cela, et qui va me renseigner via le port série.

Capture d_écran 2017-11-29 à 01.18.12

frequence_aleatoire et dc_aleatoire, définis en variables globales plus haut, vont donc se voir assigner comme valeur les nombres précédemment calculés.

Ils peuvent maintenant servir pour la fonction de contrôle.

Je dois lancer ce programme avant la fonction, au risque d’avoir un comportement chaotique (mais aussi intéressant) : celui dans lequel la fonction prendrait à chaque tour de boucle une nouvelle valeur.

Je dois également prévoir un arrêt.

J’aimerais aussi régler un autre problème, au passage. J’ai un million de lignes de code pour gérer toutes mes séquences, à base de lourds (mais efficaces) while (i<100), while (i<200) etc… pour délimiter chaque séquence.

Ne puis-je pas rassembler toutes ces valeurs 100, 200 etc… en un tableau qu’il suffirait de parcourir pour retrouver toutes ces valeurs ?

Si !

Capture d_écran 2017-11-29 à 01.18.22

Comment parcourir ce tableau ?

Très simple, je définis un compteur calé sur l’indice, et je l’incrémente simplement en fonction de ce que je souhaite obtenir.

tableau_duree[compteur_tableau] vaudra donc ici :
– 100 pour une valeur de compteur_tableau égale à 0 (un indice de tableau commence à 0)
– 200 pour une valeur de compteur_tableau égale à 1,
– 300 pour une valeur de compteur_tableau égale à 2,
– 500 pour une valeur de compteur_tableau égale à 3 etc…

Pour tout cela, j’ai finalement pris la solution du « feu vert ». Je déclare un booléen qui me servira de drapeau (« flag » en anglais). S’il vaut « vrai » (en langage machine : 1), alors, je peux lancer toute ma séquence. S’il vaut faux, alors la séquence ne doit pas se lire. Logique binaire classique.

Je dois donc, en français, demander ceci à mon programme :

Le feu est-il vert ?

Si oui, est-ce que la séquence de temps n’est pas dépassée et le feu est-il toujours vert ?

Si oui, lance moi la génération de nombre aléatoire pour assigner ces valeurs aux deux variables que j’ai précédemment définies : frequence_aleatoire et dc_aleatoire.

Maintenant, pendant que le compteur principal i, est inférieur à la première valeur du tableau contenant toutes mes valeurs de « durée » (en fait, des « quantités » définies de i) et pendant que le feu est vert, lance ma fonction avec comme paramètres les deux variables précédemment calculées. Ajoute, en passant, le nombre 1 à ce compteur principal i.

Si le compteur i arrive au bout du compte (ici, i vaudrait 5000, ce qui signifie que nous aurions fait 5000 tours de boucles de la fonction, en tout), et que le feu est toujours vert, alors, passe le feu au rouge.

Sinon, s’il n’est pas au bout du compte, ajoute la valeur 1 au compteur du tableau de durée pour qu’il parcoure la séquence d’après. [On balaye le tableau, et on se trouve donc, en beaucoup moins de lignes de codes, à l’équivalent du : while(i<100), while(i<200)…]

Dans tous les cas, reviens au tout début.

Le feu est-il vert ?

Si oui, est-ce que la séquence de temps n’est pas dépassée et le feu est-il toujours vert ?

Etc…

Mais un contrôleur ne comprend pas le français (j’ai essayé).

Donc je lui ai plutôt dit :

Capture d_écran 2017-11-29 à 01.07.59

Et il semble mieux apprécier.

Au final ?

Au final, et bien, ça fonctionne bien.

Nous avons donc un programme auto-généré qui renseigne au passage sur ce qu’il fait. Pratique !

gen.png

J’ai mis le code complet ici : https://github.com/pierre-ec/raito/blob/master/Arduino/Random1.c


S’il y a des férus dans le coin : on peut aussi se servir de l’astuce du tableau pour coder nos programmes en dur. Toujours en ondes carrées. Sans correction particulière du timing. Sur un Arduino Mega pour profiter des 12 broches PWM.

En effet, on peut se servir d’une fonction basée sur analogWrite() qui contrôle à la fois la luminosité et le flicker en même temps, en lui donnant en paramètre une fréquence, un rapport de cycle, et une « luminosité ».

Voici mon raisonnement :

Le rapport cyclique est défini comme la durée à l’état haut par rapport à la durée de la période de l’onde.

Si j’appelle DC le rapport cyclique (duty cycle), j’ai donc :

DC = Durée à l’état haut / Période de l’onde.

Donc, j’ai aussi, par une simple permutation :

Durée à l’état haut = Période de l’onde x DC

Mais la période de l’onde, c’est aussi 1 divisé par la fréquence de l’onde.

Donc je peux aussi écrire :

Durée à l’état haut = (1/fréquence) x DC

Si je nomme :
– la durée de l’état haut par la variable taf,
– la fréquence de l’onde par la variable fqa,
– et que je multiplie par 1000 le résultat précédent pour obtenir des millisecondes [la fonction delay() prend des millisecondes en paramètre]

J’obtiens :
taf = (1/fqa) x DC x 1000;

Sauf erreur je peux donc écrire :

Capture d’écran 2017-11-29 à 01.47.14.png

Je peux aller plus loin en affectant à chaque led une valeur de luminosité.

En gérant correctement les tableaux, nous avons donc un contrôle entier sur la luminosité de nos 9 leds. Nous avons aussi un contrôle sur la fréquence générale et le rapport de cycle.

Tous les tableaux contiennent des constantes. Les tableaux de fréquences contiennent des floats, ceux de luminosité contiennent des « bytes », des octets [8 bits donc 2^8 = 256 valeurs possibles, de 0 à 255].

 

Capture d_écran 2017-11-29 à 00.06.14

J’ai mis le code complet et commenté ici : https://github.com/pierre-ec/raito/blob/master/Arduino/Arduino%20Mega%20-%20Prog%20Tab.c

On peut également se servir de tableaux pour générer des pseudos ondes sinusoïdales avec un Arduino Due, ou bien un DAC externe.

En fait il faut parcourir des tableaux d’approximations de l’onde sinusoïdale. Plus il y aura de « samples » (ici 120), plus s’approche d’une onde propre. Le delayMicroseconds représente le temps que l’on attend par sample. Pour avoir 1 Hz, on a donc 120 samples à parcourir en 1 000 000 microsecondes. Environ 8333 microsecondes par sample.

En servant d’un tableau, on peut donc envoyer sur deux sorties différentes deux ondes différentes. Une carrée et une sinusoïde par exemple.

Sur un Arduino Due, cela donne ce genre de code :

Ce diaporama nécessite JavaScript.

test(10, 0, 3);

Envoie donc une onde de 10 Hz de type 0 (c’est une sinusoïde) sur la sortie DAC0 et une onde de 10 Hz de type 3 (c’est une carrée) sur la sortie DAC1. Il existe des tableaux déjà codés contenant différentes valeurs, écrites en hexadécimal. Ici je me suis servi d’un tableau officiel de l’Arduino Due, adapté aux 12 bits maximum d’une sortie DAC du Due. 12 bits, c’est 2^12 valeurs possibles, donc 4096 valeurs, de 0 à 4095 en décimal.  Voir ici pour le Waveforms.h.

En observant le Waveforms.h pour l’onde carrée par exemple, on retombe vite sur nos pattes. Reprenons l’exemple de l’onde carrée simple : 1Hz, 50% de rapport de cycle.

0xfff en hexadécimal vaut… 4095 en décimal ! 0x0 vaut bien sûr 0. Si on attend 8333 microsecondes par valeur 0xfff, on attend donc 8333 x 60 = 499 980 microsecondes pour l’état haut (environ 500 ms) et 499 980 microsecondes pour l’état bas (environ 500ms) : nous revoici sur notre onde carrée de 1Hz avec un rapport de cycle de 50%.

On peut bien sûr envoyer aussi une triangle et une sinusoïde en même temps, deux sinusoïdes, etc…

Je n’ai pas encore trouvé de moyen simple pour envoyer deux fréquences différentes sur les deux sorties par ce moyen là, mais j’imagine que ça doit être possible.

Cela peut ouvrir la porte à des générateurs de fréquences indépendants sur des circuits de LEDs indépendants…

Mais c’est une autre histoire !

 

 

 

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s