{"id":36,"date":"2023-06-06T23:08:02","date_gmt":"2023-06-06T21:08:02","guid":{"rendered":"http:\/\/blueplace.fr\/wp\/?p=36"},"modified":"2023-06-06T23:58:42","modified_gmt":"2023-06-06T21:58:42","slug":"robotdelta","status":"publish","type":"post","link":"https:\/\/blueplace.fr\/wp\/robotdelta\/","title":{"rendered":"Un robot delta dot\u00e9 de la vue (les calculs, OpenCV, Dynamixel&#8230;)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Petit projet sympa, permettant de jouer avec :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>une imprimante 3D<\/li>\n\n\n\n<li>OpenCV (avec C#)<\/li>\n\n\n\n<li>les servomoteurs Dynamixel<\/li>\n\n\n\n<li>un Arduino (uniquement pour l&rsquo;\u00e9lectroaimant)<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/20230515_140914-1024x909.jpg\" alt=\"\" class=\"wp-image-37\" width=\"586\" height=\"520\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/20230515_140914-1024x909.jpg 1024w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/20230515_140914-300x266.jpg 300w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/20230515_140914-768x682.jpg 768w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/20230515_140914-1536x1363.jpg 1536w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/20230515_140914.jpg 2046w\" sizes=\"auto, (max-width: 586px) 100vw, 586px\" \/><\/figure>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Vous trouverez une pr\u00e9sentation vid\u00e9o de ce robot ici : <a href=\"https:\/\/youtu.be\/Hbkp3n0x0qE\">https:\/\/youtu.be\/Hbkp3n0x0qE<\/a>.<\/p>\n\n\n\n<center><iframe loading=\"lazy\" width=\"480\" height=\"270\" src=\"https:\/\/www.youtube.com\/embed\/Hbkp3n0x0qE\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/center>\n\n\n\n<p class=\"wp-block-paragraph\">Le but de cet article est de donner des d\u00e9tails techniques compl\u00e9mentaires \u00e0 cette vid\u00e9o.<\/p>\n\n\n\n<h1 class=\"wp-block-heading is-style-default\">Fabrication<\/h1>\n\n\n\n<h2 class=\"wp-block-heading has-medium-font-size\">Plastique (\u00e7a pollue mais&#8230; \u00e7a s&rsquo;imprime)<\/h2>\n\n\n\n<p class=\"has-medium-font-size wp-block-paragraph\">Les parties blanches sont :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>dessin\u00e9es (patiemment) avec Fusion 360<\/li>\n\n\n\n<li>\u00ab\u00a0slic\u00e9es\u00a0\u00bb (= \u00ab\u00a0d\u00e9coup\u00e9es en tranches pour l&rsquo;imprimante\u00a0\u00bb) avec Cura<\/li>\n\n\n\n<li>imprim\u00e9es sur une Artillery Sidewinder-X1<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading has-medium-font-size\">Profil\u00e9s aluminium<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Les profil\u00e9s sont du MakerBeam XL. Ce n&rsquo;est pas indispensable ici&#8230; C&rsquo;est pratique, et c&rsquo;est beau, mais c&rsquo;est un peu cher&#8230;<\/p>\n\n\n\n<h2 class=\"wp-block-heading has-medium-font-size\">Les moteurs<\/h2>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:70%\">\n<p class=\"wp-block-paragraph\">Ce sont des servomoteurs Dynamixel XL-430-W250-T.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:30%\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-13.png\" alt=\"\" class=\"wp-image-145\" width=\"250\" height=\"250\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-13.png 300w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-13-150x150.png 150w\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" \/><\/figure>\n<\/div><\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-columns alignwide is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:70%\">\n<p class=\"has-text-align-left wp-block-paragraph\">Rien \u00e0 voir avec les servomoteurs de mod\u00e9lisme 3 fils marron, rouge, jaune&#8230;<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:30%\">\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-8-1024x1024.png\" alt=\"\" class=\"wp-image-137\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-8-1024x1024.png 1024w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-8-300x300.png 300w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-8-150x150.png 150w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-8-768x768.png 768w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-8-1536x1536.png 1536w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-8.png 2000w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Ceux-l\u00e0 sont enti\u00e8rement <strong>num\u00e9riques<\/strong>.<br>On leur envoie l&rsquo;angle de destination, ils y vont, et ils s&rsquo;y tiennent malgr\u00e9 la charge.<br>Ils peuvent atteindre cette destination avec un profil \u00ab\u00a0doux\u00a0\u00bb (=phase d&rsquo;acc\u00e9l\u00e9ration, puis vitesse maxi, puis phase de d\u00e9c\u00e9l\u00e9ration) ce qui rend les mouvements tr\u00e8s \u00ab\u00a0<strong>fluides<\/strong>\u00a0\u00bb et \u00ab\u00a0pro\u00a0\u00bb.<br>A tout moment il est possible de lire leur vitesse, position, temp\u00e9rature&#8230; (doc. constructeur <a href=\"https:\/\/emanual.robotis.com\/docs\/en\/dxl\/x\/xl430-w250\/\">ici<\/a>)<br>Bref, un plaisir \u00e0 commander !<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Et, comble du bonheur:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>ils se connectent \u00ab\u00a0les uns derri\u00e8res les autres\u00a0\u00bb (2 prises sur chaque moteur) ce qui limite drastiquement le c\u00e2blage \u00e0 effectuer ! (c\u00e2blage \u00ab\u00a0daisy chain\u00a0\u00bb)<\/li>\n\n\n\n<li>ils ne n\u00e9cessitent que 3 fils (pour la version \u00ab\u00a0TTL\u00a0\u00bb) qui transportent le courant de puissance, et le BUS TTL (la commande)<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">C&rsquo;est juste un peu cher (environ 55 EUR), mais il en existe de moins chers (ex: Dynamixel XL-320, 37 EUR) et aussi de beaucoup plus chers (plus puissants, solides, rapides&#8230;)<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Les \u00ab\u00a0liaisons pivot\u00a0\u00bb, ou \u00ab\u00a0articulation\u00a0\u00bb<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Je me suis pos\u00e9 beaucoup de questions \u00e0 ce sujet. Finalement je m&rsquo;en suis sorti avec 3 types de liaisons pivot :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>roulement \u00e0 bille + axe acier<\/li>\n\n\n\n<li>palier (recherche Google : \u00ab\u00a0Manchon de roulement autolubrifiant douilles en bronze fritt\u00e9\u00a0\u00bb) + axe acier<\/li>\n\n\n\n<li>al\u00e9sage dans le plastique + axe acier<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">La vid\u00e9o mentionn\u00e9e plus haut montre ces 3 montages.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"text-decoration: underline;\">Ce qui reste al\u00e9atoire<\/span> : les sites internet qui vendent des axes en acier et des roulements pour le \u00ab\u00a0grand public\u00a0\u00bb (=en petite quantit\u00e9) ne permettent pas de choisir des diam\u00e8tres aux dimensions tr\u00e8s pr\u00e9cises incluant une indication de <span style=\"text-decoration: underline;\">tol\u00e9rance<\/span>. On ne sait donc jamais si la bague du roulement sera serr\u00e9e ou pas sur l&rsquo;axe.<br>Cela dit, en pratique les charges \u00e9tant faibles, ce n&rsquo;est pas trop g\u00eanant.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Sch\u00e9ma de principe<\/h1>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"805\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/06\/RobotDelta.drawio-2-1024x805.png\" alt=\"\" class=\"wp-image-200\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/06\/RobotDelta.drawio-2-1024x805.png 1024w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/06\/RobotDelta.drawio-2-300x236.png 300w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/06\/RobotDelta.drawio-2-768x604.png 768w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/06\/RobotDelta.drawio-2.png 1447w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h1 class=\"wp-block-heading is-style-default\">Les calculs de cin\u00e9matique, et le code qui va avec<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Ici le but est de d\u00e9terminer les angles des 3 moteurs en fonction de la position (x, y, z) souhait\u00e9e du centre de la \u00ab\u00a0plateforme\u00a0\u00bb (celle qui supporte l&rsquo;\u00e9lectroaimant), et des dimensions du robot.<br>J&rsquo;ai tent\u00e9 de trouver les \u00e9quations. J&rsquo;y \u00e9tais presque, mais il me manquait quelques \u00ab\u00a0astuces\u00a0\u00bb de math\u00e9maticien pour finir. Heureusement il y a toujours un article qui traine sur internet.<br>Celui qui m&rsquo;a aid\u00e9 est celui-l\u00e0 :<br><a href=\"https:\/\/www.ohio.edu\/mechanical-faculty\/williams\/html\/PDF\/DeltaKin.pdf\">https:\/\/www.ohio.edu\/mechanical-faculty\/williams\/html\/PDF\/DeltaKin.pdf<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-file\"><a id=\"wp-block-file--media-3b683b02-e623-4c31-b77f-f03d4c580e9e\" href=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/DeltaKin_Robert_Williams_PhD.pdf\">DeltaKin_Robert_Williams_PhD<\/a><a href=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/DeltaKin_Robert_Williams_PhD.pdf\" class=\"wp-block-file__button wp-element-button\" download aria-describedby=\"wp-block-file--media-3b683b02-e623-4c31-b77f-f03d4c580e9e\">T\u00e9l\u00e9charger<\/a><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Les calculs reviennent \u00e0 d\u00e9terminer l&rsquo;intersection de 3 sph\u00e8res.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Vous trouverez ci-dessous le code (une fonction c#) correspondant aux \u00e9quations de cet article (chapitre \u00ab\u00a0<em>Inverse Position Kinematics (IPK) Solution<\/em>\u00a0\u00bb ).<br>Explication des variables et des entr\u00e9es \/ sorties de cette fonction :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>x, y, z<\/strong> : coordonn\u00e9es du centre de la plateforme triangulaire (cf. PDF), qui sont les <span style=\"text-decoration: underline;\">entr\u00e9es <\/span>de cette fonction.<\/li>\n\n\n\n<li><strong>teta1, teta2, teta3<\/strong> : les angles des moteurs, en radian, calcul\u00e9s par cette fonction, et d\u00e9finis comme dans le PDF<\/li>\n\n\n\n<li><strong>teta1Dyna, teta2Dyna, teta3Dyna<\/strong> : ces m\u00eames angles, mais traduits en unit\u00e9 \u00ab\u00a0dynamixel\u00a0\u00bb : de 0 \u00e0 4095. Ces sont les nombres qui seront envoy\u00e9s au contr\u00f4leur. Ils sont les <span style=\"text-decoration: underline;\">sorties<\/span> de cette fonction.<\/li>\n\n\n\n<li>Constantes : <strong>L, l, Up, Wb<\/strong> : les dimensions du robot, telles que d\u00e9finies dans le PDF. <\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pour ma part j&rsquo;ai pu mesurer <strong>Up, Wb<\/strong> et <strong>L<\/strong> sur <em>Fusion 360<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"text-decoration: underline;\">Remarque<\/span> :<strong> <\/strong>l&rsquo;unit\u00e9 de mesure des coordonn\u00e9es (x, y, z) d\u00e9termin\u00e9es par cette fonction est la m\u00eame que celle des dimensions du robot (ex: le millim\u00e8tre)<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>\/\/\n\/\/ Calculs de cin\u00e9matique inverse.\n\/\/ Source de ces calculs : https:\/\/www.ohio.edu\/mechanical-faculty\/williams\/html\/PDF\/DeltaKin.pdf\n\/\/\nprivate void calculeEtAffiche(double x, double y, double z, ref int teta1Dyna, ref int teta2Dyna, ref int teta3Dyna) {\n\t\/\/ V\u00e9rification des minimums \/ maximums\n\tif ((x &lt; -150) || (x &gt; 150) || (y &lt; -150) || (y &gt; 150) || (z &lt; -260) || (z &gt; -130)) {\n\t\ttextBoxCalculs.Text = \"ERREUR DE VALEUR !!\\r\\nx=\" + x + \", y=\" + y + \", z=\" + z;\n\t\treturn;\n\t}\n\n\t\/\/ Constantes\n\tdouble L = 90.316;\n\tdouble l = 230;\n\tdouble Up = 35;\n\tdouble Wb = 70.502;\n\tdouble Racine3 = Math.Sqrt(3);\n\n\t\/\/ Calculs\n\tdouble Wp = Up \/ 2;\n\tdouble Sp = 3 * Up \/ Racine3;\n\tdouble a = Wb - Up;\n\tdouble b = Sp \/ 2 - Racine3 \/ 2 * Wb;\n\tdouble c = Wp - Wb \/ 2;\n\tdouble E1 = 2 * L * (y+a);\n\tdouble F1 = 2 * z * L;\n\tdouble G1 = x * x + y * y + z * z + a * a + L * L + 2 * y * a - l * l;\n\tdouble E2 = -L * (Racine3 * (x + b) + y + c);\n\tdouble F2 = 2 * z * L;\n\tdouble G2 = x * x + y * y + z * z + b * b + c * c + L * L + 2 * (x * b + y * c) - l * l;\n\tdouble E3 = L * (Racine3 * (x - b) - y - c);\n\tdouble F3 = 2 * z * L;\n\tdouble G3 = x * x + y * y + z * z + b * b + c * c + L * L + 2 * (-x * b + y * c) - l * l;\n\tdouble t1 = (-F1 - Math.Sqrt(E1 * E1 + F1 * F1 - G1 * G1)) \/ (G1 - E1);\n\tdouble t2 = (-F2 - Math.Sqrt(E2 * E2 + F2 * F2 - G2 * G2)) \/ (G2 - E2);\n\tdouble t3 = (-F3 - Math.Sqrt(E3 * E3 + F3 * F3 - G3 * G3)) \/ (G3 - E3);\n\tdouble teta1 = 2 * Math.Atan(t1);\n\tdouble teta2 = 2 * Math.Atan(t2);\n\tdouble teta3 = 2 * Math.Atan(t3);\n\tteta1Dyna = radToDyna(teta1);\n\tteta2Dyna = radToDyna(teta2);\n\tteta3Dyna = radToDyna(teta3);\n}<\/code><\/pre>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:80%\">\n<p class=\"wp-block-paragraph\"><span style=\"text-decoration: underline;\">Attention<\/span> : dans l&rsquo;\u00e9quation suivante (du PDF)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">le  \u00ab\u00a0+ ou &#8211;\u00a0\u00bb implique 2 solutions, donc 2 angles possibles, pour chacun des 3 bras.<br>Pourquoi ?<br>Car pour une position (x, y, z) de la plateforme donn\u00e9e, il existe 2 positions possibles pour chacun des bras :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>celle physiquement possible<\/li>\n\n\n\n<li>une autre en g\u00e9n\u00e9ral impossible \u00e0 atteindre car le bras serait \u00ab\u00a0dans le support\u00a0\u00bb.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Dans mon cas c&rsquo;est le \u00ab\u00a0<strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-primary-color\">&#8211;<\/mark><\/strong>\u00a0\u00bb qui me permet de trouver un r\u00e9sultat correct (cf. calculs de t1, t2, et t3 dans le code : t1 = (-F1 <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-primary-color\"><strong>&#8211;<\/strong><\/mark>&#8230;.))<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:20%\">\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-14.png\" alt=\"\" class=\"wp-image-146\" width=\"199\" height=\"60\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-14.png 322w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-14-300x89.png 300w\" sizes=\"auto, (max-width: 199px) 100vw, 199px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<h1 class=\"wp-block-heading\">OpenCV<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Une fois que l&rsquo;on a compris comment installer OpenCV (avec Visual Studio c&rsquo;est en fait assez simple : packages NuGet OpenCvSharp4, OpenCvSharp4.Extensions, OpenCvSharp4.runtime.win, OpenCvSharp4.WpfExtension), et sa philosophie, c&rsquo;est un plaisir d&rsquo;utiliser cette librairie de \u00ab\u00a0computer vision\u00a0\u00bb.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pour d\u00e9terminer les positions des rondelles dans le rep\u00e8re de la cam\u00e9ra, je proc\u00e8de ainsi :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>au lancement de l&rsquo;application, j&rsquo;affiche l&rsquo;image de la cam\u00e9ra \u00e0 l&rsquo;\u00e9cran. Avec la souris je clique sur une rondelle rouge, puis verte, puis bleue (l&rsquo;ordre n&rsquo;a pas d&rsquo;importance) : cela me permet de r\u00e9cup\u00e9rer les valeurs HSV des 3 couleurs, qui varient selon la lumi\u00e8re pr\u00e9sente dans la pi\u00e8ce.<\/li>\n\n\n\n<li>J&rsquo;efface les zones \u00ab\u00a0inutiles\u00a0\u00bb de l&rsquo;image, avec 2 rectangles plein noirs, puis je convertis en HSV<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>Cv2.Rectangle(frameInitale, new Rect(0, 0, 640, 125), Scalar.FromRgb(0, 0, 0), -1);   \/\/ haut\nCv2.Rectangle(frameInitale, new Rect(0, 0, 200, 480), Scalar.FromRgb(0, 0, 0), -1);   \/\/ gauche\nMat frameHSV = frameInitale.CvtColor(ColorConversionCodes.BGR2HSV);\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Je cr\u00e9e une \u00ab\u00a0frame\u00a0\u00bb ne contenant que des pixels blancs et noir : les blancs correspondent \u00e0 des pixels ayant la couleur rouge, avec une certaine tol\u00e9rance (entre \u00ab\u00a0low\u00a0\u00bb et \u00ab\u00a0high\u00a0\u00bb)<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-5.png\" alt=\"\" class=\"wp-image-129\" width=\"296\" height=\"237\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-5.png 552w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-5-300x240.png 300w\" sizes=\"auto, (max-width: 296px) 100vw, 296px\" \/><\/figure>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"padding-top:0;padding-right:0;padding-bottom:0;padding-left:0;flex-basis:40%\">\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-7.png\" alt=\"\" class=\"wp-image-131\" width=\"252\" height=\"238\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-7.png 461w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-7-300x284.png 300w\" sizes=\"auto, (max-width: 252px) 100vw, 252px\" \/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>frameInRangeRouge = frameHSV.InRange(new Scalar(low_H, low_S, low_V), new Scalar(high_H, high_S, high_V));<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Je recherche dans cette image des \u00ab\u00a0zones\u00a0\u00bb de pixels blancs dont la taille est comprises entre 80 et 260 pixels (dans mon cas), et au minimum distants de 25 pixels:<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>paramsBlob.MinDistBetweenBlobs = 25f;\nparamsBlob.MinArea = 80f;\nparamsBlob.MaxArea = 260f;\ndetector = SimpleBlobDetector.Create(paramsBlob);\nkeypoints = detector.Detect(frameInRange);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Et voil\u00e0, avec un peu d&rsquo;organisation dans le code, on r\u00e9cup\u00e8re les coordonn\u00e9es de toutes nos rondelles (contenues dans <em>keypoints<\/em>)<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Changement de rep\u00e8re : cam\u00e9ra -&gt; robot<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Le but ici est de transformer les coordonn\u00e9es des rondelles obtenues dans le <span style=\"text-decoration: underline;\">rep\u00e8re de la cam\u00e9ra<\/span> par OpenCV, en coordonn\u00e9es dans le <span style=\"text-decoration: underline;\">rep\u00e8re du robot<\/span> (en 2D, au niveau de la \u00ab\u00a0planche\u00a0\u00bb)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Comme expliqu\u00e9 dans la vid\u00e9o, la cam\u00e9ra, m\u00eame plac\u00e9e parfaitement perpendiculairement au support, \u00ab\u00a0d\u00e9forme\u00a0\u00bb l&rsquo;image : voil\u00e0 \u00e0 quoi ressemble une feuille de papier quadrill\u00e9e vue par la cam\u00e9ra :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/deforme-1024x799.jpeg\" alt=\"\" class=\"wp-image-167\" width=\"490\" height=\"382\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/deforme-1024x799.jpeg 1024w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/deforme-300x234.jpeg 300w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/deforme-768x599.jpeg 768w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/deforme.jpeg 1258w\" sizes=\"auto, (max-width: 490px) 100vw, 490px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">On comprend ici clairement que la d\u00e9formation n&rsquo;est pas \u00ab\u00a0lin\u00e9aire\u00a0\u00bb, mais bien plus complexe.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Plut\u00f4t que de tenter de retrouver les calculs exacts de d\u00e9formations (li\u00e9s \u00e0 la g\u00e9om\u00e9trie de la lentille de la cam\u00e9ra), j&rsquo;ai pr\u00e9f\u00e9r\u00e9 effectuer une approximation (avec une m\u00e9thode tr\u00e8s personnelle) :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>je d\u00e9coupe la surface en 9 zones (quadrillage rouge)<\/li>\n\n\n\n<li>je consid\u00e8re que les d\u00e9formations sont \u00ab\u00a0lin\u00e9aires\u00a0\u00bb dans les 9 rectangles ainsi form\u00e9s.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">J&rsquo;estime que sur ces 9 surfaces r\u00e9duites, l&rsquo;erreur commise par cette approximation est raisonnable pour mon besoin.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">J&rsquo;appelle \u00ab\u00a0lin\u00e9aire\u00a0\u00bb la d\u00e9formation suivante, dont les calculs sont d\u00e9taill\u00e9s plus bas :<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter\"><video style=\"width:450px;\" controls src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/GEOLINEAIRE-5.mp4\"><\/video><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Pour effectuer ce changement de rep\u00e8re, voil\u00e0 donc comment j&rsquo;ai proc\u00e9d\u00e9 :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>sur l&rsquo;image de la cam\u00e9ra j&rsquo;ai ajout\u00e9 un quadrillage (rouge) :<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/Cadrillage.png\" alt=\"\" class=\"wp-image-165\" width=\"356\" height=\"287\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/Cadrillage.png 548w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/Cadrillage-300x242.png 300w\" sizes=\"auto, (max-width: 356px) 100vw, 356px\" \/><\/figure>\n<\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>sur une feuille fix\u00e9e au support (planche) j&rsquo;ai trac\u00e9 des croix aux intersections des lignes rouges (en me \u00ab\u00a0guidant\u00a0\u00bb avec l&rsquo;\u00e9cran) On voit ces croix ci-dessus et ci-dessous.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/repere_robot-1024x492.jpg\" alt=\"\" class=\"wp-image-164\" width=\"530\" height=\"254\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/repere_robot-1024x492.jpg 1024w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/repere_robot-300x144.jpg 300w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/repere_robot-768x369.jpg 768w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/repere_robot-1536x739.jpg 1536w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/repere_robot-2048x985.jpg 2048w\" sizes=\"auto, (max-width: 530px) 100vw, 530px\" \/><\/figure>\n<\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>j&rsquo;ai d\u00e9termin\u00e9 les coordonn\u00e9es de ces 16 points dans le <span style=\"text-decoration: underline;\">rep\u00e8re du robot<\/span>, en guidant manuellement (\u00e0 la souris) le robot au dessus de chacun d&rsquo;eux.\n<ul class=\"wp-block-list\">\n<li>Pour information voil\u00e0 ces coordonn\u00e9es (elles n&rsquo;ont aucun int\u00e9r\u00eat pour vous, lecteur, c&rsquo;est simplement pour \u00ab\u00a0concr\u00e9tiser\u00a0\u00bb) :<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>            A4\t140, -115\n            A3\t137,-56\n            A2\t138,2\n            A1\t138,71\n            B4\t68,-112\n            B3\t67,-53\n            B2\t65,6\n            B1\t59,77\n            C4\t-18, -121\n            C3\t-14, -57\n            C2\t-15, 9\n            C1\t-26, 80\n            D4\t-118, -127\n            D3\t-114,-59\n            D2\t-115, 12\n            D1\t-128, 87<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A partir de ces donn\u00e9es, je peux effectuer le changement de rep\u00e8re \u00ab\u00a0local\u00a0\u00bb (que j&rsquo;appelle \u00ab\u00a0lin\u00e9aire\u00a0\u00bb) de la mani\u00e8re suivante (\u00e0 lire avec le sch\u00e9ma un peu plus bas) :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>je d\u00e9termine dans quel rectangle se trouve le centre P de la rondelle (centre renvoy\u00e9 par OpenCV)\n<ul class=\"wp-block-list\">\n<li>Exemple: le rectangle B2, C2, B3, C3<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>je calcule les coordonn\u00e9es de P \u00ab\u00a0dans\u00a0\u00bb ce rectangle avec pour unit\u00e9 de mesure ses propres c\u00f4t\u00e9s. Exemple : (0,2 , 0,3)<\/li>\n\n\n\n<li>j&rsquo;en d\u00e9duis les coordonn\u00e9es des 4 points \u00ab\u00a0Phaut, Pbas, Pgauche, Pdroite\u00a0\u00bb dans le rep\u00e8re du robot<\/li>\n\n\n\n<li>ce qui me permet de calculer les coordonn\u00e9es de P dans le rep\u00e8re du robot : intersection du segment Phaut-Pbas avec le segment Pgauche-Pdroite.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"460\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-19-1024x460.png\" alt=\"\" class=\"wp-image-181\" srcset=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-19-1024x460.png 1024w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-19-300x135.png 300w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-19-768x345.png 768w, https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-19.png 1162w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Vous trouverez le code complet ci-dessous, chap\u00eetre \u00ab\u00a0Le code\u00a0\u00bb &#8211; Projet \u00ab\u00a0Delta_Camera\u00a0\u00bb.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">J&rsquo;ai du cr\u00e9er une fonction permettant de trouver l&rsquo;intersection de 2 droites. Je l&rsquo;\u00e9cris ici car elle peut \u00eatre utile pour d&rsquo;autres usages, et j&rsquo;aurais aim\u00e9 la trouver sur internet \ud83d\ude42<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public void <strong>intersectionDroites<\/strong>(double x1a, double y1a, double x2a, double y2a, double x1b, double y1b, double x2b, double y2b, out double xi, out double yi) {\n    xi = ((y1b - y1a) * (x1b - x2b) * (x1a - x2a) - (y1b - y2b) * (x1a - x2a) * x1b + x1a * (y1a - y2a) * (x1b - x2b)) \/ ((y1a - y2a) * (x1b - x2b) - (y1b - y2b) * (x1a - x2a));\n    yi = ((x1b - x1a) * (y1b - y2b) * (y1a - y2a) - (x1b - x2b) * (y1a - y2a) * y1b + y1a * (x1a - x2a) * (y1b - y2b)) \/ ((x1a - x2a) * (y1b - y2b) - (x1b - x2b) * (y1a - y2a));\n}<\/code><\/pre>\n\n\n\n<h1 class=\"wp-block-heading\">Le code (t\u00e9l\u00e9chargeable)<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">J&rsquo;ai choisi le langage C#, et j&rsquo;ai cr\u00e9\u00e9 2 projets (donc 2 ex\u00e9cutables) sous Microsoft Visual Studio.<br>Si vous y tenez vraiment, vous trouverez ci-joint le code (ZIP des 2 projets).<br>Je ne l&rsquo;ai pas mis sur GitHub car il n&rsquo;est pas assez \u00ab\u00a0finalis\u00e9\u00a0\u00bb, pas assez \u00ab\u00a0pro\u00a0\u00bb (les IHM ne sont pas tr\u00e8s belles etc\u2026)<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"text-decoration: underline;\">Projet \u00ab\u00a0Delta_Dynamixel\u00a0\u00bb<\/span>\n<ul class=\"wp-block-list\">\n<li>permet de piloter les moteurs (manuellement, automatiquement&#8230;) avec la librairie fournie par le constructeur des moteurs.<\/li>\n\n\n\n<li><a href=\"https:\/\/drive.google.com\/file\/d\/1aTWaOxb7lITodqY3ZOU4g5vi7rKztXY7\/view?usp=sharing\">T\u00e9l\u00e9chargeable ici<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"text-decoration: underline;\">Projet \u00ab\u00a0Delta_Camera\u00a0\u00bb<\/span>\n\n\n\n\n\n\n\n\n\n\n\n\n<ul class=\"wp-block-list\">\n<li>avec OpenCV, il r\u00e9cup\u00e8re l&rsquo;image de la cam\u00e9ra, calcule les positions des rondelles dans le rep\u00e8re de la cam\u00e9ra<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li>calcule ces positions dans le rep\u00e8re du robot (calculs d\u00e9taill\u00e9s ici plus haut)<\/li>\n\n\n\n<li>envoie ces informations \u00e0 l&rsquo;ex\u00e9cutable de Delta_Dynamixel, sur sa demande, en utilisant les \u00ab\u00a0Named Pipe\u00a0\u00bb (package NuGet IPC.NamedPipe) pour cette transmission.<\/li>\n\n\n\n<li>Packages NuGet \u00e0 installer pour OpenCV : OpenCvSharp4, OpenCvSharp4.Extensions, OpenCvSharp4.runtime.win, OpenCvSharp4.Windows, OpenCvSharp4.WpsExtensions<\/li>\n\n\n\n<li><a href=\"https:\/\/drive.google.com\/file\/d\/1p-l6b02Zdw0Ov2i0VaQM6rrzLqgY1sEI\/view?usp=sharing\">T\u00e9l\u00e9chargeable ici<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Pourquoi \u00ab\u00a0Delta\u00a0\u00bb<\/h1>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:80%\">\n<p class=\"wp-block-paragraph\">La lettre grecque Delta majuscule ressemble \u00e0 un triangle, comme la disposition des moteurs.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:20%\">\n<figure class=\"wp-block-image size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/blueplace.fr\/wp\/wp-content\/uploads\/2023\/05\/image-16.png\" alt=\"\" class=\"wp-image-158\" width=\"78\" height=\"87\"\/><\/figure>\n<\/div>\n<\/div>\n\n\n\n<h1 class=\"wp-block-heading\">Pr\u00e9cision<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Les moteurs sont tr\u00e8s pr\u00e9cis&#8230; m\u00eame si je n&rsquo;ai pas de mesures pr\u00e9cises \u00e0 vous donner. Pour information, leur positionnement se fait avec un nombre compris en 0 et 4095.<br>Avec ma construction \u00ab\u00a0faite maison\u00a0\u00bb j&rsquo;arrive \u00e0 une pr\u00e9cision d&rsquo;environ 2mm ou 3mm sur le positionnement de la plateforme. Je pensais faire mieux, mais ce n&rsquo;est pas grave, c&rsquo;est d\u00e9j\u00e0 suffisant pour bien s&rsquo;amuser !<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Limitations<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Les moteurs Dynamixel me permettent facilement de <span style=\"text-decoration: underline;\">positionner<\/span> la plateforme. Je maitrise donc cette position, mais pas la <span style=\"text-decoration: underline;\">trajectoire<\/span>. C&rsquo;est parfois g\u00eanant : par exemple si je veux \u00ab\u00a0raser le sol\u00a0\u00bb \u00e0 grande vitesse, la <span style=\"text-decoration: underline;\">g\u00e9om\u00e9trie du robot delta<\/span> fait que, dans certaines configurations, la plateforme va vouloir \u00ab\u00a0rentrer\u00a0\u00bb l\u00e9g\u00e8rement dans le \u00ab\u00a0sol\u00a0\u00bb, elle va donc le \u00ab\u00a0racler\u00a0\u00bb.<br>Une solution est d&rsquo;atteindre successivement les diff\u00e9rents points de cette trajectoire. Mais dans ce cas le d\u00e9placement est plus lent.<br>Maitriser les trajectoires, les vitesses et les positions demanderait une commande tr\u00e8s fine des moteurs, avec des notions de dynamiques. Je ne me suis pas lanc\u00e9 l\u00e0-dedans, et je ne sais pas s\u00a0\u00bbil est possible d&rsquo;obtenir de bons r\u00e9sultats avec ces moteurs, et une commande en C#&#8230; Des moteurs pas \u00e0 pas seraient peut-\u00eatre plus adapt\u00e9s.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Postface<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">J&rsquo;ai essay\u00e9 de rassembler ici (et dans la vid\u00e9o) des informations qui m&rsquo;auraient aid\u00e9 \u00e0 r\u00e9aliser ce projet. J&rsquo;esp\u00e8re qu&rsquo;elles seront utiles \u00e0 d&rsquo;autres personnes. Si c&rsquo;est le cas, un commentaire me fera plaisir !<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Petit projet sympa, permettant de jouer avec : Vous trouverez une pr\u00e9sentation vid\u00e9o de ce robot ici : https:\/\/youtu.be\/Hbkp3n0x0qE. Le<\/p>\n","protected":false},"author":1,"featured_media":37,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12],"tags":[22,17,20,21,16,15,19,18],"class_list":["post-36","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-robotique","tag-c","tag-calculs","tag-cinematique-inverse","tag-csharp","tag-dynamixel","tag-opencv","tag-robot","tag-robot-delta"],"_links":{"self":[{"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/posts\/36","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/comments?post=36"}],"version-history":[{"count":68,"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/posts\/36\/revisions"}],"predecessor-version":[{"id":218,"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/posts\/36\/revisions\/218"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/media\/37"}],"wp:attachment":[{"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/media?parent=36"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/categories?post=36"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blueplace.fr\/wp\/wp-json\/wp\/v2\/tags?post=36"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}