Étiquette : AxiDraw

Projets

Logo « Ami » avec l’AxiDraw

L’AxiDraw est une machine permettant de dessiner sur une feuilles avec un stylo selon un programme. En spé Nsi nous avons la possibilité de l’utiliser pour ce projet de fin première.

Introduction

J’ai décidé de reprendre un logo tiré du manga « 20th century boys », car j’aime beaucoup le design et il me semblait simple à recréer avec le code python pour l’AxiDraw.

Le début du travail

Nous avons appris comment utiliser l’AxiDraw avec nos professeurs pendant le cours, et donc la première chose à comprendre a été de coder ce dessin. C’est plutôt simple à comprendre, en effet l’AxiDraw marche seulement avec les coordonnés, on a des fonctions « segment » et « segments » fourni.

def segment(x_depart:int, y_depart:int, x_arrivee:int, y_arrivee:int):
    if not coord_in_cadre(x_depart,y_depart) or not coord_in_cadre(x_arrivee,y_arrivee):
        # raise ValueError("Dépassement du cadre imposé")
        global dessin_valide
        dessin_valide = False
        print("Segment ne pouvant être tracé")
        return
    if axi_connect and dessin_valide:
        ad.goto(x_depart * 8.267 / 793.7, y_depart * 8.267 / 793.7) 
        ad.pendown() # Le stylo est baissé
        ad.lineto(x_arrivee * 8.267 / 793.7, y_arrivee * 8.267 / 793.7) 
        ad.penup()  # Le stylo est relevé en fin de tracé
    else:
        draw.line((x_depart, y_depart, x_arrivee, y_arrivee), fill = black) # Tracé du segment
   
def segments(points:list):
    for i in range(len(points) - 1):
        if not coord_in_cadre(points[i][0],points[i][1]) or not coord_in_cadre(points[i+1][0],points[i+1][1]):
            global dessin_valide
            dessin_valide = False
            print("Segments ne pouvant être tracés")
            return        
    if axi_connect and dessin_valide:
        for i in range(len(points)):
            points[i][0], points[i][1] = points[i][0] * 8.267 / 793.7, points[i][1] * 8.267 / 793.7
        ad.goto(points[0][0], points[0][1])
        ad.draw_path(points) 
        ad.penup() 
    else:
        for i in range(len(points)-1):
            draw.line((points[i][0], points[i][1], points[i+1][0], points[i+1][1]), fill = black) 

Ces deux fonctions ont besoin de coordonnés précises pour fonctionner. Pour avoir ces coordonnés j’ai eu une idée plutôt simple à utiliser, j’ai utilisé Paint car l’application donne les coordonné de la souris en temps réel. La dernière étape était de simplifier mon dessin d’origine en usant de segments et de points, puis j’ai pu reprendre tout les coordonnées et les mettre dans mon code python.

Différentes parties du dessin :

Pour l’intérieur de l’oeil j’ai utilisé les fonctions cercles codé par mes professeurs, cette fonction a besoin des coordonnés du centre du cercle et du rayon pour pouvoir dessiner les cercles. C’est assez facile à dessiner, voici le résultat :

Pour tout le contour de l’oeil et la main à l’intérieur, j’ai utilisé la fonction segments qui permet de dessiner plusieurs segments les uns à la suite des autres à partir des coordonné de chaque point noté sur le screenshot de paint juste au dessus.

Le dessin que j’ai choisi n’étant pas vraiment répétitif je n’ai pas pu utilisé de fonction crée par moi même alors j’ai simplement tout fait avec les fonctions segment, segments, cercle et polygone.

Voici tout le code que j’ai écris et l’image final :

Le code python

segments(([443,207],[400,219],[355,254],[289,315],[236,353],[190,374],[230,394],[265,415],[315,455],[360,490],[425,509],[610,510],[708,452],[759,410],[823,380],[840,369],[819,355],[764,324],[699,261],[635,224],[568,202],[482,202]))


segment(422,530,422,507)
segment(607,530,607,507)
segments(([435,507],[435,475],[594,475],[594,507]))
segments(([458,475],[435,421],[427,357],[427,283],[440,237],[444,131],[454,120],[468,120],[478,136],[481,255]))
segments(([471,266],[490,241],[509,225],[529,230],[539,251]))
segments(([524,269],[552,236],[574,240],[587,262]))
segments(([566,286],[587,262],[599,256],[612,259],[619,273],[605,302],[604,409],[590,444],[566,475]))


polygone([[427,365],[459,335],[486,317],[513,309],[541,316],[575,332],[605,362],[579,392],[550,412],[513,422],[487,416],[464,404],[439,377]])

segments(cercle(514,367,40))
segments(cercle(514,367,19))
segments(cercle(514,367,10))

Conclusion

Ce projet de Nsi était intéressant à faire car l’AxiDraw est un outil nouveau pour moi. J’ai pu apprendre plein de chose

L’image finale

Art

Un rafale en AxiDraw

Il est parfois compliqué de se motiver pour travailler surtout en période de vacance scolaire. C’est pourquoi j’ai choisis lors de ce projet de NSI de mêler travail et passion en vous proposant un projet en lien avec l’aéronautique.

Fait de ta vie un rêve et de ton rêve une réalité.

Antoine de Saint-Exupéry

Naissance du projet :

Lorsque nos professeurs ont présenté les différentes possibilités parmi lesquelles nous pourrions réaliser notre projet, j’ai tout de suite pensé à utiliser l’ Axidraw et ce pour plusieurs raisons.

Tout d’abord, pour découvrir cette machine mais aussi pour les nombreuses possibilités d’utilisation que cette mécanique avait à m’offrir.

Ensuite, j’ai utilisé la maxime  » Il faut joindre l’utile à l’agréable » en choisissant d’utiliser ma passion, qui est celle de l’aéronautique, afin de pouvoir travailler sans regret durant les vacances.

C’ est ainsi que je me suis mis à coder un Rafale ( un célèbre avion de chasse Français ), en python !

Développement du projet

Pour commencer, il me fallait une image sur papier, une sorte de plan, de ce à quoi je voulais que mon Rafale ressemble, et ce tout en traits puisque l’Axidraw ne peut tracer de courbes.

Ma « feuille de route », une véritable œuvre d’art…

Mise en place

Une fois après avoir réalisé mon esquisse, il ne restait plus qu’à mettre à l’échelle mes différentes valeurs que je pouvais dès maintenant mesurer à la règle.

Ainsi, on obtenait :

  • 1cm sur la feuille en longueur -> 30 de longueur pour l’AXIDRAW
  • 1cm sur la feuille en largeur -> 36.5 de largeur pour l’AXIDRAW.

Ensuite, j’ai crée de nombreuses listes que j’ai ensuite appelé en utilisant les fonctions mises à notre disposition par nos professeurs de NSI :

percheravito = [[153,317.55], [141,295.65],[141,295.65], [117,292], [117,288.35], [147,292],[156,313.9]]
haut_aileron = [[759,193,45],[828,193.45],[804,175.2],[784.5,175.2]]
segments(percheravito)
polygone(haut_aileron)

Ainsi, dans l’exemple ci-dessus nous pouvons voir la liste permettant de faire la perche qui sert au ravitaillement en vol du rafale avec son appellation par la fonctions segments qui relie les points aux coordonnées x et y définis dans ma liste. L’appellation de la fonction polygone va elle rajouter un segment qui ira de mon premier point au dernier présent dans la liste haut_aileron afin de former un polygone.

Création des verrières du rafale.

Comme vous avez pu le voir dans mon esquisse de l’œuvre que je voulais produire, les verrières du rafale devaient être constellées de traits afin de donner un esthétique au rendu final mais aussi afin d’introduire quelques fonctions dans ma création.

Mais, je ne pouvais pas créer une seule et même fonction que j’appellerai pour les trois verrières puisque ces mêmes verrières étaient disposées à des endroits différents et séparés par l’armature de l’avion.

image des différentes verrières que je voulais remplir

Ainsi, j’ai du créer trois verrières :

Première verrière :

Pour cette première verrière, vu sa configuration, je n’avais pas besoin de créer un code trop important. En effet, une simple boucle for permettrait de répéter x fois en fonction du nombre de répétitions des segments, grâce à la fonctions segments fournie, en décalant x_depart, y_depart et y_arrivee à chaque répétition. Ainsi, nous obtenons ce code :

def trait(x_depart: float, y_depart: float, x_arrivee: float, y_arrivee: float, repetitions: int):
    for i in range(repetitions):
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart += 4.5
        y_depart -= 2.25
        y_arrivee -= 2.25

Seconde verrière :

Pour cette verrière, il n’était cette fois plus question de prendre une boucle for puisque si vous regardez bien elle se compose de deux parties. J’ai donc utilisé une succession de deux boucles while consécutives qui détermineraient les variations des points x et y en fonction des coordonnées d’arrivée des points de mes segments.

def traits(x_depart: float, y_depart: float, x_arrivee: float, y_arrivee: float, ):
    while x_depart >= 209 and y_depart >= 270:
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart -= 1
        x_arrivee += 0.75
        y_depart -= 2.25
        y_arrivee -= 2.25

    while x_depart <= 255 and y_depart >= 273.75:
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart += 6.5
        x_arrivee += 0.25
        y_depart -= 2.25
        y_arrivee -= 2.25

Troisième verrière :

Pour cette troisième verrière, j’ai réutilisé le code de ma seconde verrière en changeant les points x_depart, x_arrivee, y_depart, y_arrivee ainsi que les variations de ces points en fonction des boucles while ce qui nous donne :

def traittss(x_depart: float, y_depart: float, x_arrivee: float, y_arrivee: float):
    while x_arrivee <= 360 and y_arrivee >= 290.75:
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart += 0.8
        x_arrivee += 1.2
        y_depart -= 2.25
        y_arrivee -= 2.25

    while y_depart >= 278:
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart += 0.3
        x_arrivee -= 8
        y_depart -= 2.25
        y_arrivee -= 2.25

Compte rendu final des verrières :

Ainsi, après avoir appelé ces fonctions j’obtenais les verrières en image ci-dessous :

Néanmoins, comme vous vous en doutez surement, cette réalisation n’a pas été aussi facile que ce qu’il vous a été présenté puisque il a fallu calculer les variations des points x et tester différentes variations des points y afin d’obtenir le meilleur rendu visuel.

Création du réacteur :

Pour le réacteur, j’ai souhaité ajouter des segments de la même manière que pour mes verrières. J’ai donc repris le code utilisant les boucles while que j’ai développé puisqu’il ma fallu créer une troisième boucle while pour obtenir le rendu souhaité.

def react(x_depart: float, y_depart: float, x_arrivee: float, y_arrivee: float):
    while  y_arrivee >= 405.15:
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart += 0
        x_arrivee += 10
        y_depart -= 5
        y_arrivee -= 5

    while y_arrivee >= 372:
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart += 0
        x_arrivee += 0
        y_depart -= 5
        y_arrivee -= 5
        
    while y_arrivee >= 355.875:
        segment(x_depart, y_depart, x_arrivee, y_arrivee)
        x_depart -= 0
        x_arrivee -= 10
        y_depart -= 5
        y_arrivee -= 5

L’exécution de ce code ma ensuite donné ce rendu :

Dernières finitions :

Maintenant que les parties complexes de mon code ont été réalisées, il ne me restait plus que deux choses à faire :

  • Positionner la fameuse cocarde tricolore ( qui sera unicolore sur mon rendu graphique car l’Axidraw ne prend pas en charge les couleurs ) sur mon rafale.
  • « Légender » mon œuvre en écrivant le nom de l’avion représenté en dessous.

Pour la cocarde, je n’eu qu’à utiliser la fonction cercle déjà donnée et en tracer deux consécutivement, avec le même centre mais avec le rayon du second cercle moitié moins grand que le rayon du premier cercle.

Pour légender le dessin obtenu, il ne me restait seulement qu’ à exécuter une succession de segments formant le mot RAFALE.

Conclusion :

Ainsi, ce projet m’a permis de normaliser mon utilisation des fonctions et des listes. Néanmoins, je pense que de nombreuses améliorations auraient pu être possible avec un peu plus de temps notamment en ajoutant des segments pour rendre mon image plus précise mais aussi en modifiant la bordure dessinée par l’Axidraw afin qu’elle mette plus en valeur le rafale représenté.

Mais je dois quand même ajouter que je suis fier de ce que j’ai déjà réalisé car jamais je ne me serais attendu à un rendu comme celui là en n’ utilisant que des segments !

Télécharger le .py :

L’image finale :

Art

Les différentes étapes pour coder un dessin avec AxiDraw

Vous souhaitez dessiner avec précision mais vous n’avez pas le coup de main ? Vous désirez représenter plusieurs fois des images ou textes à l’identique ? L’AxiDraw est fait pour vous !

Qu’est ce que l’AxiDraw ?

Dans le cadre de notre projet libre de fin d’année en NSI, nos professeurs, Monsieur Robert et Monsieur Clemente, nous ont présenté l’AxiDraw qui permet de dessiner un projet que l’on a imaginé.

L’AxiDraw est une machine composée de deux moteurs et d’un bras automatisé au bout duquel il est possible d’ajouter différents types d’outils de graphisme.

Son fonctionnement est assez simple : il suffit de programmer les traits que l’on souhaite tracer, à l’aide du logiciel « Inskape » ou avec du langage python, et l’AxiDraw réalise alors notre modèle au format SVG (Scalable Vector Graphics).

Par où commencer ?

Au préalable, il est primordial de définir parfaitement le rendu final désiré.

Il existe différentes façons de le faire. Pour ma part, j’ai choisi de dessiner mon modèle à la main mais on peut aussi préparer son projet à l’aide de logiciels comme Paint.

J’ai donc dessiné une maison sur une feuille à petits carreaux afin de respecter plus facilement une échelle donnée. En effet, notre réalisation ne devait pas être supérieure à un cadre défini par une abscisse comprise entre 20 et 1040 pixels et une ordonnée comprise entre 20 et 730 pixels.

Programme et fonctions de codage

Une fois mon modèle prêt, il ne restait plus qu’à passer au codage !

Nos professeurs nous ont fourni un programme où de nombreux paramètres étaient déjà prédéfinis, comme la bordure de la feuille, la vitesse de l’AxiDraw ou encore différentes fonctions (pouvant tracer une succession de segments par exemple). J’ai donc utilisé ce programme et je l’ai inséré dans l’IDE Thonny. J’ai ensuite installé la bibliothèque Pyaxidraw et Pillow afin que ce dernier puisse fonctionner.

J’ai alors pu commencer réellement la programmation de mon dessin.

Tout d’abord, il était nécessaire de convertir toutes les longueurs, sur ma feuille en centimètres, en pixels. A partir des valeurs obtenues, j’ai alors défini les points délimitant les segments que je souhaitais tracer.

J’ai notamment utilisé la fonction « segments », qui permet de tracer une succession de segments en fonction d’une liste d’abscisses et d’ordonnées de points successifs, comme présentée ci dessous:

def segments(points:list):
    for i in range(len(points) - 1):
        if not coord_in_cadre(points[i][0],points[i][1]) or not coord_in_cadre(points[i+1][0],points[i+1][1]):
            global dessin_valide
            dessin_valide = False
            print("Segments ne pouvant être tracés")
            return        
    if axi_connect and dessin_valide:
        for i in range(len(points)):
            points[i][0], points[i][1] = points[i][0] * 8.267 / 793.7, points[i][1] * 8.267 / 793.7
        ad.goto(points[0][0], points[0][1])
        ad.draw_path(points) 
        ad.penup() 
    else:
        for i in range(len(points)-1): 
            draw.line((points[i][0], points[i][1], points[i+1][0], points[i+1][1]), fill = black)

ma_liste = [(926.25,661.5625),(958.75,661.5625),(975,593.125),(910,593.125),(926.25,661.5625)]
segments(ma_liste)

Cet extrait de code permet, une fois la fonction « segments » définie, de produire très simplement et d’un seul trait l’image suivante:

D’autres fonctions comme celles traçant des cercles, des rectangles ou des paraboles m’ont aussi été très utiles.

Utilisation de boucles for

Lors de la réalisation de mon dessin, j’ai veillé à utiliser des motifs qui se répétaient afin de réduire le nombre de lignes de code et ainsi, me faciliter le travail.

J’ai donc par exemple utilisé la boucle for i in range() afin de créer un panneau de bois sur la façade de la maison en soustrayant une même longueur à la hauteur du rectangle à chaque incrémentation :

def rectangle(x_depart,y_depart,delta_x,delta_y):
    polygone([[x_depart,y_depart],[x_depart + delta_x,y_depart],[x_depart + delta_x,y_depart + delta_y],[x_depart,y_depart + delta_y]])

for i in range(9):
    rectangle(568.75,319.375,113.75, 91.25 - 11.40625*i)

Image associée :

J’ai aussi voulu dessiner des platebandes d’herbe avec des boucles for i in range() mais ne sachant pas comment coder un demi-cercle, j’ai utilisé la fonction parabole, ce qui a d’ailleurs donné un rendu plus réaliste. Afin de donner un effet de profondeur à la succession de paraboles, l’ordonnée du point initiant la parabole devait être différente de l’ordonnée du point terminant la parabole. Pour cela, il fallait veiller à ajouter la bonne valeur à chaque incrémentation. En effet, il ne fallait donc plus ajouter l’écart exact entre les deux abscisses (ici 6) mais cette valeur moins 1 (ce qui revenait à ajouter 5).

def parabole1(x_depart, y_depart):
    return[(a+x_depart,a**2+y_depart) for a in range(-3,3)]

for i in range(37):
    segments(parabole1(341.25+5*i,638.75))
    
for i in range(26):
    segments(parabole1(480+5*i,604))

Image associée :

Rendu final :

Après ces petites explications, je vous partage le rendu final de mon travail qui peut être réalisé par l’AxiDraw que nous avons la chance d’avoir au Lycée Louis Pasteur d’Avignon !

Merci pour votre lecture.

Télécharger le .py :

Et pour finir, vous pouvez télécharger mon projet afin que vous puissiez le découvrir plus en détail !