树莓派+opencv三阶魔方还原源码

 转自gitee hemn1990大佬,记录一下学习过程

源文件地址:


hemn/cube_robot - 码云 - 开源中国 (gitee.com)

#!/usr/bin/python3
import serial
import time
import cv2
import numpy as np
from functools import cmp_to_key
import kociemba
# 终端绘制魔方
def draw_cube(cube_str, color = ['Y', 'R', 'B', 'W', 'O', 'G']):
    color_dist = {'Y':'43', 'R':'41', 'B':'44', 'W':'47', 'O':'45', 'G':'42'}
    cube_colors = {}
    cube_colors['U'] = color_dist[color[0]]
    cube_colors['R'] = color_dist[color[1]]
    cube_colors['F'] = color_dist[color[2]]
    cube_colors['D'] = color_dist[color[3]]
    cube_colors['L'] = color_dist[color[4]]
    cube_colors['B'] = color_dist[color[5]]
    #print(''.join(cube_str))
    # URFDLB -> YRBWOG
    cube_map = [99, 99, 99, 0,  1,  2,  99, 99, 99, 99, 99, 99, 98,
                99, 99, 99, 3,  4,  5,  99, 99, 99, 99, 99, 99, 98,
                99, 99, 99, 6,  7,  8,  99, 99, 99, 99, 99, 99, 98,
                36, 37, 38, 18, 19, 20, 9,  10, 11, 45, 46, 47, 98,
                39, 40, 41, 21, 22, 23, 12, 13, 14, 48, 49, 50, 98,
                42, 43, 44, 24, 25, 26, 15, 16, 17, 51, 52, 53, 98,
                99, 99, 99, 27, 28, 29, 99, 99, 99, 99, 99, 99, 98,
                99, 99, 99, 30, 31, 32, 99, 99, 99, 99, 99, 99, 98,
                99, 99, 99, 33, 34, 35, 99, 99, 99, 99, 99, 99, 98]
    for x in cube_map:
        if x == 99:
            print("\033[40m  ", end='')
        elif x == 98:
            print("\033[0m")
        else:
            code = cube_str[x]
            color = cube_colors[code]
            print("\033[" + color + "m  ", end='')
# 等待电机停转
def block_until_stop(num_list):
    #等待运动完成
    time.sleep(0.2)#0.1不可靠
    for num in num_list:
        while is_moving(num):
            pass
def block_until_stop_and_preview_camera(num_list):
    #等待运动完成
    time.sleep(0.2)#0.1不可靠
    for num in num_list:
        while is_moving(num):
            ret,preview = cap.read()
            cv2.imshow("preview", preview)
            cv2.waitKey(1)
            pass
# 等待所有电机停转
def block_until_all_stop():
    time.sleep(0.2)#0.1不可靠
    for i in range(1,9):
        while is_moving(i):
            pass
# 设定电机的目标位置
def move_none_block(num, pos):
    if pos > 32766 or pos < -32766:
        raise Exception("pos > 32766 or pos < -32766")
    if pos >= 0:
        cmd = new_cmd(num, 3, [ 0x2A, pos & 0xFF, (pos >> 8) & 0x7F ])
    else:
        pos = - pos
        cmd = new_cmd(num, 3, [ 0x2A, pos & 0xFF, (pos >> 8) & 0x7F | 0x80])
    ser.write(cmd)
    recv = ser.read(6)
    if len(recv) != 6:
        print("Error: move_none_block(): uart timeout error")
# 判断电机是否转动
def is_moving(num):
    cmd = new_cmd(num,2,[0x42,1])
    ser.write(cmd)
    recv = ser.read(7)
    if len(recv) == 7:
        return recv[5] == 1
    else:
        print("Error: uart timeout error")
        return True
# 编码指令
def new_cmd(id_num, instruction, parameters):
    length = len(parameters) + 2
    checksum = id_num + length + instruction
    for x in parameters:
        checksum += x
    checksum = ~checksum & 0xFF
    cmd_list = [0xFF, 0xFF, id_num, length, instruction] + parameters + [checksum]
    return bytes(cmd_list)
# 十六进制打印
def print_hex(str1):
    print("[",end="")
    for x in str1:
        print(hex(x),end=",")
    print("\b]")
# 0 - 4095
def get_pos_now(num):
    cmd = new_cmd(num,2,[0x38,2])
    ser.write(cmd)
    recv = ser.read(8)
    pos = recv[5] | (recv[6] << 8)
    return pos
# -32766 - 36766
def get_pos_target(num):
    cmd = new_cmd(num,2,[0x2A,2])
    ser.write(cmd)
    recv = ser.read(8)
    pos = recv[5] | (recv[6] << 8)
    if pos & 0x8000 != 0:
        pos = - (pos & 0x7FFF) 
    return pos
 
# 控制机械爪旋转
def init_servo_pos_tab(servo_pos_tab):
    for i in (2, 4, 6, 8):
        servo_pos_tab[i] = get_pos_target(i)
        #if servo_pos_tab[i] == 0: # 刚刚上电
        #    servo_pos_tab[i] = get_pos_now(i)
        #    if servo_pos_tab[i] >= 4000:
        #        servo_pos_tab[i] = 0
    print("init_servo_pos_tab")
    print(servo_pos_tab[2], servo_pos_tab[4], servo_pos_tab[6], servo_pos_tab[8])
    
    if (abs(servo_pos_tab[2]) > 20000 or abs(servo_pos_tab[4]) > 20000 or
            abs(servo_pos_tab[6]) > 20000 or abs(servo_pos_tab[8]) > 20000):
        servo_pos_tab[2] = 0
        servo_pos_tab[4] = 0
        servo_pos_tab[6] = 0
        servo_pos_tab[8] = 0
    
    move_none_block(1, 2048)
    move_none_block(3, 1850)
    move_none_block(5, 2048)
    move_none_block(7, 1850)
    
    time.sleep(0.3)
    claw_left_right(4, True)
    claw_left_right(8, True)
    claw_up_down(2, True)
    claw_up_down(6, True)
    block_until_all_stop()

# 0 2048  
def claw_up_down(num, skip_pos_check = False):
    if num not in (2,4,6,8):
        print("servo number must be 2 4 6 8")
        return
    now = servo_pos_tab[num]
    if now % 4096 == 0 or now % 4096 == 2048: # 已经是想要的位置蓝
        if skip_pos_check:
            target = now // 2048 * 2048
        else:
            return
    elif now % 1024 != 0: # 没有对齐
        if abs(now % 4096 - 0) < abs(now % 4096 - 2048):
            target = now // 4096 * 4096 + 0
        else:
            target = now // 4096 * 4096 + 2048
    else:
        if now > 0: # 防止超越正负七圈的限制
            target = now - 1024
        else:
            target = now + 1024
    servo_pos_tab[num] = target
    print(num,target)
    move_none_block(num, target)
    
# 1024 3072
def claw_left_right(num, skip_pos_check = False):
    if num not in (2,4,6,8):
        raise Exception("servo number must be 2 4 6 8")
    now = servo_pos_tab[num]
    if now % 4096 == 1024 or now % 4096 == 3072: # 已经是想要的位置蓝
        if skip_pos_check:
            target = now // 2048 * 2048 + 1024
        else:
            return
    elif now % 1024 != 0: # 没有对齐
        if abs(now % 4096 - 1024) < abs(now % 4096 - 3072):
            target = now // 4096 * 4096 + 1024
        else:
            target = now // 4096 * 4096 + 3072
    else:
        if now > 0: # 防止超越正负七圈的限制
            target = now - 1024
        else:
            target = now + 1024
    servo_pos_tab[num] = target
    print(num,target)
    move_none_block(num, target)

def claw_cw(num):
    if num not in (2,4,6,8):
        raise Exception("servo number must be 2 4 6 8")
    now = servo_pos_tab[num]
    target = now - 1024
    servo_pos_tab[num] = target
    print(num,target)
    move_none_block(num, target)
    
def claw_ccw(num):
    if num not in (2,4,6,8):
        raise Exception("servo number must be 2 4 6 8")
    now = servo_pos_tab[num]
    target = now + 1024
    servo_pos_tab[num] = target
    print(num,target)
    move_none_block(num, target)
    
def claw_route_any(num, angle):
    if num not in (2,4,6,8):
        raise Exception("servo number must be 2 4 6 8")
    now = servo_pos_tab[num]
    target = now + angle
    servo_pos_tab[num] = target
    print(num, target)
    move_none_block(num, target)
    
def claw_180(num):
    if num not in (2,4,6,8):
        raise Exception("servo number must be 2 4 6 8")
    now = servo_pos_tab[num]
    if now > 0:
        target = now - 2048
    else:
        target = now + 2048
    servo_pos_tab[num] = target
    print(num,target)
    move_none_block(num, target)
    
#     
# def set_zero(num):
#     for i in range (1, 9):
#         cmd = new_cmd(i, 3, [0x28,128])
#         ser.write(cmd)
#         recv = ser.read(6)
    
def all_servo_power_off():
    for i in range (1, 9):
        cmd = new_cmd(i, 3, [0x28,0])
        ser.write(cmd)
        recv = ser.read(6)
def all_servo_power_on():
    for i in range (1, 9):
        cmd = new_cmd(i, 3, [0x28,1])
        ser.write(cmd)
        recv = ser.read(6)
# 抓起魔方 1.27s
def pick_up_cube():
    move_none_block(3, 1650)
    move_none_block(7, 1650)
    #block_until_stop([3, 7])
    time.sleep(0.15)
    claw_cw(4)
    claw_ccw(8)
    #block_until_stop([4, 8])
    time.sleep(0.5)
    move_none_block(5, 1650)
    move_none_block(1, 1650)
    #block_until_stop([1, 5])
    time.sleep(0.15)
    move_none_block(3, 1600)# 校准位置
    move_none_block(7, 1600)
    move_none_block(5, 1600)
    move_none_block(1, 1600)
    block_until_stop([1, 5, 3, 7])
    move_none_block(3, 1650)
    move_none_block(7, 1650)
    move_none_block(5, 1650)
    move_none_block(1, 1650)
# 放下魔方
def put_dwon_cube():
    move_none_block(3, 1600)
    move_none_block(7, 1600)
    #block_until_stop([3,7])
    time.sleep(0.1)
    move_none_block(1, 2048)
    move_none_block(5, 2048)
    #block_until_stop([1,5])
    time.sleep(0.15)
    
    claw_ccw(4)
    claw_cw(8)
    block_until_stop([4,8])
    move_none_block(3, 1850)
    move_none_block(7, 1850)
    block_until_stop([3,7])

# 翻转魔方
def flip_cube(cmd_str):
    cube_cmd_dict = {"Y'":[3, 7, 1, 5, 4, 8],
                     "Y" :[3, 7, 1, 5, 8, 4],
                     "X'":[1, 5, 3, 7, 2, 6],
                     "X" :[1, 5, 3, 7, 6, 2]}
    t = cube_cmd_dict[cmd_str]
    
    move_none_block(t[0], 1600)# 抓的紧一些
    move_none_block(t[1], 1600)
    #block_until_stop([t[0], t[1]])
    move_none_block(t[2], 1900)# 不接触魔方
    move_none_block(t[3], 1900)
    #block_until_stop([t[2],t[3]])
    time.sleep(0.25)
    claw_ccw(t[4])
    claw_cw(t[5])
    time.sleep(0.65)
    #block_until_stop([t[4],t[5]]) #0.92-0.93s
    
    move_none_block(t[2], 1650)
    move_none_block(t[3], 1650)
    #block_until_stop([t[2], t[3]])
    time.sleep(0.15)
    move_none_block(t[0], 1900)
    move_none_block(t[1], 1900)
    #block_until_stop([t[0],t[1]])
    time.sleep(0.15)
    claw_up_down(t[4])
    claw_up_down(t[5])
    #block_until_stop([t[4], t[5]])
    time.sleep(0.5)
    move_none_block(t[0], 1650)
    move_none_block(t[1], 1650)
    time.sleep(0.15)
    #block_until_stop([t[0], t[1]])

# 拍照部分
def get_cube_image():
    move_none_block(3, 1600)# 抓的紧一些
    move_none_block(7, 1600)
    #block_until_stop_and_preview_camera([3,7])
    time.sleep(0.15)
    move_none_block(1, 1900)
    move_none_block(5, 1900)
    #block_until_stop_and_preview_camera([1,5])
    time.sleep(0.15)
    for i in (0,1,2,3):
        claw_ccw(4)
        claw_cw(8)
        block_until_stop_and_preview_camera([4,8])
        cap.grab()
        ret,img[i] = cap.retrieve()

    move_none_block(1, 1600)
    move_none_block(5, 1600)
    #block_until_stop_and_preview_camera([1,5])
    time.sleep(0.15)
    move_none_block(3, 1900)
    move_none_block(7, 1900)
    #block_until_stop_and_preview_camera([3,7])
    time.sleep(0.15)
    
    for i in (4,5,6,7):
        claw_ccw(2)
        claw_cw(6)
        block_until_stop_and_preview_camera([2,6])
        cap.grab()
        ret,img[i] = cap.retrieve()
    
    move_none_block(1, 1650)
    move_none_block(3, 1650)
    move_none_block(5, 1650)
    move_none_block(7, 1650)
    time.sleep(0.15)

# 拧魔方
def claw_route(cmd_str):
    fix = 35 #根据魔方和机械抓之间的间隙设置,乐高积木版本设置为100,3D打印版本间隙小,不用这个设计也能工作
    cube_cmd_dict = {"F":[1, 2], "R":[3, 4], "B":[5, 6], "L":[7, 8]}
    t = cube_cmd_dict[cmd_str[0]]
    frag_180 = False
    if len(cmd_str) == 1:
        move_1 = - 1024 - fix
        move_2 = fix
    elif cmd_str[1] == "'":
        move_1 = 1024 + fix
        move_2 = -fix
    elif cmd_str[1] == "2":
        frag_180 = True
        now = servo_pos_tab[ t[1] ]
        if now > 0:
            move_1 = - 2048 - fix
            move_2 = fix
        else:
            move_1 = 2048 + fix
            move_2 = -fix
    
    claw_route_any(t[1], move_1)
    block_until_stop([t[1]]) # 90: 0.92s 180: 1.29s
    claw_route_any(t[1], move_2)# 不用等待,和其他动作一起完成
    if not frag_180:
        move_none_block(t[0], 1900) # 远离一点点
        #block_until_stop([t[0]])
        time.sleep(0.15)
        claw_up_down(t[1])
        #block_until_stop([t[1]])
        time.sleep(0.5)
        move_none_block(t[0], 1650)
        #block_until_stop([t[0]])
        time.sleep(0.15)
# 两侧同时拧魔方
def claw_route_2(cmd_str_a, cmd_str_b):
    fix = 35
    cube_cmd_dict = {"F":[1, 2], "R":[3, 4], "B":[5, 6], "L":[7, 8]}
    t_a = cube_cmd_dict[cmd_str_a[0]]
    t_b = cube_cmd_dict[cmd_str_b[0]]
    t_ab = cmd_str_a[0] + cmd_str_b[0]
    if t_ab != 'FB' and t_ab != 'BF' and t_ab != 'LR' and t_ab != 'RL' :
        print("can not do this. ", cmd_str_a, cmd_str_b)
        return
    
    frag_180_a = False
    if len(cmd_str_a) == 1:
        move_1_a = - 1024 - fix
        move_2_a = fix
    elif cmd_str_a[1] == "'":
        move_1_a = 1024 + fix
        move_2_a = -fix
    elif cmd_str_a[1] == "2":
        frag_180_a = True
        now = servo_pos_tab[ t_a[1] ]
        if now > 0:
            move_1_a = - 2048 - fix
            move_2_a = fix
        else:
            move_1_a = 2048 + fix
            move_2_a = -fix
    
    frag_180_b = False
    if len(cmd_str_b) == 1:
        move_1_b = - 1024 - fix
        move_2_b = fix
    elif cmd_str_b[1] == "'":
        move_1_b = 1024 + fix
        move_2_b = -fix
    elif cmd_str_b[1] == "2":
        frag_180_b = True
        now = servo_pos_tab[ t_b[1] ]
        if now > 0:
            move_1_b = - 2048 - fix
            move_2_b = fix
        else:
            move_1_b = 2048 + fix
            move_2_b = -fix
    
    claw_route_any(t_a[1], move_1_a)
    claw_route_any(t_b[1], move_1_b)
    # 两组动作都是180或者90度,等待动作完成
    if not (frag_180_a ^ frag_180_b):
        block_until_stop([t_a[1], t_b[1]])
        claw_route_any(t_a[1], move_2_a)
        claw_route_any(t_b[1], move_2_b)
    else:
    # 两组动作一组180一组90度,等待90度动作完成
        if not frag_180_a:
            block_until_stop([t_a[1]])
            claw_route_any(t_a[1], move_2_a)
        if not frag_180_b:
            block_until_stop([t_b[1]])
            claw_route_any(t_b[1], move_2_b)
    # 两组都是180度,不用归位
    if frag_180_a and frag_180_b:
        #block_until_stop([t_a[1], t_b[1]])
        return
    if not frag_180_a:
        move_none_block(t_a[0], 1900)
    if not frag_180_b:
        move_none_block(t_b[0], 1900) # 远离一点点
    #block_until_stop([t_a[0], t_b[0]])
    time.sleep(0.15)
    if not frag_180_a:
        claw_up_down(t_a[1])
    if not frag_180_b:
        claw_up_down(t_b[1])
    #block_until_stop([t_a[1], t_b[1]])
    time.sleep(0.5)
    if not frag_180_a:
        move_none_block(t_a[0], 1650)
    if not frag_180_b:
        move_none_block(t_b[0], 1650)
    
    if frag_180_a ^ frag_180_b:
        if frag_180_a:
            claw_route_any(t_a[1], move_2_a)
        if frag_180_b:
            claw_route_any(t_b[1], move_2_b)
    #block_until_stop([t_a[0], t_b[0]])
    time.sleep(0.15)
def four_point_transform(image, rect):
    # 获取坐标点,并将它们分离开来
    # 图像尺寸
    maxWidth = 256
    maxHeight = 256
    # 构建新图片的4个坐标点
    edge = 2
    dst = np.array([
        [edge, edge],
        [maxWidth - 1 - edge, edge],
        [maxWidth - 1 - edge, maxHeight - 1 - edge],
        [edge, maxHeight - 1 - edge]], dtype = "float32")

    # 获取仿射变换矩阵并应用它
    M = cv2.getPerspectiveTransform(rect, dst)
    # 进行仿射变换
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))

    # 返回变换后的结果
    return warped

def mouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print(x,y)
    
def mark_cube_one_point(img, x_center, y_center, text):
    half_size = 12
    color_line = (0,0,0)
    color = [0,0,0]
    dot_count = 0
    for y in range(x_center-half_size, x_center+half_size,1):
        for x in range(y_center-half_size, y_center+half_size,1):
            color[0] += img[x,y,0]
            color[1] += img[x,y,1]
            color[2] += img[x,y,2]
            dot_count += 1
    color[0] = int(color[0]/dot_count)
    color[1] = int(color[1]/dot_count)
    color[2] = int(color[2]/dot_count)
    cv2.rectangle(img, (x_center-half_size, y_center-half_size),
                  (x_center+half_size, y_center+half_size), color_line)
    if text != -1:
        cv2.putText(img, str(text), (x_center+half_size+1,y_center+half_size),
                    cv2.FONT_HERSHEY_DUPLEX, 0.5, color_line)
    return color

def rgb2hsv(r, g, b):
    r, g, b = r/255.0, g/255.0, b/255.0
    mx = max(r, g, b)
    mn = min(r, g, b)
    m = mx-mn
    if mx == mn:
        h = 0
    elif mx == r:
        if g >= b:
            h = ((g-b)/m)*60
        else:
            h = ((g-b)/m)*60 + 360
    elif mx == g:
        h = ((b-r)/m)*60 + 120
    elif mx == b:
        h = ((r-g)/m)*60 + 240
    if mx == 0:
        s = 0
    else:
        s = m/mx
    v = mx
    # h,s,v,值的范围分别是0-360, 0-1, 0-1
    return h, s, v

def mark_cube(img,face):
    color_line = (0,0,0)
    colors = [0,0,0,0,0,0,0,0,0]
    # 0 1 2
    # 3 4 5
    # 6 7 8
    colors[0] = mark_cube_one_point(img,42,42,face[0])
    colors[1] = mark_cube_one_point(img,128,42,face[1])
    colors[2] = mark_cube_one_point(img,214,42,face[2])
    colors[3] = mark_cube_one_point(img,42,128,face[3])
    colors[4] = mark_cube_one_point(img,128,128,face[4])
    colors[5] = mark_cube_one_point(img,214,128,face[5])
    colors[6] = mark_cube_one_point(img,42,214,face[6])
    colors[7] = mark_cube_one_point(img,128,214,face[7])
    colors[8] = mark_cube_one_point(img,214,214,face[8])
    
    hsv = [0] * 9
    for i in range(0,9):
        h,s,v = rgb2hsv(colors[i][2], colors[i][1], colors[i][0]);
        hsv[i] = [h,s,v,face[i]]
        
    return hsv

def serial_ping(num):
    cmd = new_cmd(num,1,[])
    ser.write(cmd)
    recv = ser.read(6)
    if len(recv) != 6:
        print("Error: self_test(): uart timeout error")
        return False
    else:
        return True
# 进行通信自检,上电后的第一次通信低概率是失败的,原因未知
def self_test():
    t1 = time.time()
    succ = True
    for x in range (0,10):
        for i in range(1,9):
            if serial_ping(i) == False:
                print("Error: self_test fail, loop = %d, servo ID = %d, retry..."%(x, i))
                succ = False
    if not succ:
        for x in range (0,10):
            for i in range(1,9):
                if serial_ping(i) == False:
                    print("Error: self_test fail, loop = %d, servo ID = %d"%(x, i))
                    quit()
    t2 = time.time()
    print("self test.  time=%.2f"%(t2-t1))
    
def class_color(hsv_9x5):
    min_std_shift = 0;
    min_std = 1000; # 0 - 360
    hsv_9x5_only_h = []
    for x in hsv_9x5:
        hsv_9x5_only_h.append(x[0])
    
    for shift in range(0,9):
        hsv_9x5_shift = list(hsv_9x5_only_h)
        for i in range(0, shift):
            hsv_9x5_shift[i] += 360
        hsv_9x5_shift = hsv_9x5_shift[shift:45] + hsv_9x5_shift[0:shift]
        
        std = [0] * 5
        for i in range(0,5):
            std[i] = np.std(hsv_9x5_shift[i * 9 : i * 9 + 9])
        std_mean = np.mean(std)
        
        if std_mean < min_std:
            min_std_shift = shift
            min_std = std_mean
            
    print("min_std_shift =",min_std_shift,"min_std =",min_std)
    return hsv_9x5[min_std_shift:45] + hsv_9x5[0:min_std_shift] 

# 转换kociemba返回的字符串
def flip_cube_update_state(now, cmd_str):
    ret = list(now)
    if cmd_str == 0:
        ret[0] = now[2]
        ret[2] = now[3]
        ret[3] = now[5]
        ret[5] = now[0]
    elif cmd_str == 1:
        ret[1] = now[0]
        ret[3] = now[1]
        ret[4] = now[3]
        ret[0] = now[4]
    return ret

def flip_cube_trans_cmd(now, cmd_str):
    if cmd_str[0] == now[4]:
        ret = "L" + cmd_str[1:]
    elif cmd_str[0] == now[2]:
        ret = "F" + cmd_str[1:]
    elif cmd_str[0] == now[1]:
        ret = "R" + cmd_str[1:]
    elif cmd_str[0] == now[5]:
        ret = "B" + cmd_str[1:]
    else:
        ret = ""
    return ret

def flip_cube_get_step(now, solve, step_int):
    filp_count = 0
    for step in solve:
        if step[0] == now[0] or step[0] == now[3]:
            d = step_int & 1
            step_int >>= 1
            filp_count += 1
            now = flip_cube_update_state(now, d)
    return filp_count

def flip_cube_find_min_step(solve):
    stat_now = ('U', 'R', 'F', 'D', 'L', 'B')
    min_count = flip_cube_get_step(stat_now, solve, 0)
    min_count_step_int = 0
    while True:
        for i in range (0, 2 ** min_count):
            count = flip_cube_get_step(stat_now, solve, i)
            if count < min_count:
                min_count = count
                min_count_step_int = i
                break
        else:
            break
        print("flip_cube_find_min_step: ", min_count, bin(min_count_step_int))

    step_int = min_count_step_int
    now = list(('U', 'R', 'F', 'D', 'L', 'B'))
    new_solve = []
    for step in solve:
        if step[0] == now[0] or step[0] == now[3]:
            d = step_int & 1
            step_int >>= 1
            #print(d)
            now = flip_cube_update_state(now, d)
            new_solve.append(["Y", "X"][d])
            new_solve.append(flip_cube_trans_cmd(now, step))
        else:
            new_solve.append(flip_cube_trans_cmd(now, step))
            
    return new_solve

#自定义比较函数
def comp_s(x,y):
    if x[1] > y[1]:
         return 1
    elif x[1] < y[1]:
        return -1
    else:
        return 0
def comp_h(x,y):
    if x[0] > y[0]:
        return 1
    elif x[0] < y[0]:
        return -1
    else :
        return 0
    
ser = serial.Serial("/dev/ttyAMA1", 115200, timeout=0.5)

### test start ###
# servo_pos_tab = [0] * 9
# init_servo_pos_tab(servo_pos_tab)
# pick_up_cube()
# for x in ("X", "Y", "X'", "Y'"):
#     flip_cube(x)
# for x in ("F", "R", "B" ,"L","F'", "R'", "B'" ,"L'","F2", "R2", "B2" ,"L2"):   
#     claw_route(x)  
# claw_route_2("F","B")
# claw_route_2("R","L")
# claw_route_2("F2","B")
# claw_route_2("R","L2")
# put_dwon_cube()
# all_servo_power_off()
# quit()
### test end

cap = cv2.VideoCapture(0)
if cap.isOpened() != True:
    print("camera error")
    quit()
    
self_test()
all_servo_power_on()
servo_pos_tab = [0] * 9

#截取需要的部分 TODO:开发图像识别算法,自动判断
# A -- B
# |    |
# D -- C
a = [166,90]
b = [468,96]
c = [466,397]
d = [164,390]
pts1 = np.array([b, c, d, a], dtype = "float32")
null_img = np.zeros((256, 256, 3), np.uint8)

while True:
    init_servo_pos_tab(servo_pos_tab)
    while True:
        ret,preview = cap.read()
        cv2.imshow("preview", preview)
        
        img0 = four_point_transform(preview, pts1)
        row1 = np.hstack((img0, null_img, null_img, null_img))
        row2 = np.hstack((null_img, null_img, null_img, null_img))
        img_disp = np.vstack((row1, row2))
        cv2.imshow("img", img_disp)
    
        key = cv2.waitKey(1)
        if key == 27:
            all_servo_power_off()
            cv2.destroyAllWindows()
            ser.close()
            quit()
        elif key != 255:
            break
    
    time_start = time.time()
    pick_up_cube()
    img = [0]*8
    get_cube_image()
    time_image = time.time()
    for i in range (0,8):
        img[i] = four_point_transform(img[i], pts1)

    #记录hsv颜色
    hsv_6_face = []
    hsv_6_face_54 = []
    hsv_6_face.extend(mark_cube(img[0], [47,50,53,46,49,52,45,48,51]))
    hsv_6_face.extend(mark_cube(img[1], [33,-1,27,34,31,28,35,-1,29]))
    hsv_6_face.extend(mark_cube(img[2], [24,21,18,25,22,19,26,23,20]))
    hsv_6_face.extend(mark_cube(img[3], [ 6,-1, 0, 7, 4, 1, 8,-1, 2]))
    hsv_6_face.extend(mark_cube(img[4], [ 9,10,11,12,13,14,15,16,17]))
    hsv_6_face.extend(mark_cube(img[5], [-1,32,-1,-1,-1,-1,-1,30,-1]))
    hsv_6_face.extend(mark_cube(img[6], [44,43,42,41,40,39,38,37,36]))
    hsv_6_face.extend(mark_cube(img[7], [-1, 3,-1,-1,-1,-1,-1, 5,-1]))
    
    # 显示处理好的图片
    row1 = np.hstack((img[0], img[1], img[2], img[3]))
    row2 = np.hstack((img[4], img[5], img[6], img[7]))
    img_disp = np.vstack((row1, row2))
    cv2.imshow("img", img_disp)
    k = cv2.waitKey(1)
        
    #剔除无用数据
    for item in hsv_6_face:
        if item[3] != -1:
            hsv_6_face_54.append(item)
    #print(hsv_6_face_54)
    #print(len(hsv_6_face_54))

    #根据饱和度挑出白色
    #cube_string = "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB"
    cube_string = ['?']*54
    cube_string_kociemba = ['?']*54
    hsv_6_face_54 = sorted(hsv_6_face_54, key=cmp_to_key(comp_s))
    for i in hsv_6_face_54[0:9]:
        cube_string[i[3]] = 'W'
    #根据色调分离其他颜色
    hsv_6_face_54 = sorted(hsv_6_face_54[9:], key=cmp_to_key(comp_h))
    hsv_6_face_54 = class_color(hsv_6_face_54)
    for i in hsv_6_face_54[0:9]:
        cube_string[i[3]] = 'O'
    for i in hsv_6_face_54[9:18]:
        cube_string[i[3]] = 'Y'
    for i in hsv_6_face_54[18:27]:
        cube_string[i[3]] = 'G'
    for i in hsv_6_face_54[27:36]:
        cube_string[i[3]] = 'B'
    for i in hsv_6_face_54[36:45]:
        cube_string[i[3]] = 'R'
    print(''.join(cube_string))
    # RGBWOY -> URFDLB
    u_color = cube_string[4]
    r_color = cube_string[13]
    f_color = cube_string[22]
    d_color = cube_string[31]
    l_color = cube_string[40]
    b_color = cube_string[49]
    for i in range(0,54):
        if cube_string[i] == u_color:
            cube_string_kociemba[i] = 'U'
        elif cube_string[i] == r_color:
            cube_string_kociemba[i] = 'R'
        elif cube_string[i] == f_color:
            cube_string_kociemba[i] = 'F'
        elif cube_string[i] == d_color:
            cube_string_kociemba[i] = 'D'
        elif cube_string[i] == l_color:
            cube_string_kociemba[i] = 'L'
        elif cube_string[i] == b_color:
            cube_string_kociemba[i] = 'B'
    cube_string_kociemba = ''.join(cube_string_kociemba)
    len_solve = 0
    if "?" in cube_string_kociemba:
        print("Error: wrong cube partton")
        solve = []
    else:
        draw_cube(cube_string_kociemba, [u_color,r_color,f_color,d_color,l_color,b_color])
        print(cube_string_kociemba)
        
        if cube_string_kociemba != "UUUUUUUUURRRRRRRRRFFFFFFFFFDDDDDDDDDLLLLLLLLLBBBBBBBBB":
            try:
                solve = kociemba.solve(cube_string_kociemba, max_depth=21)
                len_solve = len(solve.split(" "))
                print(solve)
                solve = flip_cube_find_min_step(solve.split(" "))
                print(solve)
            except Exception as e:
                #f_obj = open(file_name+".err","w")
                #f_obj.write(repr(e))
                #f_obj.close()
                print(repr(e))
                solve = []
        else:
            print("solved cube")
            solve = []
    time_calc = time.time()
            
    i = 0
    while i < len(solve):
        if i + 1 < len(solve):
            t_ab = solve[i][0] + solve[i+1][0]
            if t_ab != 'FB' and t_ab != 'BF' and t_ab != 'LR' and t_ab != 'RL' :
                step = solve[i]
                if step in ("X", "Y", "X'", "Y'"):
                    flip_cube(step)
                else:
                    claw_route(step)
                i =  i + 1
            else:
                claw_route_2(solve[i], solve[i+1])
                i =  i + 2
        else: # 剩下最后一步
            step = solve[i]
            if step in ("X", "Y", "X'", "Y'"):
                flip_cube(step)
            else:
                claw_route(step)
            i =  i + 1
    put_dwon_cube()
    time_end = time.time()
    print("总耗时 %.2fs"%(time_end - time_start))
    print("拍照耗时 %.2fs"%(time_image - time_start))
    print("计算耗时 %.2fs"%(time_calc - time_image))
    print("拧魔方耗时 %.2fs"%(time_end - time_calc))
    print("步骤数量 %d"%(len_solve))

(重要!!!其中使用了easyx图形库,easyx的外部文件需自己另外下载并配置好,本资源未包括该扩展库的文件,即把几个文件放进VC6.0的Lib文件夹里就好了) 作品名称:魔方还原 作品功能:进行三阶魔方还原。 界面介绍:打开程序首先进入一个有着发光魔方背景的欢迎界面,有“Rubik”和“Help”两个按钮。按“Help”按钮进入帮助界面,显示用键盘操作魔方的方法。按“Rubik”进入魔方还原的主界面,左边是一个可以看到三面的立体魔方,右边是与立体魔方对应的六面展开图。魔方初始状态是未被打乱的状态。另外搭配主界面的还有一个控制台窗口,用于显示操作步骤。 操作说明:从键盘直接输入字符控制,各字符含义如下。 0: 按数字零退出程序。 *: 按星号键执行逆序法还原魔方。 +: 按加号键执行魔方传统的“层先法”进行还原。 R: 顺时针90°转右面。 r: 逆时针90°转右面。 U: 顺时针90°转顶面。 u: 逆时针90°转顶面。 L: 顺时针90°转左面。 l: 逆时针90°转左面。 D: 顺时针90°转底面。 d: 逆时针90°转底面。 F: 顺时针90°转前面。 f: 逆时针90°转前面。 B: 顺时针90°转背面。 b: 逆时针90°转背面。 M: 向下转中层。 m: 向上转中层。 X: 顺着x轴转90°。 x: 逆着x轴转90°。 Y: 顺着y轴转90°。 y: 逆着y轴转90°。 Z: 顺着z轴转90°。 z: 逆着z轴转90°。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值