İçeriğe geç
Türkçe

Labirentte yol bul

Bu eğitimde adım adım eksiksiz bir program yazacaksın. Robot, duvarlardan ve çukurlardan kaçınarak labirentte dolaşır ve duvar işaretine benzeyen her şeyi bildirir. Bu, İlk çalıştırman sayfasında çalıştırdığın programdır.

Program, başlangıç robotunu ve Hareket ile Sensörler sayfalarında öğrendiklerini kullanır.

Programın tamamı: maze.py · maze.cpp

Programı şuna benzeyen world1.wbt üzerinde çalıştır:

Webots’ta world1 dünyası

Program önce robotu oluşturur, tekerlek motorlarını alır ve motorların sınırsız dönmesine izin verir. speeds her tekerleğin hızını tutar; programın geri kalanı bu değerleri değiştirir. reported, robotun daha önce nerelerde işaret bildirdiğini hatırlar.

from controller import Robot
import struct
import numpy as np
import cv2 as cv
robot = Robot()
timeStep = 32 # Milliseconds between steps
maxVelocity = 6.28 # The maximum speed of the wheels, in radians per second
leftWheel = robot.getDevice("left wheel motor")
rightWheel = robot.getDevice("right wheel motor")
leftWheel.setPosition(float("inf")) # Let the wheels turn without limit
rightWheel.setPosition(float("inf"))
speeds = [maxVelocity, maxVelocity] # [left wheel speed, right wheel speed]
reported = [] # Positions where a token has already been reported

Sonra başlangıç robotunun sensörlerini alır ve etkinleştirir:

Sensörleri etiketlenmiş örnek robot

leftDist = robot.getDevice("leftDist")
frontDist = robot.getDevice("frontDist")
rightDist = robot.getDevice("rightDist")
camera = robot.getDevice("camera")
colorSensor = robot.getDevice("color")
gps = robot.getDevice("gps")
emitter = robot.getDevice("emitter") # The emitter does not need to be enabled
for sensor in [leftDist, frontDist, rightDist, camera, colorSensor, gps]:
sensor.enable(timeStep)

Bu fonksiyonlar, robotun dönüş yapması ve olduğu yerde dönmesi için hızları değiştirir. delay, robotun belirli bir milisaniye boyunca aynı şeyi yapmaya devam etmesini sağlar; getBrightness ise renk sensörünü 0 (siyah) ile 255 (beyaz) arasında tek bir değer olarak okur.

def turnRight():
speeds[0] = 0.6 * maxVelocity
speeds[1] = -0.2 * maxVelocity
def turnLeft():
speeds[0] = -0.2 * maxVelocity
speeds[1] = 0.6 * maxVelocity
def spin():
speeds[0] = 0.6 * maxVelocity
speeds[1] = -0.6 * maxVelocity
def delay(ms):
start = robot.getTime()
while robot.step(timeStep) != -1:
if (robot.getTime() - start) * 1000 > ms:
break
def getBrightness():
image = colorSensor.getImage()
return colorSensor.imageGetGray(image, colorSensor.getWidth(), 0, 0) # 0 (black) to 255 (white)

Bu fonksiyon, kamera görüntüsünde duvar işaretlerini arar. İşaretler, koyu duvarların üzerindeki parlak karelerdir. Bu yüzden fonksiyon, kabaca kare biçiminde olan ve görüntünün kenarına (genellikle zeminin göründüğü yere) değmeyen parlak şekiller arar.

def seesToken(image):
height, width = camera.getHeight(), camera.getWidth()
image = np.frombuffer(image, np.uint8).reshape((height, width, 4)) # BGRA image for OpenCV
gray = cv.cvtColor(image, cv.COLOR_BGRA2GRAY)
_, bright = cv.threshold(gray, 200, 255, cv.THRESH_BINARY) # Bright parts in white
contours, _ = cv.findContours(bright, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for contour in contours:
x, y, w, h = cv.boundingRect(contour)
if x == 0 or y == 0 or x + w == width or y + h == height:
continue # Shapes touching the edge of the image are usually the floor
if cv.contourArea(contour) > 40 and 0.65 < w / h < 1.5:
return True # A bright, roughly square shape on a wall
return False

Bu basit bir başlangıçtır: sembolleri ayırt edemez ve bilişsel hedefleri iyi göremez. Duvar işaretleri eğitimi, nasıl daha iyisini yapabileceğini gösterir.

Bir işaretten puan almak için robot 1 saniyeden uzun süre durmalı, sonra işaretin konumunu ve türünü göndermelidir. Her işaretten yalnızca bir kez puan alınabilir ve aynı işareti tekrar bildirmek 5 puana mal olur; bu yüzden program, nerelerde bildirim yaptığını hatırlar. Bu mesajlar İletişim sayfasında açıklanır.

def report(tokenType):
leftWheel.setVelocity(0) # Stop for more than 1 second
rightWheel.setVelocity(0)
delay(1300)
x = int(gps.getValues()[0] * 100) # Meters to centimeters
z = int(gps.getValues()[2] * 100)
emitter.send(struct.pack("i i c", x, z, tokenType.encode()))
robot.step(timeStep)
reported.append((x, z))
def alreadyReported():
# Reporting the same token again is a misidentification
x = gps.getValues()[0] * 100
z = gps.getValues()[2] * 100
return any(abs(x - rx) < 12 and abs(z - rz) < 12 for rx, rz in reported) # Closer than 1 tile

Son olarak ana döngü her şeyi bir araya getirir. Her adımda tam hızla başlar, duvarlardan uzaklaşmak için döner, çukurlardan geri döner ve önünde yakın bir duvar olduğunda kameranın gördüğünü bildirir.

while robot.step(timeStep) != -1:
speeds[0] = maxVelocity
speeds[1] = maxVelocity
if leftDist.getValue() < 0.05: # Wall on the left: turn right
turnRight()
if rightDist.getValue() < 0.05: # Wall on the right: turn left
turnLeft()
if frontDist.getValue() < 0.05: # Wall in front: spin
spin()
if getBrightness() < 80: # Black floor: turn away from the hole
spin()
leftWheel.setVelocity(speeds[0])
rightWheel.setVelocity(speeds[1])
delay(600)
# Close to a wall, and something on it: report it
if frontDist.getValue() < 0.07 and not alreadyReported() and seesToken(camera.getImage()):
report("H") # The type cannot be told yet, so guess "H"
leftWheel.setVelocity(speeds[0])
rightWheel.setVelocity(speeds[1])

Bu robot rastgele dolaşır: nerelerde bulunduğunu bilmez ve her kazazedenin türünü tahmin eder. Bazen sıkışır ve oyun onu 20 saniye sonra bir kontrol noktasına geri taşır. İlk program için bu gayet iyi.

  • Robotun için en iyi hızları ve mesafeleri bul.
  • Bir taraftaki duvarı izle: yan sensörü sabit bir mesafede tut ve ön sensör bir duvar gördüğünde dön.
  • Hızı duvarların ne kadar yakın olduğuna göre değiştir.

Sonra İletişim sayfasında puan kazanmayı öğren.