ماشین خودران DIY چیست؟ (مبتدی)
یک ماشین خودران DIY یک ماشین RC است که به جای دریافت دستور از ریموت، با بینایی ماشین (Computer Vision) خودش مسیر را میبیند و دنبال میکند. سادهترین روش Line Following است — دوربین یک خط سفید روی زمین را میبیند و ماشین آن را دنبال میکند.
AWS DeepRacer یک پلتفرم تجاری ۴۰۰ دلاری است که با یادگیری تقویتی (Reinforcement Learning) کار میکند. اما با یک ESP32-CAM (۵ دلار) و OpenCV روی Raspberry Pi میتوان یک سیستم مشابه با ۵۰ دلار ساخت که خط را با PID دنبال کند — پایه یادگیری ماشین در رباتیک!
محصولی که میسازید
یک ماشین RC خودران Line Follower با OpenCV PID.
- هزینه: RC Car + RPi Zero + ESP32-CAM = ۵۰ دلار
- الگوریتم: Line Detection + PID Steering
- پلتفرم: OpenCV Python روی RPi
کد Python — Line Following با PID
import cv2, numpy as np
import serial, time
# ارتباط با ESP32-CAM (MJPEG) و Arduino (موتور):
cap = cv2.VideoCapture("http://192.168.1.100/stream")
motor_serial = serial.Serial('/dev/ttyUSB0', 115200)
# PID Constants:
Kp, Ki, Kd = 0.4, 0.002, 0.15
prev_error = integral = 0
CENTER_X = 320 # نصف عرض ۶۴۰
def find_line_center(frame):
"""پیدا کردن مرکز خط سفید در ROI"""
roi = frame[300:400, :, :] # فقط قسمت پایین
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY)
M = cv2.moments(thresh)
if M["m00"] > 5000:
cx = int(M["m10"] / M["m00"])
return cx
return None
def pid_steer(error):
global prev_error, integral
integral += error
derivative = error - prev_error
output = Kp*error + Ki*integral + Kd*derivative
prev_error = error
return int(max(-45, min(45, output))) # زاویه فرمان
BASE_SPEED = 60 # 0-100
while True:
ret, frame = cap.read()
if not ret: continue
cx = find_line_center(frame)
if cx is not None:
error = cx - CENTER_X
steer = pid_steer(error)
cmd = f"S:{BASE_SPEED},T:{steer}\n"
motor_serial.write(cmd.encode())
cv2.circle(frame, (cx, 350), 8, (0,255,0), -1)
cv2.line(frame, (CENTER_X,0), (CENTER_X,480), (255,0,0), 1)
else:
motor_serial.write(b"S:0,T:0\n") # خط از دست رفت
cv2.imshow("Self Driving", frame)
if cv2.waitKey(1) == ord('q'): break
کد Arduino — دریافت دستور فرمان
#include <Servo.h>
Servo steering;
const int M_F=6, M_B=7;
void setup() {
Serial.begin(115200);
steering.attach(9);
pinMode(M_F,OUTPUT); pinMode(M_B,OUTPUT);
}
void loop() {
if(Serial.available()) {
String line = Serial.readStringUntil('\n');
// فرمت: "S:60,T:-20"
int si = line.indexOf("S:"); int ti = line.indexOf(",T:");
if(si>=0 && ti>0) {
int spd = line.substring(si+2,ti).toInt();
int turn = line.substring(ti+3).toInt();
// حرکت موتور:
if(spd>0){ digitalWrite(M_F,1); digitalWrite(M_B,0); }
else { digitalWrite(M_F,0); digitalWrite(M_B,0); }
// فرمان سرو (۹۰ = مستقیم، ±۴۵):
steering.write(90 + turn);
}
}
}
چکلیست خودران
| بررسی | روش |
|---|---|
| خط سفید روی زمین تاریک | کاغذ A4 یا نوار سفید |
| Threshold درست تنظیم؟ | با trackbar (cv2.createTrackbar) |
| PID اوسیله نمیزند؟ | Kp را کم کنید |
| تأخیر ویدیو زیر ۱۰۰ms؟ | cap.set(CAP_PROP_BUFFERSIZE,1) |