membuat kontrol game mobil pc dengan kardus - Ini adalah projek kecil-kecilan yang saya bikin dalam rangka belajar OpenCV dan python. Sedikit cerita latar belakang, awalnya saya menemukan postingan dari orang luar negeri di grup facebook machine learning internasional. Disitu terlihat bahwa dia bisa mengendalikan game mobil dengan stir yang dideteksi oleh kamera. Saya coba download source codenya, ternyata gak dapet. Akhirnya saya coba buat sendiri dan inilah hasilnya.
Bagaimana Saya Membuatnya?
Cara kerja dari projek ini cukup simpel. AI dari kamera hanya perlu mendeteksi warna dari titik tertentu pada stir dari kardus. Setelah warna yang dimaksud terdeteksi, saya mengambil titik koordinat dari titik tengah warna tersebut. Kemudian dari titik koordinat tersebut, bisa didapatkan sudut lingkaran. Sudut inilah yang dikonversi ke simulator/game.
Berikut ini langkah-langkah pembuatannya.
1. Import library yang dibutuhkan. Dalam hal ini, kita membutuhkan:
- cv2 (pip install opencv-python)
Untuk mendeteksi warna pada kamera.
- math
Untuk menggunakan fungsi matematika dengan mudah.
- socketio
Untuk mengirim data ke server game.
my_project/steering.py
import cv2 as cv
import math
import socketio
2. Siapkan variabel dan koneksikan ke socket.
my_project/steering.py
cap = cv.VideoCapture(0)3. Siapkan fungsi yang dibutuhkan.
pointsList = [0, 0]
sio = socketio.Client()
@sio.on('connect')
def connect():
print("connect")
sio.connect('http://localhost:4567')
def getAngle(pointsList):
pt1, pt2 = pointsList
angR = math.atan2(-(pt1[0] - pt2[0]), (pt1[1] - pt2[1]))
angD = round(math.degrees(angR))
return angD
def centroid(contour, mask):
for c in contour:
area = cv.contourArea(c)
if area > 200:
M = cv.moments(mask)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
return [cX, cY]
def trainingColor(hsv, low, upp, pt):
mask = cv.inRange(hsv, low, upp)
contour, hierarchy = cv.findContours(mask, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
center = centroid(contour, mask)
if center != None: pointsList[pt] = center
# else: pointsList[pt] = [0, 0]
def drawFrame(frame):
cv.circle(frame, tuple(pointsList[0]), 5, (255, 0, 0), -1)
cv.circle(frame, tuple(pointsList[1]), 5, (0, 255, 0), -1)
cv.line(frame, tuple(pointsList[0]), (pointsList[0][0], pointsList[0][1]-100), (0,0,255), 2)
cv.line(frame, tuple(pointsList[1]), tuple(pointsList[0]), (0,0,255), 2)
cv.putText(frame, str(pointsList[0]), (pointsList[0][0]-100, pointsList[0][1]), cv.FONT_HERSHEY_COMPLEX, 0.5, (255,0,0),2)
cv.putText(frame, str(pointsList[1]), (pointsList[1][0]+50, pointsList[1][1]), cv.FONT_HERSHEY_COMPLEX, 0.5, (0,255,0),2)
while True:
_, frame = cap.read()
frame = cv.flip(frame, 1)
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
# Origin Color
trainingColor(hsv, (0, 98, 171), (73, 255, 255), 0)
# Point Color
trainingColor(hsv, (21, 77, 81), (81, 255, 255), 1)
if pointsList[0] != 0 and pointsList[1] != 0:
drawFrame(frame)
angle = getAngle(pointsList)
sio.emit('steering', angle/180/0.5)
cv.imshow("frame", frame)
key = cv.waitKey(1)
if key == 27: # ESC BUTTON
break
sio.wait()
import socketio
import eventlet
import eventlet.wsgi
from flask import Flask
sio = socketio.Server()
app = Flask(__name__)
@sio.on('telemetry')
def telemetry(sid, data):
if data:
pass
else:
# NOTE: DON'T EDIT THIS.
sio.emit('manual', data={}, skip_sid=True)
@sio.on('connect')
def connect(sid, environ):
print("connect ", sid)
@sio.on('steering')
def steering(sid, data):
send_control(data, 0.4)
def send_control(steering_angle, throttle):
sio.emit(
"steer",
data={
'steering_angle': steering_angle.__str__(),
'throttle': throttle.__str__()
},
skip_sid=True)
if __name__ == '__main__':
# wrap Flask application with engineio's middleware
app = socketio.Middleware(sio, app)
# deploy as an eventlet WSGI server
eventlet.wsgi.server(eventlet.listen(('', 4567)), app)
$ python drive.py
$ python steering.py
Oke, itulah pembahasan tentang projek sederhana saya. Semoga bermanfaat! Terima kasih!