机器人学科建设沙盘套件!mechArm机械臂智慧农业3D分拣套装详解

作为最热门的技术领域,机器人技术正在彻底改变产业,并推动全球的创新。为了满足这个快速发展的领域对技术人才日益增长的需求,高校开发了一个开创性的机器人教育解决方案。这个创新的解决方案将自动化水果采摘机的模拟与水果分拣和运送的自动化复合机器人结合起来,为学生提供了一个在最受欢迎和最有趋势的技术领域中的全面学习经验。 在本文中我们将详细为你介绍水果采摘和分拣机器人场景。我们将会从套装的介绍和使用的场景介绍,到套装功能机械臂的实现。

智慧农业套装

图中所展示的就是我们的智慧农业套装,它是由以下的内容组成。

mechArm 270 M5Stack

*2

传送带

*1

3D摄像头/深度摄像头

*2

仿真模拟果树

*1

结构件

若干

你肯定很好奇这个套装是怎么运转的,接下来我将为你介绍这个套装的运作流程。

首先你可以看到我们有两台机械臂,他们分别执行不同的功能,离果树最近的那一台机械臂是采摘机器人下面简称R1;中间那台机械臂是分拣机器人下面简称是R2。从他们的名字上就可以知道它们分别做的是什么工作,R1负责将果树上的果实采摘下来放置在传送带上,R2则是将传送带上不合格的水果分拣出来。

流程:

采摘:R1通过深度摄像头对果树上果实的识别然后对果子进行定位,将果实的坐标发送给R1去采摘。

运输:通过R1的采摘,果实被放置在传送带上。传送带经过运转将果实运输到R2可识别的范围内进行果实好坏的判断。

分拣:R2上方的摄像头将视线范围内的果实进行识别算法的判断,判断为好果实的话,果实将随着传送带传输到果实收集区;判断为坏果实的话,将坏果实的坐标信息传递给R2,R2将坏果实目标进行抓取出来,放置在特定区域。

持续循环上面的流程:采摘->运输->分拣->采摘->运输

产品介绍

下面将简要介绍套装中的产品。

Robotic Arm - mechArm 270 M5Stack

这是一款小六轴机械臂,以M5Stack-Basic为核心控制,ESP32为辅助控制,结构是中心对称结构(仿工业结构)。mechArm 270-M5本体重量1kg, 负载250g,工作半径270mm,设计紧凑便携,小巧但功能强大,操作简单,能与人协同、安全工作。

传送带

传送带是一种用于运输物品的机械设备,通常由一个带状物体和一个或多个滚动轴组成。它们可以运输各种物品,例如包裹、箱子、食品、矿石、建筑材料等等。传送带的工作原理是将物品放置在运动的带子上,然后将其移动到目标位置。传送带通常由电机、传动系统、带子和支撑结构组成。电机提供动力,传动系统将动力传递给带子,使其移动。

目前市面上可以根据用户的需求定制各种传送带,例如传送带的长宽高,履带的材质等。

深度摄像头

随着使用场景的多样性,普通的2D摄像头无法满足我们使用的需求。在场景中我们使用到的是深度摄像头。深度摄像头是一种能够获取场景深度信息的相机。它不仅能够捕捉场景的颜色和亮度信息,还能够感知物体之间的距离和深度信息。深度摄像头通常使用红外线或其他光源来进行测量,以获取物体和场景的深度信息。

它可以获取很多信息,例如深度的画面,彩色的画面,红外线的画面,点云画面。

有了深度相机,我们就可以精准的获取到果树上果实的位置,以及颜色信息。

自适应夹爪-机械臂末端执行器

自适应夹爪是一种用来抓取、握取或夹持物体的末端执行器,它由两个可移动的爪子组成,可以通过机械臂的控制系统来控制其开合程度和开合速度。

项目功能的实现

我们先要准备好编译的环境,该场景是用Python语言来进行编写的。在使用和学习的时候得安装好环境。

编译环境:

numpy==1.24.3
opencv-contrib-python==4.6.0.66
openni==2.3.0
pymycobot==3.1.2
PyQt5==5.15.9
PyQt5-Qt5==5.15.2
PyQt5-sip==12.12.1
pyserial==3.5

复制

项目的功能点我们主要分为三部分:

● 机器视觉识别算法,深度识别算法● 机械臂的控制,路径的规划● 多台机器之间通信和逻辑的处理

复制

我们先从机器视觉识别算法介绍:

机器视觉识别算法

使用深度摄像头之前需要进行相机标定。相机标定的教程(https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html)

相机标定:

相机标定是指通过对摄像机进行一系列测量和计算,确定摄像机内部参数和外部参数的过程。摄像机内部参数包括焦距、主点位置、像素间距等,而摄像机外部参数则包括摄像机在世界坐标系中的位置和方向等。相机标定的目的是为了使摄像机能够准确地捕捉并记录世界坐标系中物体的位置、大小、形状等信息。

我们的目标物体是果实,它颜色不一,形状也不一定,有红的,橙的,黄的。想要准确的抓取且不伤害到果实,就需要获取果实的各个信息,宽度,厚度等,智能的进行抓取。

我们看一下目标果实,它们目前较大的区别就是颜色的不一样,我们设定红色和橙色的目标将被选中,这里就要用到HSV色域来进行目标的定位。下面的代码是用来检测目标果实。

Code:

class Detector:class FetchType(Enum):FETCH = FalseFETCH_ALL = True"""Detection and identification class"""HSV_DIST = {
# "redA": (np.array([0, 120, 50]), np.array([3, 255, 255])),
# "redB": (np.array([176, 120, 50]), np.array([179, 255, 255])),
"redA": (np.array([0, 120, 50]), np.array([3, 255, 255])),
"redB": (np.array([118, 120, 50]), np.array([179, 255, 255])),
# "orange": (np.array([10, 120, 120]), np.array([15, 255, 255])),
"orange": (np.array([8, 150, 150]), np.array([20, 255, 255])),
"yellow": (np.array([28, 100, 150]), np.array([35, 255, 255])), # old
# "yellow": (np.array([31, 246, 227]), np.array([35, 255, 255])),   # new
}default_hough_params = {
"method": cv2.HOUGH_GRADIENT_ALT,
"dp": 1.5,
"minDist": 20,
"param2": 0.6,
"minRadius": 15,
"maxRadius": 40,
}def __init__(self, target):self.bucket = TargetBucket()self.detect_target = targetdef get_target(self):return self.detect_targetdef set_target(self, target):if self.detect_target == target:returnself.detect_target = targetif target == "apple":self.bucket = TargetBucket(adj_tolerance=25, expire_time=0.2)elif target == "orange":self.bucket = TargetBucket()elif target == "pear":self.bucket = TargetBucket(adj_tolerance=35)def detect(self, rgb_data):if self.detect_target == "apple":self.__detect_apple(rgb_data)elif self.detect_target == "orange":self.__detect_orange(rgb_data)elif self.detect_target == "pear":self.__detect_pear(rgb_data)def __detect_apple(self, rgb_data):maskA = color_detect(rgb_data, *self.HSV_DIST["redA"])maskB = color_detect(rgb_data, *self.HSV_DIST["redB"])mask = maskA + maskBkernelA = cv2.getStructuringElement(cv2.MORPH_RECT, (8, 8))kernelB = cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2))mask = cv2.erode(mask, kernelA)mask = cv2.dilate(mask, kernelA)targets = circle_detect(mask, {"minDist": 15, "param2": 0.5,
"minRadius": 10, "maxRadius": 50}
)self.bucket.add_all(targets)self.bucket.update()def __detect_orange(self, rgb_data):mask = color_detect(rgb_data, *self.HSV_DIST["orange"])targets = circle_detect(mask, {"minDist": 15, "param2": 0.1,
"minRadius": 7, "maxRadius": 30}
)self.bucket.add_all(targets)self.bucket.update()def __detect_pear(self, rgb_data):mask = color_detect(rgb_data, *self.HSV_DIST["yellow"])kernelA = cv2.getStructuringElement(cv2.MORPH_RECT, (25, 25))kernelB = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))mask = cv2.erode(mask, kernelA)mask = cv2.dilate(mask, kernelA)mask = cv2.erode(mask, kernelB)targets = circle_detect(mask, {"minDist": 15, "param2": 0.1,
"minRadius": 15, "maxRadius": 70}
)self.bucket.add_all(targets)self.bucket.update()def fetch(self):return self.bucket.fetch()def fetch_all(self):return self.bucket.fetch_all()def debug_view(self, bgr_data, view_all=True):if view_all:targets = self.bucket.fetch_all()else:targets = self.bucket.fetch()if targets is not None:targets = [targets]if targets is not None:for target in targets:x, y, radius = target["x"], target["y"], target["radius"]
# draw outlinecv2.circle(bgr_data, (x, y), radius, BGR_GREEN, 2)# draw circle centercv2.circle(bgr_data, (x, y), 1, BGR_RED, -1)

复制

左边为彩色流视频,右边为深度视频

我们的第一步就是要将目标果实能够正确的检测出来,以便后续获取目标物体的坐标,深度等其他信息。我们定义需要获取的信息方便后续的存储以及调用。

code:

class VideoCaptureThread(threading.Thread):def __init__(self, detector, detect_type = Detector.FetchType.FETCH_ALL.value):threading.Thread.__init__(self)self.vp = VideoStreamPipe()self.detector = detector                  self.finished = True                      self.camera_coord_list = []               self.old_real_coord_list = []             self.real_coord_list = []                 self.new_color_frame = None              self.fruit_type = detector.detect_target  self.detect_type = detect_type            self.rgb_show = Noneself.depth_show = None

复制

最后我们要获取的是果实的坐标,能够发送给机械臂去执行抓取的坐标,通过深度坐标转化为世界坐标,已经是成功了一大半了,最后只需要将世界坐标跟机械臂的坐标系进行转换就可以获得抓取目标果实的坐标了。

# get world coordinatedef convert_depth_to_world(self, x, y, z):fx = 454.367fy = 454.367cx = 313.847cy = 239.89ratio = float(z / 1000)world_x = float((x - cx) * ratio) / fxworld_x = world_x * 1000world_y = float((y - cy) * ratio) / fyworld_y = world_y * 1000world_z = float(z)return world_x, world_y, world_z

复制

该阶段,我们实现了检测目标物体,并且返回可抓取的坐标,传递给机械臂。接下来我们来处理机械臂的控制以及轨迹的规划。

机械臂的控制和轨迹规划

说到机械臂的控制,一开始大家可能都会觉得很困难,怎么让机械臂按照自己的想法动起来。不用担心,我们mechArm270机械臂有pymycobot,一个相对比较成熟的机械臂控制库,只需要简单的几行代码就能够让机械臂运动起来。

PS:pymycobot 是pyhon的一个库,用于控制机械臂运动的一个库,我们使用的是最新版,pymycobot==3.1.2

#Introduce two commonly used control methods
'''
Send the degrees of all joints to robot arm.
angle_list_degrees: a list of degree value(List[float]), length 6
speed: (int) 0 ~ 100,robotic arm's speed
'''
send_angles([angle_list_degrees],speed)
send_angles([10,20,30,45,60,0],100)
'''
Send the coordinates to robot arm
coords:a list of coordiantes value(List[float]), length 6
speed: (int) 0 ~ 100,robotic arm's speed
'''
send_coords(coords, speed)
send_coords([125,45,78,-120,77,90],50)

复制

以角度/坐标都可以把发送给机械臂去进行执行。

控制机械臂运动

采摘机器人轨迹规划

在实现简单的控制之后,我们就要设计机械臂抓取果实的轨迹规划了。在识别算法当中,我们获得到了果子的世界坐标。处理果子的世界坐标,转化到机械臂坐标系坐标进行目标抓取。

#处理果实世界坐标的方法
deftarget_coords(self):coord = self.ma.get_coords()
whilelen(coord)==0:coord = self.ma.get_coords()target = self.model_track()coord[:3]= target.copy()self.end_coords = coord[:3]if DEBUG ==True:
print("coord: ", coord)
print("self.end_coords: ", self.end_coords)self.end_coords = coordreturn coord

复制

有了目标坐标之后,我们规划机械臂运动的轨迹。在机械臂运动的途中,不能撞到其他结构,打落水果等。

在规划的时候可以考虑设计:

● 初始姿态● 待抓取姿态● 避障姿态

复制

各种的姿态应该根据自己的场景需求来设定。

分拣机器人路径规划

前有采摘机器人,现在来讲解分拣机器人路径的规划。其实这两个机器人的路径规划都是大同小异,分拣目标是传送带上的目标,通过深度摄像头获取传送带上坏果实的坐标将其分拣出来。

采摘机器人和分拣机器人的控制和轨迹规划就到这里了,接下来我们来介绍比较重要的,也是这个套装的重中之重,这两台机械臂之间是如何通信的呢,它们是如何有效让两台机械臂和一台传送带不进入死循环能够运行的如此顺畅。

多台机械臂的通信和逻辑的处理

如果没有一个完整的逻辑,相信这两个机械臂早就打起架来了。我们看整个程序的流程图。

 

就是在R2发现坏果的时候,R1是机械臂是暂停的状态,等到R2完成分拣工作了之后会给R1传递信息让R1继续进行采摘工作。

Socket通信

既然要通信,那就少不了Socket这个库。Socket库是一个在网络编程中经常使用的标准库,它提供了一组用于网络通信的API,可以方便地实现不同计算机之间的数据传输。为了解决R1 和R2 之间通信的问题,我们的解决方法是简历一个服务器,和一个客户端的效果。

 

服务器建立的相关代码,提前初始化需要传递的信息

Code:

classTcpServer(threading.Thread):
def__init__(self, server_address)->None:threading.Thread.__init__(self)self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.s.bind(server_address)
print("server Binding succeeded!")self.s.listen(1)self.connected_obj =Noneself.good_fruit_str ="apple"self.bad_fruit_str ="orange"self.invalid_fruit_str ="none"self.target = self.invalid_fruit_strself.target_copy = self.targetself.start_move =False

复制

客户端建立的相关代码。 Code:

classTcpClient(threading.Thread):
def__init__(self, host, port, max_fruit =8, recv_interval =0.1, recv_timeout =30):threading.Thread.__init__(self)self.good_fruit_str ="apple"self.bad_fruit_str ="orange"self.invalid_fruit_str ="none"self.host = hostself.port = port# Initializing the TCP socket object
# specifying the usage of the IPv4 address family
#  designating the use of the TCP stream transmission protocolself.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.client_socket.connect((self.host, self.port))self.current_extracted =0self.max_fruit = max_fruitself.recv_interval = recv_intervalself.recv_timeout = recv_timeoutself.response_copy = self.invalid_fruit_strself.action_ready =True

复制

建立好了服务器和客户端,我们就可以让R1和R2像我们平时发信息一样进行通信了。

R1:"我现在在抓果实“

R2:"收到好的"

技术要点

这整个项目下来关键是多台机械臂之间的通信和逻辑的处理。要让两个机械臂之间建立通信有很多种办法,例如常见的物理通信串口通信,以太网口通信,蓝牙通信等。

我们现在使用的就是以太网口通信,使用现有的TCP/IP协议,用python当中的socket库来进行实现。

建房子先建地基这个道理大家都懂吧,建立一个项目就要搭建好它的框架也是同一个道理。此外机械臂控制的原理也是至关重要的,学会如何将目标物体转化为世界坐标在换成机械臂坐标系中的目标。

总结

该水果采摘和分拣机器人的应用场景不仅可以帮助学生更好地理解机械原理和电子控制技术,还可以促进他们对科学技术的兴趣和热爱,并提供一个锻炼实践能力和竞赛思维的机会。

学习机械臂相关知识需要实践操作,而该应用场景提供了一个具有实际意义的机会,让学生通过实际操作来加深对机械臂的理解和认识。此外,该场景还可以让学生学习和掌握机械臂运动控制、视觉识别和物品抓取等技术,帮助他们更好地掌握机械臂的相关知识和技能。

除此之外,该应用场景还可以帮助学生锻炼团队合作、创新思维和竞赛思维等能力,为他们未来的职业发展打下坚实的基础。通过参与机器人竞赛、科技展览等活动,学生可以不断提高自己的竞赛水平和创新能力,从而更好地适应未来的社会发展和科技变革。作为最热门的技术领域,机器人技术正在彻底改变产业,并推动全球的创新。为了满足这个快速发展的领域对技术人才日益增长的需求,大象机器人公司为高校开发了一个开创性的机器人教育解决方案。这个创新的解决方案将自动化水果采摘机的模拟与水果分拣和运送的自动化复合机器人结合起来,为学生提供了一个在最受欢迎和最有趋势的技术领域中的全面学习经验。

mechArm 270 M5Stack

*2

传送带

*1

3D摄像头/深度摄像头

*2

仿真模拟果树

*1

结构件

若干

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/7551.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Simulink 中基于 FPGA 的波束成形:算法设计(附源码)

一、前言 本示例显示了在 Simulink中开发适用于在硬件(如现场可编程门阵列 (FPGA))上实现的波束成形器的工作流程的前半部分。它还演示如何将实现模型的结果与行为模型的结果进行比较。 示例 Simulink 中基于 FPGA 的波束成形&…

docker专题系列之十五:卸载docker

一、准备工作 1.杀死docker有关的容器: docker kill $(docker ps -a -q)2.删除所有docker容器: docker rm $(docker ps -a -q)3.删除所有docker镜像: docker rmi $(docker images -q)4.停止 docker 服务: systemctl stop dock…

redis知识复习

redis知识复习 redis基础知识一. redis的认识1. 非关系型数据库 与 传统数据库 的区别2. 安装redis并设置自启动3. 熟悉命令行客户端4. 熟悉图形化工具RDM 二. redis的命令与数据结构1. 数据结构介绍2. redis通用命令(熟练掌握) 三. redis的Java客户端1.…

背光图像增强论文调研

背光图像增强 M. Akai, Y. Ueda, T. Koga and N. Suetake, “A Single Backlit Image Enhancement Method For Improvement Of Visibility Of Dark Part,” 2021 IEEE International Conference on Image Processing (ICIP), Anchorage, AK, USA, 2021, pp. 1659-1663, doi: 10…

springboot中Thymeleaf模板插入Freemarker模板页面

概述 最近在修改springboot架构的项目,项目之前配置的是Thymeleaf模板, 但是在我新加的功能中,我非常想用Freemarker模板来新加一些页面功能。 看到网上很多其他地方描述,要么用不同的文件后缀来区分(如html文件为Thymeleaf&…

C# 交错数组学习

C# 交错数组是元素为数组的数组。 一个示例; using System;class Program {static void Main(string[] args) {string[][] weeks new string[3][];weeks[0] new string[] { "星期日", "星期一", "星期二", "星期三", &…

举例说明什么是循环神经网络

循环神经网络(Recurrent Neural Network, RNN)是一种处理时间序列数据和自然语言等具有顺序信息的数据的神经网络模型。与普通的前馈神经网络(Feedforward Neural Network)不同,RNN具有循环连接,使得网络能…

区块链技术如何改变Web3认证的现状?

随着加密货币和区块链技术的迅猛发展,Web3钱包成为了数字经济时代中的重要组成部分。Web3钱包是一种工具,用于存储、管理和交互加密货币及其他数字资产,以及与去中心化应用程序(DApp)进行交互。它们是实现Web3.0理念的…

谈高考志愿填报

目录 不如先说说我自己。 一、选专业还是选学校: 二、你想推荐/避雷的专业: 三、填报志愿的策略: 四、影响专业选择的因素: 各省高考成绩已出,又到一年高考季。张雪峰提到:“普通家庭不要光谈理想&…

LINUX系统(ubuntu)安装以及应用调试(不定时更新)

一:linux的介绍 Linux是一种基于UNIX操作系统的开源(Open Source)操作系统。它由芬兰计算机科学家 Linus Torvalds 在1991年首次发布,目前已经发展成为最流行和广泛使用的操作系统之一。 Linux以其稳定性、安全性和灵活性而闻名…

探究Vue源码:mustache模板引擎(4) 了解mustache转换概念,简述tokens转换

上文 探究Vue源码:mustache模板引擎(3) 通过编写简单正则了解mustache转换思路我们用正则表达式构建了一个简易版的render模板编译函数 但是 我们有特意强调过 mustache的render函数并非用简单正则实现的 因为这样无法实现循环和一些比较复杂的逻辑处理 它的实现基理可以参考这…

基础的git命令使用

Git区域概念 Git命令行操作 Git单人使用 注意项(务必认真阅读) Git Bash Here”终端 初始化仓库 提交工作区的内容到版本库 查看版本的记录 查看工作区的状态 版本回退 版本前进 Git远程仓库 克隆项目 推送到远程 拉取远程的更新 Git区域概…