arduino.tone()??

ou comment faire vibrer un Piezo branché à l'Arduino depuis Processing

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour à tous !!! Me voila fraîchement débarqué sur ce citron tout aussi frais !

Ma première question est d'abord d'ordre pratique : où placer une question sur la liaison Arduino/Processing? Plutôt matériel ou programmation? (J'ai eu le même dilemme sur OC pour une question sur l'API Python de Blender : ignoré d'un côté par les utilisateurs de Blender qui ne programmait pas, et boulé de l'autre par les programeur Python qui s’empaillait le caillou de Blender… et je réitère avec une autre utilisation bâtarde x)) Bref j'ai choisi programmation parce que voici mon problème :

Je souhaite faire vibrer un buzer piezo branché sur Arduino UNO depuis une fenêtre graphique Processing. En gros, lorsque ma souris est en haut de la fenêtre, le signal envoyé est de haute fréquence donc le son est aigu. Inversement, en bas, basse fréquence, son grave. Pas de problème avec les branchements électroniques très simples. Pour le code, j'ai déjà fait varier la luminosité d'une LED depuis Processing grâce au script Firmata intégré à Arduino.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//Code Processing

import processing.serial.*;
import cc.arduino.*;

Arduino arduino;

float lum;

void setup(){
  arduino=new Arduino(this,Arduino.list()[0],57600);
  arduino.pinMode(9,Arduino.OUTPUT);
}

void draw(){
  background(204);
  lum=map(mouseY,100,0,0,255);

  arduino.analogWrite(9,int(lum));
}

Je me suis donc dit qu'il suffisait de remplacer dans ce code processing la fonction arduino.analogWrite() par arduino.tone(), mais voila : la fonction arduino.tone() n'existe pas…

J'ai cru comprendre ici http://forum.arduino.cc/index.php?topic=195927.0 que la library Firmata n'était pas complète et qu'il valait mieux écrire son propre protocole de communication entre Arduino et Processing mais je doute que ce soit très simple… J'ai un niveau assez rudimentaire de Processing et d'Arduino donc j'aime bien les librairies toutes cuites (oui je sais : l'ignorance volontaire, ça craint ^^).

Voila, que pensez-vous de ce problème? Est-ce qu'il existe d'autres librairies avec des fonctions équivalentes à tone() capable de produire un signal à une fréquence précise accessible depuis Processing? ou bien est-ce qu'il existe d'autre manière de faire faire quelque chose à l'Arduino depuis Processing?

Bonne journée à tout les lecteurs de ce messages (et même au autre enfaîtes (et puis non !)). Merci !

Ulic3

+0 -0

perso, j'aurais posté dans matériel, parce que le probleme se trouve sur arduino, et dans une lib arduino. et comme tu l'as dit plus tot, la plupart des dev' informatique "s'empaillent le caillou" d'arduino, et si j'étais vache, je dirais que c'est pareil pour processing, mais ce serait troller…

sinon, bonne nouvelle, c'est assez simple, et y'a pas besoin d'une lib pour résoudre ton probleme: tu branche ton buzzer sur une sortie PWM de ton arduino, et…

  • le volume est réglé par le rapport cyclique de ta PWM (rapport cyclique en anglais c'est duty cycle)
  • la fréquence de la note c'est la fréquence de la PWM

je ne saurais pas mieux te dire comment faire là maintenant sur arduino, parce que je connais très mal cette plateforme, mais y'a surement de quoi bosser avec ce que je t'ai donné.

Oui. Non. Attends, je regarde mieux et je te dis.

+0 -0
Auteur du sujet

Merci de ta réponse !

Je comprends très bien que ces langages ne passionnent pas tout le monde, mais permettent vraiment aux néophytes (étudiant en design entre autre) de faire du prototypage très simplement et comprendre dans les grandes lignes comment les appareils électroniques qui nous entourent fonctionnent. Ce qui me semble important quand on est amené à travailler dessus xD

Quand y est de mon problème: je voyais comment régler le duty cycle du PWM avec la fonction analogWrite() qui permet de faire varier entre 0 et 255 la tension moyenne de sortie et heureusement google m'a fourni ce lien pour faire varier la fréquence du PWM. J'étudie tout ça et te tiens au courant. Si j'ai d'autres questions je vais ouvrir une nouvelle conversation dans la partie matérielle.

Merci pour la piste de recherche !

+0 -0

j'ai regardé vite, arduino (enfin l'entreprise…) n'a pas fait de lib qui permette de changer la fréquence facilement sans perturber tout le fonctionnement du reste de la carte. sans compter que tu n'auras que quelques fréquences de disponibles avec cette méthode (clique c'est un lien)

et ça, ça craint pas mal pour toi, parce que du coup y'a des chances que tu aie à te plonger un peu dans le fonctionnement intérieur d'un module PWM, si tu veux vraiment faire mieux.

Oui. Non. Attends, je regarde mieux et je te dis.

+0 -0
Auteur du sujet

Je suis arrivé au même lien et testé cette fonction qui en effet offre très peu de possibilités. De plus, je ne sais pas non plus comment l’appeler depuis Processing. Je ne sais pas comment fonctionne la fonction tone() en détail mais elle doit bien agir sur la fréquence du PWM pour faire vibrer un buzer à une fréquence précise. Je fais quelque recherche dessus car je pense que c'est la meilleur façon d'arriver au résultat voulu et que le problème se pose dans la communication entre Processing et Arduino que je ne comprend pas du-tout

(la plus part des tutoriaux pour arduino, et processing d’ailleurs, sont quand même très basiques et la marche est très hautes avec la doc officielle en anglais et les projets très complexes… j'ai suivi le tuto d'Esikimon sur OC et c'est un des seul qui pousse un peu les notions de communication série, de comptage binaire… le dialogue reste la meilleur façon d'apprendre, merci de participer !

+0 -0

Salut !

Comme d'hab mon petit rappel et auto-promotion : Le tuto Arduino n'est pas du tout a jour (nouveau chapitre, nombreuses corrections etc…) je te conseille vivement de le lire sur mon blog (et peut etre un jour sur ZdS).

Sinon, je n'ai jamais fait de lien entre Arduino et Processing. Comment ca marche ? Tu fais juste un programme sous Processing et rien sur Arduino ?

Car effectivement la fonction Tone() est nickel sur Arduino pour ce que tu cherches. Avec une liaison serie tu pourrais envoyer une valeur et presque simplement la recopier dans Tone dans l'Arduino.

ZdS, le best du Zeste ! Tuto Arduino, blog, etc

+0 -0

ha mais tu fais tout depuis processing? houlàààà je comprends mieux pourquoi c'est difficile!!!

selon moi, processing doit juste envoyer des coordonnées, (ou une fréquence, pour plus de portabilité) par une voie série à l'arduino, qui se contente de recopier en boucle le résultat dans une fonction Tone(), c'est beaucoup plus simple…

Oui. Non. Attends, je regarde mieux et je te dis.

+0 -0
Auteur du sujet

Salut Eskimon ! j'ai lu la fin de ton tuto sur ton blog et c'est d'ailleurs là où j'ai entendu parler de ZdS. :)

Pour la liason entre Processing et Arduino, il y a la manière simple :

  • Uploader le code Firmata (disponible dans les exemples) sur l'Arduino (et c'est tout).
  • Importer sur Processing les librairies processing.serial et cc.arduino et deux trois trucs pour creer un objet arduino.
  • Appeler une fonction de l'arduino par un code genre arduino.fonction().

le code que j'ai partagé dans mon premier message en est un exemple.

Après il y a la manière compliqué que me propose Remace où il faut aussi programmer sur Arduino mais c'est sur qu'elle permet sans doute de tout faire, alors je m'y lance :D

Ps: c'est une peu compliqué que "Les simples retours à la ligne ne sont pas pris en compte" et je n'arrvie pas à faire des listes à puces :( [EDIT] merci Remace pour le tuto ^^

Édité par Ulic3

+0 -0

pour les listes à puces, il suffit simplement de de:

  • faire 2 retours à la ligne normaux (juste entrée)
  • faire un seul retour par nouvelle puce (et le petit + a chaque nouvelle puce aussi mais ça tu l'as compris je pense)
  • et faire un double retour pour finir proprement avec un bel espace

simple non?

sinon, si j'ai vraiment un conseil, fais juste une acquisition de la postion de la souris et l'envoi des données dans une voie série dans le programme processing (éventuellement si tu y tiens un conditionnement, pour que l'arduino ait juste à recopier les valeurs…) , et fais tout le reste dans l'arduino, c'est beaucoup plus simple.

Oui. Non. Attends, je regarde mieux et je te dis.

+0 -0
Auteur du sujet

Bon OK, je jette l'éponge… je me suis relu le tuto de Eskimon sur la communication série et bouffer la référence Serial Processing et celle de Serial Arduino et il y a trop de… mots x|

bref j'en suis arrivé à ça :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// code Processing
// Example by Tom Igoe

import processing.serial.*;

// The serial port:
Serial myPort;       

// List all the available serial ports:
println(Serial.list());

// Open the port you are using at the rate you want:
myPort = new Serial(this, Serial.list()[0], 9600);

// Send a capital A out the serial port:
myPort.write(65);

la com à l'aire de bien se faire puisque Processing m'indique le COM3, emplacement de mon Arduino UNO

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
//code Arduino
int incomingByte = 0;   // for incoming serial data

void setup() {
        Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
}

void loop() { if (Serial.available() > 0) {
                // read the incoming byte:
                incomingByte = Serial.read();

                // say what you got:
                Serial.print("I received: ");
                Serial.println(incomingByte, DEC);
        }
}

après un sévère "serial port already in use" indiqué par arduino puis un léger "port busy" de processing maintenant tout semble fonctionner mais rien ne s'affiche de la fenêtre de com série de l'ardunio pourtant dès que j'envois manuellement une chaine de caractère via la fenêtre send, arduino m’indique fièrement ce qu'il a reçu par voie série (converti en décimal selon la table ASCII) donc le code arduino fonctionne ! Le problème doit venir de processing qui n’envoie rien par la voie série et j'ai cru comprendre que vous ne programmez pas avec processing.. alors je m'en vais relire la référence processing puisque le peu d'exemple que je trouve sont postés sur les forums parce-qu’ils ne fonctionnent pas.. –'

+0 -0

A mon avis tu as bien compris les choses.

Juste un rappel : une voie serie est "exclusive", si tu l'utilises/l'ouvre via l'IDE Arduino, alors ton code Processing n'aura pas le droit de l'ouvrir en meme temps.

Du coup avec le code que tu as dans Processing, ca semble OK pour envoyer un caractere, par contre tu n'as rien pour lire le retour fait par ton Arduino donc on se retrouve avec juste un envoi, sans information sur si ca marche ou non (a part la petite led Tx/Rx Arduino qui doit flashouiller quand tu lance le programme processing)

ZdS, le best du Zeste ! Tuto Arduino, blog, etc

+0 -0
Auteur du sujet

Justement, le code fournit par la référence processing ne fonctionnait pas car la fonction serial.write n'était pas dans la void draw donc jamais rafraîchit. Si je modifie le code et rajoute un delay de une seconde, MIRACLE les leds Tx et Rx clignotent joyeusement toute les secondes mais en effet je ne peux toujours pas ouvrir le serial monitor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
//voici le nouveau code Processing
import processing.serial.*;

// The serial port:
Serial myPort;       

// List all the available serial ports:
//println(Serial.list());


void setup(){
  // Open the port you are using at the rate you want:
  myPort = new Serial(this, Serial.list()[0], 9600);
}

void draw(){  
// Send a capital A out the serial port:
myPort.write(65);
delay(1000);
}

Tu penses que la donnée est bien reçu par l'Arduino mais ne peux pas l'indiquer puisque c'est Processing qui a ouvert la voie? Je test deux trois moyens de savoir si c'est le cas mais d'abord : pose goutté :)

merci de ton aide!

+0 -0
Auteur du sujet

j'ai suivit ta technique en utilisant ton code

pour write(65) Processing m'affiche en boucle une série de valeur

(73,32,114,101,99,101,99,101,105,118,101,100,58,32,54,53,13,10) 16 valeurs

si je change la valeur que j'envois à la base certaines valeurs varient par exemple si je fais write(100) :

(73,32,114,101,99,101,105,118,101,100,58,32,49,48,48,13,10) 17 valeurs

je ne comprend pas à quoi correspondent chaque valeur? est-ce des bits, des bytes..? il doit y avoir des tonnes d'information rajoutées ensuite par arduino?

Édité par Ulic3

+0 -0
Auteur du sujet

Ah ok "I received: 65" ou "100" xD. Mais c'est moi qui n'est pas malin, j'avais oublié le petit message sympathique destiné au monitor ^^ sans fioriture, ça fonctionne mieux x)

Si je convertis la valeur ASCII par un char(int()), j'obtiens bien, par exemple:

  • 6
  • 5
  • 6
  • 5

que de progrès :! :D

+0 -0

et maintenant, il ne te reste qu'à faire un petit bidouilage pour recevoir des nombres un peu grands (comme une fréquence, par exemple) qui soient un équivalent de la position de souris à la place.

ou alors, si t'as pas envie de bidouiller, un char peut aussi être un petit nombre (255 maxi). et ça, c'est badass pour toi, parce que tu peux via un produit en croix envoyer un caractère (qui représente la position de ta souris) par la voie série. et faire ça en boucle. et côté arduino, y'a plus qu'à recopier la valeur dans la fonction tone() avec un multiplicateur, style 100 (250*100=25000, soit un peu plus que la limite de l'audible chez l'adulte);

Oui. Non. Attends, je regarde mieux et je te dis.

+0 -0
Auteur du sujet

Haou ! J'avoue ne pas être encore très à l'aise avec l'ASCII et toutes ces conversions mais le problème semble se décanter et la solution plutôt élégante. Je tente de terminer ça tout seul (juste pour l'ego ;) ) Vous devriez avoir de mes nouvelles avant le weekend.

Merci encore pour votre aide, j'ai compris pas mal de truc depuis quelque jours :)

Édité par Ulic3

+0 -0

conversion? ASCII? hein? j'en ai jamais fait une de ma vie, et pourtant des problèmes dans le style du tien, j'en ai résolu un paquet (et même deux, si j'étais taquin)…

pour t'aider, dans du code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
char car = 'A'; /* une variable qui contient la lettre A, et c'est représenté dans la variable 
comme un nombre qui vaut... 
(petit temps pour aller lire une table de conversion) 65.*/

/*Mais!!! comme tu n'as pas envie de faire les conversions, 
partant du principe que tu as un nombre assez petit, tu peux très bien faire ça: */
char position = 65;
serial.print(position);
/*l'arduino, lui recevra 65, comme toujours d'ailleurs. et c'est uniquement au moment de l'afficher 
ou de s'en servir pour un humain, et si on lui demande de le faire, qu'il le convertira en 'A'. 
en fait, en tant que dev', on le voit pas, parce que c'est déjà fait dans les fonctions d'affichage de 
base.*/

pour conclure sur du concret, parce que j'ai pas mal divagué, et que c'est surement pas clair, l'alphabet, c'est un truc qui est uniquement pour nous, les humains, parce que pour un ordi, ou n'importe quoi d'électronique, une lettre c'est un nombre, et la conversion est faite uniquement au moment de l'affichage.

et donc transmettre un caractère (donc un nombre entre 0 et 255), et le multiplier par 50 ou 100 une fois arrivé sur l'arduino pour avoir un son dont la note dépend de la position de ta souris, c'est largement faisable. reste le découpage de l'écran en 255 zones à faire dans processing (multiplier la valeur de la souris par 255, puis diviser par screen.size() se fait facilement).

tu te rends peut-être pas compte mais t'as déjà tout fait là. y'a plus qu'à faire de la finition, c'est tout (envoyer des données sensées au lieu d'envoyer 65 ou 100 dans la voie série, et du côté de l'arduino, les utiliser).

Édité par remace

Oui. Non. Attends, je regarde mieux et je te dis.

+0 -0
Auteur du sujet

Merci Remace pour l'astuce des Caractères! car…

Tadam !

Quand je parlais de conversion c'était justement ce jeu entre entier et caractère qui au final n'était fastidieux que lors d'un retour via Processing. Mais là, tout c'est fait simplement et tout marche !!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
//code Processing
import processing.serial.*;
Serial myPort;       

void setup(){
  myPort = new Serial(this, Serial.list()[0], 9600);
}

void draw(){  
  int positionY=int(map(mouseY,100,0,0,225));
  char outcomingByte=char(positionY);
  myPort.write(outcomingByte);
  delay(1);
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
//code Arduino
int incomingByte = 0; 

void setup() {
  Serial.begin(9600);
}

void loop(){ 
  if (Serial.available() > 0) {
    incomingByte=Serial.read();
    int note=0;
    note=incomingByte*20;
    tone(9,note);
  }

}

Forcément la forme du code reste à être peaufinée et les variables ajustées mais comme il me reste une interface graphique sur processing à faire et surtout ajouter un noTone, je vais sans doute mettre tout ça dans des fonctions. En tout cas vraiment super, au lieu d'utiliser le "protocole" firmata très limité, tout semble possible :D

Édité par Ulic3

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte