Lewati ke konten
Bahasa Indonesia

Menavigasi labirin

Di tutorial ini, kamu membuat program lengkap, langkah demi langkah. Robot berkeliling labirin sambil menghindari dinding dan lubang, lalu melaporkan apa pun yang tampak seperti penanda dinding. Ini adalah program yang kamu jalankan di Percobaan pertamamu.

Program ini menggunakan robot pemula, serta apa yang sudah kamu pelajari di Gerakan dan Sensor.

Program lengkapnya: maze.py · maze.cpp

Jalankan di world1.wbt, yang tampilannya seperti ini:

World world1 di Webots

Pertama, program membuat robot, mengambil motor roda, dan membiarkannya berputar tanpa batas. speeds menyimpan kecepatan setiap roda, yang diubah oleh bagian program lainnya. reported mengingat tempat-tempat robot sudah melaporkan penanda.

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

Selanjutnya, program mengambil dan mengaktifkan sensor-sensor robot pemula:

Robot contoh dengan label pada sensor-sensornya

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)

Fungsi-fungsi ini mengubah kecepatan untuk berbelok dan berputar. delay membuat robot terus melakukan hal yang sama selama sejumlah milidetik tertentu, dan getBrightness membaca sensor warna sebagai satu nilai dari 0 (hitam) sampai 255 (putih).

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)

Fungsi ini mencari penanda dinding di gambar kamera. Penanda adalah kotak terang di dinding yang gelap, jadi fungsi ini mencari bentuk terang yang kurang lebih persegi dan tidak menyentuh tepi gambar, tempat lantai biasanya terlihat.

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

Ini awal yang sederhana: fungsi ini tidak bisa membedakan simbol, dan tidak bisa melihat target kognitif dengan baik. Tutorial Penanda dinding menunjukkan cara melakukannya dengan lebih baik.

Untuk mencetak poin dari penanda, robot harus berhenti lebih dari 1 detik, lalu mengirim posisinya dan jenis penandanya. Setiap penanda hanya bisa dihitung sekali, dan melaporkannya lagi mengurangi 5 poin, jadi program mengingat tempat-tempat yang sudah dilaporkannya. Komunikasi menjelaskan pesan-pesan ini.

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

Terakhir, loop utama menggabungkan semuanya. Di setiap langkah, robot mulai dengan kecepatan penuh, berbelok menjauhi dinding, berbalik dari lubang, dan melaporkan apa yang dilihat kamera saat robot dekat dengan dinding di depannya.

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])

Robot ini berkeliaran tanpa arah: robot tidak tahu ke mana saja ia sudah pergi, dan hanya menebak jenis setiap korban. Kadang robot terjebak, dan permainan memindahkannya kembali ke checkpoint setelah 20 detik. Itu tidak masalah untuk program pertama.

  • Cari kecepatan dan jarak terbaik untuk robotmu.
  • Susuri dinding di satu sisi: jaga sensor samping pada jarak yang tetap, dan berbelok saat sensor depan melihat dinding.
  • Ubah kecepatan sesuai jarak ke dinding.

Lalu, pelajari cara mencetak poin di Komunikasi.