Bonjour,
je suis en STI2D je réalise un projet avec un aéroglisseur piloter a distance grâce a des NRF.
J'ai 2 fonction sur mon code, la première est de contrôler un servo moteur grâce a un joystick et la deuxième et de contrôler un moteur bushless avec un potentiomètre.
J'ai donc réaliser le codes suivant qui fonctionne chacun en test unitaire sois (potentiomètre/moteur brusless) sois (joystick/servo-moteur) sans effectuer de modification au code. Mon problème est que je n'arrive pas a faire fonctionner mais 2 fonction sur le meme code en dédoublant chaque fonction pour avoir une seul carte émettrice et une seul carte réceptrice. Voici le code sachant que le codes est le même sur la carte émettrice et réceptrice ainsi que pour chaque fonction.
Code (potentiomètre/moteur brusless) et (joystick/servo-moteur) :
#include <SPI.h>
#include <RF24.h>
#include <Servo.h>
#define pinCE 7 // On associe la broche "CE" du NRF24L01 à la sortie digitale D7 de l'arduino
#define pinCSN 8 // On associe la broche "CSN" du NRF24L01 à la sortie digitale D8 de l'arduino
#define pinSERVO 9 // On associe la broche "SIGNAL" du SERVO à la sortie digitale D9 de l'arduino
#define pinPOT A0 // On associe le point milieu du potentiomètre à l'entrée analogique A0 de l'arduino
#define tunnel1 "PIPE1" // On définit un premier "nom de tunnel" (5 caractères), pour pouvoir envoyer des données à l'autre NRF24
#define tunnel2 "PIPE2" // On définit un second "nom de tunnel" (5 caractères), pour pouvoir recevoir des données de l'autre NRF24
RF24 radio(pinCE, pinCSN); // Instanciation du NRF24L01
Servo servomoteur; // Instanciation d'un objet pour contrôler le servomoteur
const byte adresses[][6] = {tunnel1, tunnel2}; // Tableau des adresses de tunnel, au format "byte array"
int valeurPotLocal; // Variable contenant la valeur du potentiomètre
int valeurAngleServoLocal; // Variable contenant la valeur de l'angle du servomoteur
int valeurAngleServoDistant; // Variable contenant la valeur de l'angle du servomoteur
void setup() {
pinMode(pinPOT, INPUT); // Déclaration de la pin "pinPOT" en entrée
servomoteur.attach(pinSERVO); // Liaison de la pin "pinSERVO" au servomoteur branché sur l'arduino
radio.begin(); // Initialisation du module NRF24
radio.openWritingPipe(adresses[0]); // Ouverture du "tunnel1" en ÉCRITURE
radio.openReadingPipe(1, adresses[1]); // Ouverture du "tunnel2" en LECTURE
radio.setPALevel(RF24_PA_MIN); // Sélection d'un niveau "MINIMAL" pour communiquer (pas besoin d'une forte puissance, pour nos essais)
servomoteur.write(90); // Rotation du servomoteur pour le mettre en position médiane
delay(2000); // puis démarrage du programme
}
void loop() {
// ******** ENVOI ********
radio.stopListening(); // On commence par arrêter le mode écoute, pour pouvoir émettre les données
valeurPotLocal = analogRead(pinPOT); // On lit la valeur du potentiomètre (résultat retourné entre 0 et 1023)
valeurAngleServoDistant = map(valeurPotLocal, 0, 1023, 0, 180); // On converti la valeur [0..1023] en [0..180] (pour correspondre à l'angle d'un servo)
valeurAngleServoDistant = 2*(int)(valeurAngleServoDistant/2); // Léger arrondi, pour limiter les "tremblements" du servomoteur
radio.write(&valeurAngleServoDistant, sizeof(valeurAngleServoDistant)); // … et on envoi cette valeur à l'autre arduino, via le NRF24
delay(5); // avec une petite pause, avant de passer à la suite
// ******** RÉCEPTION ********
radio.startListening(); // On commence par arrêter le mode envoi, pour pouvoir réceptionner des données
if(radio.available()) { // On regarde si une donnée a été reçue
while (radio.available()) { // Si une donné est en attente de lecture, on va la lire
radio.read(&valeurAngleServoLocal, sizeof(valeurAngleServoLocal)); // Lecture des données reçues, une par une
servomoteur.write(valeurAngleServoLocal); // … et ajustement de l'angle du servomoteur à chaque fois
}
delay(20); // avec une petite pause, avant de reboucler
}
delay(5);
}
J'aimerais donc savoir si quelqu'un a une idée de comment m'y prendre pour faire fonctionner les 2 fonctions sur un seul code.
Si jamais vous ne comprenez pas mon explication n'hésitez pas a me demander je ferrais au mieux pour vous réexpliquez.
Merci d'avance.
Ce sujet a déjà été traité des dizaines de fois.
La première chose à faire est de bien comprendre le rôle des fonctions setup() et loop().
setup() ne s'exécute qu'une seule fois, elle est faite pour les configurations.
loop() s'appelle ainsi parce qu'elle est placée dans une boucle infinie dont elle ne peut sortir
while (1==1)
{
loop() ;
}
Une fois cette étape franchie, tu utilises le moteur de recherche de ce forum (en haut et à droite de l'écran) et tu y entres "fusionner deux codes"
Tu lis, tu cherches à appliquer.
Si tu as encore des incompréhensions, poste le code fusionné, indiques ce qui ne va pas.
Comme tes questions seront plus précises, les réponses seront plus utiles.
Une solution, la structure de données.
Ainsi tu y regroupes les données du joystick et celle du potentiomètre:
//------------------------------------- Structure de données
struct valeursDef // Structure de données du servo et du moteur
{
int moteurSpeed; // Valeur de vitesse du moteur
int angleServo; // Valeur angle du servo
};
valeursDef valeursFct; // Valeurs de sfonctione
données que tu tien à jour ainsi:
valeursFct.angleServo = valeurAngleServoDistant; // Mise de la valeur du servo dans la structure valeursFct
valeursFct.moteurSpeed = 126; // Valeur bidon, à calculr
Que tu envoies ainsi:
radio.write(&valeursFct, sizeof(valeursFct)); // … et on envoi cette structure qui contient toutes les valeurs, via le NRF24
et que tu reçois ainsi: radio.read(&valeursFct, sizeof(valeursFct)); // Lecture toutes des données reçues, en même temps
Pour faire marcher le servo:
servomoteur.write(valeursFct.angleServo); // … et ajustement de l'angle du servomoteur à chaque fois
Tu peux, ainsi, transmettre d'autres données via cette structure, il suffit juste d'y ajouter la décalartion d cette nouvelle valeur de fonction.
il vaut mieux prendre l'habitude d'utiliser les types de dimension fixe quand on fait de la communication binaire. un int16_t par exemple ou un int32_t pour le cas où l'émetteur et le récepteur n'auraient pas la même architecture (un int sur UNO c'est 2 octets alors que c'est 4 octets sur un ESP32 ou un MKR ➜ ce que l'on reçoit ne correspondrait pas)
pour éviter aussi que le compilateur prenne des libertés avec le padding ou l'alignement c'est aussi important d'utiliser l'attribut packed au moins
un truc comme cela est plus robuste
struct __attribute__((packed)) Message {
int16_t moteurSpeed; // Valeur de vitesse du moteur
int16_t angleServo; // Valeur angle du servo
};
Bonjour @J-M-L
Bien que ce ne soit pas mon sujet, j'aime bien suivre ceux des autres, on apprend toujours des trucs. Je ne suis pas sûr de comprendre le code que vous avez fourni en exemple. Pourriez vous l'expliquer ?
Merci d'avance et désolé @sam_292 pour cette petite intrusion
Cordialement
Pandaroux007
Si le code est le même, tu n'a pas une carte émettrice et l'autre réceptrice.
Mais deux carte qui émettent et reçoivent en même temps.
Ton projet n'est pas de faire une carte émettrice avec un potentiomètre et un joystick qui envoi ses informations à une carte réceptrice qui pilote un servomoteur et un moteur brushless en fonction des données reçues?
je suppose que vous comprenez ce qu'est une structure ?
Dans une structure, le language C++ (ou C) vous garantit que les différents attributs sont rangés dans cet ordre là en mémoire mais il ne vous garantit pas qu'il n'y a pas des octets vides (on appelle cela du padding) entre les attributs.
Par exemple dans certaines architectures, c'est plus rapide de lire une variable dans un registre si son premier octet tombe sur une adresse multiple de 4. si vous déclarez la structure
struct {
bool toto;
uint32_t titi;
} maStructure;
le compilateur pourrait décider de stocker maStructure à une adresse multiple de 4, d'allouer 1 octet pour toto, laisser 3 octets vides et mettre titi ensuite de façon à ce que l'adresse de titi soit aussi sur une adresse multiple de 4. dans ce cas la taille de la structure serait de 8 octets (1 pour toto, 3 octets vides et 4 pour titi)
Quand on rajoute __attribute__((packed)) on dit au compilateur GCC (c'est spécifique, pas dans la norme) que l'on ne veut pas que le compilateur essaye de faire des optimisations d'alignement des données en mémoire. On lui demande que la structure occupe le moins d'octets possibles et donc la structure précedente n'aurait que 5 octets (1 pour toto et 4 pour titi).
c'est important car les optimisations de vitesse d'accès dépendent du code que vous avez et du compilateur. Si d'un côté le compilateur a fait du padding, votre structure fait 8 octets, et si de l'autre côté (réception) il n'y a pas de padding, la structure fait 5 octets.
Quand vous allez envoyer les 8 octets il seront reçus et mis dans une structure de 5 octets et vous aurez les mauvaises valeurs.
c'est pour cela que l'on rajoute __attribute__((packed)) pour ce genre de communication.