【问题标题】:How to combine arduino programm with astar algorithm?如何将arduino程序与astar算法结合起来?
【发布时间】:2022-10-15 04:20:28
【问题描述】:

我需要将 arduino 与 astar 算法相结合来控制机器人。我们有 6x6 的机器人需要骑行的区域,并且控制器(F(前),L(左),R(右))必须用 python 代码编写。所以我有 arduino 串行代码,我找到了 astar 算法和程序来用 arduino 控制电机。我如何结合串行代码和astar算法来控制python中的机器人?

在 python 中连接 arduino 的串行代码

import serial # pip install pyserial

"""
Inside serial library (module), Serial class is used to define port and baudrate
"""
arduino = serial.Serial('COM3', baudrate=9600) # Same baudrate, as in Arduino program
print('Established serial connection to Arduino')



while True:
    """ Reading from Serial port """
    inp = input("Write one character: ")
    arduino.write(bytes(inp, 'utf-8')) # writing 
    False

我发现的 Astar 算法

class Node():
    """A node class for A* Pathfinding"""

    def __init__(self, parent=None, position=None):
        self.parent = parent
        self.position = position

        self.g = 0
        self.h = 0
        self.f = 0

    def __eq__(self, other):
        return self.position == other.position


def astar(maze, start, end):
    """Returns a list of tuples as a path from the given start to the given end in the given maze"""

    # Create start and end node
    start_node = Node(None, start)
    start_node.g = start_node.h = start_node.f = 0
    end_node = Node(None, end)
    end_node.g = end_node.h = end_node.f = 0

    # Initialize both open and closed list
    open_list = []
    closed_list = []

    # Add the start node
    open_list.append(start_node)

    # Loop until you find the end
    while len(open_list) > 0:

        # Get the current node
        current_node = open_list[0]
        current_index = 0
        for index, item in enumerate(open_list):
            if item.f < current_node.f:
                current_node = item
                current_index = index

        # Pop current off open list, add to closed list
        open_list.pop(current_index)
        closed_list.append(current_node)

        # Found the goal
        if current_node == end_node:
            path = []
            current = current_node
            while current is not None:
                path.append(current.position)
                current = current.parent
            return path[::-1] # Return reversed path

        # Generate children
        children = []
        for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)]: # Adjacent squares

            # Get node position
            node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1])

            # Make sure within range
            if node_position[0] > (len(maze) - 1) or node_position[0] < 0 or node_position[1] > (len(maze[len(maze)-1]) -1) or node_position[1] < 0:
                continue

            # Make sure walkable terrain
            if maze[node_position[0]][node_position[1]] != 0:
                continue

            # Create new node
            new_node = Node(current_node, node_position)

            # Append
            children.append(new_node)

        # Loop through children
        for child in children:

            # Child is on the closed list
            for closed_child in closed_list:
                if child == closed_child:
                    continue

            # Create the f, g, and h values
            child.g = current_node.g + 1
            child.h = ((child.position[0] - end_node.position[0]) ** 2) + ((child.position[1] - end_node.position[1]) ** 2)
            child.f = child.g + child.h

            # Child is already in the open list
            for open_node in open_list:
                if child == open_node and child.g > open_node.g:
                    continue

            # Add the child to the open list
            open_list.append(child)


def main():

    maze = [[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

    start = (0, 0)
    end = (7, 6)

    path = astar(maze, start, end)
    print(path)


if __name__ == '__main__':
    main()

【问题讨论】:

  • 1. 将两个脚本合并为一个文件 2. 在path 列表中,您需要获取命令列表,例如 [(0, 0), (1, 1)] -> ["F", "R"]。但似乎A *允许机器人不能做的对角线移动,所以你需要禁止对角线移动或其他东西。 3. 遍历命令列表,一一发送给机器人

标签: python arduino


【解决方案1】:

您需要将运动方向从开始到结束转换为turtle like commands(受系统限制:仅转 90 度(“L”、“R”)并且仅向前移动(“F”)但不是落后)。

不是最有效的,不是简洁/Pythonic,但希望是一个足够简单的例子:

def path_to_turtle(path):
        dir_to_turtle = {
            (0,0)  : '',
            (1,0)  : 'F',       # to the right: move forward
            (0,1)  : 'RF',      # bellow: turn right, then move forward
            (1,1)  : 'FRF',     # right diagonal down: move forward, turn right, then move forward again
            (-1,0) : 'RRF',     # left: turn right twice (180 degrees), then move forward
            (0,-1) : 'LF',      # up: turn left once (90 degrees), then move forward
            (-1,-1): 'LLFRF',   # left diagonal up: go back one (turn 180 then forward), turn right one (90 degrees) to point up, then go forward
            (1,-1) : 'FLF',     # right diagonal up: forward, turn left (90 degrees), (1,) then go forward (,-1)
            (-1,1) : 'RRFRF'    # left down diagonal: turn right twice (180 degrees), move forward (-1,), then turn right again (90 degrees) and forward agan (,1)
        }
        turtle = ""
        for i in range(len(path) - 1):
            curr_point = path[i]
            next_point = path[i+1]
            dx = next_point[0] - curr_point[0]
            dy = next_point[1] - curr_point[0]
            print(i,path[i],'->',path[i+1],'=',(dx, dy),dir_to_turtle[(dx,dy)])
            turtle += dir_to_turtle[(dx,dy)]
        # append 
 if arduino buffers each char until new line
        turtle += '
'
        return turtle

以上:

  1. 查找可能的相对方向(上、下、左、右 + 4 条对角线)转换为F,L,R 命令
  2. 遍历从第一个点到最后一个点之前的路径,一次两个点(当前点和下一个点)
  3. 下一个和当前(在每个轴上)之间的区别是移动方向:使用查找将其转换为命令

    这假设您的机器人像乌龟:自上而下的视图,左/右转为 90 度。

    函数内部的print() 调用纯粹是出于调试/可视化的原因:

    path = [(0, 0), (1, 1), (2, 2), (3, 3), (4, 3), (5, 4), (6, 5), (7, 6)]
    step 0 (0, 0) -> (1, 1) = (1, 1) FRF
    step 1 (1, 1) -> (2, 2) = (1, 1) FRF
    step 2 (2, 2) -> (3, 3) = (1, 1) FRF
    step 3 (3, 3) -> (4, 3) = (1, 0) F
    step 4 (4, 3) -> (5, 4) = (1, 1) FRF
    step 5 (5, 4) -> (6, 5) = (1, 1) FRF
    step 6 (6, 5) -> (7, 6) = (1, 1) FRF
    serial_commands FRFFRFFRFFFRFFRFFRF
    

    另一个假设是 arduino 固件缓冲每个字符,直到换行符(' ')。

    使用您的 path 变量作为 A* 结果,您应该能够执行以下操作:

    import serial
    serial_commands = path_to_turtle(path)
    print(serial_commands)
    arduino = serial.Serial('COM3', baudrate=9600)
    try:
        arduino.write(str.encode(serial_commands))
    except Exception as e:
        print(e)
        exit(1)
    

    为了好玩,我推荐使用 turtle 模块。 它将允许您构建一个基本的模拟器来测试路径,然后再发送到动作机器人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-08
    • 2012-03-17
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多