基于mediapipe的机械手控制系统

目录

所需工具:

Mediapipe技术:

MediaPipe 实现手部跟踪

总体硬件电路的框架设计

上位机软件设计程序流程

下位机软件设计程序流程

想要完整工程私信留邮箱


所需工具:

硬件部分:数字舵机5个 ,摄像头 ,stm32f103rbt6 。

软件部分:Python 3.7 ,Mediapipe 0.8.9.1 ,Numpy 1.21.6 ,Opencv -python 4.5.5.64

                  Opencv -contrib -python 4.5.5.64 ,Pyserial 3.4

开发工具:PyCharm Community Edition 2021.2.3

Mediapipe技术:

        MediaPipe 的核心框架由 C++ 实现,并提供 Java 以及 Objective C 等编程语 言的支持。MediaPipe 有如下几个重要的模块:图 Graph,子图 Subgraph ,数据流 Stream,数据包 Packet。

        官方也提供了可以将解决方案可视化的工具:

viz.mediapipe.dev/

        MediaPipe 框架的主要组成部分包括:媒体处理管道(media processing pipeline), 处理单元(processing units),工具包(tooling)。媒体处理管道用于数据采集、预处理、 特征提取等功能,支持流式处理。处理单元将不同算法、模型集成到管道中,用于对 运动捕捉、面部分析、虚拟化增强现实等任务进行处理。工具包包括一系列的 sdk 工 具,可以用于模型构建、模型转换、性能测试等操作,以满足各种需求。

MediaPipe 实现手部跟踪

        为了检测手部的初始位置,本次设计使用了类似 BlazeFace 组件在移动端实时优 化的单一检测模型。检测手是一个十分艰难的任务。有下面几种不同的原因:

        1.人的手,有各种各样的差别,大小差别,亦或者手指长度的差别;

         2.检测时手部有遮挡或者自遮挡的问题;

         3.手部和身体其他部位的检测有一定的差距,手部其中缺乏高对比度;

手部检测流程如下图:

总体硬件电路的框架设计

 

 

上位机软件设计程序流程

上位机代码参考: 

import cv2 #opencv 头文件
import mediapipe as mp #mediapipe 头文件
import math
import time
import serial #串口头文件
odder_mode = 0
#手指的初始角
yi = er = san = si = wu = 0
#串口定义
ser = serial.Serial()
def port_open_recv():#对串口的参数进行配置
 ser.port='com9'
 ser.baudrate=115200
 ser.bytesize=8
 ser.stopbits=1
 ser.parity="N"#奇偶校验位
 ser.open()
 if ser.isOpen():
 print("串口打开成功!")
 else:
 print("串口打开失败!")
def vector_2d_angle(v1,v2):
 v1_x=v1[0]
 v1_y=v1[1]
 v2_x=v2[0]
 v2_y=v2[1]
 try:
 angle_= 
math.degrees(math.acos((v1_x*v2_x+v1_y*v2_y)/(((v1_x**2+v1_y**2)**0.5)*((v2_x**2+v2_y**2)*
*0.5))))
 #degrees:方法将角度 x 从弧度转换为度数
 #acos:返回 x 的反余弦弧度值
 except:
 angle_ =65535.

 if angle_ > 180.:
 angle_ = 65535.
 return angle_
def hand_angle(hand_):
 global yi,er,san,si,wu
 angle_list = []
 #---------------------------- thumb 大拇指角度
 angle_ = vector_2d_angle(
 ((int(hand_[0][0])- int(hand_[2][0])),(int(hand_[0][1])-int(hand_[2][1]))),
 ((int(hand_[3][0])- int(hand_[4][0])),(int(hand_[3][1])- int(hand_[4][1])))
 )
 yi = int(angle_)
 angle_list.append(angle_)
 #---------------------------- index 食指角度
 angle_ = vector_2d_angle(
 ((int(hand_[0][0])-int(hand_[6][0])),(int(hand_[0][1])- int(hand_[6][1]))),
 ((int(hand_[7][0])- int(hand_[8][0])),(int(hand_[7][1])- int(hand_[8][1])))
 )
 er = int(angle_)
 angle_list.append(angle_)
 #---------------------------- middle 中指角度
 angle_ = vector_2d_angle(
 ((int(hand_[0][0])- int(hand_[10][0])),(int(hand_[0][1])- int(hand_[10][1]))),
 ((int(hand_[11][0])- int(hand_[12][0])),(int(hand_[11][1])- int(hand_[12][1])))
 )
 san = int(angle_)
 angle_list.append(angle_)
 #---------------------------- ring 无名指角度
 angle_ = vector_2d_angle(
 ((int(hand_[0][0])- int(hand_[14][0])),(int(hand_[0][1])- int(hand_[14][1]))),
 ((int(hand_[15][0])- int(hand_[16][0])),(int(hand_[15][1])- int(hand_[16][1])))
 )
 si = int(angle_)
 angle_list.append(angle_)
 #---------------------------- pink 小拇指角度
 angle_ = vector_2d_angle(
 ((int(hand_[0][0])- int(hand_[18][0])),(int(hand_[0][1])- int(hand_[18][1]))),
 ((int(hand_[19][0])- int(hand_[20][0])),(int(hand_[19][1])- int(hand_[20][1])))
 )
 wu = int(angle_)
 angle_list.append(angle_)
 return angle_list
def h_gesture(angle_list):
 thr_angle = 65.
 thr_angle_thumb = 53.
 thr_angle_s = 49.
 gesture_str = "0"
 if 65535. not in angle_list:
 if (angle_list[0]>thr_angle_thumb) and (angle_list[1]>thr_angle) and 
(angle_list[2]>thr_angle) and (angle_list[3]>thr_angle) and (angle_list[4]>thr_angle):
 gesture_str = "0"
 elif (angle_list[0]<thr_angle_s) and (angle_list[1]<thr_angle_s) and 
(angle_list[2]<thr_angle_s) and (angle_list[3]<thr_angle_s) and (angle_list[4]<thr_angle_s):
 gesture_str = "5"
 elif (angle_list[0]<thr_angle_s) and (angle_list[1]<thr_angle_s) and
(angle_list[2]>thr_angle) and (angle_list[3]>thr_angle) and (angle_list[4]>thr_angle):
 gesture_str = "8"
 elif (angle_list[0]<thr_angle_s) and (angle_list[1]<thr_angle_s) and 
(angle_list[2]>thr_angle) and (angle_list[3]>thr_angle) and (angle_list[4]<thr_angle_s):
 gesture_str = "9"
 elif (angle_list[0]>5) and (angle_list[1]<thr_angle_s) and (angle_list[2]>thr_angle) and 
(angle_list[3]>thr_angle) and (angle_list[4]>thr_angle):
 gesture_str = "1"
 elif (angle_list[0]<thr_angle_s) and (angle_list[1]>thr_angle) and (angle_list[2]>thr_angle) 
and (angle_list[3]>thr_angle) and (angle_list[4]<thr_angle_s):
 gesture_str = "6"
 elif (angle_list[0]>thr_angle_thumb) and (angle_list[1]<thr_angle_s) and 
(angle_list[2]<thr_angle_s) and (angle_list[3]<thr_angle_s) and (angle_list[4]>thr_angle):
 gesture_str = "3"
 elif (angle_list[0]>thr_angle_thumb) and (angle_list[1]<thr_angle_s) and 
(angle_list[2]<thr_angle_s) and (angle_list[3]<thr_angle_s) and (angle_list[4]<thr_angle):
 gesture_str = "4"
 elif (angle_list[0]<thr_angle_s) and (angle_list[1]>thr_angle) and (angle_list[2]>thr_angle) 
and (angle_list[3]>thr_angle) and (angle_list[4]>thr_angle):
 gesture_str = "7"
 elif (angle_list[0]>thr_angle_thumb) and (angle_list[1]<thr_angle_s) and 
(angle_list[2]<thr_angle_s) and (angle_list[3]>thr_angle) and (angle_list[4]>thr_angle):
 gesture_str = "2"
 return gesture_str
def detect():
 pTime = 0
 mp_drawing = mp.solutions.drawing_utils
 mp_hands = mp.solutions.hands
 hands = mp_hands.Hands(
 static_image_mode=False,
 max_num_hands=1,
 min_detection_confidence=0.75,
 min_tracking_confidence=0.75)
 cap = cv2.VideoCapture(0)
 while True:
 ret,frame = cap.read()
 frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
 frame= cv2.flip(frame,1)
 results = hands.process(frame)
 frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
 if results.multi_hand_landmarks:
 for hand_landmarks in results.multi_hand_landmarks:
 mp_drawing.draw_landmarks(frame, hand_landmarks, 
mp_hands.HAND_CONNECTIONS)
 hand_local = []
 for i in range(21):
 x = hand_landmarks.landmark[i].x*frame.shape[1]
 y = hand_landmarks.landmark[i].y*frame.shape[0]
 hand_local.append((x,y))
 if hand_local:
 angle_list = hand_angle(hand_local)
 gesture_str = h_gesture(angle_list)
 cv2.putText(frame, gesture_str, (30, 100), 0, 1, (0, 0, 255), 2)
 ser.write(gesture_str.encode('utf-8'))
 ser.write("\r\n".encode('utf-8'))
 cTime = time.time()
 fps = 1 / (cTime - pTime)
 pTime = cTime
 cv2.putText(frame, f"FPS : {int(fps)}", (30, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 
0, 0), 2)
 cv2.imshow('MediaPipe Hands', frame)
 if cv2.waitKey(1) & 0xFF == ord('q'):
 break
 cap.release()
if __name__ == '__main__':
 port_open_recv()
 #odder_mode = input("选择你想要执行的模式(0:数字 1:角度) :")
 detect()

下位机软件设计程序流程

 下位机控制代码参考:

#include "include.h"
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大 USART_REC_LEN 个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到 0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记 
void uart_init(u32 bound)
{
//GPIO 端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, 
ENABLE); //使能 USART1,GPIOA 时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIOA.9
//USART1_RX GPIOA.10 初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIOA.10 
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级 3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄存器
//USART 初始化设置

USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//
无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
 USART_Init(USART1, &USART_InitStructure); //初始化串口 1
 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
 USART_Cmd(USART1, ENABLE); //使能串口 1 
}
void USART1_IRQHandler(void) //串口 1 中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS.
OSIntEnter(); 
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据
必须是 0x0d 0x0a 结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了 0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到 0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;// 接收数
据错误,重新开始接收 
}
}
} 

 } 
#if SYSTEM_SUPPORT_OS //如果 SYSTEM_SUPPORT_OS 为真,则需要支持 OS.
OSIntExit(); 
#endif
}
int main(void)
{
SystemInit(); //系统时钟初始化为 72M SYSCLK_FREQ_72MHz
InitDelay(72); //延时初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置 NVIC 中断分组 2:2 位抢占优先级,
2 位响应优先级
InitPWM();
InitTimer2();//用于产生 100us 的定时中中断
uart_init(115200);
InitUart3();//外接模块的串口
InitADC();
InitLED();
InitKey();
int odder;//接收到的数据
u8 len,i;
int pwm_odder[6]={500,500,500,500,500,500};
while(1)
{
TaskRun();
if(USART_RX_STA&0x8000)
{ 
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
for(int t=0;t<len;t++)
{
USART_SendData(USART1, USART_RX_BUF[t]);//向串口 1 发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结
束
}
// printf("\r\n\r\n");//插入换行
 odder = atoi((const char *)USART_RX_BUF);
USART_RX_STA=0;
}
 if(odder == 0)
{
pwm_odder[1] = 2500;pwm_odder[2] = 500;pwm_odder[3] = 500;pwm_odder[4] = 
500;pwm_odder[5] = 500;
}

想要完整工程私信留邮箱

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chen_kng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值