Robot Omnidirectionnel pour Suivi de Personne en Sécurité
Composants et fournitures
| Composant | Quantité |
|---|---|
| Driver moteur double L298N (stepper/DC) | 2 |
| Régulateur abaisseur LM2596 (12V → 5V) | 1 |
| Alarme batterie LiPo (détecteur basse tension) | 1 |
| Moteur DC 12V 24 tr/min arbre 4mm (réducteur) | 3 |
| Arduino Nano R3 | 1 |
| Webcam Microsoft LifeCam HD-3000 | 1 |
| Fils de liaison (beaucoup !) | 1 lot |
| Carte Ci20 (IMagination Technologies) | 1 |
| Batterie LiPo 11,1V 3 cellules | 1 |
Outils nécessaires
- Imprimante 3D
- Fer à souder
Applications et services en ligne
- OpenCV (vision par ordinateur)
À propos du projet
Soumission initiale
Pour le concours « Hackster Terminate the Competition » : un robot qui cherche les humains mais pour les complimenter, pas les éliminer ! Robot omnidirectionnel qui vous détecte, vous suit et vous flatte.
Contrainte auto-imposée : aucune électronique à fabriquer soi-même. Tout s'achète sur eBay, s'assemble avec tutos publics. Châssis imprimable 3D (soi-même ou via 3D Hubs).
Architecture système
4 blocs principaux :
- Gestion alimentation (batterie → 5V/12V)
- Ci20 = cerveau (OpenCV détection visage)
- Arduino Nano = contrôle moteurs (réception commandes série Ci20)
- Moteurs + roues omnidirectionnelles
Gestion alimentation ("Électrickery")
Schéma complet : batterie LiPo 3S → LM2596 (5V pour Ci20/Arduino) → L298N (12V direct pour moteurs) + alarme basse tension.
Connexion Arduino → L298N
Suivre ce tutoriel : Instructables L298N. Une fois câblé : lumières bleues, pas de fumée bleue = c'est bon !
Impression 3D du châssis
Design : look cool + mise en valeur du Ci20. Fichiers STL dispo dans PIÈCES PERSONNALISÉES : base, couvercle, roues omnidirectionnelles (remix Thingiverse). Assemblage : colle ou ruban adhésif, vis M4 pour moteurs.
Magie du Ci20 (OpenCV)
- Installer OpenCV : suivre tutoriel standard (compilation depuis sources)
- Compiler & lancer le tracking facial :
g++ -I/usr/local/include/opencv -I/usr/local/include/opencv2 -L/usr/local/lib/ -g -o binary main.cpp \ -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video \ -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib \ -lopencv_legacy -lopencv_stitching
Ci20 + Arduino : Communication série
Flasher l'Arduino (code ci-dessous), le brancher en USB sur le Ci20, lancer le FaceTracker, brancher la webcam. Si votre visage est centré → le robot avance !
Travail restant (défis ouverts)
- Ajouter haut-parleur + fichiers son : compliment quand le visage remplit l'écran
- Si pas de visage détecté pendant 1-2 min → rotation sur place (commande
R XXenvoyée à l'Arduino, XX = durée ms)
Codes
Arduino - Principal (réception commandes Ci20 → moteurs)
// Moteur 1
int dir1PinA = 3, dir2PinA = 2, speedPinA = 9; // PWM
// Moteur 2
int dir1PinB = 4, dir2PinB = 5, speedPinB = 8; // PWM
// Moteur 3
int dir1PinC = 6, dir2PinC = 7, speedPinC = 10; // PWM
int x = 0, y = 0, dominantUltrasonic = 0;
bool moveMotor = false;
unsigned long startTime = 0;
String rpiString;
void setup() {
Serial.begin(9600);
pinMode(dir1PinA, OUTPUT); pinMode(dir2PinA, OUTPUT); pinMode(speedPinA, OUTPUT);
pinMode(dir1PinB, OUTPUT); pinMode(dir2PinB, OUTPUT); pinMode(speedPinB, OUTPUT);
pinMode(dir1PinC, OUTPUT); pinMode(dir2PinC, OUTPUT); pinMode(speedPinC, OUTPUT);
startTime = millis();
}
void loop() {
readDataFromRPi();
delay(30);
}
void readDataFromRPi() {
while (Serial.available()) {
delay(3);
if (Serial.available() > 0) {
char c = Serial.read();
rpiString += c;
if (c == 'n') break;
}
}
if (rpiString.length() > 0) {
Serial.println(rpiString);
String isRotate = getValue(rpiString, ' ', 0);
String xval = getValue(rpiString, ' ', 1);
String yval = getValue(rpiString, ' ', 2);
x = xval.toInt(); y = yval.toInt();
startTime = millis();
if (isRotate == "r") rotate(x);
else driveInDirection(x, y);
rpiString = "";
}
}
String getValue(String data, char separator, int index) {
int found = 0, strIndex[] = {0, -1}, maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++; strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
Arduino - Contrôle Moteurs (cinématique omnidirectionnelle 3 roues)
void driveInDirection(float newX, float newY) {
delay(20);
float x = newX, y = newY;
float theta = atan2(y, x);
float mag = sqrt(x*x + y*y);
float vx = mag * cos(theta), vy = mag * sin(theta);
float w1 = -vx;
float w2 = 0.5 * vx - sqrt(3)/2 * vy;
float w3 = 0.5 * vx + sqrt(3)/2 * vy;
float wSet[3] = {w1, w2, w3};
float largestValue = 0;
for (int i = 0; i < 3; i++) if (abs(wSet[i]) > largestValue) largestValue = abs(wSet[i]);
float speedCoef = 147.0 / largestValue;
w1 *= speedCoef; w2 *= speedCoef; w3 *= speedCoef;
if (x == 0 && y == 0) { w1 = w2 = w3 = 0; }
w1 = constrain(w1, -150, 150);
w2 = constrain(w2, -150, 150);
w3 = constrain(w3, -150, 150);
bool w1_ccw = w1 < 0, w2_ccw = w2 < 0, w3_ccw = w3 < 0;
byte w1_speed = map(abs(w1), 0, 150, 0, 255);
byte w2_speed = map(abs(w2), 0, 150, 0, 255);
byte w3_speed = map(abs(w3), 0, 150, 0, 255);
analogWrite(speedPinA, w1_speed); analogWrite(speedPinB, w2_speed); analogWrite(speedPinC, w3_speed);
digitalWrite(dir1PinA, !w1_ccw); digitalWrite(dir2PinA, w1_ccw);
digitalWrite(dir1PinB, !w2_ccw); digitalWrite(dir2PinB, w2_ccw);
digitalWrite(dir1PinC, w3_ccw); digitalWrite(dir2PinC, !w3_ccw);
}
void rotate(float milliseconds) {
float w1 = 255, w2 = 255, w3 = 255;
byte w1_speed = map(abs(w1), 0, 150, 0, 255);
byte w2_speed = map(abs(w2), 0, 150, 0, 255);
byte w3_speed = map(abs(w3), 0, 150, 0, 255);
analogWrite(speedPinA, w1_speed); analogWrite(speedPinB, w2_speed); analogWrite(speedPinC, w3_speed);
digitalWrite(dir1PinA, LOW); digitalWrite(dir2PinA, HIGH);
digitalWrite(dir1PinB, LOW); digitalWrite(dir2PinB, HIGH);
digitalWrite(dir1PinC, HIGH); digitalWrite(dir2PinC, LOW);
delay(milliseconds);
analogWrite(speedPinA, 0); analogWrite(speedPinB, 0); analogWrite(speedPinC, 0);
}
Ci20 - FaceTracking C++ (OpenCV)
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
#include
#include
#include
#include
using namespace std; using namespace cv;
CascadeClassifier face_cascade;
String window_name = "Face Detection";
int sendSerial(char* message) {
int fd = open("/dev/ttyUSB0", O_RDWR);
if (fd == -1) { perror("dev/ttyUSB0"); return 1; }
struct termios tios; tcgetattr(fd, &tios);
tios.c_iflag = IGNBRK | IGNPAR; tios.c_oflag = 0; tios.c_lflag = 0;
cfsetspeed(&tios, B9600); tcsetattr(fd, TCSAFLUSH, &tios);
usleep(1000); write(fd, message, strlen(message)); return 0;
}
void detectFaces(Mat frame) {
vector faces; Mat frame_gray;
cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
equalizeHist(frame_gray, frame_gray);
face_cascade.detectMultiScale(frame_gray, faces, 1.1, 3, 0|CASCADE_SCALE_IMAGE, Size(30,30));
for (size_t i = 0; i < faces.size(); i++) {
Point center(faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2);
ellipse(frame, center, Size(faces[i].width/2, faces[i].height/2), 0, 0, 360, Scalar(255,0,255), 4, 8, 0);
if (center.x > frame.cols/3 && center.x < frame.cols/3*2) sendSerial("F 50 50");
else sendSerial("0 0 ");
}
imshow(window_name, frame);
}
int main() {
sendSerial("0 0 ");
VideoCapture cap(0);
cap.set(CV_CAP_PROP_FRAME_WIDTH, 480);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
Mat frame;
if (!face_cascade.load("haarcascade_frontalface_default.xml")) { cout << "classifier"; return -1; }
while (cap.read(frame)) {
detectFaces(frame);
if (waitKey(30) >= 0) break;
}
return 0;
}
Pièces personnalisées (STL)
- Base robot omnidirectionnel (conçue pour tout loger + couvercle)
- Couvercle mettant en valeur le Ci20
- Roues omnidirectionnelles (design original + remix pour arbre moteur)
Schémas
Description détaillée dans la section "Histoire" du projet original.
Processus de fabrication
- Suivi avancé de balle de ping-pong sur Raspberry Pi avec OpenCV
- Raspoulette : Prototype de système autonome de porte de poulailler à énergie solaire
- Robot DIY inspiré de Wall‑E : Raspberry Pi dans une boîte de CD recyclée
- Robot réveil roulant : Système mobile intelligent piloté par Raspberry Pi et Google Calendar
- Construire un robot vision par ordinateur piloté par la parole sur Windows 10 IoT Core
- Robot ROS : Navigation pilotée par terminal sur Raspberry Pi
- Simple Pi Robot – Construire un rover autonome 2 roues motrices avec Raspberry Pi
- Kit de robot de navigation intérieure intelligente pour projets Arduino
- Comprendre les moteurs linéaires : de l'énergie électrique au mouvement linéaire précis