Bonjour a tous, je me tourne vers vous pour vous demander de l'aide afin d'optimiser un programme.
Je réalise actuellement un système de laser-tag (jeux de tir avec des faisceau infrarouge) a base d'Arduino le programme bien que probablement très torturé fonctionne mais la réception des code infrarouge n'est pas fiable.
Lorsque j'utilise un programme d'exemple qui ne se charge que d'afficher les code reçue, aucuns problème tout les tirs sont détecter, mais avec le programme complet incluant l'affichage sur écran alphanumérique, les menus, la fonctions de tir, le son etc, les tirs sont détecter une fois sur sur 5 ou 6.
Je pense que cela provient du temps que le programme met pour faire une boucle.
Ce problème est réellement gênant car du coup le jeu n'est pas fiable.
Voila simplement je souhaiterais que vous puissiez me donnait des idée et me dire si mon code a une réelle lacunes quelque-part.
Salut, désolé mais je ne suis pas allez lire ton code, et je n'ai pas bien compris comment tout ce petite monde fonctionnait, mais il me viens directement une idée assez simple, délégué le travaille à un autre arduino afin qu'il face la détection des tires laser ( si j'ai bien compris ), comme ça il n'en rate pas un seul et transmet directement l'info par port série, étant doté d'un buffer de réception série, tu ne ratera pas de tire même si parfois tu sera en retard sur le traitement et l'affichage d'un nouveau tire, il finira quand même par être traité, puis le temps de latence ne dépassera pas la 1/2 seconde je pense.
Le seul problème c'est de savoir si tu peut intégré un second arduino dans ton montage ( contrainte de place et de prix ).
Bonjour skizoh, alors en gros le montage comprend deux boutons poussoir (tirer et recharger) un afficheur alphanumérique en I²c un buzer puis une led IR couplé a une lentille pour le tir et un récepteur TSOP4856.
La led émet un code joueur (celui du tireur) qui indique a la cible par qui elle a était toucher.
Les deux arduino résoudrais a coût sur ce problème mais la contrainte de prix serait trop lourde, deux arduino par appareil multiplié par au moins 4 appareil ça va faire très cher ^^
lemat:
Je pense que cela provient du temps que le programme met pour faire une boucle.
bonjour
rapidement regardé, le point critique est de ne pas loupé un tir ?
le reste est de la gestion
pourquoi ne pas gerer le photorecepteur dans une interruption ?
tu rentre dans l'interruption lorsque le TSOP reçoit de l'IR modulé
le reste du temps tu gere le cosmetique
Bonjour, ce qui rend critique ce problème c'est que lors d'une partie avec des joueur en mouvement et des tir en rafale, si lorsque la led et le tsop vont se retrouver aligner l'arduino n'est pas à l’écoute les joueur ne pourrons pas se toucher.
J'avait penser au interruption j'ai fait un petit test non concluant le problème c'est que si je ne me trompe pas les broche d'interruption sont la 2 et la 3 (sur une UNO), mais seule la 3 et en PWM, cette broche est malheureusement déjà utiliser par les led IR et la librairie IRremote que j'utilise n'a pas prévue de pouvoir configurer la broche d’émission utilisé.
Lors de mon test j'avait connecté la sortie du tsop a la broche 5 (qui et celle que j'utilise en PWM actuellement) mais aussi a la broche 2 pour détecter l'interruption, mais le programme planté systématiquement a la première interruption je crois que la modulation lancer plusieurs interruption dans un délais très très court.
lemat:
Lors de mon test j'avait connecté la sortie du tsop a la broche 5 (qui et celle que j'utilise en PWM actuellement) mais aussi a la broche 2 pour détecter l'interruption, mais le programme planté systématiquement a la première interruption je crois que la modulation lancer plusieurs interruption dans un délais très très court.
Pourrez tu me montrer un exemple artouste ?
Merci.
quand tu entre dans l'interruption la premiere chose à faire est d'empecher la prise en compte d'un autre evenement
par detachinterrupt et la reatacher en sortie (apres delai et/ou verif de bonne reception).
Je n'ai pas d'exemple là sous la main, mais des meilleurs codeurs que moi vont te repondre
Hum... oui interruption c'est bien mais si tu peut pas bidouiller la lib pour changer de pin tu va rester bloqué sur ce problème..
Pour l'histoire de prix, tu à quand même des arduino bien moins chère, si deux petit peuvent remplacer une gros niveau capacitée, niveau prix tu devrais t'y retrouver !
Je te conseil de testé tout de même si jamais tu est dans une impasse, jete un oeil c'est vraiment abordable :
Tu compare les prix, le mini tu peut le trouver jusqu'à 9, 10€ minimum avec des capacités pas loin d'être similaire et surtout une même vitesse d'horloge donc si tu t'en tire pour 30€ la uno et environs 25, 30€ les deux mini c'est jouable !
En jettant un oeil à ton programme, sans essayer de comprendre à 100% on comprend déjà que ça ne pouvait pas fonctionner : y'a pas mal de delay() déjà, forcement, du temps perdu ... Si tu veux optimiser le temps de réaction d'une manière globale : comme évoqué, l'utilisation des interruptions est quasiment obligatoire. Ensuite une meilleure des interruptions temporelles te permettra de te passer des delay(). Ensuite je vois que ton écran et en i2c, as-tu passer l'arduino en mode 400 khz ? Tu peux utiliser la lib digitalWriteFast pour gagner du temps. Enfin faire ta librairie IR perso peut te faire gagner du temps et l'optimiser pour ton application.
Skizoh j'utilise une arduino UNO pour les prototype le modèle final recevra une Arduino Nano mais je préférais n'utiliser qu'une seule arduino je t'avoue ^^
Je vient de faire quelque essais avec les interruptions en connectant l'entrée pwm 5 du recepteur avec l'entrée 2 pour l'interruption.
L'interruption est bien détecter mais le code reçue n'est pas interpréter.
B@tto:
En jettant un oeil à ton programme, sans essayer de comprendre à 100% on comprend déjà que ça ne pouvait pas fonctionner : y'a pas mal de delay() déjà, forcement, du temps perdu ... Si tu veux optimiser le temps de réaction d'une manière globale : comme évoqué, l'utilisation des interruptions est quasiment obligatoire. Ensuite une meilleure des interruptions temporelles te permettra de te passer des delay(). Ensuite je vois que ton écran et en i2c, as-tu passer l'arduino en mode 400 khz ? Tu peux utiliser la lib digitalWriteFast pour gagner du temps. Enfin faire ta librairie IR perso peut te faire gagner du temps et l'optimiser pour ton application.
Bonjour B@tto la je doit avouer que tu me pose pas mal de colle, comment puis je gérer des interruptions temporelles sans delay() ?
Passer l'arduino en 400Khz je savais même pas que c'etait possible xD
Je vais me renseigner la dessus, ce sera aussi possible sur l'arduino NANO ?
Je vais regarder cette fameuse librairie, pour ce qui est de crée ma propre librairie IR je n'en et pas les compétences lol.
Je pense que la structure du programme n'est pas pensée pour être optimum question temps de réponse.
Ce loop énorme est LE problème.
Il faut écrire ton programme autour de la fonction critique car c'est elle qui conditionne le bon fonctionnement de l'ensemble.
Si tu as une partie de code qui doit être parcourue très régulièrement alors il faut que le reste du code soit découpé de manière à pouvoir être exécuté en tâche de fond. Tout ce qui est affichage (écran LCD, voyants, son, ...) peut supporter un délai dans son exécution et peux aussi être réalisé au cours de plusieurs itération de loop.
Alors j'ai essayé de passer l'arduino en 400Khz (dans le fichier twi de la librairie Wire) c'est bien de ca qu'on parle ? En 400Khz la fonction de réception IR ne fonctionne plus du tout
J'ai un petit peu restructuré mon code :
C'est bien ça que tu entendais quand tu me disais de découper mon code fdufnews ?
Vous auriez des info sur la fameuse librairie DigitalFastWrite j'ai pas réussi a trouver beaucoup de documentation.
lemat:
Skizoh j'utilise une arduino UNO pour les prototype le modèle final recevra une Arduino Nano mais je préférais n'utiliser qu'une seule arduino je t'avoue ^^
Je vient de faire quelque essais avec les interruptions en connectant l'entrée pwm 5 du recepteur avec l'entrée 2 pour l'interruption.
L'interruption est bien détecter mais le code reçue n'est pas interpréter.
déjà voir si il n'y a pas des conflitrs avec les differentes lib
Mais là tu transfere trop de chose dans l'interruption ex l'affichage
l'interruption ne devrait te servir qu'a receptionner pas a traiter/afficher
en gros si IR detecté , entree en int , stockage brut des info, sortie d'int , traitement affichage fonctions de la trame IR reçue.
C'est bien ça que tu entendais quand tu me disais de découper mon code fdufnews ?
Pas encore eu le temps de regarder.
J'ai regardé vite fait, je ne vois pas trop la différence.
En fait pour être honnête ton code est dur à lire. Les fonctions setup() et loop() en particulier sont illisibles et incompréhensible de par leur taille.
Une bonne pratique de codage veut qu'une fonction ne dépasse pas une vingtaine de ligne, cela permet de voir l'intégralité de la fonction à l'écran (ce n'est pas toujours possible je le concède).
Pour cela c'est pas compliqué, on découpe, on découpe et on découpe.
Par exemple, dans ton setup() tu as 3 gros pavés : lecture de paramètres dans l'EEPROM, intialisation de l'afficheur, définition de caractères spéciaux pour l'afficheur.
Et bien tu fais 3 fonctions: litEEPROM(), initAfficheur() et defCarSpeciaux(). Ton setup() va perdre 50 lignes et gagner en lisibilité. En plus cela permet de les tester séparément et de les réutiliser facilement dans un autre développement.
Tu peux faire la même chose dans loop(). Dans loop() une fois que tu as découpé en fonction tu peux plus facilement décider d'appeler la fonction de mise à jour de l'écran sous condition (si un évenement particulier est survenu, ou bien une fois sur quatre,.....). Ce découpage va peut être aussi te permettre de simplifier ton code car il y a pas mal de code redondant avec beaucoup de if imbriqués qui sont sources d'erreurs car on a assez vite des cas non traités lorsqu'il y a trop d'imbrications de tests.
lemat:
Vous auriez des info sur la fameuse librairie DigitalFastWrite j'ai pas réussi a trouver beaucoup de documentation.
Fonctionne comme digitalRead() ou digitalWrite()
Tu ajoutes Fast derrière. Attention: Il y a une condition importante (expliquée dans la doc). Cette librairie utilise des macro, elle n'est performante que si le numéro des broches et la valeur à mettre sont connus à la compilation si l'appel à digitalWriteFast() contient une (ou des) variable(s) le code "rapide" n'est pas implémenté et la fonction standard digitalWrite() est appelée. Idem pour digitalReadFast().
Merci pour tous ces conseil fdufnews, je vais commencer par restructurer mon code comme tu me le suggère, je n'aurais ainsi peut être pas besoin d'interruption si je récupère suffisamment de vitesse.
Il faut que je vérifie en multipliant les test mais j'ai l'impression que le fait d'avoir sortie le gros bloc de réglage de la loop principale a accéléré un peu la détection, c'est pas encore ça mais c'est un plus.
J'ai compris l'idée pour le découpage, crée des fonction pour sortir le code de la loop principale et appeler ces fonctions que au besoin c'est bien cela ?
Pour DigitalWriteFast si je comprend bien la, ça marche : DIgitalWriteFast(7, HIGH;); mais pas comme ça : DIgitalWriteFast(pinSept, etat;); j'ai bon ?
lemat:
Pour DigitalWriteFast si je comprend bien la, ça marche : DIgitalWriteFast(7, HIGH); mais pas comme ça : DIgitalWriteFast(pinSept, etat); j'ai bon ?
Merci pour tout vos conseils j'y suis arriver sans interruption l'arduino en et largement capable, costaud cette petite bête
Ça réagit a chaque tir avant que j'ai pue relâcher la gâchette c'est parfait, le programme est encore optimisable, mais ça se fera au fur et a mesure des mise a jour et évolutions
lemat:
Merci pour tout vos conseils j'y suis arriver sans interruption l'arduino en et largement capable, costaud cette petite bête
Ça réagit a chaque tir avant que j'ai pue relâcher la gâchette c'est parfait, le programme est encore optimisable, mais ça se fera au fur et a mesure des mise a jour et évolutions
Artouste:
ce qui serai interessant pour les futurs lecteurs
ce serait de faire une synthese de l'optimisitation
sans rentrer dans le code du debut et le code de fin
Quelles ont été les grands points d'optimistations ? 8)
Pas de soucis, alors les principale optimisations c'est a dire celle qui ont résolue le problème sont :
Le découpage de la fonction loop en plusieurs sous fonction afin que la loop principale passe le plus de fois possible sur la partie réception infrarouge.
L’écran de jeu est maintenant actualiser que lorsque un événement a eu lieu, hormis pour le compte a rebours qui nécessite une actualisation constante.
Diverse erreur et oublie sur la réinitialisation du récepteur infrarouge après un tir.
La librairie DIgitalWriteFast qui à également donner un petit plus en rapidité lorsque le buzzer sonne ou lorsque les led clignote pour signale une "touche".
Voila ce qui a suffit à résoudre mon problème mais l'optimisation la plus importante a était le découpage, et j'en prend note pour mes prochains programmes