Trajectoires courbes

De Wiki INTech
Révision datée du 2 mars 2017 à 15:07 par Discord (discussion | contributions) (Sauf que...)
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)
Aller à : navigation, rechercher

Merci à Pierre-François GIMENEZ, Paul TURPIN, François CHARLES et Sylvain GAULTIER pour leur soutien ! - Julian "Discord" DESVIGNES

Préambule

Ce petit guide explique les bases des trajectoires courbes pour un robot “classique” bi-moteur. Ainsi, il ne concerne pas les robots holonomes ou à tout autre système de locomotion. Peut-être que à l’époque de lecture, le robot INTech utilise des techniques avancées de locomotion rendant ce guide désuet.

En tout cas, ce guide s’attarde à décrire comment sont formées les trajectoires courbes, comment piloter les moteurs pour faire suivre une telle trajectoire et leur traitement haut-niveau. Le code bas-niveau n’est pas spécifique à une architecture, il s’agit d’algorithmie en grande partie, même si le code fourni est en C++. Pour ce qui est du haut-niveau, le code dans ce guide est en JAVA, la base algorithmique reste cependant applicable à tout type de langage.

Maintenant Billy, viens te réfugier entre mes cuisses saillantes et étudions les trajectoires courbes !

Mais c’est quoi une trajectoire courbe ?

Très bonne question, Billy !

La trajectoire

En une phrase : Une trajectoire courbe est un enchaînement continu d’arcs de cercles tangents bout-à-bout.
1.PNG


Chaque arc est représenté soit par trois points, soit par deux points et les angles des tangentes à ces points.
2.PNG


Pour la robotique, on peut assimiler les trois points aux points de passage du robot. Pour ce qui est des tangentes, les angles représentent l’orientation du robot avant et après le parcours de l’arc. Ainsi, quand je dis que les arcs sont tangents bout-à-bout, je veux surtout dire que l’orientation du robot à la fin de l’arc n doit être celle au début de l’arc n+1, ainsi la courbe créée est continue en tout point.
L’intérêt majeur des trajectoires courbes est de pouvoir contourner des obstacles sans devoir s’arrêter pour tourner. Mais j’imagine que vous le saviez déjà si vous cherchez à faire des trajectoires courbes !

L’arc

Vu que ces trajectoires ne sont qu’un enchaînement d’arcs de cercle, il faut en déterminer les caractéristiques et les enchaîner. Les deux plus importantes dans notre cas sont le rayon de courbure R et la longueur d’arc L. La raison de cela est expliquée plus loin.

La formule qui lie les deux est simplement : L = \theta.R\theta est l’angle de balayage

Nous pouvons déduire l’angle de balayage de la différence entre l’angle de la tangente à la fin de l’arc et l’angle de celle au début.
3.PNG


Ici on a bien \theta = \alpha_{b} - \alpha_{a}

Comment les déduire ?

Les deux méthodes que nous prenons en compte pour décrire un arc ne définissent ni rayon de courbure, ni longueur d’arc, il faut ainsi les déduire. Un peu de trigonométrie et nous pouvons les trouver mathématiquement. Les méthodes suivantes peuvent être améliorées, je ne suis pas l’exemple à suivre en terme de trigonométrie...

Ayant les positions de départ et de fin de l’arc dans les deux méthodes, nous devons déduire le centre de l’arc pour connaître le rayon de courbure.

Avec les deux points et l’angle d’une tangente

L’idée est, comme les deux tangentes sont... tangentes (à l’arc), les droites perpendiculaires à ces dernières au point de tangence se coupent au centre de l’arc.

On prend c la longueur de la corde et R le rayon de courbure.
4.PNG


On en déduit une relation par les angles : \cos{(\dfrac{\pi}{2}-\alpha)} = \dfrac{c}{2R}

Il faut ainsi juste déterminer l’angle entre la tangente et la corde de l’arc. On en déduit :

R = \dfrac{c}{2.\cos{(\dfrac{\pi}{2}-\alpha)}} \qquad \qquad L = R.2.|\alpha|

Avec les trois points

Le troisième point est un point au hasard sur l’arc. Ici, on utilise les vecteurs reliant le point de départ au troisième et le point d’arrivée au troisième, puis on les translate vers l’autre extrémité, ces vecteurs sont directeurs de deux droites qui se coupent au centre de l’arc.
5.PNG

On pose : \qquad A = \begin{pmatrix}X_{a}\\Y_{a}\end{pmatrix} \qquad B = \begin{pmatrix}X_{b}\\Y_{b}\end{pmatrix} \qquad C = \begin{pmatrix}X_{c}\\Y_{c}\end{pmatrix} \qquad les points sur l’arc.

On a égalité des normes des vecteurs allant du centre aux points :

\left\{
\begin{array}{r c l}
(X_{a} - X_{Centre})^{2}+(Y_{a} - Y_{Centre})^{2} = (X_{b} - X_{Centre})^{2}+(Y_{b} - Y_{Centre})^{2}\\
(X_{a} - X_{Centre})^{2}+(Y_{a} - Y_{Centre})^{2} = (X_{c} - X_{Centre})^{2}+(Y_{c} - Y_{Centre})^{2}
\end{array}
\right.

On en déduit :

X_{Centre} = -\dfrac{Y_{b}(Y_{c}^{2}-Y_{a}^{2}+X_{c}^{2}-X_{a}^{2})+Y_{a}(-Y_{c}^{2}-X_{c}^{2}+X_{b}^{2})+Y_{a}^{2}Y_{c}-X_{b}^{2}Y_{c} +X_{a}^{2}Y_{c}+Y_{b}^{2}(Y_{a}-Y_{c})}{2X_{b}Y_{c}-2X_{a}Y_{c}+(2X_{a}-2X_{c})Y_{b}+(2X_{c}-2X_{b})Y_{a}} Y_{Centre} = \dfrac{X_{b}(Y_{c}^{2}+X_{c}^{2}-X_{a}^{2})+X_{a}(-Y_{c}^{2}-X_{c}^{2})+(X_{a}-X_{c})Y_{b}^{2}+(X_{c}-X_{b})Y_{a}^{2}+X_{a}^{2}X_{c}+X_{b}^{2}(X_{a}-X_{c})}{2X_{b}Y_{c}-2X_{a}Y_{c}+(2X_{a}-2X_{c})Y_{b}+(2X_{c}-2X_{b})Y_{a}} R = \sqrt{(X_{a} - X_{Centre})^{2}+(Y_{a} - Y_{Centre})^{2}} \qquad \qquad L = R.|\arccos{\dfrac{X_{a}-X_{Centre}}{R}} - \arccos{\dfrac{X_{c}-X_{Centre}}{R}}|

Et tout ça pour ?

La ferme, Billy !
La méthode de pilotage expliquée plus tard utilise le rayon de courbure et la longueur d’arc pour commander les moteurs, ces formules mathématiques servent à rendre la mise en place de trajectoires courbes de manière plus intuitive. La méthode des trois points sont à voir comme des points de passage, alors que la méthode des angles peut servir à maîtriser l’orientation du robot après le déplacement courbe, très utile pour se placer correctement et rapidement ! Attention cependant aux courbes spéciales, demander la même orientation au début et à la fin de l’arc revient à faire une ligne droite, et le robot en fera autant !

L’odométrie en trajectoire courbe

Le problème

C’est bien joli de faire un arc, mais il vaudrait mieux que l’on ne perde pas sa position en cours de chemin. Le système actuel de codeuses montées sur roues auxiliaires, bien que ce système ne soit pas optimal, il permet sans problème de ne pas perdre sa position en toute condition, il faut juste faire attention à ne pas faire “le crabe”.Sauf que, la méthode utilisée actuellement pour déterminer le point en t+dt, c’est de prendre la distance parcourue et de la projeter par rapport à l’orientation actuelle du robot. Totalement valide pour une trajectoire rectiligne ou quand on tourne sur place, cela devient imprécis en trajectoire courbe.
6.PNG

On observe bien un décalage assez élevé entre la vraie position et la position déterminée par le robot.

Sauf que...

Pas d’inquiétude, Billy !

Prenons en compte les caractéristiques actuelles de l’asservissement. Nous avons une fréquence d’asservissement de 2\ kHz, sachant que la vitesse maximale du robot est de 1\ m.s^{-1}, déterminons la distance maximale parcourue :

D_{max} = V.dt = 0.5\ mm

Si nous prenons maintenant en compte le rayon de courbure d’un arc d’une telle longueur et d’un angle de balayage assez grand pour observer le décalage de position :

R = \dfrac{D_{max}}{\dfrac{\pi}{2}} = 0.32\ mm

Donc vu la faiblesse du rayon de courbure, la différence de position est de l’ordre du 1/10ème de millimètre, soit 10x inférieur à l’erreur induite par les codeuses en cours de match !

Le rayon de courbure étant tellement faible que cela revient quasiment à tourner sur place, le résultat obtenu est largement exagéré, le balayage entre t et t+dt étant plutôt de l’ordre de 10^{-2}\ rad, ce qui nous donne :

R = \dfrac{D_{max}}{10^{-2}} = 50\ mm

Or un arc de 0.5\ mm de longueur avec un rayon 100x plus grand est quasiment un petit segment rectiligne. Ainsi, l’approximation est légitime dans notre cas.

- Mais... Mais c’est pas rigoureux !
- Ça suffit Billy !

En effet, cela peut sembler rapide comme approximation, mais il faut penser que l’erreur induite est de l’ordre d’environ 1/100ème de millimètre, or nous avons déjà une erreur de quelques millimètres induite par les codeuses, donc cela ne nous gène pas du tout d’assimiler la courbe à un ensemble de petits segments.
Cependant, si vous souhaitez obtenir une meilleure précision par interpolation circulaire, vous pouvez lire ce cours de RCVA sur le sujet : www.rcva.fr/wp-content/uploads/2016/12/Localisation.pdf

Le suivi de l’arc : pilotage des moteurs

Avant de commencer

Le robot étant asservit à la fois en translation et en rotation, il faut cependant faire attention aux idées fausses sur l’asservissement en trajectoire courbe. Durant sa trajectoire, le robot n’est pas asservi en rotation, il se contente d’effectuer une “translation spéciale”. Je m’explique :
7.PNG

On a \vec{V} la vitesse du centre du robot, \vec{V_{g}} la vitesse du moteur gauche et \vec{V_{d}} la vitesse du moteur droit.
Ce que l’on observe, c’est que pour une trajectoire courbe, les vitesses des deux moteurs sont différentes, ce qui change fondamentalement d’une translation où ils ont la même, et d’une rotation où la vitesse de l’un est l’opposée de l’autre. Sauf que, nous souhaiterions quand même garder une vitesse \vec{V} contrôlée, comme pour un autre mouvement.

La technique

Sans grande surprise, nous allons affecter des coefficients aux moteurs de telle manière que la moyenne des vitesses gauche et droite reste égale à ||\vec{V}||.

Mais que choisir comme coefficient ?

Et bien cela dépend de ce qui définit l’arc à parcourir. Dans notre cas, comme vu précédemment, nous allons utiliser le rayon de courbure et la longueur d’axe. Il y a une raison simple à cela : La simplicité de commande. On calcule les coefficients à l’aide du rayon de courbure, on les applique et on demande d’avancer de la longueur d’arc. Une seule variable dépend du robot et est à mesurer, la distance entre les différents arcs gauche et droite par rapport à l’arc central, on l’appellera d. Attention, d est un valeur pouvant être négative, elle dépend du sens vers lequel l’on tourne. Ici nous somme en sens anti-trigonométrique, donc d sera négative.
Ainsi les coefficients deviennent :

C_{gauche} = \dfrac{R-d}{R} \qquad \qquad C_{droite} = \dfrac{R+d}{R}

Avec, bien sûr :

V_{gauche} = C_{gauche}.V_{translation} \qquad \qquad V_{droite} = C_{droite}.V_{translation}

Détermination de d

 
- C’est la distance entre les roues, nan ?
- Pas exactement, Billy. Laisse ma profonde voix éclaircir ton jeune esprit encore vierge!

Et c’est justement là où il ne faut pas se précipiter. Comme je l’ai dit précédemment, cette valeur dépend du sens de rotation, un sens anti-trigonométrique donne un d négatif. Cette valeur n’est pas à calculer mais à mesurer, il s’agit de la distance entre les deux codeuses divisée par 2. Donc, sauf s’il s’agit de moteurs à codeuses intégrées, il ne s’agit pas de la distance entre les roues motorisées ! Cela risque de rendre une courbe suivie avec un rayon différent de ce qui était prévu.

Le code

Je ne compte pas décrire le fonctionnement de l’asservissement et interruptions dans ce guide, ce n’est pas son but après tout. Sachez juste que le robot vérifie son état périodiquement pour ajuster les vitesses et agir en cas de mesures anormales.


Le premier morceau est le traitement des données reçues :


float radiusDiff = WHEEL_DISTANCE_TO_CENTER; //C'est la distance d
float finalAngle = (arcLength / ABS(curveRadius)) + getAngleRadian(); //C'est l'orientation du robot 
                                                                      //  à la fin de l'arc
if(curveRadius < 0 ) // Si le rayon de courbure est négatif, on tourne dans l'autre sens
    radiusDiff = (-1)*radiusDiff;

leftCurveRatio = (ABS(curveRadius)-radiusDiff)/ABS(curveRadius); //Mise en place du coefficient gauche
rightCurveRatio = (ABS(curveRadius)+radiusDiff)/ABS(curveRadius); //Mise en place du coefficient droit

enableRotationControl(false); //On désactive l'asservissement en rotation, PENSEZ A LA REACTIVER A LA FIN !!
curveMovement = true; //On indique que l'on se déplace en arc
orderTranslation(static_cast<int32_t>(arcLength)); //On ordonne une translation de la longueur d'arc
orderRotation(finalAngle, FREE); //On informe quand même que l'on va tourner jusqu'à l'angle final

 
Ces deux lignes servent à l’application des coefficients :


leftSpeedSetpoint = translationSpeed*leftCurveRatio - rotationSpeed;
rightSpeedSetpoint = translationSpeed*rightCurveRatio + rotationSpeed;

Attention cependant s’il y a une limitation d’accélération, il faut appliquer les coefficients aux limitations pour garder le ratio de vitesse et éviter d’avancer tout droit au début de l’arc, et ainsi dévier de la trajectoire prévue. Ce bout de code est une limitation adaptée :


// Limitation de l'accélération du moteur gauche
if(leftSpeedSetpoint - previousLeftSpeedSetpoint > maxAcceleration)
{
    leftSpeedSetpoint = previousLeftSpeedSetpoint + maxAcceleration*leftCurveRatio;
}
else if(leftSpeedSetpoint - previousLeftSpeedSetpoint < -maxAcceleration)
{
    leftSpeedSetpoint = previousLeftSpeedSetpoint - maxAcceleration*leftCurveRatio;
}

// Limitation de l'accélération du moteur droit
if(rightSpeedSetpoint - previousRightSpeedSetpoint > maxAcceleration)
{
    rightSpeedSetpoint = previousRightSpeedSetpoint + maxAcceleration*rightCurveRatio;
}
else if(rightSpeedSetpoint - previousRightSpeedSetpoint < -maxAcceleration)
{
    rightSpeedSetpoint = previousRightSpeedSetpoint - maxAcceleration*rightCurveRatio;
}
    
previousLeftSpeedSetpoint = leftSpeedSetpoint;
previousRightSpeedSetpoint = rightSpeedSetpoint;

Un point obligatoire : l’asservissement en vitesse des moteurs

C’est bien d’ordonner une vitesse aux moteurs, mais faut-il encore qu’ils la suivent ! Or, si cette vitesse n’est pas contrôlée (donc asservie), la vitesse des moteurs risque juste d’être aléatoire au possible. Implicitement, le code présenté précédemment suppose un asservissement en vitesse, cette sous-partie n’a pas pour but de détailler la mise en place d’un asservissement en vitesse, je ne décris qu’un problème propre à notre système qui se doit d’être corrigé : la non-continuité de la mesure.
Dans notre système actuel, nous ne mesurons que le nombre de ticks passés entre deux interruptions (0.5\ ms). Or à basse vitesse, cela peut valoir 0, le robot se croyant à l’arrêt, donc il va augmenter l’alimentation des moteurs, mais forcera le robo à aller plus vite que prévu, nous n’avons plus une vitesse contrôlée.
La méthode que nous avons utilisé est la moyenne mobile : Il s’agit d’une moyenne faite sur un nombre n constant de valeurs, ainsi quand le nombre de valeurs mesurées i dépasse n, on soustrait à la somme la valeur i-n et on ajoute la valeur n :

V(t=i) = \dfrac{1}{n}\sum\limits_{k=i-n+1}^{i}V_{instantanee}(t=k)

n est à choisir judicieusement, une valeur trop grande risque de saturer le peu de mémoire vive de la STM32 et risque de créer un effet “d’inertie” de la vitesse (le robot est arrêté, mais le code ne le voit pas à cause de la moyenne non nulle), alors qu’une valeur trop petite ne représente pas bien la vitesse.
Une valeur correcte est de n=25.

La gestion haut-niveau des trajectoires courbes

N’aie crainte, Billy ! Tu as déjà vu le plus difficile !

Créer un arc

Nous voilà arrivés au haut-niveau, il est temps de passer à la gestion des trajectoires courbes dans ce dernier. Nous allons avoir besoin d’une nouvelle classe définissant les arcs. Deux constructeurs sont à prévoir, l’un avec trois points, l’autre avec deux points et un angle (de départ ou de fin, un booléen indicateur est à rajouter en argument). Je ne vais pas détailler cette classe, les constructeurs sont assez simple à mettre en place, et il suffit d’utiliser les formules de la partie 2. pour calculer les caractéristiques de l’arc.
Le système de locomotion reste quasiment identique à une trajectoire rectiligne, seul deux choses changent la symétrisation et la détection d’obstacles.

La symétrisation de l’arc

Sûrement la plus petite les sous-parties, la symétrisation d’un arc consiste à inverser le sens de parcours, c’est-à-dire de “tourner” dans l’autre sens. Or, comme vu dans une note de la sous-section 4.3, le sens de rotation est défini par le signe du rayon de courbure, ainsi il suffit de multiplier le rayon de courbure par -1 si on est de l’autre côté de la table. Voilà.

La détection d’obstacles

Comment ne pas se manger l’ennemi en pleine trajectoire ? Normalement, vous avez déjà un évitement des obstacles qui sont en face du robot quand il translate rectilignement. Mais cette méthode vérifie si un cercle devant le robot est libre de tout obstacle, or ici, ce n’est plus exactement valide :
8.PNG

L’idée serait de déplacer le centre de cercle sur l’arc, tout en gardant la même distance par rapport au robot. L’idée est de construire un arc temporaire à partir du point par lequel il a été commencé et le point actuel du robot, ainsi que l’orientation actuelle du robot (par deux points et un angle). Ensuite on suppose que cet arc a été prolongé et la corde de cette prolongation est la distance de vérification d. Et on détermine enfin le point final de l’arc prolongé, ce sera le centre du cercle de détection.
9.PNG

Ce que l’on va faire en réalité, c’est prendre le vecteur entre le centre de l’arc et la position du robot, calculer l’angle de battement de la prolongation d’arc à l’aide de la formule C = 2.R.\cos{(\dfrac{\theta}{2})}, tourner le vecteur à l’aide de la matrice de rotation, puis récupérer la position de la fin du vecteur en ajoutant les coordonnées du centre de l’arc.


Voici le code JAVA de cette méthode (“startingPos” est le début de l’arc, “actualPos” est la position du robot, “actualOrientation” est l’orientation actuelle du robot et “distance” est la distance de vérification) :

public Vec2 getNextPosition(Vec2 startingPos, Vec2 actualPos, double actualOrientation, double distance)
{
   //On créé un arc temporaire pour obtenir des infos comme le centre, le true est pour dire qu'il s'agit
   //   d'un angle de fin
   Arc tempArc = new Arc(startingPos, actualPos, actualOrientation, true);

   //L'angle de balayage que va faire le robot, distance est la corde
   double sweepAngle = 2 * Math.asin(distance / (2 * Math.abs(this.radius)));

   //Inversion de signe d'angle selon le sens de rotation, si on tourne dans le sens anti-trigo, on doit
   //   mettre un angle de balayage négatif
   int signe = 1;
   if(radius<0)
      signe = -1;

   //Ce vecteur va du centre de l'arc vers le point actuel
   Vec2 actualVect = actualPos.minusNewVector(tempArc.center);

   //On tourne le vecteur de l''angle de balayage et on ajoute les coordonnées du centre, 
   //   on renvoie le résultat
   return actualVect.turnNewVector(signe*sweepAngle).plusNewVector(tempArc.center);
}

Reprendre une trajectoire interrompue et bien se placer

C’est bien de s’arrêter avant de foncer dans l’ennemi, mais cela serait bien de reprendre le mouvement une fois le danger écarté. Sauf que, nous avons sûrement fait un déplacement pour se dégager ou autre, donc il conviendrait de créer un nouvel arc vers le point que l’on souhaitait atteindre originellement. Puis de continuer comme si de rien n’était. On doit alors stocker l’arc original pour pouvoir récupérer l’angle d’arrivée et le point d’arrivée, le nouvel arc aura seulement le point de départ de différent.
Il est totalement envisageable de continuer l’arc si le danger disparaît sans action de notre part, la méthode précédente reste cependant valable, le haut-niveau construira un arc de même rayon de courbure, il sera juste plus court.

Avant de commencer à ordonner de décrire l’arc, il convient d’être dans la bonne orientation de départ. Il faut ainsi ordonner une rotation vers l’angle de départ avant de lancer le mouvement.

Limites des trajectoires courbes

Tout n’est pas rose comme mon magnifique fessier, Billy !

Théoriquement, les trajectoires courbes c’est génial, elles permettent d’optimiser les mouvements du robot afin d’être les meilleurs à la coupe de France ! Mais... quelques problèmes assez difficiles à régler viennent ternir le tableau. Ce ne sont pas des problèmes complètement irrésolubles, peut-être la solution a déjà été trouvée, dans tous les cas, je vous invite à y réfléchir pour y trouver une solution si cela vous chante.

La non-discontinuité de l’accélération

’scontinuité de l’accélération.

Il est très tentant d’enchaîner les arcs pour suivre une trajectoire courbe sans s’arrêter, sauf que les vitesses doivent alors brutalement changer pour suivre le nouveau rayon de courbure. Or, cette chère inertie et la simple non-discontinuité de l’accélération fait qu’il y aura un petit régime transitoire qui ne respectera pas le ratio des vitesses et donc faussera la trajectoire demandée par le haut-niveau.
10.PNG


La seule possible méthode serait d’entamer la transition avant la fin de l’arc en cours pour garder le ratio des vitesses, mais l’inertie risque de poser problème tôt ou tard.

L’angle mort des capteurs

En général, on ne place pas de capteurs aux coins du robot et dirigés selon la diagonale, et cela peut poser problème si le robot effectue un arc avec un rayon de courbure assez faible. Si un ennemi passe sur la trajectoire à ce moment, impossible de le détecter, il y a de fortes chances de rentrer dans le robot adverse. Ce cas tombe rarement, mais la probabilité reste non nulle et peut entraîner une pénalité élevée.

L’accélération des moteurs

Même si la commande est parfaite, les moteurs peuvent mal réagir suivant l’état de surface de la table ou la position actuelle du robot (son équilibre, etc...). Il faut ainsi minimiser au possible ces problèmes en induisant un fort taux d’amortissement sur l’asservissement en vitesse, mais cela va forcément entraîner un vitesse plus basse et une accélération plus faible. Il faut bien adapter le système aux caractéristiques physiques du robot, tout en gardant une vitesse convenable, rien ne sert d’aller à MACH 10 si c’est pour se manger un mur !

L’asservissement à la trajectoire

Il serait plus viable de mettre en place un asservissement en rotation durant le mouvement, permettant de corriger l’angle durant le mouvement et ainsi de bien suivre la trajectoire prévue. Si l’on couple ce manquement de précision angulaire à la non-discontinuité de l’accélération, nous nous retrouvons avec une trajectoire modifiée n’arrivant pas au bon point final, faussant complètement le match prévu. Nous pouvons toujours lancer une correction en tournant vers le point prévu en y avançant, mais nous perdons alors tout le temps gagné par les trajectoires courbes. L’asservissement à la trajectoire devient alors important quand les mouvements du robot sont en grande partie des trajectoires courbes.

Conclusion

Et bien, Billy, satisfait ?
Nous voilà arrivés à la fin de ce petit guide sur les trajectoires courbes, il n’apporte certainement pas des réponses absolues aux problèmes des trajectoires courbes, mais j’ai compilé tous les problèmes qui me sont tombés dessus et comment j’ai pu les régler (ou pas).
N’hésitez pas à me poser des questions ou à m’envoyer des mails à julian.desvignes@telecom-sudparis.eu . Je vous souhaite bon courage pour la suite !
El Psy Congroo.