Partie électronique du projet

Le schéma électronique ne change quasiment pas du schéma du mini écran LCD pour usb. En effet la seule évolution c'est le rajout de la diode infrarouge et de sa résistance pour l'envoi des commandes infrarouges vers le récepteur de Lego.
Le programme informatique de l'adaptateur USB vers commande infrarouge lego
Le programme est très simple. La boucle principale s'occupe de lire les messages séries arrivant par le port USB puis de les retranscrire en signaux légo grâce a la classe Lego détaillée dans l'article télécommande infrarouge lego power function. Les messages USB sont eux générés par un autre programme tournant cette fois ci sur le PC. Dans le programme du teensy (équivalent arduino) vous pouvez voir une méthode permettant d'utiliser l'écran LCD pour afficher ce qui se passe en ce qui concerne la réception des messages en USB. Cette phase est évidement chronophage, de ce fait si on cherche a optimiser la fluidité de transmission de notre interface il s'agira de commenter tout ce qui commence par lcd dans la fonction sendRc.
#include <liquidcrystal.h> #include "LegoRC.h" LegoRC legoRC(2, 50); LiquidCrystal lcd(24, 25, 8, 9, 27, 0); String l1="", l2="", tmpl=""; char incomingByte; int newMSG = 0; int led = 12; void setup() { pinMode(led, OUTPUT); lcd.begin(16, 2); Serial.begin(9600); } void loop() { // Lecture d'une chaine de carracteres while (Serial.available()) { digitalWrite(led, HIGH); incomingByte = Serial.read(); // will not be -1 tmpl = tmpl + char(incomingByte); newMSG = 1; } digitalWrite(led, LOW); if (newMSG) { l1 = l2; l2 = tmpl.trim(); String myString = l2; int myStringLength = myString.length()+1; char myChar[myStringLength]; myString.toCharArray(myChar,myStringLength); int result = atoi(myChar); sendRc(result); tmpl = ""; } newMSG = 0; } void sendRc(int i) { int m1 = i / 100; int m2 = i % 100; lcd.clear(); lcd.setCursor(0, 0); lcd.print(m1); lcd.setCursor(0, 1); lcd.print(m2); legoRC.sendCommand(4, m1, m2); }
Le programme informatique côté PC

La libraire openCV propose la fonction HoughCircles permettant de détecter tous les cercles reconnus à l'image. Pour chaque cercle les coordonnées x et y ainsi que le rayon du cercle détecté sont renvoyés par la fonction. Dans mon code je pars du principe qu'un seul cercle est présent a l'image, si tel n'est pas le cas, alors je prends le cercle qui a été détecté en dernier dans l'image courante. Une fois que nous disposons des coordonnées (x,y) du cercle détecté, nous pouvons donc estimer la direction de la rotation de la tourelle afin que x et y soient le plus proche possible du centre de l'image. Dans le code j'ai implémenté une variable servant d'erreur acceptée afin qu'un déplacement minime du cercle dans la vision de la webcam ne déclenche pas une rotation de la tourelle. Ce procédé me permet d'éviter la réaction de la tourelle au bruit induit par la détection des cercles par OpenCV.
#include "stdio.h" #include "opencv/cv.h" #include <math.h> #include "opencv/highgui.h" void xl(); void xr(); void yt(); void yb(); void xys(); using namespace cv; int main() { VideoCapture cap(1); // open the default camera if(!cap.isOpened()) // check if we succeeded return -1; Mat edges; namedWindow("edges",1); int circlex = 0; int circley = 0; int bbox = 0; for(;;) { Mat frame; cap >> frame; // get a new frame from camera cvtColor(frame, edges, CV_BGR2GRAY); GaussianBlur(edges, edges, Size(9,9), 2, 2); vector<vec3f> circles; HoughCircles(edges, circles, CV_HOUGH_GRADIENT, 2, edges.rows/4, 200, 100 ); if (circles.size() > 0) { for (int i = 0; i < circles.size(); i++) { circlex = cvRound(circles[i][0]); circley = cvRound(circles[i][1]); Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); int radius = cvRound(circles[i][2]); circle(frame, center, 3, Scalar(0,255,0), -1, 8, 0 ); circle( frame, center, radius, Scalar(0,0,255), 3, 8, 0 ); printf("x %d ; y %d \n", cvRound(circles[i][0]), cvRound(circles[i][1]) ); } bbox = 20; if (circlex > (320 + bbox)) { xr(); xys(); } else if ((circlex < (320 - bbox)) && (circlex != 0)) { xl(); xys(); } if (circley > (240 + bbox)) { yb(); xys(); } else if ((circley < (240-bbox)) && (circley != 0)) { yt(); xys(); } } else { circlex = 0; circley = 0; } imshow("edges", frame); if(waitKey(30) >= 0) break; } return 0; } void xl() { system("echo \"408\" > /dev/ttyACM0"); } void xr() { system("echo \"1208\" > /dev/ttyACM0"); } void yt() { system("echo \"812\" > /dev/ttyACM0"); } void yb() { system("echo \"804\" > /dev/ttyACM0"); } void xys() { system("echo \"808\" > /dev/ttyACM0"); }
Partie mécanique en légos technics et Lego Power functions
La mécanique de ce robot suiveur de balles est entièrement faite en légos technics. Seule la caméra usb est fixé sur une pièce légo standard avec des vices. Le principe est simple. La caméra peut tourner a droite ou a gauche en actionnant un des deux petits moteurs des power functions. L'autre moteur sert a la commande monter et descendre la caméra. Les deux moteurs sonts reliés a un récepteur infrarouge (première version) Légo. Le récepteur en lui même est évidement connecté a un bloc d'alimentation légo. Le récepteur infrarouge dervé évidement être mis en face de la diode infrarouge qui émet les signaux transmis par le programme PC via le port USB. La webcam utilisée dans ce projet est une simple caméra usb générique acheté une quinzaine d'euros dans une boutique d'informatique. J'ai privilégié ce modèle pour la facilité de fixation.
Fichiers du projet robot suiveur de balles a télécharger
Code source complet arduino de l'adaptateur USB vers commande légo infrarouge
Code source complet C programme de détection opencv et envoi USB (code::blocks)
Toutes les photos du projet robot suiveur de balles
Aucun commentaire:
Enregistrer un commentaire