Python+PyQt5实现火星探矿机器人(人工智能Agent实验)
Posted sgsx11
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python+PyQt5实现火星探矿机器人(人工智能Agent实验)相关的知识,希望对你有一定的参考价值。
火星探矿机器人
一、问题描述
1.1需求分析
“火星探矿机器人”旨在要开发若干个自主机器人,将其送到火星上去搜寻和采集火星上的矿产资源
火星环境对于开发者和自主机器人而言事先不可知,但是可以想象火星表面会有多样化的地形情况,如河流、巨石、凹坑等,机器人在运动过程中会遇到各种障碍;另外,火星
上还可能存在一些未知的动态因素(如风暴等),会使得环境的状况发生变化。概括起来,火星环境具有开放、动态、不可知,难控等特点。
为了简化案例的开发和演示,可以将机器人探矿的区域(即机器人的运动环境)简化和抽象成m*m的单元格,每个单元格代表某个火星区域,火星矿产分布在这些单元格中,同时这些单元格中还存在阻碍机器人运行的障碍物。探矿机器人在这些网格中运动,根据感知到的网格环境信息自主地决定自身的行为。如果所在的单元格有矿产,则采集矿产;如果探测到附近的单元格存在矿产,则移动到该单元格;如果周围的单元格存在障碍物﹐则避开这些障碍物。环境网格有两个特殊的单元格:一个是矿产堆积单元格,用于存放机器人采集到的矿产,如图6-21中的左下角;另一个是能量补充单元格,机器人可以从该单元格获得能量。
1.2 功能
下面通过多个场景描述机器人如何在上述火星环境下采集火星矿产,这些场景分别描述了机器人采矿的不同工作模式,反映了实现这些自主机器人的不同难易程度。
场景一:独立采集矿产。
在该场景中,有多个自主机器人参与到火星矿产的采集工作中,每个机器人都有移动,探测﹑采集,卸载的能力,它们在火星表面随机移动,根据其所在位置探测到的矿产信息和障碍物等环境信息自主地实施行为。但是,这些机器人都是单独工作,它们之间没有任何交互与合作。因此,可以将本场景中的每个机器人都抽象和设计为自主的 Agent
场景二:合作采集矿产。
在该场景中,有多个自主机器人参与到火星矿产的采集工作中,每个机器人都有移动、探测,采集,卸载的能力,它们在完成各自矿产采集任务的同时,相互之间还进行交互和合作,以更高效地开展工作。例如,某个机器人探测到大片的矿产信息,那么它可以将该信息告诉给其他机器人,或者请求其他机器人来该区域采矿。因此,可以将本场景中的机器人抽象和设计为由多个自主Agent所构成的多Agent系统。该系统的设计和实现不仅要考虑到各个自主Agent,还要考虑到这些Agent之间的交互和协同。
场景三:多角色合作采集矿产。
在该场景中,有多个具有不同职责,扮演不同角色的机器人参与到火星矿产的采集工作中,每类机器人承担矿产采集中的某项工作(如探测,采集),它们之间通过交互和合作共同完成矿产采集任务﹐即该场景有多种类型的机器人,包括:①采矿机器人﹐采集矿产并将其运送到指定区域;②探测机器人,负责探测矿产并将其探测到的矿产信息通知给采矿机器人。因此,可以将本场景中的机器人抽象和设计为由多个自主Agent所构成的多Agent系统。该系统的设计和实现不仅要考虑到各个自主Agent,还要考虑到这些Agent之间的交互和协同。显然,该场景比前一个场景更复杂,它涉及的Agent类型和数量、交互和合作关系等更多。
二、功能实现
2.1独立采集矿产
2.2合作采集矿产
2.3多角色合作采集矿产
2.3.1 探测机器人
2.3.2 采矿机器人
三、代码
3.1 探测机器人线程类
class SearchRobotThread(QThread):
_signal = pyqtSignal(str)
def __init__(self,pieces,textBrowser,seach_robot,label_4):
self.pieces = pieces
self.textBrowser = textBrowser
self.seach_robot = seach_robot
self.seach_robot_id = -1
self.label_4 = label_4
super(SearchRobotThread, self).__init__()
def run(self):
self.textBrowser.append("探测机器人开始工作......")
self.textBrowser.moveCursor(self.textBrowser.textCursor().End)
#八个方向,随机一个前进,遇到边界后转向,碰到障碍绕开,碰到钻石获取
directions = [(-1,0),(1,0),(0,1),(0,-1),(1,1),(-1,-1),(1,-1),(-1,1)]
row_num = len(region)
col_num = len(region[0])
#当前位置
x = self.seach_robot[0]
y = self.seach_robot[1]
self.seach_robot_id = region[x][y][3]
last_direction = -1 # 记录上一次走的方向,以免走回头路
while 1:
sleep(0.3)
#循环判断是否能走
while 1:
temp = random.randint(0, 7)
#判断是否走回头路
if temp % 2 == 0 and last_direction == temp+1:
continue
elif temp % 2 == 1 and last_direction == temp-1:
continue
#边界
if x + directions[temp][0] < 0 or x + directions[temp][0] >= row_num or y + directions[temp][1] < 0 or y + directions[temp][1] >= col_num:
print("到边界了!")
#障碍
elif region[x + directions[temp][0]][y + directions[temp][1]][2] == 2:
print("有障碍物!")
#探测机器人
elif region[x + directions[temp][0]][y + directions[temp][1]][2] == 4:
print("这是采矿机器人!")
# 钻石
elif region[x + directions[temp][0]][y + directions[temp][1]][2] == 1:
row = x + directions[temp][0]
col = y + directions[temp][1]
pos_row = region[row][col][0]
pos_col = region[row][col][1]
#记录钻石位置
if (row,col) not in diamonds_pos:
global search_diamonds
search_diamonds += 1
self.label_4.setText('已探测矿产:个'.format(search_diamonds))
diamonds_pos.append((row,col))
self.textBrowser.append("SearchRobot: (,)这里有钻石!".format(pos_row,pos_col))
self.textBrowser.moveCursor(self.textBrowser.textCursor().End)
# 结束循环
else:
region[x][y][3] = -1 # 重置当前位置id
region[x][y][2] = 0 # 重置当前位置资源
x = x + directions[temp][0]
y = y + directions[temp][1]
# 移动到该位置
self.pieces[self.seach_robot_id].setGeometry(region[x][y][0], region[x][y][1], 30, 30)
region[x][y][3] = self.seach_robot_id # 重置当前位置id
region[x][y][2] = 3 # 重置当前位置资源
last_direction = temp
# 结束循环
break
3.2 采矿机器人线程类
class WorkRobotThread(QThread):
_signal = pyqtSignal(list)
def __init__(self,pieces,textBrowser,work_robot,label_4):
self.pieces = pieces
self.textBrowser = textBrowser
self.work_robot = work_robot
self.work_robot_id = -1
self.label_4 = label_4
super(WorkRobotThread, self).__init__()
def take_first(self,elem):
return elem[0]
def run(self):
#轮询判断,如果diamonds_pos不为空则开始工作
while 1:
sleep(1)
global diamonds_pos
if not len(diamonds_pos):
continue
target_pos = diamonds_pos[0]
del diamonds_pos[0]
global region
self.textBrowser.append("采矿机器人开始工作......目标".format(region[target_pos[0]][target_pos[1]][:2]))
self.textBrowser.moveCursor(self.textBrowser.textCursor().End)
row_num = len(region)
col_num = len(region[0])
#当前位置
x = self.work_robot[0]
y = self.work_robot[1]
self.work_robot_id = region[x][y][3]
# 八个方向,每次选择离钻石最近的那个方向,如果有障碍则选择第二近方向,依此类推
directions = [(-1, 0), (1, 0), (0, 1), (0, -1), (1, 1), (-1, -1), (1, -1), (-1, 1)]
t = 0
while 1:
# 计算下一步离目标的距离列表
distances = []
for i in range(8):
row_temp = x + directions[i][0]
col_temp = y + directions[i][1]
distance = ((row_temp - target_pos[0]) ** 2 + (col_temp - target_pos[1]) ** 2) ** 0.5
distances.append((distance, i))
# 排序
print(distances)
distances.sort(key=self.take_first)
print(distances)
sleep(0.5)
#循环判断是否能走
for i in range(8):
direction = directions[distances[i][1]]
#边界
if x + direction[0] < 0 or x + direction[0] >= row_num or y + direction[1] < 0 or y + direction[1] >= col_num:
print("到边界了!")
#障碍
elif region[x + direction[0]][y + direction[1]][2] == 2:
print("有障碍物!")
#探测机器人
elif region[x + direction[0]][y + direction[1]][2] == 3:
print("这是探测机器人!")
#钻石
elif region[x + direction[0]][y + direction[1]][2] == 1:
#判断是不是目标钻石,如果不是就跳过
if x + direction[0] != target_pos[0] or y + direction[1] != target_pos[1]:
continue
region[x][y][3] = -1 #重置当前位置id
region[x][y][2] = 0 #重置当前位置资源
x = x + direction[0]
y = y + direction[1]
#获取钻石
global get_diamonds
get_diamonds += 1
#self.label_4.setText('已探测矿产:个'.format(get_diamonds))
self.textBrowser.append("钻石+1")
self.textBrowser.moveCursor(self.textBrowser.textCursor().End)
#钻石图标消失
diamond_id = region[x][y][3]
self.pieces[diamond_id].setPixmap(QPixmap(""))
#移动到该位置
self.work_robot = [x,y]
self.pieces[self.work_robot_id].setGeometry(region[x][y][0], region[x][y][1], 30, 30)
region[x][y][3] = self.work_robot_id # 重置当前位置id
region[x][y][2] = 4 # 重置当前位置资源
#结束循环
t = 1
break
else:
region[x][y][3] = -1 # 重置当前位置id
region[x][y][2] = 0 # 重置当前位置资源
x = x + direction[0]
y = y + direction[1]
# 移动到该位置
self.work_robot = [x, y]
self.pieces[self.work_robot_id].setGeometry(region[x][y][0], region[x][y][1], 30, 30)
region[x][y][3] = self.work_robot_id # 重置当前位置id
region[x][y][2] = 4 # 重置当前位置资源
# 结束循环
break
#如果取到钻石,结束该次任务
if t:
break
3.3 start.py
# -*- coding: utf-8 -*-
#主窗口
import random
import sys
from time import sleep
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtWidgets import QMainWindow, QApplication, QLabel
from Mars_robot_ui import Ui_MarsRobot
from copy import deepcopy
#定义全局变量
region = []
get_diamonds = 0
search_diamonds = 0
diamonds_pos = []
class SearchRobotThread(QThread):
_signal = pyqtSignal(str)
def __init__(self,pieces,textBrowser,seach_robot,label_4):
self.pieces = pieces
self.textBrowser = textBrowser
self.seach_robot = seach_robot
self.seach_robot_id = -1
self.label_4 = label_4
super(SearchRobotThread, self).__init__()
def run(self):
self.textBrowser.append("探测机器人开始工作......")
self.textBrowser.moveCursor(self.textBrowser.textCursor().End)
#八个方向,随机一个前进,遇到边界后转向,碰到障碍绕开,碰到钻石获取
directions = [(-1,0),(1,0),(0,1),(0,-1),(1,1),(-1,-1),(1,-1),(-1,1)]
row_num = len(region)
col_num = len(region[0])
#当前位置
x = self.seach_robot[0]
y = self.seach_robot[1]
self.seach_robot_id = region[x][y][3]
last_direction = -1 # 记录上一次走的方向,以免走回头路
while 1:
sleep(0.3)
#循环判断是否能走
while 1:
temp = random.randint(0, 7)
#判断是否走回头路
if temp % 2 == 0 and last_direction == temp+1:
continue
elif temp % 2 == 1 and last_direction 以上是关于Python+PyQt5实现火星探矿机器人(人工智能Agent实验)的主要内容,如果未能解决你的问题,请参考以下文章