J'ai développé un contrôleur pour 5 vidéoprojecteurs qui contrôle des fonctions basiques (power, shutter, lampe, etc). Il utilise le protocole TCP.
Il y a des boutons lumineux pour certaines fonctions, et selon le retour d'informations, il allume les boutons ou leds correspondants.
Le arduino est accessible via une page web où on peut modifier son adresse IP, ainsi que les IP de chaque projecteur, moyennant un reset.
Voilà pour la présentation.
Dans la loop il y a notamment une fonction où, chaque seconde, le arduino demande toutes les infos aux machines. Il met 2 à 300ms pour faire le tour complet des projecteurs et demander toutes les infos à tout le monde.
C'est en 3 étapes:
1- Projecteur 1 - question 1
2 - si client dispo, lis son message en retour
3 - traitement d'info et allumage bouton.
1 - Projecteur 1 question 2
etc etc
Voici un extrait de code:
for (byte i = 0; i < 5; i++) {
// ---------- Demande d'infos PWR VP ----------
Serial.print("VP"); Serial.print(i); Serial.println("(PWR?)");
clients[i].print("(PWR?)");
delay(30);
if (clients[i].available()) {
while (clients[i].available()) {
char cmd = clients[i].read();
responsePWR[i].concat(cmd);
}
Serial.print("Réponse VP "); Serial.print(i); Serial.print(" :"); Serial.println(responsePWR[i]);
}
// ---------- Traitement des retours d'info PWR VP ----------
if (responsePWR[i] == ("(PWR!0)") or responsePWR[i].startsWith ("(PWR!000")) { // = VP1 éteint
etatVP[i] = LOW;
etat_led_power[i] = 000;
analogWrite (led_powerR[i], 0);
analogWrite (led_powerV[i], 255);
}
Le problème est qu'avec 1 seul projecteur, pendant ce laps de temps on ne peut rien faire d'autre: Si on appuie sur un bouton pendant ces 300ms, le arduino ne réagit pas à cet appui.
J'en suis à me poser la question si le Arduino est vraiment adapté à ce genre de projet, est-ce qu'un raspberry pi ne serait pas mieux pour un traitement en temps réel (si j'appuie sur un bouton en même temps) ?
pourquoi poster dans les projets finis si ce n'est pas un projet qui est fini?
➜ déplacé dans le forum francophone principal
pour votre question, c'est votre code qui est synchrone. Il faut le rendre asynchrone et lire la réponse quand elle arrive et non pas dans une boucle que vous ne pouvez pas interrompre comme vous le faites avec cela:
Les 30ms sont là pour améliorer la stabilité. Sans ça il y avait des pertes aléatoires et des messages non reçus, ce qui pouvait me donner plusieurs secondes sans réponse.
La solution du feignant serait de remplacer le delay(30) par l'appel d'une fonction qui scrute le bouton pendant ces 30 ms. Si le bouton est enfoncé, il exécute l'action reliée au bouton (en espérant qu'elle même ne dure pas trop longtemps).
1 - Pour gagner du temps, si je lis les données au fil de l'eau et qu'il concat plusieurs réponses d'un coup venant du même serveur, il faudra qu'il cherche plusieurs infos dans le même string.
Seulement je n'ai jamais réussi à faire fonctionner cette fonction, où il "cherche" une suite de caractères à l'intérieur d'un string. J'y ai passé des heures, j'en ai même rêvé
2 (le plus important) -
Aussi court soit ce temps de latence, les boutons doivent avoir la priorité sur tout et exécuter leur fonction, y compris si on appuie pendant ces 200 millisecondes.
Sans compter le fait que si il y a déconnexion sur un des 5 serveurs, l'attente de connexion en client peut bloquer le Arduino jusqu'à 1 seconde. Les 4 autres doivent rester fonctionnels dans ce laps de temps.
C'est surtout cette 2ème contrainte qui est vitale sur ce projet, d'où ma question initiale. Est-ce que le Arduino est capable de gérer cette priorité absolue des boutons, même si il est en train de faire autre chose de bloquant à ce moment là.
Étant complètement novice (c'est mon 2ème projet), je me demande si c'est une bonne idée de continuer ce projet sur Arduino. Est-ce qu'il ne vaudrait pas mieux basculer sur un autre type de carte qui rendrait la chose possible (un Raspberry Pi ?) ou autre chose que je ne connaitrais pas encore...?
Votre MEGA n’a qu’un seul cœur et pas d’OS donc il ne fait qu’une seule chose à la fois et si vous voulez affecter du temps partagé à différentes tâches c’est à vous de le gérer. Le mécanisme d’interruption permet de façon autoritaire de prendre la main sur le processus en cours mais pose des contraintes.
Imaginons que vous soyez dans une requête réseau, il se peut que les interruptions soient bloquées. Si elles ne le sont pas, vous appuyez sur un bouton qui déclenche une interruption pour aller faire autre chose, que se passe-t-il si j’appuie sur un autre bouton pendant cette tâche? …
Vous n’avez qu’un seul cœur donc vous ne réaliserez de toutes façons qu’une seule chose à un instant T
Du coup est-ce qu'une utilisation d'un duo RaspberryPi + Arduino ne serait pas plus judicieux ?
RPi pour la communication réseau, interface web et commandes + arduino pour gérer les 19 PWM et les 12 boutons
Où même Rpi tout seul...?
Y a-t-il des choses à savoir? Est-ce qu'à votre avis ce serait fonctionnel (surtout pour l'histoire de priorité de bouton), vaut-il mieux privilégier une config que l'autre...
faudrait faire des tests et définir ce que vous entendez par votre besoin de temps réel.. le multitâche du RPi pour la gestion des pins n'est pas non plus un foudre de guerre...
quel est le besoin en temps de réaction max quand vous appuyez sur un bouton?
Si déjà la commande part à tous les coups et tout de suite quand on appuie, y compris dans les temps de blocage de transmission d'info, ou pendant la seconde de blocage en cas de reconnexion d'un serveur, ça ira.
Tant que la mise à jour des variables se fait en arrière plan, sans impacter la réactivité de la commande.
Tu peux comme je suggérais plus haut remplacer les delay(n) par un appel de fonction:
void myDelay(duration) { # duration in milliseconds
unsigned long chrono = millis();
bool pushed = false;
while (millis() - chrono < duration) {
bool state = digitalRead(buttonPin); # je suppose un bouton en INPUT_PULLUP qui renvoie LOW si enfoncé
if (!pushed && !state) {
pushed = true;
# Placer ici l'action du bouton
}
}
}
Si tu remplaces delay(30) par myDelay(30), ça scrutera le bouton et lancera l'action en cas d'appui.
Il faudrait connaitre la durée de l'action en question. Supposons qu'elle dure 10ms. Dans ce cas, tu peux insérer aux endroits où tu sais que le code attends quelque chose (connexion à un serveur ou attente d'information) un mydelay(10) qui permettra de lire le bouton à ces moments-là.
Par contre, il faut être sûr que ça ne va pas faire perdre des informations qui arrivent à ces instants...
Une autre solution serait de passer sur un ESP32 qui a 2 cœurs. Tu pourrais dédier un de ces cœurs à la gestion du bouton. En C c'est assez compliqué car je pense qu'il faut faire ça avec RTOS, mais je viens de découvrir Micropython, et là la gestion du multithreading est beaucoup plus simple. Par contre, il faut connaître le Python et refaire le reste du code... (on n'a rien sans rien)
Merci pour le code.
Le problème de l'action est qu'elle dépend du projeteur, son temps de réponse est très variable et j'ai plusieurs modèles de projecteurs qui pourront interchanger leur place (d'ou la page web pour la gestion des IP). Mais en gros la réponse peut monter parfois jusqu'à 30ms.
Je pense passer sur une autre carte pour le code principal. J'ai regardé un peu python et ça n'a pas l'air plus difficile que le C. Il faut juste tout réapprendre..
A quel ESP32 vous pensiez? Le multithreading que ce soit sur Python ou Micropython, c'est la même chose?
J'ai chez moi un Pi 2-B qui traine depuis un moment, il me semble qu'il a 4 coeurs.
Le MultiThread n'est pas réservé au multicœur et d'ailleurs le nombre de thread n'est pas limité par le nombre de coeur.
le problème est plutôt d'avoir une librairie qui implémente les Thread, comme c'est le cas, je crois avec FreeRTOS qui a été porté sur AVR.
Mais cela sera encore plus simple avec un Raspberry est un système Linux ou Windows.
C'est vrai, mais pour éviter tout problème le plus sûr est de séparer les fonctions sur deux cœurs. Sinon ce sera du concurrent.
Il faut choisir soit un ancien ESP32, soit un modèle ESP32 S3. Pas le C3 qui n'a qu'un seul cœur.
Il faudrait savoir si tu peux utiliser l'Arduino pendant ce temps d'attente. Dans le bout de code posté plus haut, je ne vois pas d'attente, si ce n'est le delay(30)