Robô de Jogo da Velha

Tutorial em vídeo: Tutorial em vídeo OpenMV da SingTown - Robô braço robótico de jogo da velha 2024 Concurso Eletrônico

O robô de jogo da velha é dividido em três etapas: 1. Reconhecimento de imagem, para obter a matriz de peças. 2. Algoritmo de estratégia de jogo. 3. Controle do braço robótico para pegar e posicionar as peças.

No hardware, usamos o OpenMV4 H7 da SingTown. Todo o código é executado no próprio OpenMV! Isso inclui o controle do braço robótico, o controle do relé, o algoritmo de estratégia de jogo e o algoritmo de reconhecimento de imagem.

O braço robótico é impresso em 3D e usa 3 servomotores, que podem ser controlados diretamente pela placa de expansão de servos do OpenMV.

A captura das peças é feita com um eletroímã, já que aproveitei 10 baterias tipo botão como peças. O OpenMV pode controlar o eletroímã por meio de um relé.

  1. O reconhecimento de imagem é bem simples: primeiro obtemos a imagem em escala de cinza e, em seguida, coletamos as informações de cor dentro das 9 regiões do tabuleiro, usando a função statistics do OpenMV. Com base nos valores de cinza, é possível determinar se a casa tem uma peça preta, uma peça branca ou está vazia.
  2. Para calcular a próxima jogada, meu bom amigo, o professor ChatGPT, me disse para usar o algoritmo minimax e já escreveu essa parte do código para mim.
  3. O controle do braço robótico também é relativamente simples: obtemos a posição do braço tanto na área de espera de captura das peças quanto em cada uma das 9 posições do tabuleiro. Normalmente isso pode ser feito com uma função de ensino (teaching), mas como meu braço robótico foi feito às pressas em apenas um dia, defini as posições diretamente no código.
# robot.py

import time
from servo import Servos
from machine import SoftI2C, Pin
import math

# Controla o relé, que por sua vez controla o eletroímã
pin1 = Pin('P1', Pin.OUT_PP, Pin.PULL_NONE)
pin1.value(0)

# Placa de expansão de servos PCA9685
i2c = SoftI2C(sda=Pin('P5'), scl=Pin('P4'))
servo = Servos(i2c, address=0x40, freq=50, min_us=650, max_us=2800, degrees=180)

# Posição inicial dos três servomotores
servo.position(0, 0)
servo.position(1, 90)
servo.position(2, 90)

# Variável global, usada para movimento suave
servo_positions = [0,90,90]


# Controla o movimento de um servomotor
def move(index, angle):
    servo.position(index, angle)
    servo_positions[index] = angle


# Controla o movimento dos três servomotores
def move_list(angle_list):
    print(angle_list)
    move(0, int(angle_list[0]))
    move(1, int(angle_list[1]))
    move(2, int(angle_list[2]))


# Controla o movimento lento dos três servomotores
def slow_move_to(angle_list):

    init_positions = servo_positions.copy()

    d0 = angle_list[0] - init_positions[0]
    d1 = angle_list[1] - init_positions[1]
    d2 = angle_list[2] - init_positions[2]

    dm = int(max(abs(d0), abs(d1), abs(d2)))
    if dm == 0:
        return

    for i in range(dm+1):
        move_list([init_positions[0]+i*d0/dm,
        init_positions[1]+i*d1/dm,
        init_positions[2]+i*d2/dm])

        time.sleep_ms(40)


# Define a posição da área de captura das peças
PICK = [[74,128,19], [82,128,17], [90,125,14], [98,128,17], [106,128,19]]
# Posição elevada do braço na área de captura
HIGH_PICK = [90,95,55]

# Posições de colocação no tabuleiro
BOARD = [
    [[82,150,55], [82,140,40], [81,133,30]],
    [[90,150,55], [90,140,40], [90,133,30]],
    [[98,150,55], [98,140,40], [99,133,30]]
]

# Posição acima do tabuleiro para posicionar a peça
HIGH_BOARD = [90,120,70]


# Pega a peça e a coloca em x,y
def pick_and_place(x,y):

    slow_move_to(HIGH_PICK)
    time.sleep_ms(500)

    slow_move_to(PICK[2])
    time.sleep_ms(500)

    slow_move_to(HIGH_PICK)
    time.sleep_ms(500)

    slow_move_to(HIGH_BOARD)
    time.sleep_ms(500)

    slow_move_to(BOARD[y][x])
    time.sleep_ms(500)
    pin1.value(1) # liga o relé
    time.sleep_ms(500)

    slow_move_to(HIGH_PICK)
    pin1.value(0) # desliga o relé
    time.sleep_ms(500)

    slow_move_to([0,90,90])


if __name__ == "__main__":
# usado para teste de calibração

    time.sleep_ms(1)

    for order in [
        BOARD[1][1], BOARD[0][0], BOARD[1][0],
        BOARD[2][0], BOARD[2][1], BOARD[2][2],
        BOARD[1][2], BOARD[0][2], BOARD[0][1],
    ]:
        slow_move_to(HIGH_BOARD)
        time.sleep_ms(500)
        slow_move_to(order)
        time.sleep_ms(500)

    #slow_move_to(BOARD[0][2])


    #for x in PICK:
        #slow_move_to(HIGH_PICK)
        #time.sleep_ms(500)
        #slow_move_to(x)
        #time.sleep_ms(500)

    slow_move_to([0,90,90])
# chess.py
SIZE = 3

# Verifica se alguém venceu
def check_win(board, player):
    # Check rows and columns
    for i in range(SIZE):
        if all(board[i][j] == player for j in range(SIZE)) or \
           all(board[j][i] == player for j in range(SIZE)):
            return True
    # Check diagonals
    if all(board[i][i] == player for i in range(SIZE)) or \
       all(board[i][SIZE - 1 - i] == player for i in range(SIZE)):
        return True
    return False

# Verifica se houve empate
def check_draw(board):
    return all(board[i][j] != ' ' for i in range(SIZE) for j in range(SIZE))


# Calcula a pontuação da estratégia
def minimax(board, depth, is_maximizing):
    computer = 'X'
    player = 'O'

    if check_win(board, computer):
        return 10 - depth
    if check_win(board, player):
        return depth - 10
    if check_draw(board):
        return 0

    if is_maximizing:
        best_score = float('-inf')
        for i in range(SIZE):
            for j in range(SIZE):
                if board[i][j] == ' ':
                    board[i][j] = computer
                    score = minimax(board, depth + 1, False)
                    board[i][j] = ' '
                    best_score = max(score, best_score)
        return best_score
    else:
        best_score = float('inf')
        for i in range(SIZE):
            for j in range(SIZE):
                if board[i][j] == ' ':
                    board[i][j] = player
                    score = minimax(board, depth + 1, True)
                    board[i][j] = ' '
                    best_score = min(score, best_score)
        return best_score


# Calcula a próxima posição
def computer_move(board):
    if board == [
        [" "," "," "],
        [" "," "," "],
        [" "," "," "]
    ]:
        return 1,1
    best_score = float('-inf')
    move = (-1, -1)
    for i in range(SIZE):
        for j in range(SIZE):
            if board[i][j] == ' ':
                board[i][j] = 'X'
                score = minimax(board, 0, False)
                board[i][j] = ' '
                if score > best_score:
                    best_score = score
                    move = (i, j)
    if move != (-1, -1):
        # board[move[0]][move[1]] = 'X'
        print(f"Computer places X at ({move[0]}, {move[1]})")
        return move[0], move[1]


# Verifica de quem é a vez
def check_turn(board):
    x_count = sum(row.count("X") for row in board)
    o_count = sum(row.count("O") for row in board)
    return "X" if x_count == o_count else "O"
# main.py
import csi, image, time
csi0 = csi.CSI()

from pyb import Pin
import robot
import chess

csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)
csi0.snapshot(time = 2000)

clock = time.clock()


# Botão de toque
pin0 = Pin('P0', Pin.IN, Pin.PULL_UP)


distance = 43
block = 10


# Gera as posições das regiões do tabuleiro 3x3
def generate_centered_rois(width, height, b, k):
    rois = []

    # Calcula o deslocamento do centro de cada ROI
    offset = (b - k) // 2

    # Calcula a largura e a altura de toda a matriz 3x3
    total_width = 3 * b
    total_height = 3 * b

    # Calcula o ponto inicial superior esquerdo para centralizar a matriz
    start_x = (width - total_width) // 2
    start_y = (height - total_height) // 2

    for i in range(3):
        row = []
        for j in range(3):
            x_center = start_x + j * b + b // 2
            y_center = start_y + i * b + b // 2
            x = x_center - k // 2
            y = y_center - k // 2
            row.append((x, y, k, k))
        rois.append(row)

    return rois


# Posições das regiões do tabuleiro 3x3
rois = generate_centered_rois(csi0.width(), csi0.height(), distance, block)


# Matriz do tabuleiro
# Peça preta: X
# Peça branca: O
# Sem peça: string vazia
board = [
     [" "," "," "],
     [" "," "," "],
     [" "," "," "],
]


# Aguarda o botão ser pressionado e solto
def wait_key():
    while pin0.value():
        img = csi0.snapshot().lens_corr(1.8)
        for y in range(len(rois)):
            for x in range(len(rois[y])):
                img.draw_rectangle(rois[y][x])
    while not pin0.value():
        time.sleep_ms(1)


while(True):
    clock.tick()
    wait_key()
    img = csi0.snapshot().lens_corr(1.8)


    # Reconhecimento de imagem para obter a matriz do tabuleiro
    for y in range(len(rois)):
        for x in range(len(rois[y])):
            gray = img.get_statistics(roi=rois[y][x]).mean
            if gray < 100:
                board[y][x] = "X"
            elif gray > 200:
                board[y][x] = "O"
            else:
                board[y][x] = " "


    # Imprime a matriz atual do tabuleiro
    for line in board:
        print(line)
    print()


    # Desenha a matriz do tabuleiro
    for y in range(len(rois)):
        for x in range(len(rois[y])):
            if board[y][x] == "X":
                color = 255
            elif board[y][x] == "O":
                color = 0
            elif board[y][x] == " ":
                color = 127
            img.draw_rectangle(rois[y][x], color=color)


    # Estratégia de jogo
    if chess.check_win(board, 'O'):
        print("你赢啦!")

    elif chess.check_win(board, 'X'):
        print("我赢啦!")
    elif chess.check_draw(board):
        print("平局啦!")
    elif chess.check_turn(board) == "X":
        # Calcula onde colocar a próxima peça
        line,row = chess.computer_move(board)
        # Desenha uma cruz na posição alvo do tabuleiro
        img.draw_cross((int(rois[line][row][0]+block/2), int(rois[line][row][1]+block/2)), size=block, color=0)
        csi0.flush()
        # O robô pega e posiciona a peça
        robot.pick_and_place(row, line)
        csi0.flush()
    elif chess.check_turn(board) == "O":
        print("该你下了!")

results matching ""

    No results matching ""