Skip to main content

Projet ROB3 : Fares, Ilyes, Albéric

Projet ROB3 : 

Ilyes Elotreuch, Fares Charni, Albéric Fasquelle

Informations

Polytech Sorbonne - Spécialité Robotique - Projet de 3eme année 

Contact des membres de l'équipe :
Albéric Fasquelle alberic.fasquelle@etu.sorbonne-universite.fr
Ilyes Elotreuch ilyes.elotreuch@etu.sorbonne-universite.fr
Fares Charni fares.charni@etu.sorbonne-universite.fr

Introduction

Dans le cadre de ce projet de robotique nous avons à réaliser un robot écrivain. Une vidéo de démonstration est disponible à la fin de cette page. Celui-ci dispose de plusieurs fonctions et mode qui participe à la complexité de ce projet. 

En premier lieu nous avons le mode manuel qui pilotera le robot à l'aide d'un joystick afin de dessiner ce que l'on souhaite. De plus notre robot dispose de quatre fonctions supplémentaires qui dessinerons de manière automatique une cercle et une ligne.

Le présent document détaille les exigences du projet, les différentes étapes de sa réalisation, ainsi que les ressources et les échéances qui nous guideront tout au long de ce processus.

Cahier des charges 

Dans ce cahier des charges, nous sommes chargés de concevoir un robot capable de réaliser des dessins sur une surface plane. Nous devons lui permettre d'accomplir différentes tâches, telles que tracer des lignes et des cercles de longueurs et de rayons spécifiques dans un temps défini. De plus, il doit être en mesure de reproduire un dessin particulier dans un carré donné, tout en étant contrôlé par un joystick pour son mouvement. Nous pouvons envisager d'ajouter une fonctionnalité supplémentaire pour ajuster la vitesse du robot selon les besoins. Les contraintes incluent l'utilisation exclusive des équipements du FABLAB de Sorbonne Université, le choix des composants prédéfinis, la fabrication des pièces avec des machines spécifiques, et la programmation en C via l'IDE Arduino. Notre objectif sera également de minimiser la quantité de matériau utilisé pour ce projet.

1. Conception préliminaire 

Dans cette section, nous présentons trois solutions potentielles pour la conception et la réalisation du robot écrivain, en tenant compte des exigences du cahier des charges et des contraintes spécifiées. Chaque solution est accompagnée de schémas, ainsi qu'une explication pour faciliter la compréhension. Nous avons retenu une proposition parmi les trois proposé ci dessous en fonction du cahier des charges et de nos préférences personnelles. 

Solution 1 :


La première solution utilise pour les mouvements dans le plan horizontal de la feuille un mécanisme en boucle fermée à 4 barres, 5 liaisons pivots, dont deux sont motorisées. Voir une explication de son fonctionnement sur ce site . Pour les mouvements verticaux, on produit une translation verticale de la base qui soulève l'ensemble du robot.

Nous nous sommes inspiré du robot Cozmo WeDraw pour la création de cette solution. Voir ici (minute 2:25 de la vidéo)

Solution 2 : 

Notre deuxième solution est un bras robotique classique utilisant les servomoteurs en série afin de déplacer le bras selon les axes X et Y. Le troisième servo est utilisé ici pour soulever l'effecteur. Cette solution possède certains avantage comme une configuration cinématique assez simple. Cependant, elle présente des risques de stabilité structurelle, surtout lors de mouvements rapides. De plus, la précision du robot peut être compromise aux extrémités au niveau de l'effecteur, en raison des effets de la gravité et de la flexion des composants(notamment des servomoteurs).

Solution 3 : 

Notre 3eme solution s'appuie sur un principe de guidage linéaire, à la manière des imprimantes 3D en retirant la composante Z. Un dispositif de guidage supporte le crayon et se déplace le long de rails des guidages pour réaliser les dessins sur la plaque support. Cette solution utilise deux rails de guidage ainsi que des courroies pour déplacer l'effecteur selon l'axe X et Y. Pour soulever le stylo nous ajoutons un servomoteur au niveau du stylo. Cette solution ne sera pas retenu en raison des contraintes matériels. 

Choix de la solution 

L’idée 3 à été écarté des possibilités en raison des composants disponibles.

Solution  Avantages Inconvénients

Idée 1

-Facilité de conception 

-Esthétique

-Précision : pas de contraintes mécanique trop importante sur l'axe des servomoteurs

 

-Possibilité d'une écriture du code plus complexe en raison de la forme.
Idée 2

-Mise en place simple

-Architecture simple

-Pas de contrainte potentielle sur les composants

-Possiblement difficile à réaliser car la contrainte mécanique sur l'axe d'un des servomoteur.

-Pas spécialement beau

 

Idée 3

- modèle cinématique facile à réaliser

-Guidage difficile à réaliser au niveau des courroies

-Composant non disponibles: courroie, rails de guidage 

-possibilité de perte de précision lors des déplacements à causes des roulements

Nous avons décidé après l'étude des différentes solution de sélectionner la première proposition. D'une part puisque nous trouvions le design  agréable et original. Et d'autre part pour certaines raisons pratiques cités ci-dessus. 

Ensemble des tâches à réaliser pour la conception du robot :

Voici dessous l'ensemble des tâches réaliser lors des différentes étapes de la réalisation de ce projet. 

image.png

Diagramme de Gantt :

Voici ci dessous le diagramme de Gantt prévisionnel du projet. Celui-ci est amené à être modifié selon l'avancement du projet. 

image.png

2. Conception détaillé du robot

2.1 Schéma électronique :

Pour la réalisation du schéma électronique, nous avons tout d'abord fait la liste de tout le matériel nécessaire à la bonne conception de celle-ci. La carte électronique est segmenté en plusieurs parties: 

  • Nous avons  tout d'abord l'élément central, l'Arduino. Il s'agit du microcontrôleur, c'est à dire le "cerveau" de la carte. Celui-ci est relié à chaque composant afin de les faire fonctionner entre eux.
  • Ensuite nous avons la partie des servomoteurs visualisés ici par des autocoms. 
  • Nous avons également ajouté une partie debug pour la partie des 4 modes à réaliser. Nous avons ajouter un bouton pour activer ou non les modes. Et nous avons ajouter une led rgb pour deux intérêts, d'une par pour pouvoir afficher l'état ou l'avancement du mode en court, il s'agit donc d'une aide pour debug. Et il y a également un côté esthétique. 
  • Enfin nous avons l'alimentation et le joystick modélisé également par des autocoms. 

image.png

Pour modélisé la carte nous avons fait le choix d'utiliser le logiciel KiCad pour deux raisons. LA première est que ce logiciel a déjà été utilisé par certains membres du groupe. Et la seconde pour son côté pratique qui nous permettra si le temps nous le permet d'imprimer une carte électronique(PCB). Pour rendre le projet encore plus attrayant. 

2.2 Équations de mouvement du robot

Dans cette section, nous nous concentrerons sur la manière pratique de gérer le mouvement du robot dessinateur. Notre objectif est de comprendre comment convertir les coordonnées souhaitées de la pointe du stylo sur la surface de dessin en mouvements précis des articulations du robot. Pour ce faire, nous aborderons les principes de base de la cinématique directe, qui nous permettent de déterminer la position du stylo en fonction des angles des articulations du robot.

Ensuite, nous explorerons le modèle géométrique inverse, une méthode essentielle pour programmer le mouvement du robot avec précision et efficacité. Ce modèle nous permettra d'établir les équations qui relient les coordonnées de la pointe du stylo aux angles des articulations du robot, fournissant ainsi un cadre pratique pour contrôler le mouvement du robot dessinateur dans diverses situations.

Modèle géométrique inverse

image.png

image.png

image.png

image.png

Nous avons ensuite réalisé une esquisse de notre robot sur SolidWorks pour vérifier les équations. En rendant les cotations des angles pilotées, nous pouvons introduire une position de la pointe du stylo, et obtenir les angles correspondants, avec la prise en compte des longueurs des bielles du robot. On observe que les valeurs concordent avec celles données par les équations.

image.png

Nous avons ensuite fait un code python pour calculer les valeurs des angles à partir de la position de la pointe du stylo:

image.png

image.png

On observe que les valeurs obtenues avec SolidWorks concordent avec celles obtenues par les équations.

On peut valider le modèle géométrique.

On prendra en particulier pour simplifier les calculs une structure de losange formée par les bielle 1 2 3 et 4 .

2.3 Conception de la structure du code et de l'interface

Pour structurer notre code, nous avons d'abord conçu l'interface utilisateur à l'aide du matériel fourni.
Cette interface permet de répondre aux exigences du cahier des charges en assurant un changement dynamique entre différents modes de dessins et une interruption rapide du processus en cas de besoin. 

Logigramme de l'interface :

Notre interface est composé du bouton démarrage, du joystick et d'un bouton de changement de mode.

On a choisit, pour rendre notre interface plus compacte d'implémenter le système suivant, où l'appui sur le bouton changement de Mode suivi d'un mouvement du joystick permettra de changer entre 4 modes.


L'appui sur le joystick permet par ailleurs d'interrompre ou de reprendre de manière aisée et rapide le dessin.

Capture d'écran 2024-05-29 162655.png

Détaillons le logigramme du code pour le mouvement du stylo et le changement de l'état Stylo levé/Stylo bas :

Changement de position :

On voit que les nouvelles valeurs des angles dépendent d'elles mêmes.
On implémentera lors de nos tests 2 codes différents pour le calcul de la nouvelle position:


Le premier calculera les nouvelles positions à partir des positions actuelles -> Plus rapide

Le deuxième utilisera la dichotomie pour résoudre l'équation du mouvement ->Plus précis mais calcul très coûteux

Logigramme Mouvement Joystick.png

Changement d'état :

Le guidage du moteur 3 ainsi que l'angle de la rotation pour le changement de l'état restent à définir.

Logigramme Appuie sur Joystick.png

2.4 Écriture du code

A partir de ce logigramme nous avons réalisé la création du code (deplacement_robot_final.ino en pièce-jointe).

En résumé, ce code permet de contrôler un bras robotisé à trois servomoteurs via un joystick, avec des modes spécifiques pour tracer des lignes et des cercles. Il utilise des calculs de cinématique inverse pour déterminer les angles des servomoteurs nécessaires pour atteindre des positions spécifiques. Voici une explication de son fonctionnement :

  1. Initialisation:

    • Les broches pour les LEDs RGB, les servomoteurs, le joystick et un bouton de sélection de mode sont définies.
    • Les servomoteurs sont attachés à leurs broches respectives et initialisés à des positions spécifiques.
    • Les LEDs RGB sont également configurées pour indiquer les états et les sélections de mode.
  2. Variables et paramètres:

    • Les limites de lecture du joystick et de mouvement du robot sont définies.
    • Les dimensions géométriques des bras du robot (longueurs des segments) sont définies.
    • Les variables pour stocker les positions actuelles du robot sont initialisées.
  3. Fonctions de mouvement:

    • calculate_theta_1 et calculate_theta_2 : Calculent les angles des servomoteurs nécessaires pour atteindre une position donnée (x, y) en utilisant la cinématique inverse.
    • move_in_line et move_in_line_disc : Permettent au robot de tracer des lignes droites, continues et discontinues respectivement.
    • move_in_circle_half1, move_in_circle_half2, move_in_circle_half1_disc, move_in_circle_half2_disc : Permettent de tracer des cercles continus et discontinus.
  4. Fonction principale (loop):

    • Lecture des valeurs du joystick.
    • Si le bouton de sélection de mode est activé, le code entre dans un mode de sélection où différentes couleurs de LED indiquent les différents modes. Selon la position du joystick, un mode est sélectionné.
    • En mode 1 et 2, le robot trace une ligne droite continue ou discontinue en fonction du mode sélectionné.
    • Si aucun mode n'est activé, le joystick contrôle directement les mouvements du robot en temps réel, avec un lissage pour les mouvements.
  5. Détails des modes:

    • Mode 1 : Tracer une ligne droite.
    • Mode 2 : Tracer une ligne droite discontinue.
    • Mode 3 et 4 : Tracer un cercle continu
    • Mode 4: Tracer un cercle discontinu.
  6. LED de validation:

    • Les LEDs RGB changent de couleur pour indiquer la sélection et le fonctionnement des différents modes.

Voici un détail des fonctions utilisées :

Fonction move_in_line

Cette fonction permet au robot de se déplacer le long d'une ligne droite en plusieurs étapes.

  1. Initialisation des paramètres:

    • x_start et y_start définissent le point de départ de la ligne.
    • length est la longueur de la ligne.
    • steps est le nombre de segments en lesquels la ligne sera divisée.
    • l_1, l_2, l_3, l_4, l_5 sont les paramètres géométriques du robot.
  2. Calcul des incréments de déplacement:

    • step_size est la distance à parcourir à chaque étape.
    • time_per_step est le temps alloué pour chaque étape.
  3. Boucle de déplacement:

    • Pour chaque étape i, les nouvelles coordonnées x_p et y_p sont calculées en fonction du point de départ et de l'incrément de déplacement.
    • Les angles theta_1 et theta_2 sont calculés pour positionner les servomoteurs en utilisant les fonctions calculate_theta_1 et calculate_theta_2.
    • Les servomoteurs sont déplacés aux angles calculés.
    • Un délai est introduit pour attendre jusqu'au moment approprié pour la prochaine étape.

Fonction move_in_circle_half1 et half2

Cette fonction permet au robot de se déplacer le long d'un arc de cercle en plusieurs étapes. L'association de move_in_circle_half1 et half2 permet de faire un demi cercle supérieur puis un demi cercle inférieur ce qui donne un cercle complet.

  1. Initialisation des paramètres:

    • center_x et center_y définissent le centre du cercle.
    • radius est le rayon du cercle.
    • steps est le nombre de segments en lesquels le cercle sera divisé.
    • l_1, l_2, l_3, l_4, l_5 sont les paramètres géométriques du robot.
  2. Calcul des incréments de déplacement:

    • time_per_step est le temps alloué pour chaque étape.
    • angle est l'angle incrémental en radians pour chaque étape.
  3. Boucle de déplacement:

    • Pour chaque étape i, les nouvelles coordonnées x_p et y_p sont calculées en utilisant les équations paramétriques du cercle.
    • Les angles theta_1 et theta_2 sont calculés pour positionner les servomoteurs en utilisant les fonctions calculate_theta_1 et calculate_theta_2.
    • Les servomoteurs sont déplacés aux angles calculés.
    • Un délai est introduit pour attendre jusqu'au moment approprié pour la prochaine étape.

Gestion du temps et découpage en étapes

Les fonctions utilisent une méthode de découpage en étapes pour créer un mouvement fluide et précis. Le mouvement est divisé en un nombre défini d'étapes (steps), et chaque étape est exécutée en un intervalle de temps déterminé (time_per_step). Voici comment cela fonctionne:

  1. Calcul du temps total et du temps par étape:

    • Le temps total pour effectuer le mouvement est défini (par exemple, 9800 ms pour move_in_line).
    • Le temps par étape est calculé en divisant le temps total par le nombre d'étapes.
  2. Boucle de contrôle temporelle:

    • Pour chaque étape, le programme calcule les nouvelles positions et les angles correspondants.
    • Les servomoteurs sont déplacés aux positions calculées.
    • Le programme utilise une boucle while pour attendre jusqu'au moment approprié pour passer à l'étape suivante, en vérifiant constamment l'heure actuelle (millis()) par rapport au temps de début et au temps alloué pour chaque étape.

Nous avons remarqué que du à l'encombrement du robot et les limites des angles des servo-moteurs, nous ne pouvons pas atteindre toutes les positions. Ainsi nous avons restreint le robot à une zone de dessin :

Drawing_area.png

1) Dessin de la ligne continue de 5 cm:
// Tracer une ligne droite horizontale dans le sens des x négatifs
void move_in_line(double x_start, double y_start, double length, int steps, double l_1, double l_2, double l_3, double l_4, double l_5) {
    double step_size = length / steps;
    // double time_per_step = 10000.0 / steps; // 10 secondes (10000 ms) divisé par le nombre de steps
    unsigned long total_time = 9800; // Temps total en millisecondes (10 secondes)
    unsigned long time_per_step = total_time / steps;
    unsigned long start_time = millis(); // Start time
    
    for (int i = 0; i <= steps; i++) {
        double x_p = x_start - i * step_size; //Tracer la ligne dans le sens des x négatifs
        double y_p = y_start;
        
        double theta_1 = calculate_theta_1(x_p, y_p, l_1, l_4, l_5);
        double theta_2 = calculate_theta_2(x_p, y_p, theta_1, l_1, l_2, l_3, l_4, l_5);

        // Convertir les angles en degrés
        double theta_1_deg = theta_1 * 180 / M_PI;
        double theta_2_deg = theta_2 * 180 / M_PI;

        // Déplacer les servos aux angles calculés
        servo1.write(theta_1_deg);
        servo2.write(180 - theta_2_deg);

        // Afficher les angles actuels dans le moniteur série
        Serial.print("Step ");
        Serial.print(i);
        Serial.print(": Theta_1 = ");
        Serial.print(theta_1_deg);
        Serial.print(", Theta_2 = ");
        Serial.println(theta_2_deg);

        // delay(time_per_step);  // Délai pour chaque étape

        // Attendre jusqu'au temps approprié pour le prochain pas
        unsigned long current_time = millis();
        unsigned long next_step_time = start_time + (i + 1) * time_per_step;
        while (current_time < next_step_time) { // Boucle while remplace le delay
            current_time = millis();
        }
    }

    // Vérification finale du temps écoulé
    unsigned long actual_end_time = millis();
    Serial.print("Temps total: ");
    Serial.println(actual_end_time - start_time);
    
}
2) Dessin de la ligne discontinue de 5 cm:
// Tracer une ligne droite discontinue
void move_in_line_disc(double x_start, double y_start, double length, int steps, double l_1, double l_2, double l_3, double l_4, double l_5) {
  servo3.write(115);
  double step_size = length / steps;
  unsigned long total_time = 9800;  // Temps total en millisecondes (10 secondes)
  unsigned long time_per_step = total_time / steps;
  unsigned long start_time = millis();  // Start time

  for (int i = 0; i <= steps; i++) {
    double x_p = x_start - i * step_size;  // Tracer la ligne dans le sens des x négatifs
    double y_p = y_start;

    double theta_1 = calculate_theta_1(x_p, y_p, l_1, l_4, l_5);
    double theta_2 = calculate_theta_2(x_p, y_p, theta_1, l_1, l_2, l_3, l_4, l_5);

    // Convertir les angles en degrés
    double theta_1_deg = theta_1 * 180 / M_PI;
    double theta_2_deg = theta_2 * 180 / M_PI;

    // Déplacer les servos aux angles calculés
    servo1.write(theta_1_deg);
    servo2.write(180 - theta_2_deg);

    // Lever et abaisser le stylo pour créer une ligne discontinue
    if (i % 10 < 5) {
      servo3.write(90);  // Abaisser le stylo
    } else {
      servo3.write(100);  // Lever le stylo
    }

    // Afficher les angles actuels dans le moniteur série
    Serial.print("Step ");
    Serial.print(i);
    Serial.print(": Theta_1 = ");
    Serial.print(theta_1_deg);
    Serial.print(", Theta_2 = ");
    Serial.println(theta_2_deg);

    // Attendre jusqu'au temps approprié pour le prochain pas
    unsigned long current_time = millis();
    unsigned long next_step_time = start_time + (i + 1) * time_per_step;
    while (current_time < next_step_time) {  // Boucle while remplace le delay
      current_time = millis();
    }
  }

  // Vérification finale du temps écoulé
  unsigned long actual_end_time = millis();
  Serial.print("Temps total: ");
  Serial.println(actual_end_time - start_time);
}

3) Dessin du cercle continu de rayon 2.5 cm:
// Utiliser les équations paramétriques d'un cercle pour calculer les positions des points autour du cercle

void move_in_circle_half1(double center_x, double center_y, double radius, int steps, double l_1, double l_2, double l_3, double l_4, double l_5) {
    unsigned long total_time = 4800; // Total time in milliseconds (10 seconds)
    unsigned long time_per_step = total_time / steps;
    unsigned long start_time = millis(); // Start time

    for (int i = 0; i <= steps; i++) { 
        // Calcul des coordonnées x et y pour le cercle
        double angle = 1 * M_PI * i / steps; // Angle en radians
        double x_p = center_x + radius * cos(angle);
        double y_p = center_y + radius * sin(angle);

        double theta_1 = calculate_theta_1(x_p, y_p, l_1, l_4, l_5);
        double theta_2 = calculate_theta_2(x_p, y_p, theta_1, l_1, l_2, l_3, l_4, l_5);

        // Convertir les angles en degrés
        double theta_1_deg = theta_1 * 180 / M_PI;
        double theta_2_deg = theta_2 * 180 / M_PI;

        // Déplacer les servos aux angles calculés
        servo1.write(theta_1_deg);
        servo2.write(180 - theta_2_deg);

        // Afficher les angles actuels dans le moniteur série
        Serial.print("Step ");
        Serial.print(i);
        Serial.print(": Theta_1 = ");
        Serial.print(theta_1_deg);
        Serial.print(", Theta_2 = ");
        Serial.println(theta_2_deg);

        // Attendre jusqu'au temps approprié pour le prochain pas
        unsigned long current_time = millis();
        unsigned long next_step_time = start_time + (i + 1) * time_per_step;
        while (current_time < next_step_time) {
            current_time = millis();
        }
        //delay(time_per_step);
    }

    // Vérification finale du temps écoulé
    unsigned long actual_end_time = millis();
    Serial.print("Temps total: ");
    Serial.println(actual_end_time - start_time);
}

// Utiliser les équations paramétriques d'un cercle pour calculer les positions des points autour du cercle
void move_in_circle_half2(double center_x, double center_y, double radius, int steps, double l_1, double l_2, double l_3, double l_4, double l_5) {
    unsigned long total_time = 4800; // Total time in milliseconds (10 seconds)
    unsigned long time_per_step = total_time / steps;
    unsigned long start_time = millis(); // Start time

    for (int i = 0; i <= steps; i++) { 
        // Calcul des coordonnées x et y pour le cercle
        double angle = 1 * M_PI * i / steps; // Angle en radians
        double x_p = center_x - radius * cos(angle);
        double y_p = center_y - radius * sin(angle);

        double theta_1 = calculate_theta_1(x_p, y_p, l_1, l_4, l_5);
        double theta_2 = calculate_theta_2(x_p, y_p, theta_1, l_1, l_2, l_3, l_4, l_5);

        // Convertir les angles en degrés
        double theta_1_deg = theta_1 * 180 / M_PI;
        double theta_2_deg = theta_2 * 180 / M_PI;

        // Déplacer les servos aux angles calculés
        servo1.write(theta_1_deg);
        servo2.write(180 - theta_2_deg);

        // Afficher les angles actuels dans le moniteur série
        Serial.print("Step ");
        Serial.print(i);
        Serial.print(": Theta_1 = ");
        Serial.print(theta_1_deg);
        Serial.print(", Theta_2 = ");
        Serial.println(theta_2_deg);

        // Attendre jusqu'au temps approprié pour le prochain pas
        unsigned long current_time = millis();
        unsigned long next_step_time = start_time + (i + 1) * time_per_step;
        while (current_time < next_step_time) {
            current_time = millis();
        }
        //delay(time_per_step);
    }

        // // Position finale
         double x_f = center_x - radius * cos(M_PI / 6);
         double y_f = center_y - radius * sin(M_PI / 6);

         double theta_1_f = calculate_theta_1(x_f, y_f, l_1, l_4, l_5);
         double theta_2_f = calculate_theta_2(x_f, y_f, theta_1_f, l_1, l_2, l_3, l_4, l_5);

         // Convertir les angles en degrés
         double theta_1_deg_f = theta_1_f * 180 / M_PI;
         double theta_2_deg_f = theta_2_f * 180 / M_PI;

         // Déplacer les servos aux angles calculés
         servo1.write(theta_1_deg_f);
         servo2.write(180 - theta_2_deg_f);

    // Vérification finale du temps écoulé
    unsigned long actual_end_time = millis();
    Serial.print("Temps total: ");
    Serial.println(2*(actual_end_time - start_time));
}

4) Dessin du cercle discontinue de rayon 2.5 cm:
void move_in_circle_half1_disc(double center_x, double center_y, double radius, int steps, double l_1, double l_2, double l_3, double l_4, double l_5) {
  unsigned long total_time = 4800;
  unsigned long time_per_step = total_time / steps;
  unsigned long start_time = millis();

  for (int i = 0; i <= steps; i++) {
    double angle = 1 * M_PI * i / steps;
    double x_p = center_x + radius * cos(angle);
    double y_p = center_y + radius * sin(angle);

    double theta_1 = calculate_theta_1(x_p, y_p, l_1, l_4, l_5);
    double theta_2 = calculate_theta_2(x_p, y_p, theta_1, l_1, l_2, l_3, l_4, l_5);

    double theta_1_deg = theta_1 * 180 / M_PI;
    double theta_2_deg = theta_2 * 180 / M_PI;

    servo1.write(theta_1_deg);
    servo2.write(180 - theta_2_deg);

    if (i % 10 < 5) {
      servo3.write(90);  // Stylo en bas
    } else {
      servo3.write(100);  // Stylo en haut
    }

    Serial.print("Step ");
    Serial.print(i);
    Serial.print(": Theta_1 = ");
    Serial.print(theta_1_deg);
    Serial.print(", Theta_2 = ");
    Serial.println(theta_2_deg);

    unsigned long current_time = millis();
    unsigned long next_step_time = start_time + (i + 1) * time_per_step;
    while (current_time < next_step_time) {
      current_time = millis();
    }
  }

  unsigned long actual_end_time = millis();
  Serial.print("Temps total: ");
  Serial.println(actual_end_time - start_time);
}

void move_in_circle_half2_disc(double center_x, double center_y, double radius, int steps, double l_1, double l_2, double l_3, double l_4, double l_5) {
  unsigned long total_time = 4800;
  unsigned long time_per_step = total_time / steps;
  unsigned long start_time = millis();

  for (int i = 0; i <= steps; i++) {
    double angle = M_PI + M_PI * i / steps;
    double x_p = center_x + radius * cos(angle);
    double y_p = center_y + radius * sin(angle);

    double theta_1 = calculate_theta_1(x_p, y_p, l_1, l_4, l_5);
    double theta_2 = calculate_theta_2(x_p, y_p, theta_1, l_1, l_2, l_3, l_4, l_5);

    double theta_1_deg = theta_1 * 180 / M_PI;
    double theta_2_deg = theta_2 * 180 / M_PI;

    servo1.write(theta_1_deg);
    servo2.write(180 - theta_2_deg);

    if (i % 10 < 5) {
      servo3.write(90);  // Stylo en bas
    } else {
      servo3.write(100);  // Stylo en haut
    }

    Serial.print("Step ");
    Serial.print(i);
    Serial.print(": Theta_1 = ");
    Serial.print(theta_1_deg);
    Serial.print(", Theta_2 = ");
    Serial.println(theta_2_deg);

    unsigned long current_time = millis();
    unsigned long next_step_time = start_time + (i + 1) * time_per_step;
    while (current_time < next_step_time) {
      current_time = millis();
    }
  }

  unsigned long actual_end_time = millis();
  Serial.print("Temps total: ");
  Serial.println(actual_end_time - start_time);
}
5) Dessin en mode manuel (avec le joystick) :
void loop() {
 // Lire les valeurs du joystick
    int vrxValue = analogRead(VrxPin);
    int vryValue = analogRead(VryPin);

    // Inverser la valeur du joystick pour l'axe Y
    vryValue = joystickMax - vryValue;

    // Vérifier si le joystick est centré (dans la tolérance)
    bool joystickCentered = (abs(vrxValue - (joystickMax / 2)) < joystickCenterTolerance) &&
                            (abs(vryValue - (joystickMax / 2)) < joystickCenterTolerance);

    if (!joystickCentered) {
        // Mapper les valeurs du joystick aux coordonnées (xp, yp)
        double target_x_p = map(vrxValue, joystickMin, joystickMax, minX, maxX);
        double target_y_p = map(vryValue, joystickMin, joystickMax, minY, maxY);

        // Lissage des mouvements
        current_x_p += (target_x_p - current_x_p) * smoothingFactor;
        current_y_p += (target_y_p - current_y_p) * smoothingFactor;
    }


    double theta_1 = calculate_theta_1(current_x_p, current_y_p, l_1, l_4, l_5);
    double theta_2 = calculate_theta_2(current_x_p, current_y_p, theta_1, l_1, l_2, l_3, l_4, l_5);

    // Convertir les angles de radians en degrés
    int angleServo1 = int(theta_1 * 180 / M_PI);
    int angleServo2 = 180 - int(theta_2 * 180 / M_PI);

    Serial.print("Theta_1 = ");
    Serial.println(theta_1 * 180 / M_PI);
    Serial.print("Theta_2 = ");
    Serial.println(theta_2 * 180 / M_PI);

    servo1.write(angleServo1);
    servo2.write(angleServo2);

    delay(100);
  
}

2.5 Conception mécanique du robot

La conception mécanique du robot écrivain est essentielle pour assurer sa stabilité, sa précision et sa facilité d'utilisation. Pour la réalisation de celui-ci nous nous sommes inspiré du Wedraw de Cozmo que nous avons trouvé original. Notre robot est composé d'un corps principal sur lequel sont montés deux servomoteurs pour contrôler les bras. Les bras, joints au niveau de leur main, supportent le crayon utilisé pour le traçage des figures sur la surface de la plaque support.

Description du Robot

Le corps principal du robot est conçu pour abriter l'électronique de contrôle ainsi que les mécanismes de mouvement. Les deux servomoteurs, placés de manière symétrique de chaque côté du corps, assurent les mouvements des bras dans le plan horizontal de la feuille. À l'extrémité de chaque bras se trouve une articulation permettant le mouvement du crayon dans toutes les directions nécessaires pour dessiner les figures spécifiées dans le cahier des charges.

Ci dessous notre vue 3D de notre robot. Les couleurs ont été apportés pour amener du contraste dans notre structure afin de mieux visualiser les composants. 

7l9image.png

Choix des matériaux 

Lors de ce projet, nous avons fait le choix de privilégier certains matériaux. Nous avons choisi en priorité l'utilisation de la découpe laser pour la fabrication des pièces principales de la structure, notamment le corps principal du robot et les bras articulés. La découpe laser offre une grande précision dans la réalisation des pièces, permettant ainsi d'obtenir des assemblages parfaitement ajustés et une structure globalement robuste. De plus, ce processus de fabrication est rapide et efficace, ce qui nous permet de produire les pièces simplement. 

Quant aux pièces de l'effecteur, telles que le support du crayon et les éléments de fixation, nous avons opté pour l'impression 3D. Ce procédé nous offre une grande flexibilité dans la conception des pièces, nous permettant ainsi de réaliser des formes complexes. L'impression 3D est très utile pour les petites pièces mais peut vite devenir un problème si nous devions réaliser de grande pièce. C'est pour cela nous avons privilégier la découpe laser pour les pièces structurant notre projet. 

Choix de la structure général 

En ce qui concerne la disposition des composants mécaniques, nous avons décidé de placer les deux servomoteurs sur le même axe verticale. Cette disposition simplifie non seulement les équations de mouvement du robot, mais elle offre également une répartition uniforme des charges.

Les bras du robot sont articulés à l'extrémité du corps principal, permettant ainsi une grande liberté de mouvement pour le crayon utilisé dans le traçage des figures sur la surface de la plaque support. Cette conception garantit également une précision optimale dans l'exécution des dessins. Celle-ci nous permet donc de séparer  la partie utilisateur du bras mécanique.

Maintien de la structure

Afin de maintenir la structure en place nous avons fait le choix de prendre des tiges filetés pour serrer la structure sur elle même. Des écrous maintiendrons le tout en place. Nous avons fait le choix de cette solution puisqu'elle présente plusieurs avantages. La première est la simplicité de mise en place. Et la seconde est le fait de pouvoir accéder facilement au composant si l'on veut faire de la maintenance. Nous avons besoin seulement de dévisser 4 écrous. 

Mécanisme de Relevage du Crayon

Pour relever le crayon du support horizontal lorsqu'il n'est pas en cours d'utilisation, nous avons envisagé plusieurs solutions. Initialement, l'idée était de soulever le corps du robot, mais des préoccupations ont été soulevées quant à la capacité du servomoteur à supporter la charge de tout le système sans que la précision ne soit affecté. Nous nous sommes finalement rabattu sur la seconde solution. Nous avons donc placé un servomoteur au niveau du stylo qui viendra directement lever celui-ci sans avoir à relever l’ensemble de la structure.

Afin de lever le stylo de manière linéaire nous avons fait le choix d'une glissière. Un principe souvent utilisé en mécanique et simple à mettre en œuvre. 

Voici ci dessous les différentes vu de l'intérieur de notre robot :

image.png

Ci-joint le fichier SolidWorks du projet

Montage final du robot :

Le processus de montage et de réalisation de notre robot dessinateur a été conçu pour être simple et efficace, grâce à une planification minutieuse en CAO.

Étape 1 : Préparation des Pièces
  1. Découpe Laser : Les pièces principales de la structure, comme le corps et les bras articulés, ont été découpées avec précision grâce à une machine de découpe laser.

  2. Impression 3D : Les petites pièces, telles que le support du crayon et les éléments de fixation, ont été réalisées par impression 3D pour permettre des conceptions complexes.

Étape 2 : Assemblage de la Structure Principale
  1. Montage du Corps Principal : Les pièces découpées au laser ont été assemblées à l'aide de tiges filetées et d’écrous, permettant une structure stable et facilement démontable.

  2. Installation des Servomoteurs : Les deux servomoteurs ont été montés symétriquement sur le corps principal, simplifiant les équations de mouvement et assurant une répartition uniforme des charges.

Étape 3 : Fixation des Bras et du Support de Crayon
  1. Fixation des Bras : Les bras articulés ont été fixés aux extrémités du corps principal, offrant une grande liberté de mouvement pour le crayon.

  2. Montage du Support de Crayon : Le support de crayon a été fixé à l’extrémité des bras. Un servomoteur supplémentaire permet le relevage du crayon via une glissière.

Étape 4 : Intégration de l’Électronique
  1. Installation de l’Électronique de Contrôle : L’électronique de contrôle devait être loger dans le coeur du robot au cas ou nous aurions le temps d'imprimer notre propre carte électronique. Cependant cela n'a pas été possible et nous avons donc laisser l'électronique de côté.

  2. Connexion des Servomoteurs : Les servomoteurs ont été connectés au microcontrôleur pour contrôler les mouvements des bras et du crayon.

Étape 5 : Tests et Ajustements
  • Calibration Initiale : Après le montage, le robot a été calibré pour assurer la précision des mouvements.

  • Tests de Dessin : Des tests de dessin ont été réalisés pour évaluer et optimiser les performances du robot. 

Pour conclure, le montage et la réalisation de notre robot dessinateur ont été simplifiés grâce à une conception CAO réfléchie, combinant découpe laser et impression 3D. Cette approche a permis d'obtenir une structure robuste, précise et facile à entretenir, capable de réaliser des dessins avec une précision très correcte.

Simplicité de Montage et Démontage

La conception CAO a été pensée pour simplifier le montage et le démontage du robot. Les assemblages par tiges filetées et écrous permettent d'accéder facilement aux composants pour la maintenance en ne dévissant que quelques écrous. Cela assure une intervention rapide et efficace, facilitant les ajustements et les réparations.

Voici ci-dessous le résultat de notre robot monté:

WhatsApp Image 2024-05-31 à 18.11.06_b596a62a.jpgWhatsApp Image 2024-05-31 à 18.11.06_12579ce7.jpg



Bilan du travail de l'équipe
  • Séance 1: Après avoir pris connaissance du sujet du projet, nous nous sommes directement mis à la recherche et à l'exploration de robots similaires existants pour s'en inspirer et nous aider à construire une idée concrète de notre but.
  • On s'est également réparti les tâches grâce à un diagramme de Gantt et à une liste des objectifs à atteindre.
    Nous avons enfin entamé la CAO après avoir établi des sketchs du robot et nous avons également commencé à chercher les équations du mouvement, indispensables par la suite.

  • Séance 2: Durant cette séance, on a réussi à finir, comme prévu la CAO, le schéma du branchement préliminaire ainsi que le calcul des équations du mouvement, adaptés à la structure "losange" de notre robot pour simplifier par la suite les programmes. On a ensuite commencé à s'interroger sur la logique suivie par notre robot surtout sur différentes manières de changer de mode. Après une bonne réflexion, pour prendre le moins d'espace possible et pour rendre les interactions plus rapides, on a décidé d'implémenter une interface permettant de contrôler le robot grâce à un seul bouton et du mouvement du joystick. On a pour cela établi les logigrammes correspondants.
  • Séance 3: Lors de cette séance, on  a finalisé la conception du robot en prévoyant les solutions de guidages et de roulements à considérer pour le mouvement. Nous avons également commencé à coder tout d'abord en insistant sur une bonne structure du code pour simplifier les tests et la résolution d'éventuels bugs. On a aussi décidé d'utiliser la découpe laser pour la création de notre robot, vu qu'elle est plus rapide, économique et convenable quant aux dimensions et aux formes du robot.
  • Séance 4 : Pendant cette séance, on a tâché de construire notre robot et de l'assembler. On a testé un premier code sur le robot mais en vain. En effet, une partie de notre modèle géométrique n'était pas assez adapté à la structure de notre robot, à cause des contraintes réelles du montage. À ce moment, on a décidé qu'il était judicieux de se partager la tâche de la programmation sur deux personnes, Ilyes, qui essaiera d'adapter le modèle géométrique aux contraintes réelles notamment celle de la zone de dessin grâce à des tests successifs et Fares, qui continuera à coder un programme final, complet, qui intègrera les résultats trouvés par Ilyes. 
  • Séance 5 : La dernière séance avant le rendu, on s'est retrouvé face à plusieurs problèmes notamment du côté de la programmation, vu que le programme complet ne fonctionnait pas , la zone de dessin étant très particulière, mais aussi du côté de l'assemblage du robot car certaines pièces n'étaient pas parfaitement faites par la découpe laser et on a eu besoin de les remplacer. Heureusement, on a pu, mais dans des programmes séparés, effectuer chacune des figures du cahier des charges , mais avec une certaine imprécision vu la nature expérimentale des constantes appliquées.

Guide d'utilisation :

  • Démarrage : brancher le câble Arduino. 
  • Le robot se met dans une position initiale (-50,100) par rapport à son repère.
  • Mode de fonctionnement par défaut : le déplacement du joystick, c'est à dire que dès qu'on bouge le joystick si aucun autre mode n'est sélectionné alors le bras bougera en fonction de la position du joystick. 
  • Choix d'un mode spécifique de fonctionnement : Pour choisir un mode spécifique, il faut tout d'abord appuyer sur le bouton afin de dire que l'on veut choisir un mode. Une fois le bouton activer le mode de déplacement avec le joystick est mis en pause le temps du choix du mode. Pour chacun des modes la led RGB changera de couleur afin de savoir quel mode nous allons sélectionner. Pour sélectionner un mode il faut déplacer le joystick dans l'une des 4 directions. 

               →Vers le haut → Mode 1: Dessine une ligne de 5 cm en trait continu.

               →Vers la bas → Mode 2: Dessine une ligne de 5cm en trait discontinu.

               →Vers la droite → Mode 3: Dessine un cercle continu de 2.5 cm de rayon.

               →Vers la gauche → Mode 4: Dessine un cercle discontinu de 2.5 cm de rayon. 

Après avoir sélectionner un mode, il faut le valider en rappuyant sur le bouton. Le mode se met donc en marche. A la fin de l'execution d'un mode le mode par défaut se remet en route. 

  • Bouton Pause : Appuyer sur le bouton du joystick, permet de mettre le stylo en position haute et donc de déplacer le stylo sans dessiner. Réappuyer sur le bouton permet de remettre le stylo ne position basse et de continuer le fonctionnement.

Démonstration :

Voici le lien youtube pour visionner notre démonstration de notre robot : https://youtu.be/blnAuUA3ipw