[项目分享]Mediapipe智能控制机械臂 精华

1601浏览
查看: 1601|回复: 9

[项目分享] Mediapipe智能控制机械臂

[复制链接]
本帖最后由 云天 于 2022-8-22 19:21 编辑

【项目背景】
MonAugust-202208226980..png

最近入手了一台机械臂(DF 6自由度机械臂),使用威龙24路舵机控制器,配合Veyron_Servo_Driver_24-Channel 软件,实现了一些简单动作后,就一直放在茶几上吃灰。
在做了几个有关Mediapipe相关项目后,今天准备将机械臂与Mediapipe相结合,实现手部运动控制机械臂运动,进行抓取实物、移动位置。此项目将制作、改进、优化整个过程一步一步进行介绍。
【入门知识】
1.机械臂
(1)六自由度机械臂简介
机械臂是机器人技术领域中使用最广泛的自动机械装置。它可以在工业制造,医疗,娱乐服务,军事,半导体制造和太空探索中看到。虽然它们的形状不同,但它们都具有共同的特征,即它们可以接受指令并准确地定位三维(或二维)空间中的点以进行操作。

六自由度机械手臂,顾名思义,由六个关节组成,由伺服电机机械臂驱动。既然它是手臂,那么就有几个关节,可以想象我们的人体手臂,除了肩膀,肘部,手腕三个关节外,加上手指的关节,还有很多关节。我们的机器人手臂也是如此,它使用六个伺服电机来实现简单的手部结构。除了没有人的关节外,还有一些神经组织和神经系统缺失。然而,已经开发出具有“灵巧手”(其可以完成复杂的组装,处理或手动抓取蛋的手)的“人形”机器。

(2)自由度
自由度: 自由度是机器人的一个重要技术指标,它是由机器人的结构决定的,并直接影响到机器人的机动性。
物体上任何一点都与坐标轴的正交集合有关。物体能够对坐标系进行独立运动的数目称为自由度(DOF,degree of freedom)。如下图所示:
MonAugust-202208221453..png


2.Mediapipe
MediaPipe是一个用于构建机器学习管道的框架,用于处理视频、音频等时间序列数据。这个跨平台框架适用于桌面/服务器、Android、iOS和嵌入式设备,如Raspberry Pi和Jetson Nano。MediaPipe只需要最少的资源。它是如此微小和高效,甚至嵌入式物联网设备都可以运行它。2019年,MediaPipe公开发布后,为研究人员和开发人员开辟了一个全新的机会世界。
【实现过程】
1.使用Mind+软件中的Python模式直接控制威龙24路舵机控制器
MonAugust-202208228356..png

在控制器的产品维护文档中,有“Arduino与Veyron_Servo_Driver_24-Channel串口通讯实例”,经测试,成功!刚开始的想法是Python通过Pinpong库与Arduino通信,然后Arduino再发送控制指令给舵机控制器,一是过程繁琐,二是它们都使用到串口通信,互相干扰,经测试结果失败。再看技术文档,既然可以使用串口通信,那么可以去掉中间的Arduino,直接让Python使用串口与舵机控制器进行通信,经测试,成功!
1230819079.jpg

  1. import serial
  2. import time
  3. serialPort="COM6"
  4. baudRate=9600
  5. ser=serial.Serial(serialPort,baudRate,timeout=0.5)
  6. print(ser.name)#打印设备名称
  7. ser.write("#4 P1500".encode())#通道5到达指定位置
  8. time.sleep(0.005)
  9. ser.write("\r".encode())
  10. time.sleep(3)
  11. ser.write("#5 P2250 T5000".encode())#通道5舵机花5秒转到接近中间位置。
  12. time.sleep(0.005)
  13. ser.write("\r".encode())
  14. time.sleep(5)
  15. ser.write("#5 P750 S1000".encode())#使舵机从2250us移动到750us(大概170度),一共耗时1.5秒。
  16. time.sleep(0.005)
  17. ser.write("\r".encode())
  18. time.sleep(2)
  19. ser.write("#0 P1000 #1 P1000 #2 P1700 #3 P2200 T3000".encode())#同时到达指定位置
  20. time.sleep(0.005)
  21. ser.write("\r".encode())
  22. time.sleep(3)
  23. ser.write("#0 P2100 #1 P2200 #5 P1000 #3 P1500  T3000".encode())#同时到达指定位置
  24. time.sleep(0.005)
  25. ser.write("\r".encode())
  26. time.sleep(3)
  27. ser.close()#关闭端口
复制代码


2.移动物品
使用单舵机移动、多舵机同时移动、时间控制、速度控制多种方法,实现循环移动固定位置物品。
  1. import serial
  2. import time
  3. serialPort="COM6"
  4. baudRate=9600
  5. ser=serial.Serial(serialPort,baudRate,timeout=0.5)
  6. print(ser.name)#打印设备名称
  7. while 1:
  8.     #舵机4回中间位置,机械臂竖直
  9.     ser.write("#4 P1500 T3000".encode())
  10.     time.sleep(0.005)
  11.     ser.write("\r".encode())
  12.     time.sleep(3)
  13.     #舵机0开口最大,其它舵机回中间位置
  14.     ser.write("#0 P800 #1 P1500 #2 P1700 #3 P1500 #5 P1500 T5000".encode())#同时到达指定位置
  15.     time.sleep(0.005)
  16.     ser.write("\r".encode())
  17.     time.sleep(5)
  18.    #舵机1抬头
  19.     ser.write("#1 P2400 S500".encode())
  20.     time.sleep(0.005)
  21.     ser.write("\r".encode())
  22.     time.sleep(2)
  23.     #舵机4前倾
  24.     ser.write("#4 P300 S500".encode())
  25.     time.sleep(0.005)
  26.     ser.write("\r".encode())
  27.     time.sleep(2)
  28.     #舵机3稍前倾
  29.     ser.write("#3 P1800 S500".encode())
  30.     time.sleep(0.005)
  31.     ser.write("\r".encode())
  32.     time.sleep(2)
  33.     #舵机2钳口摆正
  34.     ser.write("#2 P1700 S500".encode())
  35.     time.sleep(0.005)
  36.     ser.write("\r".encode())
  37.     time.sleep(2)
  38.    #舵机0钳口夹紧
  39.     ser.write("#0 P1800 S500".encode())
  40.     time.sleep(0.005)
  41.     ser.write("\r".encode())
  42.     time.sleep(2)
  43.     #除舵机0钳口
  44.     ser.write("#1 P1500 #2 P2000 #3 P1500 #4 P1500 #5 P1500 T5000".encode())#同时到达指定位置
  45.     time.sleep(0.005)
  46.     ser.write("\r".encode())
  47.     time.sleep(5)
  48. #
  49.     ser.write("#1 P2400 S500".encode())
  50.     time.sleep(0.005)
  51.     ser.write("\r".encode())
  52.     time.sleep(2)
  53. #
  54.     ser.write("#5 P500 S500".encode())
  55.     time.sleep(0.005)
  56.     ser.write("\r".encode())
  57.     time.sleep(2)
  58. #
  59.     ser.write("#2 P1800 S500".encode())
  60.     time.sleep(0.005)
  61.     ser.write("\r".encode())
  62.     time.sleep(2)
  63. #
  64.    ser.write("#4 P300 S500".encode())
  65.     time.sleep(0.005)
  66.     ser.write("\r".encode())
  67.     time.sleep(2)
  68. #
  69.     ser.write("#3 P1600 S500".encode())
  70.     time.sleep(0.005)
  71.     ser.write("\r".encode())
  72.     time.sleep(2)
  73. #
  74.     ser.write("#0 P800 S500".encode())
  75.     time.sleep(0.005)
  76.     ser.write("\r".encode())
  77.     time.sleep(2)
  78.    
  79. ser.close()#关闭端口
复制代码



3.Mediapipe手部运动控制
首先通过Mind+python模式下的库管理安装Mediapipe、cvzone,安装好后,结合上面的程序,编写智能控制机械臂程序:
  1. import cv2
  2. from cvzone import HandTrackingModule as hd
  3. import serial
  4. import time
  5. def numberMap(x, in_min, in_max, out_min, out_max):
  6.   return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
  7. def main():
  8.     serialPort="COM6"
  9.     baudRate=9600
  10.     ser=serial.Serial(serialPort,baudRate,timeout=0.5)
  11.     length1=0
  12.     P=""
  13.     start_time=time.time()
  14.     cap = cv2.VideoCapture(0)
  15.     detector = hd.HandDetector(detectionCon=0.8, maxHands=1)
  16.     P="#0 P1500 #1 P2400 #2 P1700 #3 P1500 #4 P1500 #5 P1500 T1000"
  17.     ser.write(P.encode())
  18.     time.sleep(0.005)
  19.     ser.write("\r".encode())
  20.     time.sleep(1)
  21.     while True:
  22.         # Get image frame
  23.         success, img = cap.read()
  24.         img=cv2.flip(img,1) # 保存水平翻转图片
  25.         # Find the hand and its landmarks
  26.         hands, img = detector.findHands(img)  # with draw
  27.         # hands = detector.findHands(img, draw=False)  # without draw
  28.         if hands:
  29.             # Hand 1
  30.             hand1 = hands[0]
  31.             lmList1 = hand1["lmList"]  # List of 21 Landmark points
  32.             bbox1 = hand1["bbox"]  # Bounding box info x,y,w,h
  33.             centerPoint1 = hand1['center']  # center of the hand cx,cy
  34.             handType1 = hand1["type"]  # Handtype Left or Right
  35.             length, info, img = detector.findDistance(lmList1[8][0:2], lmList1[4][0:2], img)  # with draw
  36.             fingers1 = detector.fingersUp(hand1)
  37.             length1=250-int(length)
  38.             
  39.             length1=numberMap(length1, 0, 250, 800, 2200)
  40.             cx,cy=detector.midpoint(lmList1[8][0:2], lmList1[4][0:2])
  41.             disX=630-cx
  42.             disX=numberMap(disX, 100, 530, 0, 2200)
  43.             disY=370-cy
  44.             disY=numberMap(disY,20, 350, 400, 2000)
  45.             print(cy)
  46.             if time.time()-start_time>0.5:
  47.                P="#4 P"+str(disY)+" S500"
  48.                ser.write(P.encode())
  49.                time.sleep(0.005)
  50.                ser.write("\r".encode())
  51.                
  52.             
  53.                P="#5 P"+str(disX)+" S500"
  54.                ser.write(P.encode())
  55.                time.sleep(0.005)
  56.                ser.write("\r".encode())
  57.                start_time=time.time()
  58.          
  59.                P="#0 P"+str(length1)+" S500"
  60.                ser.write(P.encode())
  61.                time.sleep(0.005)
  62.                ser.write("\r".encode())
  63.                start_time=time.time()
  64.            
  65.         # Display
  66.         cv2.imshow("Image", img)
  67.         cv2.waitKey(1)
  68. if __name__ == "__main__":
  69.     main()
复制代码

4.进行优化
通过测试,上面的视频也可发现,有时舵机运行过快,出现抖动,这应该是由于舵机运行使用的是速度控制,中间的两个指令的时间间隔不足(上个指令舵机还没有到达指定位置),造成抖动。所以对程序进行修改,将速度控制修改为时间控制(1秒内到达指定位置),并将两指令的发送最小时间间隔也设定为1秒。
  1. import cv2
  2. from cvzone import HandTrackingModule as hd
  3. import serial
  4. import time
  5. def numberMap(x, in_min, in_max, out_min, out_max):
  6.   return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
  7. def main():
  8.     serialPort="COM6"
  9.     baudRate=9600
  10.     ser=serial.Serial(serialPort,baudRate,timeout=0.5)
  11.     length1=0
  12.     P=""
  13.     start_time=time.time()
  14.     cap = cv2.VideoCapture(0)
  15.     detector = hd.HandDetector(detectionCon=0.8, maxHands=1)
  16.     P="#0 P1500 #1 P2400 #2 P1700 #3 P1500 #4 P1500 #5 P1500 T1000"
  17.     ser.write(P.encode())
  18.     time.sleep(0.005)
  19.     ser.write("\r".encode())
  20.     time.sleep(1)
  21.     length_pre=100
  22.     cy_pre=240
  23.     cx_pre=320
  24.     while True:
  25.         # Get image frame
  26.         success, img = cap.read()
  27.         img=cv2.flip(img,1) # 保存水平翻转图片
  28.         # Find the hand and its landmarks
  29.         hands, img = detector.findHands(img)  # with draw
  30.         # hands = detector.findHands(img, draw=False)  # without draw
  31.         if hands:
  32.             # Hand 1
  33.             hand1 = hands[0]
  34.             lmList1 = hand1["lmList"]  # List of 21 Landmark points
  35.             bbox1 = hand1["bbox"]  # Bounding box info x,y,w,h
  36.             centerPoint1 = hand1['center']  # center of the hand cx,cy
  37.             handType1 = hand1["type"]  # Handtype Left or Right
  38.             length, info, img = detector.findDistance(lmList1[8][0:2], lmList1[4][0:2], img)  # with draw
  39.             fingers1 = detector.fingersUp(hand1)
  40.             length1=250-int(length)
  41.             
  42.             length1=numberMap(length1, 0, 250, 800, 2200)
  43.             cx,cy=detector.midpoint(lmList1[8][0:2], lmList1[4][0:2])
  44.             disX=630-cx
  45.             disX=numberMap(disX, 100, 530, 0, 2200)
  46.             disY=370-cy
  47.             disY=numberMap(disY,20, 350, 400, 2000)
  48.             print(cy)
  49.             if time.time()-start_time>1:
  50.            
  51.              if abs(cy-cy_pre)>5:
  52.                P="#4 P"+str(disY)+" T1000"
  53.                ser.write(P.encode())
  54.                time.sleep(0.005)
  55.                ser.write("\r".encode())
  56.                cy_pre=cy
  57.              if abs(cx-cx_pre)>5:
  58.             
  59.                P="#5 P"+str(disX)+" T1000"
  60.                ser.write(P.encode())
  61.                time.sleep(0.005)
  62.                ser.write("\r".encode())
  63.                start_time=time.time()
  64.                cx_pre=cx
  65.              if abs(length-length_pre)>5:
  66.                P="#0 P"+str(length1)+" T1000"
  67.                ser.write(P.encode())
  68.                time.sleep(0.005)
  69.                ser.write("\r".encode())
  70.                length_pre=length
  71.              start_time=time.time()
  72.            
  73.         # Display
  74.         cv2.imshow("Image", img)
  75.         cv2.waitKey(1)
  76. if __name__ == "__main__":
  77.     main()
复制代码






赤星三春牛!  中级技匠

发表于 2022-8-22 21:23:01

厉害厉害
回复

使用道具 举报

赤星三春牛!  中级技匠

发表于 2022-8-22 21:24:05

不错不错
回复

使用道具 举报

木子呢  NPC

发表于 2022-8-23 14:23:31

好像没有宋老师不会玩的东西了!!!!赞!
回复

使用道具 举报

rzegkly  版主

发表于 2022-8-23 21:19:27

喜欢,大家一起动手试试
回复

使用道具 举报

安卓机器人  中级技神

发表于 2022-8-24 13:18:38

好好 远程控制机械臂
回复

使用道具 举报

小企鹅  高级技师

发表于 2022-9-4 16:40:45

厉害厉害
回复

使用道具 举报

CPY  见习技师

发表于 6 天前

厉害了!!!
回复

使用道具 举报

yizhenggesQ  学徒

发表于 昨天 07:45

哇塞! 牛哇牛哇!!!
回复

使用道具 举报

yizhenggesQ  学徒

发表于 昨天 22:53

哇塞!牛哇!!牛哇!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2022 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail