Bonjour,
Pour me présenter rapidement, je suis enseignant et amené à enseigner l'informatique. Je maîtrise plutôt bien la programmation python ou les technoweb et BDD. Par contre, je n'ai jamais touché un arduino... si ce n'est depuis quelques jours pour commencer à comprendre comment ça fonctionne.
Afin de monter en compétences, je me suis fixé un projet mais je ne sais pas trop quels choix faire pour orienter le projet dans la bonne direction.
Mon projet est le suivant : je souhaite pouvoir lire des fichiers midi avec un arduino. Le son est directement envoyé sur des petites enceintes. Je sélectionne le fichier musique ainsi que l'instrument avec mon smartphone. Connection bluetooth.
Concernant le stockage des fichiers, les choix qui s'offrent à moi :
- S1 : Je stocke les fichiers sur une carte SD connectée à l'arduino.
- S2 : Je stocke les fichiers sur mon smartphone.
- S3 : Je stocke les fichiers sur un serveur avec une base de données pour gérer le tout.
Concernant l'interface utilisateur:
- I1 : Je développe une appli qui permet de choisir le morceau, choisir l'instrument et accessoirement régler le volume.
- I2 : Je développe une interface web avec les mêmes fonctionnalités.
Malgré l'inconvénient de devoir avoir du réseau, la combinaison S3-I2 est la plus simple pour moi en terme de développement. C'est la partie que je maîtrise. Je vais donc commencer par là. Je développerai les autres combinaison plus tard.
Alors comment l'articuler avec Arduino ?
Une fois le fichier sélectionné, comment l'envoyer à l'arduino ? C'est en php ?
Est-ce que le fichier MIDI est téléchargé, enregistré sur une carte SD connecté à l'arduino qui ensuite envoi la lecture ? Comment l'arduino lit du midi ?
Je précise que j'ai un arduino Uno et un module HC-06.
Merci pour vos éclairages.
Bonjour,
J'ai maintenant une interface web qui me permet d'accéder à ma base de données et aux fichiers MIDI stockés sur mon serveur.
L'arduino est équipé du module bluetooth HC06. J'arrive avec une petite appli à connecter le bluetooth et allumer une led. La communication fonctionne.
Comment, à l'aide de mon smartphone, envoyer un fichier MIDI à l'arduino en bluetooth ? Suis-je obligé de passer par une appli ou je peux directement le gérer via le php ?
A priori ça sous-entend : enregistrer le fichier MIDI sur le smatphone dans un premier temps et dans un second temps l'envoyer à l'arduino. Non ?
Merci pour vos réponses.
La Uno n'est pas capable de synthétiser les sons à partir des infos MIDI. Il faut un module style VS1053 ou un synthétiseur externe.
La Uno n'a que 2K de RAM c'est peu pour stocker un fichier MIDI.
La carte me parait un peu inadapté pour ce projet.
J'ai une carte avec lecteur MicroSD (adafruit) pour stocker ce que je veux ainsi qu'une carte stereo amplifieur (adafruit Max9744) à disposition.
Je me dit que c'est peut-être un peu c** de devoir à chaque fois télécharger le fichier midi, l'écrire sur la carte puis le jouer... Même si ce n'est pas lourd, autant le stocker définitivement sur la carte.
Du coup il faut que j'envisage la solution suivante :
- Mes fichiers sont stockés sur la carte SD de l'arduino.
- par BT j'envoie la liste au smartphone dans une appli App Inventor.
- Je sélectionne le fichier via l'appli et j'envoie l'info à l'arduino qui le joue.
J'arrive à lister mes fichiers mais il faut faire remonter la liste dans l'appli... je cherche de ce côté là, si vous avez des pistes, je prends ! Merci d'avance.
J'utilise la librairie SdFat32.
La commande sd.ls("/MIDI",LS_R); affiche bien la liste des fichiers contenus dans le dossier MIDI.
Je n'arrive pas à faire remonter ça sous forme de liste dans l'arduino.
J'ai cru comprendre qu'en terme de mémoire, je ne peux pas construire une liste dans l'arduino et l'envoyer ensuite. Est-ce que vous confirmez ça ? Merci.
Remarque : il y a un code qui fonctionne ici (Lister les fichiers d'une carte SD) mais avec SD et pas SDFAT. Du coup les noms des fichiers sont tronqués.
Bonjour afigiboto
J'ai "détourné" l'exemple listfiles de la bibliothèque SD.h et ça donne pour un contenu de MIDI:
DSL-LTL.STA
DSL-120.IDL
DSL-120.STA
DSL-180.IDL
DSL-180.STA
DSL-BIG.IDL
DSL-BIG.STA
DSL-LTL.IDL
Cette liste à envoyer à Bluetooth:
DSL-LTL.STA,DSL-120.IDL,DSL-120.STA,DSL-180.IDL,DSL-180.STA,DSL-BIG.IDL,DSL-BIG.STA,DSL-LTL.IDL,
A séparer dans MIT App Inventor avec une fonction split.
Le programme:
/*
Name: AF_FileDirToBluetooth.ino
Created: 16.01.2025
Author: jpbbricole source listfiles de SD.h
*/
#include <SD.h>
#include <SPI.h>
const int chipSelect = 53;
String btFileList = ""; // Liste des fichier pour Bluetooth
const String btSeparateur = ","; // Séparateur entre les noms de fichiers
File root;
void setup()
{
Serial.begin(115200 );
while (!Serial);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed");
while (true);
}
Serial.println("initialization done.");
root = SD.open("/MIDI");
btFileList = printDirectory(root, 0);
Serial.println("\nA envoyer a Bluetooth");
Serial.println(btFileList);
}
void loop()
{
}
String printDirectory(File dir, int numTabs)
{
String sdDir = ""; // Initialisation de la liste
while (true)
{
File entry = dir.openNextFile();
if (! entry)
{
break;
}
Serial.println(entry.name());
sdDir += entry.name() + btSeparateur; // Liste pour Bluetooth
if (entry.isDirectory())
{
Serial.println("/");
printDirectory(entry, numTabs + 1);
}
entry.close();
}
return sdDir;
}
A+
Cordialement
jpbbricole
Merci jp, mais ton code fonctionne avec SD et pas SDFat, les fichiers avec un nom long ne sont pas gérés.
Dans la doc de SDfat, j'ai trouvé le code suivant qui fonctionne : il retourne bien la liste des fichiers via BT, et je n'ai plus qu'à split avec les /. Mais ça ne fonctionne que si je le mets dans le setup(). J'ai essayé de créer une fonction dédiée, mais ça ne fonctionne pas. Du coup, avec mon appli, je relance le setup()... pas terrible.
if (!sd.begin(SD_CONFIG)) {
sd.initErrorHalt(&Serial);
}
// Open root directory
if (!dir.open("/MIDI")) {
error("dir.open failed");
}
// Open next file in root.
// Warning, openNext starts at the current position of dir so a
// rewind may be necessary in your application.
while (file.openNext(&dir, O_RDONLY)) {
file.printName(&Serial);
file.printName(&HC06Serie);
HC06Serie.print('/');
if (file.isDir()) {
// Indicate a directory.
Serial.write('/');
}
Serial.println();
file.close();
}
if (dir.getError()) {
Serial.println("openNext failed");
} else {
Serial.println("Done!");
}
Oui, en effet, mets moi tout ton sketch, en fin d'après-midi je regarde ça.
A+
jpbbricole
Mercijpbbricole, ça marche nickel !!!!
J'ai résolu le problème, ça marche du premier coup, il faut passer DIR\n via l'app et aussi mettre DIR\n dans l'arduino... J'avais mis que DIR dans l'arduino.
A quoi il sert ce retour à la ligne dans une commande ?
Oui, il faut faire ainsi:
Non, le test doit être: if(cmdRx == "DIR")
De toute façon, à la réception, le \n est supprimé par cmdRx.trim();
Attention, c'est un \ (backslash) pas un / (slash)
A en signaler la fin de la commande.
Si tu as un doute, mets moi ton sketch ainsi que le fichier de ton application MAI , AIA (à zipper).
PS: une légère modification dans le programme, change:
if(cmdRx == "PLAY")
par
else if(cmdRx == "PLAY")
A+
Cordialement
jpbbricole
Merci JP pour l'aide et les explications.
Tout marche nickel.
J'ai résolu le problème via App Inventor. A la connection du BT, j'envoie la commande DIR\n automatiquement. Ce qui fait que quand je l'appelle via un bouton, ça fonctionne direct.
J'ai rajouté des \n à chacune de mes commandes... ça marche mieux. Sinon j'avais une latence pour allumer une led par exemple.
Prochaine étape : ça concerne app inventor. Comment récupérer une liste de ma BDD SQL dans un listePicker... bon c'est pas de l'arduino. Pour l'arduino, j'attend la carte amplificateur pour coder la lecture. A très bientôt pour sûr !! Et encore merci.
Bonsoirafigiboto
Cette latence (1000 ms) provient du fait que la terminaison de la commande ne "fonctionnait" pas, c'est le timout qui terminait la commande.
Bonne nuit.
jpbbricole
Bonjour JP,
Ok compris. Merci.
Petite question subsidiaire :
Dans ton code, la variable cmdRx n'est pas déclarée, n'est pas typée, n'est pas initialisée.
Concernant une variable en arduino, est-ce comme en python, elle est déclarée et initialisée lors de son premier appel ?
Est-ce aussi que son type peut changer ? Dans l'absolu, puis-je mettre dans la même variable aussi bien une liste qu'un entier ?
Bonne journée.
Bonjour afigiboto
Oui, elle est typée et déclarée ici, elle est locale à la procédure void cmdExecute(String cmdRx)
Non, par contre on peut extraire un entier d'une String, pour autant qu'il n'y a que des chiffres dans la String sinon = 0.
Je t'ai mis un exemple, comment envoyer une commande, avec un paramètre numérique comme PLAY12 pour jouer la plage 12.
Dans un premier temps, on reconnaît le commande:
else if(cmdRx.startsWith("PLAY"))
Dans un deuxième temps on supprime la commande pour ne garder que le 12 en String;
cmdRx.replace("PLAY", "")
A ce stade cmdRx vaut une String 12 que l'on transforme en numérique int:
int midiPlage = cmdRx.toInt();
Le programme:
void cmdExecute(String cmdRx) // Commande reçue du moniteur ou de Bluetooth
{
cmdRx.trim(); // Nettoyage
cmdRx.toUpperCase(); // En majuscule
cmdRx.replace(" ",""); // Supprimer les espaces
if(cmdRx == "DIR")
{
dirToBluetooth();
}
else if(cmdRx.startsWith("PLAY")) // Exemple pour commander la plage 12 PLAY12
{
cmdRx.replace("PLAY", ""); //Pour ne gerder que le paramétre 2
int midiPlage = cmdRx.toInt(); // On transforme le 12 String en 12 int
Serial.println("Jouer un fichier MIDI, plage " + String(midiPlage));
}
else
{
Serial.println("Commande inbconnue !!!:" + cmdRx);
}
}
PS: Je ne connais pas du tout Python 
A+
Cordialement
jpbbricole
Autant pour moi, je n'avais pas vu le typage dans le paramètre de la fonction.
Merci pour l'explication et l'astuce du PLAY12... intéressant !
Bon, nouveau problème.
Voilà ce que je cherche à faire :
- Une fonction sur arduino qui, lorsque je l'appelle, me retourne l'adresse MAC du module Bluetooth HC-06.
- Utiliser cette adresse pour obtenir l'autorisation d'accéder à la base de données.
Le problème c'est que pour obtenir l'adresse MAC, je passe par AT+ADDR, or le mode AT nécessite une connection sur le pin KEY du module HC06.
Y'a-til une solution sans passer par AT ?
Merci
Mon code de test :
#include <SoftwareSerial.h>
SoftwareSerial BTSerial(10, 11); // RX, TX (Pin 10 et 11 de l'Arduino)
void setup() {
Serial.begin(9600);
BTSerial.begin(38400);
delay(1000);
BTSerial.println("AT+ADDR?");
}
void loop() {
if (BTSerial.available()) {
String reponse = BTSerial.readString();
Serial.println(reponse);
}
}
Bonjour afigiboto
C'est juste pour une fois ou c'est parce que le récepteur BT est susceptible de changer.
Expliques ce que tu veux faire.
Cordialement
jpbbricole
Mon arduino me sert de lecteur musical. Je veux lire, au choix, un fichier midi :
- stocké sur la carte sd de l'arduino
- stocké dans le téléphone
- stocké sur un serveur
J'ai une appli (App Inventor) qui me permet de faire ce choix.
Je veux, lorsque je me connecte au serveur, avoir une sécurité. A savoir que seuls les utilisateurs autorisés peuvent accéder à la BDD et donc aux fichiers.
Mon idée est de se servir de l'adresse MAC du module HC06 comme clé de sécurité. C'est moi qui, à l'initialisation de l'arduino, récupère cette adresse MAC et la met dans la base.
J'envisage ainsi la connexion au serveur :
- Dans l'appli, on clique sur le bouton connection
- L'appli communique en BT avec l'arduino et récupère l'adresse MAC du module BT
- La requete sql part au serveur accompagné de la l'adresse MAC
- Authentification dans la BDD et retour de l'information.
Bonjour afigiboto
Puis que ceci pose problème, pourquoi ne pas "graver" une adresse MAC dans l'EEPROM du UNO, "gravure" qui se ferait par une commande comme MAC88:13:BF:6A:A0:56.
A+
Cordialement
jpbbricole
Très bonne idée, je vais faire comme ça. C'est encore mieux !!!! Thanks' !