Omnidirectionele Robot voor Veilige Mensenvolging
Onderdelen en Benodigdheden
| Onderdeel | Aantal |
|---|---|
| L298N Dual Stepper Motor Driver | 2 |
| LM2596 DC-DC Step Down Voltage Regulator | 1 |
| Lipo Alarm Battery Checker | 1 |
| 24RPM DC 12V 4mm As Geared Motor | 3 |
| Arduino Nano R3 | 1 |
| Microsoft LifeCam HD-3000 Webcam | 1 |
| Dupont-draden | 10 |
| Creator Ci20 (Hoofdcomputer) | 1 |
| 11.1V 3-Cel LiPo Batterij | 1 |
Benodigde Tools
- 3D-printer
- Solderbout
Apps & Online Services
- OpenCV (gezichtsdetectie)
Over dit Project
Initiële Inzending
Mijn inzending voor de "Hackster Terminate the Competition" was een robot die mensen zoekt – maar niet om te doden als in Terminator, maar om complimenten te maken! Deze omnidirectionele robot vindt je, detecteert je, navigeert naar je toe en geeft je een compliment.
Mijn eis: alle elektronica moet koopbaar zijn (bijv. eBay), aan elkaar te klikken met vrij beschikbare tutorials, en de behuizing 3D-printbaar (zelf of via 3D Hubs).
Hoe Het Werkt

Vier hoofdblokken:
- Stroombeheer: Batterij → spanningen voor systeem
- Ci20 (Hoofdcomputer): Voert OpenCV gezichtsdetectie uit
- Arduino Nano: Stuurt motoren aan op basis van Ci20 commando's
- Omnidirectionele wielen: 3 wielen voor beweging in elke richting
Stroombeheer

Volg het schema voor het aansluiten van alle stroomcomponenten.
Arduino Nano ↔ L298N Aansluiten
Volg deze tutorial: Instructables L298N Handleiding.
Als er blauwe LEDjes knipperen en geen blauwe rook: goed om te gaan!
3D-print Je Eigen Behuizing
Ontwerpdoel: er cool uitzien & de Ci20 tonen. Completely 3D-printbaar. Bestanden beschikbaar onder 'Custom Parts'. Print top, bottom & wielen. Geen 3D-printer? Gebruik 3D Hubs.

Na printen: onderdelen inlijmen (of masking tape). M4 bouten voor motoren.
De Ci20 De Magie Laten Doen
De Ci20 gebruikt OpenCV voor gezichtsdetectie en stuurt via seriële poort commando's naar de Arduino voor motorbesturing.
Stap 1: OpenCV Installeren
Volg deze tutorial: OpenCV installatie handleiding (stap-voor-stap).
Stap 2: Code Compileren & Draaien
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
Bronbestand: FaceTracking.cpp → uitvoerbaar: FaceTracking.

Ci20 & Arduino Samenwerking
Na het flashen van de Arduino (code in bijlagen), plug de Arduino in de USB-poort van de Ci20 en start de FaceTracker. Webcam aansluiten! Je ziet een camerabeeld; houd je gezicht in het midden en de robot begint vooruit te rijden.
Klaar?
Vanwege tijdtekort deed het nog niet alles. Uitdaging voor jou:
- Voeg speakers en geluidsbestanden toe: bij groot gezicht in beeld → speel compliment af
- Geen gezicht gedetecteerd in 1-2 minuten? Laat de robot op zijn as draaien: stuur commando
R XXnaar Arduino (XX = draaitijd in ms)
Code
Arduino Sketch - Hoofdprogramma
Ontvangt rij-commando's van Ci20 via seriële poort en stuurt motoren correct aan. Oorspronkelijk voor Raspberry Pi, werkt ook op Ci20.
// Motor 1
int dir1PinA = 3; int dir2PinA = 2; int speedPinA = 9; // PWM
// Motor 2
int dir1PinB = 4; int dir2PinB = 5; int speedPinB = 8; // PWM
// Motor 3
int dir1PinC = 6; int dir2PinC = 7; int speedPinC = 10; // PWM
int x = 0, y = 0, dominantUltrasonic = 0;
bool moveMotor = false;
int startTime = 0;
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();
}
String rpiString;
void loop() {
readDataFromRPi();
// Buffer logica: stop na 1s geen data
// if (millis() - startTime > 1000) { x=0; y=0; dominantUltrasonic=0; moveMotor=false; startTime=millis(); }
// if (moveMotor && x!=0 && y!=0) driveInDirection(x,y);
// if (x==0 && y==0) driveInDirection(x,y);
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; int strIndex[] = {0, -1}; int 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 Sketch - MotorControl
Behoort bij hoofdprogramma, in hetzelfde projectbestand.
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[] = {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 = 0; w2 = 0; w3 = 0; }
Serial.println(w1); Serial.println(w2); Serial.println(w3);
w1 = constrain(w1, -150, 150); w2 = constrain(w2, -150, 150); w3 = constrain(w3, -150, 150);
boolean w1_ccw = w1 < 0; boolean w2_ccw = w2 < 0; boolean 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);
printMotorSpeed(w1_speed, 1); printMotorSpeed(w2_speed, 2); printMotorSpeed(w3_speed, 3);
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;
boolean w1_ccw = w1 < 0; boolean w2_ccw = w2 < 0; boolean 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);
printMotorSpeed(w1_speed, 1); printMotorSpeed(w2_speed, 2); printMotorSpeed(w3_speed, 3);
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);
delay(milliseconds);
analogWrite(speedPinA, 0); analogWrite(speedPinB, 0); analogWrite(speedPinC, 0);
}
void printMotorSpeed(byte motorSpeed, int motor) {
Serial.print("Motor"); Serial.print(motor); Serial.print(": "); Serial.println(motorSpeed);
}
FaceTracking C++ voor Ci20
Volg handleiding in 'Over dit project'.
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include
#include
using namespace std; using namespace cv;
CascadeClassifier face_cascade, eyes_cascade;
String window_name = "Face Detection";
#include #include #include
#include #include #include
#include #include
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);
Mat face = frame_gray(faces[i]);
vector eyes;
// eyes_cascade.detectMultiScale(face, eyes, 1.1, 2, 0|CASCADE_SCALE_IMAGE, Size(50,50));
// if (eyes.size() > 0)
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) {
char msg[] = "F 50 50"; sendSerial(msg);
} else {
char msg[] = "0 0 "; sendSerial(msg);
}
}
imshow(window_name, frame);
}
int main() {
char msg[] = "0 0 "; sendSerial(msg);
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; }
// eyes_cascade.load("haarcascade_eye_tree_eyeglasses.xml");
while (cap.read(frame)) {
detectFaces(frame);
if (waitKey(30) >= 0) break;
}
return 0;
}
Aangepaste Onderdelen & Behuizingen
Basis: Ontworpen om alle onderdelen te passen met deksel.
Deksel: Toont de Ci20 in al zijn glorie.
Omnidirectionele Wielen: Origineel ontwerp van Thingiverse, aangepast voor motoras. Thingiverse link & remix.
Schema's
Zie gedetailleerde beschrijving in projectverhaal.

Productieproces
- Geavanceerde Tafeltennisbal Tracking met OpenCV op Raspberry Pi
- Raspoulette: Zonnestroom-gevoede Autonome Koeienpoort Systeem Prototype
- DIY Wall-E Geïnspireerde Raspberry Pi CD-Doos Robot
- Rollende Alarmrobot: Een Slim, Mobiel Wakker-systeem Aangedreven door Raspberry Pi en Google Calendar
- Bouw een Spraak-gestuurde Computer Vision Robot op Windows 10 IoT Core
- ROS Robot: Terminal-gecontroleerde Navigatie op Raspberry Pi
- Simple Pi Robot – Bouw een 2-WD Autonome Rover met Raspberry Pi
- Slim Indoor Navigatie Robot Kit voor Arduino Projecten
- Lineaire motoren begrijpen: Van elektrische energie naar nauwkeurige lineaire beweging
- Drankrobots begrijpen: technologie, automatisering en rol in drankenindustrie
- Servomotoren Uitgelegd: Hoe Ze Werken en Waarom Ze Belangrijk Zijn