一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

如何制作和控制一只仿生手

電子發(fā)燒友論壇 ? 2025-04-15 11:52 ? 次閱讀

這個(gè)項(xiàng)目介紹了如何制作和控制一只仿生手。作者最初受到Instagram上一個(gè)視頻的啟發(fā),該視頻展示了使用MPU6050傳感器追蹤手部動(dòng)作并在屏幕上顯示3D模型。作者決定將這個(gè)想法進(jìn)一步發(fā)展,使用OpenCV來(lái)控制一只真實(shí)的仿生手。

0b4603de-19ad-11f0-9434-92fbcf53809c.png

大家好,在這篇教程中,我想和大家分享一下如何制作并控制一只自己的仿生手。這個(gè)想法源于我在無(wú)意中刷Instagram時(shí),看到一段短視頻:一個(gè)人通過(guò)MPU6050傳感器來(lái)跟蹤手部運(yùn)動(dòng),并在屏幕上顯示手的3D模型。因?yàn)槲抑耙彩褂眠^(guò)這個(gè)傳感器,所以覺(jué)得這個(gè)我也能完成。我一直喜歡將編程與現(xiàn)實(shí)世界結(jié)合起來(lái),于是我想,為什么不將這些測(cè)量數(shù)據(jù)傳輸?shù)揭粋€(gè)真實(shí)的仿生手上呢?后來(lái)我決定,使用OpenCV代替MPU6050會(huì)更加高效,部分原因也是我想借此機(jī)會(huì)學(xué)習(xí)另一種技能。

特別感謝Ga?l Langevin,他在InMoov項(xiàng)目[1]中設(shè)計(jì)了這個(gè)手的模型,并慷慨地分享了出來(lái)。

效果展示


所需材料

InMoov手及前臂

  • 3D打印機(jī)
  • 焊接工具
  • 約1公斤的耗材(PETG 或 ABS 或 PLA)
  • 3米釣魚(yú)線(xiàn)(能承重約20公斤)
  • 5根擴(kuò)展彈簧(3/16″ x 1-3/4)
  • RTV硅膠 Ecoflex 00-10

螺絲、螺母和螺栓

  • 10個(gè)M2x4平頭木螺絲
  • 10個(gè)M3x4mm平頭螺絲
  • 4個(gè)M3x12mm平頭木螺絲
  • 20個(gè)M3x12mm平頭螺絲
  • 25個(gè)M3x16mm平頭螺絲
  • 10個(gè)M3x20mm平頭螺絲
  • 35個(gè)M3螺母

電子元件

  • 1塊ESP32 38-pin 開(kāi)發(fā)模塊
  • 1根micro USB數(shù)據(jù)線(xiàn)
  • 5個(gè)線(xiàn)性霍爾傳感器(49E)
  • 5個(gè)直徑2.5mm x 1mm的磁盤(pán)磁鐵
  • 1根16芯彩排線(xiàn)
  • 5個(gè)1k電阻
  • 5個(gè)2k電阻
  • 6個(gè)伺服電機(jī)(JX PDI-6225MG-300)
  • 1塊定制PCB(可選)
  • 1個(gè)電源(理想情況下為6V或5V,功率約100W,因?yàn)槊總€(gè)伺服電機(jī)的電流可達(dá)3A)

步驟1:3D打印手部

0b5e7144-19ad-11f0-9434-92fbcf53809c.png

0b8f7c80-19ad-11f0-9434-92fbcf53809c.png

3D打印文件見(jiàn)文末。

0be4ea12-19ad-11f0-9434-92fbcf53809c.png

打印時(shí),建議使用稍高的填充率(約30%),以提高部件的耐用性。關(guān)于材料,InMoov使用的是ABS,不過(guò)如果你沒(méi)有穩(wěn)定打印ABS的設(shè)備,PETG或PLA同樣可以使用。

步驟2:3D打印前臂

0c029256-19ad-11f0-9434-92fbcf53809c.png

同樣地,手部所需的文件如下,并且也在inmoov STL零件庫(kù)[2]中。請(qǐng)注意,在inmoov零件庫(kù)中有原版inmoov機(jī)器人的文件。這個(gè)手是i2版本,因此你只需要前臂部分的一些零件。另外一個(gè)需要注意的是,當(dāng)打印Bolt_entretoise7時(shí),你只需要中間的螺栓和夾子(其他部分是為舊版手設(shè)計(jì)的)。

0c203f22-19ad-11f0-9434-92fbcf53809c.png

3D打印文件文末下載。

你還可以打印一個(gè)我自己在Fusion 360中設(shè)計(jì)的小展示支架。

0c334568-19ad-11f0-9434-92fbcf53809c.png

鏈接:https://www.printables.com/model/593999-inmoov-hand-stand?lang=cs

步驟3:組裝

0c4decd8-19ad-11f0-9434-92fbcf53809c.png

在組裝時(shí),可以參考InMoov提供的hand i2[3]前臂[4]的教程,這些教程非常詳細(xì),提供了所有必要的信息。

0c70319e-19ad-11f0-9434-92fbcf53809c.png0c946bf4-19ad-11f0-9434-92fbcf53809c.png0cbcc392-19ad-11f0-9434-92fbcf53809c.png

初始部件的組裝相對(duì)簡(jiǎn)單,只需用螺絲將整個(gè)設(shè)計(jì)固定在一起。稍微復(fù)雜的部分是確保釣魚(yú)線(xiàn)的布置不打結(jié),以及將霍爾傳感器正確安裝在指尖。

步驟4:硅膠指尖

0cd5237e-19ad-11f0-9434-92fbcf53809c.png0cf043ca-19ad-11f0-9434-92fbcf53809c.png0d11d9cc-19ad-11f0-9434-92fbcf53809c.png

對(duì)于指尖來(lái)說(shuō),使用非常柔軟的硅膠是很重要的,因?yàn)榛魻杺鞲衅鞯淖x取有一定的不確定性。硅膠越軟,內(nèi)部的磁鐵運(yùn)動(dòng)幅度越大,從而更容易從數(shù)據(jù)中識(shí)別。將硅膠部分粘到3D打印出的部件上之后,可以用它來(lái)調(diào)整霍爾傳感器的突出程度。

0d33ffb6-19ad-11f0-9434-92fbcf53809c.png

在這一切設(shè)置好之后,強(qiáng)烈建議將霍爾傳感器固定在手指的末端,否則在手指運(yùn)動(dòng)過(guò)程中,霍爾傳感器可能會(huì)稍微移動(dòng),從而影響測(cè)量結(jié)果。

步驟5:電路

0d607c12-19ad-11f0-9434-92fbcf53809c.png0d71021c-19ad-11f0-9434-92fbcf53809c.png

電路方面,使用16路舵機(jī)驅(qū)動(dòng)模塊會(huì)帶來(lái)顯著的效果,但也存在一些缺點(diǎn)。該驅(qū)動(dòng)模塊有兩種不同的版本,雖然它們幾乎相同,但在反極性保護(hù)電路(用于電容)所使用的晶體管上有區(qū)別,一個(gè)版本可承受約8A電流,而另一個(gè)版本僅可承受約0.5A,這遠(yuǎn)低于舵機(jī)實(shí)際需要的電流。因此,最好不要讓伺服電機(jī)通過(guò)驅(qū)動(dòng)模塊供電,或者按照視頻[5]中所述進(jìn)行小改動(dòng),并在使用電容時(shí)要格外小心。

關(guān)于霍爾傳感器,我們需要使用一個(gè)電壓分壓器,因?yàn)樗敵龅碾妷悍秶?V到5V之間,而ESP32只能正確讀取0V到3.3V的ADC值。

對(duì)于整個(gè)電路,可以選擇使用面包板,或者更好的是使用定制PCB(作者版本的GitHub鏈接[6])。

步驟6:測(cè)試


由于每個(gè)伺服電機(jī)和霍爾傳感器都略有不同,所以需要對(duì)它們進(jìn)行測(cè)試。

最重要的是測(cè)試霍爾傳感器,因?yàn)樗鼈儨y(cè)量的值將決定仿生手是否施加了足夠的壓力。我建議使用Arduino IDE的繪圖功能來(lái)繪制數(shù)據(jù),以觀(guān)察數(shù)值何時(shí)超過(guò)自然不確定性范圍。

為此,我們可以使用這個(gè)非常簡(jiǎn)單的代碼片段:

inthall="Pinnumberyourhallsensorisconnectedto";

voidsetup(){
Serial.begin(115200);
pinMode(hall,INPUT);
}

voidloop(){
Serial.println(analogRead(hall));
delay(10);
}

步驟7:代碼

OpenCV(在VSCode中運(yùn)行的Python代碼)

就運(yùn)行在帶有網(wǎng)絡(luò)攝像頭的PC上的代碼而言,我們需要完成兩個(gè)主要任務(wù):

第一個(gè)任務(wù)是使用OpenCV追蹤手部及其元素。基于這些元素我們可以計(jì)算每根手指的位置。

第二個(gè)任務(wù)是通過(guò)串口將數(shù)據(jù)發(fā)送到ESP32,以便控制伺服電機(jī)。這些數(shù)據(jù)可以相對(duì)簡(jiǎn)化,因?yàn)槲覀儾恍枰l(fā)送精確的角度值,而只需發(fā)送每個(gè)手指是否彎曲的信息。因此,我們可以發(fā)送五個(gè)0或1,并在末尾加一個(gè)符號(hào)以便后續(xù)識(shí)別每個(gè)數(shù)字的索引

這種方法將手部追蹤和數(shù)據(jù)傳輸簡(jiǎn)化為一個(gè)二進(jìn)制狀態(tài)系統(tǒng),使得數(shù)據(jù)處理和傳輸更加高效,同時(shí)仍能提供足夠的信息來(lái)控制仿生手的動(dòng)作。

首先,我們需要為Python代碼導(dǎo)入以下庫(kù):

importcv2
importmediapipeasmp
importtime
importserial

然后,我們需要?jiǎng)?chuàng)建一個(gè)用于處理攝像頭數(shù)據(jù)的類(lèi):

classHandDetector():
#Constructoroftheclasswithparametersforthemeasurement
def__init__(self,mode=False,maxHands=1,detectionCon=0.5,trackCon=0.5):
self.mode=mode
self.maxHands=maxHands
self.detectionCon=detectionCon
self.trackCon=trackCon

self.mpHands=mp.solutions.hands
self.hands=self.mpHands.Hands()
self.mpDraw=mp.solutions.drawing_utils

#Functionforfindinganddrawingthehand
deffindHands(self,frame,draw=True):
imgRGB=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
self.results=self.hands.process(imgRGB)

ifself.results.multi_hand_landmarks:
forhandLmsinself.results.multi_hand_landmarks:
ifdraw:
self.mpDraw.draw_landmarks(frame,handLms,self.mpHands.HAND_CONNECTIONS)
returnframe

#Functionforfindingeachhandlandmarkanddrawingitsposition
deffindPosition(self,frame,handNo=0,draw=False):
lmList=[]

ifself.results.multi_hand_landmarks:
myHand=self.results.multi_hand_landmarks[handNo]

forid,lminenumerate(myHand.landmark):
h,w,c=frame.shape
cx,cy=int(lm.x*w),int(lm.y*h)

lmList.append([id,cx,cy])

ifdrawandid==0:
cv2.circle(frame,(cx,cy),15,(255,0,255),-1)
returnlmList

接下來(lái)定義主函數(shù):

defmain():
#TheprevTimeandcurrentTimeareusedtocalculatetheFPSlater
prevTime=0
currentTime=0

#Arrayforstoringtheinfoaboutthehand
hand=[["Wrist",False],["Index",False],["Middle",False],
["Ring",False],["Thumb",False],["Pinky",False]]

#InitializingtheSerialandopencv
ser=serial.Serial(port="ThenameoftheporttheESP32isconnectedto")
#Ihadtoincludethe"cv2.CAP_DSHOW"becauseIhadissueswiththewebcamloadingonmylinuxmachine
cap=cv2.VideoCapture(0,cv2.CAP_DSHOW)
detector=HandDetector()

#MAINLOOPOFTHECODE#

#Releasingthestuffallocatedforopencv
cap.release()
cv2.destroyAllWindows()

main()

以及代碼的主循環(huán):

while(True):
#Findingthehandsandreadingthepositionofhtelandmarks
ret,frame=cap.read()
frame=detector.findHands(frame)
lmList=detector.findPosition(frame)

iflen(lmList)>0:

j=1
change=False
#Loopwhichchecksifthetopofthefingerisbelowthesecondmosttop
foriinrange(1,6):
ifi==1andlmList[4][1]3][1]andnothand[4][1]:
#Incasethatitistrueitchangesalltheneededdata
hand[4][1]=True
change=True
print(hand[4][0],hand[4][1])
elifi==1andlmList[4][1]>lmList[3][1]andhand[4][1]:
hand[4][1]=False
change=True
print(hand[4][0],hand[4][1])
elifi!=1:
iflmList[i*4][2]>lmList[(i*4)-2][2]andnothand[j][1]:
hand[j][1]=True
change=True
print(hand[j][0],hand[j][0])
eliflmList[i*4][2]4)-2][2]andhand[j][1]:
hand[j][1]=False
change=True
print(hand[j][0],hand[j][0])
ifj==3:
j+=2
else:
j+=1

#Iftherehasbeenanychangeinthestateofthehandthiscodeblockwillrun
ifchange:
msg=""
#Convertsthebooleanvaluesto0sand1s
foriinrange(6):
ifhand[i][1]:
msg+="1"
else:
msg+="0"

#AddstheendingsymbolandsendsthedataovertotheESP32
msg+='\n'
print(msg)
ser.write(msg.encode("Ascii"))

#CalculatestheFPSanddisplaysitontheframe
currentTime=time.time()
fps=1/(currentTime-prevTime)
prevTime=currentTime
cv2.putText(frame,str(int(fps)),(10,70),cv2.FONT_HERSHEY_SIMPLEX,3,(255,0,255),3)

#Showswhatthewebcamseesonaframe
cv2.imshow("frame",frame)

#Ifwepress"q"itquitsrunningtheprogram
ifcv2.waitKey(1)&0xFF==ord("q"):
break

整個(gè)代碼 OpenCV:

importcv2
importmediapipeasmp
importtime
importserial

classHandDetector():
def__init__(self,mode=False,maxHands=2,detectionCon=0.5,trackCon=0.5):
self.mode=mode
self.maxHands=maxHands
self.detectionCon=detectionCon
self.trackCon=trackCon

self.mpHands=mp.solutions.hands
self.hands=self.mpHands.Hands()
self.mpDraw=mp.solutions.drawing_utils

deffindHands(self,frame,draw=True):
imgRGB=cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
self.results=self.hands.process(imgRGB)

ifself.results.multi_hand_landmarks:
forhandLmsinself.results.multi_hand_landmarks:
ifdraw:
self.mpDraw.draw_landmarks(frame,handLms,self.mpHands.HAND_CONNECTIONS)
returnframe

deffindPosition(self,frame,handNo=0,draw=False):
lmList=[]

ifself.results.multi_hand_landmarks:
myHand=self.results.multi_hand_landmarks[handNo]

forid,lminenumerate(myHand.landmark):
h,w,c=frame.shape
cx,cy=int(lm.x*w),int(lm.y*h)

lmList.append([id,cx,cy])

ifdrawandid==0:
cv2.circle(frame,(cx,cy),15,(255,0,255),-1)
returnlmList

defmain():
prevTime=0
currentTime=0
hand=[["Wrist",False],["Index",False],["Middle",False],
["Ring",False],["Thumb",False],["Pinky",False]]


ser=serial.Serial(port="COM3")
cap=cv2.VideoCapture(0,cv2.CAP_DSHOW)
detector=HandDetector()

while(True):
ret,frame=cap.read()
frame=detector.findHands(frame)
lmList=detector.findPosition(frame)

iflen(lmList)>0:

j=1
change=False
foriinrange(1,6):
ifi==1andlmList[4][1]3][1]andnothand[4][1]:
hand[4][1]=True
change=True
print(hand[4][0],hand[4][1])
elifi==1andlmList[4][1]>lmList[3][1]andhand[4][1]:
hand[4][1]=False
change=True
print(hand[4][0],hand[4][1])
elifi!=1:
iflmList[i*4][2]>lmList[(i*4)-2][2]andnothand[j][1]:
hand[j][1]=True
change=True
print(hand[j][0],hand[j][0])
eliflmList[i*4][2]4)-2][2]andhand[j][1]:
hand[j][1]=False
change=True
print(hand[j][0],hand[j][0])
ifj==3:
j+=2
else:
j+=1

ifchange:
msg=""
foriinrange(6):
ifhand[i][1]:
msg+="1"
else:
msg+="0"

msg+='\n'
print(msg)
ser.write(msg.encode("Ascii"))

currentTime=time.time()
fps=1/(currentTime-prevTime)
prevTime=currentTime

cv2.putText(frame,str(int(fps)),(10,70),cv2.FONT_HERSHEY_SIMPLEX,3,(255,0,255),3)

cv2.imshow("frame",frame)

ifcv2.waitKey(1)&0xFF==ord("q"):
break

cap.release()
cv2.destroyAllWindows()

main()

ESP32(Arduino IDE)

我們可以充分利用ESP32是雙核這一特點(diǎn),類(lèi)似于PC的代碼,我們同樣需要完成兩項(xiàng)主要工作。

首先是接收來(lái)自PC的數(shù)據(jù)。正如前面提到的,數(shù)據(jù)基本上是一個(gè)帶有六位二進(jìn)制數(shù)和結(jié)束符的字符串。此外,由于只有在狀態(tài)變化時(shí)才會(huì)傳輸數(shù)據(jù),我們可以立即將這些值(轉(zhuǎn)換為true或false)分配給相應(yīng)的變量。將這個(gè)任務(wù)分配給核心0,而主循環(huán)則在核心1上運(yùn)行。

第二項(xiàng)工作就是控制手部運(yùn)動(dòng)。為此,我們需要不停地檢查這些變量的狀態(tài)是否發(fā)生變化,一旦有變化,伺服電機(jī)就會(huì)按小步長(zhǎng)進(jìn)行線(xiàn)性移動(dòng)。在每一步后,首先需要檢查變量是否沒(méi)有再次變化,并且還要測(cè)量霍爾傳感器讀取的值。如果霍爾傳感器的值過(guò)高,意味著磁鐵距離手指核心太近,此時(shí)也要停止伺服電機(jī)的運(yùn)動(dòng)。

最初,我們需要用于伺服驅(qū)動(dòng)的庫(kù),并且還將包含用于I2C通信的Wire庫(kù):

#include
#include

之后,我們需要定義脈沖長(zhǎng)度的值,這些值因伺服類(lèi)型而異,所以強(qiáng)烈建議查找特定伺服的信息或者像這樣測(cè)試[7]它們。

//OperatingSpeedofmyServo(6V):0.21sec/60°

#defineSERVOMIN"Yourvalue(minewas70)"//Thisisthe'minimum'pulselengthcount(outof4096)
#defineSERVOMAX"Yourvalue(minewas510)"//Thisisthe'maximum'pulselengthcount(outof4096)
#defineSERVO_FREQ50//Analogservosrunat~50Hzupdates

現(xiàn)在我們必須定義其余要使用到的變量:

//Initializingservodriverobject
Adafruit_PWMServoDriverpwm=Adafruit_PWMServoDriver();

//Index,Middle,Ring,Thumb,Pinky
//"state0"isthestatethehandonthewebcamisinand"state"
//isthestuffhappeningontheactualhand
boolstate0[6]={false,false,false,false,false,false};
boolstate[6]={false,false,false,false,false,false};

//Variablewhichindicatesiftherehasbeenanychangemadetothestate
boolchange=false;

//VariablesneededforreadingthedatafromSerial
charsData;
Stringstate;

//Variableforthehallsensor
//Index,Middle,Ring,Thumb,Pinky
//{pin,measuredvalue,maximumvalue}
//ALLOFTHEMAXVALUESWEREMEASUREDBYMETHUSTHEYWILLMOSTLIKELYNOTBESAMEFORYOU
inthall[5][3]={{26,0,2200},{27,0,2400},{14,0,2300},{25,0,2200},{12,0,2300}};

//Settingtheindexnumbersofeachmotor
intwrist=0;
intthumb=4;
intindex=1;
intmiddle=2;
intring=3;//IMPORTANTthismotorwillrotateintheopositedirection
intpinky=5;//IMPORTANTthismotorwillrotateintheopositedirection

//FunctionforcalculatingthePWMbasedonthedegreeyouwant
intdegToPwm(intdegree){
returnmap(degree,0,320,SERVOMIN,SERVOMAX);
}

//Settingthedegreethresholdsused
intdeg=degToPwm(75);
intdeg1=degToPwm(95);
intdeg2=degToPwm(85);
intstartDeg=degToPwm(180);

接下來(lái),需要定義我們將要使用的函數(shù):

//Initializationofthetask
TaskHandle_trecieveData;

//FunctionwhichreadsthedatafromSerial
voidrecieveDataCode(void*parameter){
for(;;){
//Loopwhichrunswhenthereisamessagesent
while(Serial.available()){
//Readingbyeachcharacter
sData=Serial.read();

//Ifthecharacteristhelineendingsymbolweknowitistheendofthemessage
if(sData=='\n'){
//Loopforconvertingthestring0sand1stoboolean
for(inti=0;i6;i++){
state0[i]=state.substring(i,i+1).toInt();
}

//Resetingthestatetemporaryvariable
state="";
//Showingachangeinstatehappened
change=true;
break;
}else{//Ifthecharacterisnotthelineendingsymbolweaddittothetemporarystate
state+=sData;
}
}
delay(10);
}
}

//Functionforactuallymovingtheservos
voidmoveFinger(intfingerId,boolflex,intiteration){
//Becausetheringandpinkymotorsmoveinoppositedirection
//wehavetocheckwhichmotorswearemoving
if(fingerId!=ring&&fingerId!=pinky){
//Wealsoneedtocheckifwewantthefingertoflexorstraighten
if(flex){
//Moreoverthethumbmovesalittlelesssowealsocheckforthat
if(fingerId==thumb){
//Becausewewanttobeabletocontrolthemovementthroughoutwehaveto
//divideitintosmallerparts
floatfPwm=SERVOMIN+(float(103)*float(iteration))/float(130);
//Butwealsohavetomakesuretoconvertbacktointbecausefloatwould
//notbeacceptedbypwmfunction
intiPwm=round(fPwm);
pwm.setPWM(fingerId,0,iPwm);
}else{//Ifthefingerisnotthethumbwejustmoveit
pwm.setPWM(fingerId,0,SERVOMIN+iteration);
}
}else{//Forthecasethatisretractingwehavetojustdotheopposite
if(fingerId==thumb){
floatfPwm=deg-(float(103)*float(iteration))/float(130);
intiPwm=round(fPwm);
pwm.setPWM(fingerId,0,iPwm);
}else{
pwm.setPWM(fingerId,0,deg1-iteration);
}
}
}elseif(fingerId==ring||fingerId==pinky){
//Inthecaseoftheringorpinkyfingerwedoagainthesame
if(flex){
pwm.setPWM(fingerId,0,startDeg-iteration);
}else{
pwm.setPWM(fingerId,0,deg2+iteration);
}
}
}

補(bǔ)上設(shè)置和循環(huán)功能:

voidsetup(){
//StartingSerialonthesamefrequencyasonthePC
Serial.begin(9600);

//AssigningthepinModetoallpinsconnectedtohallsensor
for(inti=0;i5;i++){
pinMode(hall[i][0],INPUT);
}

//Setupandstartingtheservodriver
pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(SERVO_FREQ);

delay(10);

//Pinningthecreatedtasktocore0
xTaskCreatePinnedToCore(
recieveDataCode,
"recieveData",
10000,
NULL,
0,
&recieveData,
0);
delay(500);
}

voidloop(){
//Oncetherehasbeenachangeinthestatethiscodeblockwillrun
if(change){
//Loopingfirstlythroughthetotalstepsoftheservos
for(inti=5;i135;i+=5){

//Secondlythroughallofthehallsensorsandreadingthevalues
for(intk=0;k5;k++){
hall[k][1]=analogRead(hall[k][0]);
//Ifthemeasuredvalueisgreaterthanmaximumvaluewestopthemovement
if(hall[k][1]>hall[k][2]){
state1[k+1]=state0[k+1];
}
}

//Thirdlythroughalltheservomotors
for(intj=0;j6;j++){
if(state0[j]!=state1[j]){
//IfthestateonthePCdoesnotmatchtheoneontheesp32we
//callthefunctionformovingtherespectivefinger
moveFinger(j,state0[j],i);
}
}
//Thisdelayisveryimportantasitsetsthespeedofthemovements
delay(17);
}

//Attheandwemakethestatevariablesequalagain
for(inti=0;i6;i++){
state1[i]=state0[i];
}
}

delay(100);
}

ESP32的完整代碼:

#include
#include

#defineSERVOMIN"Yourvalue"
#defineSERVOMAX"Yourvalue"
#defineSERVO_FREQ50

Adafruit_PWMServoDriverpwm=Adafruit_PWMServoDriver();

boolstate0[6]={false,false,false,false,false,false};
boolstate1[6]={false,false,false,false,false,false};

boolchange=false;

charsData;
Stringstate;

inthall[5][3]={{26,0,2200},{27,0,2400},{14,0,2300},{25,0,2200},{12,0,2300}};

intwrist=0;
intthumb=4;
intindex=1;
intmiddle=2;
intring=3;
intpinky=5;

intdegToPwm(intdegree){
returnmap(degree,0,320,SERVOMIN,SERVOMAX);
}

intdeg=degToPwm(75);
intdeg1=degToPwm(95);
intdeg2=degToPwm(85);
intstartDeg=degToPwm(180);

TaskHandle_trecieveData;

voidrecieveDataCode(void*parameter){
for(;;){
while(Serial.available()){
sData=Serial.read();
if(sData=='\n'){
for(inti=0;i6;i++){
state0[i]=state.substring(i,i+1).toInt();
}
state="";
change=true;
break;
}else{
state+=sData;
}
}
delay(10);
}
}

voidmoveFinger(intfingerId,boolflex,intiteration){
if(fingerId!=ring&&fingerId!=pinky){
if(flex){
if(fingerId==thumb){
floatfPwm=SERVOMIN+(float(103)*float(iteration))/float(130);
intiPwm=round(fPwm);
pwm.setPWM(fingerId,0,iPwm);
}else{
pwm.setPWM(fingerId,0,SERVOMIN+iteration);
}
}else{
if(fingerId==thumb){
floatfPwm=deg-(float(103)*float(iteration))/float(130);
intiPwm=round(fPwm);
pwm.setPWM(fingerId,0,iPwm);
}else{
pwm.setPWM(fingerId,0,deg1-iteration);
}
}
}else/*if(fingerId==ring||fingerId==pinky)*/{
if(flex){
pwm.setPWM(fingerId,0,startDeg-iteration);
}else{
pwm.setPWM(fingerId,0,deg2+iteration);
}
}
}

voidsetup(){
Serial.begin(9600);

for(inti=0;i5;i++){
pinMode(hall[i][0],INPUT);
}

pwm.begin();
pwm.setOscillatorFrequency(27000000);
pwm.setPWMFreq(SERVO_FREQ);

delay(10);

xTaskCreatePinnedToCore(
recieveDataCode,
"recieveData",
10000,
NULL,
0,
&recieveData,
0);
delay(500);
}

voidloop(){
if(change){
for(inti=5;i135;i+=5){
for(intk=0;k5;k++){
hall[k][1]=analogRead(hall[k][0]);
if(hall[k][1]>hall[k][2]){
state1[k+1]=state0[k+1];
}
}
for(intj=0;j6;j++){
if(state0[j]!=state1[j]){
moveFinger(j,state0[j],i);
}
}
delay(17);
}

for(inti=0;i6;i++){
state1[i]=state0[i];
}
}

delay(100);}


原文地址:https://www.instructables.com/Bionic-Hand-Controlled-by-OpenCV/

項(xiàng)目作者:bloudakm

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 傳感器
    +關(guān)注

    關(guān)注

    2561

    文章

    52198

    瀏覽量

    761696
  • OpenCV
    +關(guān)注

    關(guān)注

    31

    文章

    642

    瀏覽量

    42233
  • 仿生手
    +關(guān)注

    關(guān)注

    0

    文章

    14

    瀏覽量

    10219
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    意大利新型仿生手,體驗(yàn)“逼真”的觸感!

    意大利研制成功款新型仿生手,不僅能夠完成復(fù)雜的動(dòng)作,而且能夠通過(guò)與患者神經(jīng)系統(tǒng)的銜接來(lái)讓患者體驗(yàn)到“逼真”的觸感。
    發(fā)表于 02-25 11:12 ?2119次閱讀

    【開(kāi)源項(xiàng)目】做一只由 OpenCV 控制仿生手

    這個(gè)項(xiàng)目介紹了如何制作和控制一只仿生手。作者最初受到Instagram上個(gè)視頻的啟發(fā),該視頻展示了使用MPU6050傳感器追蹤手部動(dòng)作并在
    發(fā)表于 11-18 10:07

    幀頭查找程序,初學(xué)小制作,菜鳥(niǎo)一只~

    幀頭查找程序,初學(xué)小制作,菜鳥(niǎo)一只~哈哈,希望大家都能在這里有所收獲哈~
    發(fā)表于 07-26 09:17

    分享仿生手的設(shè)計(jì)方案

    是模仿人類(lèi)自然手的機(jī)械假手。它可以做人手可以做的事情。這只手是用塑料作為原材料進(jìn)行 3D 打印的。對(duì)于 PCB,將邊框直接放置在具有精確尺寸的仿生手上,它有個(gè) arduino nano 作為控制
    發(fā)表于 07-04 08:01

    一只電容救活顯象管

    一只電容救活顯象管筆者家中有臺(tái)老式的14英寸的黑白電視機(jī),使用十年來(lái),
    發(fā)表于 04-17 22:26 ?713次閱讀

    一只單連開(kāi)關(guān)控制三盞燈

    一只單連開(kāi)關(guān)控制三盞燈
    發(fā)表于 09-10 08:57 ?3131次閱讀
    <b class='flag-5'>一只</b>單連開(kāi)關(guān)<b class='flag-5'>控制</b>三盞燈

    一只單連天關(guān)控制盞燈并另外連接一只插座

    一只單連天關(guān)控制盞燈并另外連接一只插座
    發(fā)表于 09-10 08:58 ?974次閱讀
    <b class='flag-5'>一只</b>單連天關(guān)<b class='flag-5'>控制</b><b class='flag-5'>一</b>盞燈并另外連接<b class='flag-5'>一只</b>插座

    Youbionic仿生手變身多臂超人不再是夢(mèng)!

    器人,那么家叫做Youbionic的公司可以助你圓夢(mèng)。根據(jù)《每日郵報(bào)》報(bào)道,Youbionic聲稱(chēng),公司最新的仿生手設(shè)計(jì)可以賦予你“神奇能力”。 方面,該奇妙裝置通過(guò)移動(dòng)你的手指來(lái)控制
    發(fā)表于 02-13 03:48 ?1561次閱讀
    Youbionic<b class='flag-5'>仿生手</b>變身多臂超人不再是夢(mèng)!

    如何制作一只用蒸汽驅(qū)動(dòng)的能航行的小船?

    制作一只蒸汽驅(qū)動(dòng)的能航行的小船,似乎是很難的件事情,但是我們?cè)O(shè)計(jì)的這個(gè)套件讓它變得非常簡(jiǎn)單。您只需要簡(jiǎn)單的工具和材料,就能在家里跟孩子起完成這個(gè)任務(wù),共同
    的頭像 發(fā)表于 08-07 15:43 ?2.4w次閱讀

    觸控手機(jī)可穿戴仿生手將投入量產(chǎn)

    近日,微博大號(hào)“黑客師”曝光了款可穿戴仿生手設(shè)備的諜照。據(jù)“黑客師”透露,這是他從京東數(shù)科內(nèi)部拿到的最新款智能可穿戴仿生手,目前已經(jīng)完成了前期研發(fā)工作并已進(jìn)入樣機(jī)測(cè)試階段。
    的頭像 發(fā)表于 06-07 11:29 ?4303次閱讀

    3D打印定制仿生手臂,僅需10小時(shí)即可完成

    WMG和華威大學(xué)的工程師團(tuán)隊(duì)在其他公司的協(xié)助下創(chuàng)建了3D打印仿生手,可在10小時(shí)內(nèi)生產(chǎn)。
    的頭像 發(fā)表于 05-19 15:57 ?2880次閱讀

    英國(guó)游戲玩家在廠(chǎng)商幫助下獲得新仿生手

    據(jù)外媒CNET報(bào)道,英國(guó)游戲玩家Daniel Melville天生沒(méi)有右手,由于電子游戲發(fā)行商 Konami(科樂(lè)美)和Open Bionics的幫助,他現(xiàn)在擁有了一只超酷的新仿生手臂,它是基于《合金裝備》中毒蛇(Venom Snake)
    的頭像 發(fā)表于 11-18 14:58 ?1725次閱讀

    中國(guó)科學(xué)家研發(fā)新型仿生手術(shù)縫線(xiàn)

    基于“藕斷絲連”這自然現(xiàn)象,中國(guó)科學(xué)家再次秀出了令人側(cè)目的研究成果,而它就是新型仿生手術(shù)縫線(xiàn)。
    的頭像 發(fā)表于 01-21 09:26 ?1815次閱讀

    arduino nano作為控制器的仿生手

    電子發(fā)燒友網(wǎng)站提供《arduino nano作為控制器的仿生手.zip》資料免費(fèi)下載
    發(fā)表于 07-07 10:47 ?5次下載
    arduino nano作為<b class='flag-5'>控制</b>器的<b class='flag-5'>仿生手</b>

    通過(guò)基于CNN的EMG識(shí)別進(jìn)行實(shí)時(shí)仿生手控制

    電子發(fā)燒友網(wǎng)站提供《通過(guò)基于CNN的EMG識(shí)別進(jìn)行實(shí)時(shí)仿生手控制.zip》資料免費(fèi)下載
    發(fā)表于 10-24 10:03 ?4次下載
    通過(guò)基于CNN的EMG識(shí)別進(jìn)行實(shí)時(shí)<b class='flag-5'>仿生手</b>臂<b class='flag-5'>控制</b>