[星瞳科技]如何用OpenMV制造三子棋机器人?

三子棋机器人,一共分三个步骤:

1,图像识别,获得棋子数组。

2,下棋策略算法。

3,机械臂控制抓取和落子。

硬件上我们使用了星瞳科技的OpenMV4 H7,所有的代码都是在OpenMV上运行的!包括机械臂控制,继电器控制,下棋策略算法,图像识别算法。

机械臂是直接3D打印的,使用了3个舵机,可以直接通过OpenMV的舵机扩展板控制。

棋子拾取是电磁铁来实现的,因为我顺手薅了10个纽扣电池当棋子。OpenMV可以通过继电器控制电磁铁。

1,图像识别很简单,先获取灰度图,然后在9个棋盘区域内,获取颜色信息,在OpenMV中使用statics完成。通过灰度信息,可以得到是黑子,还是白子,还是空子。 2,计算下一步棋应该怎么走,我的好朋友CHATGPT老师告诉我用minimax算法,并且给我写好了这部分的代码。 3,机械臂控制也比较简单,在等候取子区,以及每个9宫格落子区,都获取机械臂的位置,通常可以通过示教功能来完成,因为我的机械臂只用了一天时间做的很赶,所以是通过代码直接看位置。

# robot.py

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

# 控制继电器,继电器控制电磁铁
pin1 = Pin('P1', Pin.OUT_PP, Pin.PULL_NONE)
pin1.value(0)

# PCA9685 舵机扩展板
i2c = SoftI2C(sda=Pin('P5'), scl=Pin('P4'))
servo = Servos(i2c, address=0x40, freq=50, min_us=650, max_us=2800, degrees=180)

# 三个舵机的初始位置
servo.position(0, 0)
servo.position(1, 90)
servo.position(2, 90)

#全局变量,用于缓慢移动
servo_positions = [0,90,90]


# 控制一个舵机移动
def move(index, angle):
    servo.position(index, angle)
    servo_positions[index] = angle


# 控制三个舵机移动
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]))


# 控制三个舵机慢速移动
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)


# 设置棋子拾取区的位置
PICK = [[74,128,19], [82,128,17], [90,125,14], [98,128,17], [106,128,19]]
# 拾取区机械臂提起来的位置
HIGH_PICK = [90,95,55]

# 棋盘的放置位置
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]]
]

# 棋盘落子上方的位置
HIGH_BOARD = [90,120,70]


# 拾取棋子,并放置到 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) # 继电器打开
    time.sleep_ms(500)

    slow_move_to(HIGH_PICK)
    pin1.value(0) # 继电器关闭
    time.sleep_ms(500)

    slow_move_to([0,90,90])


if __name__ == "__main__":
# 校准测试用

    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

# 检查赢了吗
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

# 检查平局了吗
def check_draw(board):
    return all(board[i][j] != ' ' for i in range(SIZE) for j in range(SIZE))


# 计算策略得分
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


# 计算下一步位置
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]


# 检查该谁走了
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 sensor, image, time
from pyb import Pin
import robot
import chess

sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)

clock = time.clock()


# 轻触开关
pin0 = Pin('P0', Pin.IN, Pin.PULL_UP)


distance = 43
block = 10


# 生成九宫格的区域位置
def generate_centered_rois(width, height, b, k):
    rois = []

    # 计算每个ROI中心的位置偏移
    offset = (b - k) // 2

    # 计算整个3x3矩阵的宽度和高度
    total_width = 3 * b
    total_height = 3 * b

    # 计算左上角的起始点,使矩阵居中
    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


# 九宫格的区域位置
rois = generate_centered_rois(sensor.width(), sensor.height(), distance, block)


# 棋盘数组
# 黑子:X
# 白子:O
# 没有棋子:空字符串
board = [
     [" "," "," "],
     [" "," "," "],
     [" "," "," "],
]


#等开关按下并松开
def wait_key():
    while pin0.value():
        img = sensor.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 = sensor.snapshot().lens_corr(1.8)


    # 图像识别得到棋盘数组
    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] = " "


    # 打印当前棋盘数组
    for line in board:
        print(line)
    print()


    # 画棋盘数组
    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)


    # 下棋策略
    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":
        # 计算下一步棋子放在哪里
        line,row = chess.computer_move(board)
        # 目标棋盘上画十字
        img.draw_cross(int(rois[line][row][0]+block/2), int(rois[line][row][1]+block/2), size=block, color=0)
        sensor.flush()
        # 机器人拾取并放置棋子
        robot.pick_and_place(row, line)
        sensor.flush()
    elif chess.check_turn(board) == "O":
        print("该你下了!")

星瞳科技OpenMV视频教程-三子棋

相关推荐
FreakStudio40 分钟前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
python·嵌入式·面向对象·电子diy
QTDS13882 小时前
为什么说开放式比入耳式耳机更受欢迎?精选开放式耳机推荐
科技·手机
redcocal2 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
artificiali2 小时前
Anaconda配置pytorch的基本操作
人工智能·pytorch·python
RaidenQ2 小时前
2024.9.13 Python与图像处理新国大EE5731课程大作业,索贝尔算子计算边缘,高斯核模糊边缘,Haar小波计算边缘
图像处理·python·算法·课程设计
花生了什么树~.3 小时前
python基础知识(六)--字典遍历、公共运算符、公共方法、函数、变量分类、参数分类、拆包、引用
开发语言·python
酱香编程,风雨兼程3 小时前
深度学习——基础知识
人工智能·深度学习
Lossya3 小时前
【机器学习】参数学习的基本概念以及贝叶斯网络的参数学习和马尔可夫随机场的参数学习
人工智能·学习·机器学习·贝叶斯网络·马尔科夫随机场·参数学习
Trouvaille ~3 小时前
【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧
图像处理·python·机器学习·numpy·信号处理·时间序列分析·科学计算
爆更小小刘3 小时前
Python基础语法(3)下
开发语言·python