๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

[Spot Dynamixel - 5] Kinematics ์ฝ”๋“œ ์„ค๋ช…

 

๐Ÿฆต๐Ÿฟ

Kinematics ์ฝ”๋“œ ์„ค๋ช…

Kinematic class ์„ค๋ช…

1. ํด๋ž˜์Šค ์ƒ์„ฑ์ž - init

๋‹ค๋ฆฌ ๊ธธ์ด ๋ฐ ๋ชธํ†ต์˜ ๊ธธ์ด ๋„ˆ๋น„ ๋“ฑ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์ž…๋ ฅ์„ ํ•ด์ฃผ๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค.
def __init__(self):
        self.l1=50
        self.l2=20
        self.l3=100
        self.l4=100

        self.L = 140
        self.W = 75
        
        #leg iterators. ex. LEG_BACK + LEG_LEFT -> array[2]
        self.LEG_FRONT = 0
        self.LEG_BACK = 2
        self.LEG_LEFT = 0
        self.LEG_RIGHT =1

        #thetas, which will be used on controllers
        self.thetas = np.array([[0, 0, 0],[0, 0, 0],[0, 0, 0],[0, 0, 0]], dtype=np.float64)

 

  • L : ๋กœ๋ด‡ ๋ชธํ†ต์˜ ๊ธธ์ด
  • W: ๋กœ๋ด‡ ๋ชธํ†ต์˜ ๋„ˆ๋น„

 

 

๊ฐ๋ชจํ„ฐ๋“ค์˜ ๊ฐ๋„๋“ค์„ ๋ชจ์•„ ๋‘” thetas ๋ฐฐ์—ด์ด ์„ ์–ธ๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ด๋Š” 4๊ฐœ์˜ ๋‹ค๋ฆฌ * 3๊ฐœ์˜ ๋ชจํ„ฐ์— ๋”ฐ๋ผ 12๊ฐœ์˜ ๊ฐ’์„ ๊ฐ–์Šต๋‹ˆ๋‹ค.

        #leg iterators. ex. LEG_BACK + LEG_LEFT -> array[2]
        self.LEG_FRONT = 0
        self.LEG_BACK = 2
        self.LEG_LEFT = 0
        self.LEG_RIGHT = 1

 

 

๊ฐ ๋‹ค๋ฆฌ์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ๋ฒˆํ˜ธ๊ฐ€ ๋ถ™์œผ๋ฉฐ,

์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์Šคํ…œ์—์„œ๋Š” ๊ทธ๋ฆผ๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ๋ฒˆํ˜ธ๊ฐ€ ๋งค๊ฒจ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„ ์ฝ”๋“œ๋Š” ์ด๋Ÿฐ ์ ‘๊ทผ์„ ์œ„ํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด

  • Front Left : self.LEG_FRONT + self.LEG_LEFT = 0
  • Back Right : self.LEG_BACK + self.LEG_RIGHT = 3

์ด๋Ÿฐ ์‹์œผ๋กœ ์ ‘๊ทผ์ด ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒƒ์ด์ง€์š”

 

2. bodyIK ํ•จ์ˆ˜

์›ํ•˜๋Š” ๋กœ๋ด‡ ๋ชธ์ฒด์˜ ์œ„์น˜/๊ฐ๋„๋ฅผ Input ํ•˜๋ฉด ์ด์— ๋Œ€ํ•œ ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ Output ํ•ด์ฃผ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
def bodyIK(self,omega,phi,psi,xm,ym,zm):
        Rx = np.array([[1,0,0,0],
                    [0,np.cos(omega),-np.sin(omega),0],
                    [0,np.sin(omega),np.cos(omega),0],[0,0,0,1]])
        Ry = np.array([[np.cos(phi),0,np.sin(phi),0],
                    [0,1,0,0],
                    [-np.sin(phi),0,np.cos(phi),0],[0,0,0,1]])
        Rz = np.array([[np.cos(psi),-np.sin(psi),0,0],
                    [np.sin(psi),np.cos(psi),0,0],[0,0,1,0],[0,0,0,1]])
        Rxyz = Rx.dot(Ry.dot(Rz))

        T = np.array([[0,0,0,xm],[0,0,0,ym],[0,0,0,zm],[0,0,0,0]])
        Tm = T+Rxyz

        sHp=np.sin(pi/2)
        cHp=np.cos(pi/2)
        (L,W)=(self.L,self.W)

        return([Tm.dot(np.array([[cHp,0,sHp,L/2],[0,1,0,0],[-sHp,0,cHp,W/2],[0,0,0,1]])),
                Tm.dot(np.array([[cHp,0,sHp,L/2],[0,1,0,0],[-sHp,0,cHp,-W/2],[0,0,0,1]])),
                Tm.dot(np.array([[cHp,0,sHp,-L/2],[0,1,0,0],[-sHp,0,cHp,W/2],[0,0,0,1]])),
                Tm.dot(np.array([[cHp,0,sHp,-L/2],[0,1,0,0],[-sHp,0,cHp,-W/2],[0,0,0,1]]))])

 

  • ์—ฌ๊ธฐ์„œ์˜ ๋ณ€ํ™˜ ํ–‰๋ ฌ์€ ํŠน์ • ์ขŒํ‘œ์˜ ๊ธฐ์ค€์ด ๋˜๋Š” ์ขŒํ‘œ๊ณ„๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํ–‰๋ ฌ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ์˜ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ƒ ๋ณดํ–‰ํŒจํ„ด์— ๊ด€ํ•œ ์ •๋ณด๋Š” ์›์ ์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ๋‹ค๋ฆฌ ๋์ ์˜ ์œ„์น˜๋กœ ์ฃผ์–ด์ง€๋Š”๋ฐ์š”,

 

ํ•˜์ง€๋งŒ ์ด ๋ณดํ–‰ํŒจํ„ด์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ ๋‹ค๋ฆฌ์˜ ๋ชจํ„ฐ ๊ฐ๋„๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” Kinematics ๊ณผ์ •์„ ์ง„ํ–‰ํ•˜๋ ค๋ฉด ์›์ ์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ์œ„์น˜๊ฐ€ ์•„๋‹Œ ๋กœ๋ด‡์˜ ๊ฐ ์–ด๊นจ ๋ถ€๋ถ„์„ ๊ธฐ์ค€์œผ๋กœ ํ•œ ๋‹ค๋ฆฌ ๋์˜ ์œ„์น˜๋ฅผ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

⇒ ์ฆ‰ ๊ธฐ์ค€ ์ขŒํ‘œ๊ณ„๋ฅผ ์›์ ์—์„œ ๊ฐ ๋กœ๋ด‡์˜ ์–ด๊นจ๋กœ ์˜ฎ๊ฒจ์•ผ ํ•˜๋ฏ€๋กœ ๋ณ€ํ™˜ ํ–‰๋ ฌ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

 

๋ณ€ํ™˜ ํ–‰๋ ฌ์€ ํšŒ์ „๊ณผ ์ด๋™ 2๊ฐ€์ง€๋กœ ๋‚˜๋‰˜๊ณ , ๊ฐ๊ฐ์€ ์œ„ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ์œ„์น˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ( ์ œ์ผ ํ•˜๋‹จ ํ–‰์€ ๋ฌด์กฐ๊ฑด [0 0 0 1]์„ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.)

⇒ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์ด ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ๋กœ๋ด‡๊ณตํ•™ ๋™์ฐจํ–‰๋ ฌ์„ ์ฐพ์•„๋ณด์‹œ๊ธธ

 

์ „์ฒด์ ์ธ ๋ฐฉํ–ฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. ์ขŒํ‘œ๊ณ„๋ฅผ ์›์ ์—์„œ ๋กœ๋ด‡ ๋ชธ์ฒด ์ค‘์‹ฌ์œผ๋กœ ๋ฐ”๊พธ๋Š” ํ–‰๋ ฌ๊ณผ
  1. ๋กœ๋ด‡ ๋ชธ์ฒด์—์„œ ๊ฐ ๋กœ๋ด‡ ์–ด๊นจ๋กœ ๋ฐ”๊พธ๋Š” ํ–‰๋ ฌ์„ ๊ฐ๊ฐ ๊ตฌํ•ด์„œ ์„œ๋กœ ์—ฐ๊ฒฐํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

์›์  ⇒ ๋กœ๋ด‡ ๋ชธ์ฒด ์ค‘์‹ฌ์œผ๋กœ ์ขŒํ‘œ๊ณ„๋ฅผ ๋ณ€๊ฒฝ (ํšŒ์ „ ๋ณ€ํ™˜ ํ–‰๋ ฌ)


				Rx = np.array([[1,0,0,0],
                    [0,np.cos(omega),-np.sin(omega),0],
                    [0,np.sin(omega),np.cos(omega),0],[0,0,0,1]])
        Ry = np.array([[np.cos(phi),0,np.sin(phi),0],
                    [0,1,0,0],
                    [-np.sin(phi),0,np.cos(phi),0],[0,0,0,1]])
        Rz = np.array([[np.cos(psi),-np.sin(psi),0,0],
                    [np.sin(psi),np.cos(psi),0,0],[0,0,1,0],[0,0,0,1]])
        Rxyz = Rx.dot(Ry.dot(Rz))
  • ๋ชธ์ฒด์˜ ๊ธฐ์šธ์–ด์ง„ ๊ฐ๋„๋ฅผ ๋ณ€ํ™˜ ํ–‰๋ ฌ์— ๋ฐ˜์˜ํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ์œ„์˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์€ 3์ฐจ์› ํšŒ์ „ ๋ณ€ํ™˜ ํ–‰๋ ฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด๋•Œ ์‚ฌ์šฉํ•˜๋Š” 3์ฐจ์› ๊ฐ๋„ ํ‘œ์‹œ ์ฒด๊ณ„๋Š” ์˜ค์ผ๋Ÿฌ ๊ฐ๋„ ์ด๋ฏ€๋กœ(z์ถ• y์ถ• x์ถ• ์ˆœ์„œ๋กœ ํšŒ์ „์‹œํ‚ค๋Š” ์ฒด๊ณ„) ๊ณฑํ•ด์ง€๋Š” ํšŒ์ „ ๋ณ€ํ™˜ ํ–‰๋ ฌ์˜ ์ˆœ์„œ๋Š” Rx Ry Rz ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.(๊ณ„์‚ฐ์‹œ ์˜ค๋ฅธ์ชฝ ํ–‰๋ ฌ๋ถ€ํ„ฐ ์ˆœ์„œ๋Œ€๋กœ ๊ณฑํ•ด์ง)

๐Ÿ’ก
๋งŒ์•ฝ ์‚ฌ์šฉํ•˜๋Š” ๊ฐ๋„ ์ฒด๊ณ„๊ฐ€ ๋‹ค๋ฅด๋‹ค๋ฉด ์ฝ”๋“œ์˜ ๊ณฑํ•ด์ง€๋Š” ์ˆœ์„œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

์›์  ⇒ ๋กœ๋ด‡ ๋ชธ์ฒด ์ค‘์‹ฌ(์ด๋™ ๋ณ€ํ™˜ ํ–‰๋ ฌ)


T = np.array([[0,0,0,xm],[0,0,0,ym],[0,0,0,zm],[0,0,0,0]])
Tm = T + Rxyz

๋ชธ์ฒด์˜ ์œ„์น˜์— ๊ด€ํ•œ ์ •๋ณด๋ฅผ ๋ฐ˜์˜ํ•ด ์ฃผ๊ณ  ์•ž์—์„œ ๊ตฌํ–ˆ๋˜ ํšŒ์ „ ๋ณ€ํ™˜ ํ–‰๋ ฌ๊ณผ ํ•ฉ์ณ ์ตœ์ข… ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ ์™„์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ตœ์ข…์ ์œผ๋กœ Tm ํ–‰๋ ฌ์€ ๊ณง, ์›์  ์ขŒํ‘œ๊ณ„์—์„œ ๋กœ๋ด‡ ๋ชธ์ฒด์˜ ์ค‘์‹ฌ ์ขŒํ‘œ๊ณ„๋กœ ๋ฐ”๊พธ์–ด์ฃผ๋Š” ๋ณ€ํ™˜ ํ–‰๋ ฌ์ด ๋ฉ๋‹ˆ๋‹ค.

 

๋กœ๋ด‡ ๋ชธ์ฒด ์ค‘์‹ฌ ์ขŒํ‘œ๊ณ„ ⇒ ์–ด๊นจ ์ขŒํ‘œ๊ณ„


sHp=np.sin(pi/2)
cHp=np.cos(pi/2)
(L,W)=(self.L,self.W)

return([Tm.dot(np.array([[cHp,0,sHp,L/2],[0,1,0,0],[-sHp,0,cHp,W/2],[0,0,0,1]])),
        Tm.dot(np.array([[cHp,0,sHp,L/2],[0,1,0,0],[-sHp,0,cHp,-W/2],[0,0,0,1]])),
        Tm.dot(np.array([[cHp,0,sHp,-L/2],[0,1,0,0],[-sHp,0,cHp,W/2],[0,0,0,1]])),
        Tm.dot(np.array([[cHp,0,sHp,-L/2],[0,1,0,0],[-sHp,0,cHp,-W/2],[0,0,0,1]]))])

์•ž์„œ ์„ค๋ช…ํ–ˆ๋˜ ํšŒ์ „&์ด๋™ ๋ณ€ํ™˜ ํ–‰๋ ฌ์„ ํ™œ์šฉํ•˜์—ฌ ๋กœ๋ด‡ ๋ชธ์ฒด ์ค‘์‹ฌ์—์„œ ์–ด๊นจ๋กœ์˜ ์ขŒํ‘œ๊ณ„ ์ด๋™์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  • ํšŒ์ „์€ y์ถ•(๊ทธ๋ฆผ์ƒ์—์„œ ๋นจ๊ฐ•์ƒ‰ ์ถ•) 90๋„ ํšŒ์ „์„ ์ง„ํ–‰ํ•˜๊ณ 
  • ์ด๋™์€ x์ถ•(๊ทธ๋ฆผ์ƒ์—์„œ ์ดˆ๋ก์ƒ‰ ์ถ•)์œผ๋กœ W/2, z์ถ•(๊ทธ๋ฆผ์ƒ์—์„œ ํŒŒ๋ž‘์ƒ‰ ์ถ•)์œผ๋กœ L/2 ์ด๋™์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋•Œ์˜ ๋ณ€ํ™˜ ํ–‰๋ ฌ 4๊ฐœ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ์ตœ์ข… OUTPUT์„ ํ•ฉ๋‹ˆ๋‹ค.

 

legIK


์–ด๊นจ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ํ•œ ๋‹ค๋ฆฌ ๋์ ์˜ ์ขŒํ‘œ๊ฐ€ input ๋˜๋ฉด ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ๊ด€์ ˆ์˜ ๋ชจํ„ฐ๊ฐ€ ๊ตฌ๋™ํ•ด์•ผ ํ•  ๊ฐ๋„๋ฅผ Output ํ•ด์ค๋‹ˆ๋‹ค.

def legIK(self,point):
        (x,y,z)=(point[0],point[1],point[2])
        (l1,l2,l3,l4)=(self.l1,self.l2,self.l3,self.l4)
        try:        
            F=sqrt(x**2+y**2-l1**2)
        except ValueError:
            print("Error in legIK with x {} y {} and l1 {}".format(x,y,l1))
            F=l1
        G=F-l2  
        H=sqrt(G**2+z**2)
        theta1=-atan2(y,x)-atan2(F,-l1)
        
        D=(H**2-l3**2-l4**2)/(2*l3*l4)
        try:        
            theta3=acos(D) 
        except ValueError:
            print("Error in legIK with x {} y {} and D {}".format(x,y,D))
            theta3=0
        theta2=atan2(z,G)-atan2(l4*sin(theta3),l3+l4*cos(theta3))
        
        return(theta1,theta2,theta3)

 

์ด๋Ÿฌํ•œ ๊ณ„์‚ฐ ๊ณผ์ •์„ ์—ญ๊ธฐ๊ตฌํ•™(inverse kinematics)๋ผ๊ณ  ํ•˜๋ฉฐ, ์ •ํ™•ํžˆ ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์„ ์ž˜ ์„ค๋ช…ํ•˜๋Š” ์˜์ƒ์ด ์žˆ์–ด ๋งํฌ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.

⇒ ์˜์ƒ์ด ๊ธธ์ง€ ์•Š๊ณ  ์ง๊ด€์ ์œผ๋กœ ์ž˜ ์„ค๋ช…๋˜์–ด ์žˆ์–ด ๊ผญ ์‹œ์ฒญํ•˜์‹œ๊ธธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค!