λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

μΉ΄ν…Œκ³ λ¦¬ μ—†μŒ

[Spot Dynamixel - 7] 보행 μ½”λ“œ 뢄석

 

πŸ•

보행 μ½”λ“œ 뢄석

 

SD_automatic_gait_test.py

μ‹€μ§ˆμ μœΌλ‘œ λ‘œλ΄‡μ„ μ›€μ§μ΄λŠ” μ΅œμ’… μ½”λ“œλ₯Ό 뢄석해 λ΄…λ‹ˆλ‹€.

 

  • 라이브러리 import 및 초기 μ„ΈνŒ…μ„ μ§„ν–‰ν•©λ‹ˆλ‹€.
from os import system, name 
import sys, os
sys.path.append("..")
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))
import matplotlib.animation as animation
import numpy as np
import time
import math
import datetime as dt
import keyboard
import random
import board
import busio

import Kinematics.kinematics as kn
import spotmicroai
from SD_servo_controller_test import Dynamixel_Controllers

from multiprocessing import Process
from Common.multiprocess_kb import KeyInterrupt
from Kinematics.kinematicMotion import KinematicMotion, TrottingGait

rtime=time.time()

def reset():
    global rtime
    rtime=time.time()    

 

spotmicroai λŠ” μ§€κΈˆκΉŒμ§€ 우리 μ‚΄νŽ΄λ³Έ λ‘œλ΄‡μ˜ Kinematics, 보행에 λŒ€ν•œ λͺ¨λ“  λ‚΄μš©μ„ μ·¨ν•©ν•˜μ—¬ μΆ”μƒν™”ν•œ ν΄λž˜μŠ€μž…λ‹ˆλ‹€. μ•žμœΌλ‘œ μš°λ¦¬λŠ” 이λ₯Ό 톡해 λ‘œλ΄‡μ„ μ œμ–΄ν•˜λŠ” main loopλ₯Ό μ‹€ν–‰μ‹œν‚¬ κ²ƒμž…λ‹ˆλ‹€.

robot=spotmicroai.Robot(False,False,reset)

 

  • IMU μ„Όμ„œμ˜ 초기 μ„ΈνŒ…μ„ μ§„ν–‰ν•©λ‹ˆλ‹€.
πŸ’‘
μ‹€ν–‰μ „, μ—°κ²° μ—¬λΆ€ 확인을 μœ„ν•΄ 예제 μ½”λ“œκ°€ μ‹€ν–‰λ˜λŠ”μ§€ λ°˜λ“œμ‹œ ν™•μΈν•΄λ³΄μ„Έμš”!
import adafruit_bno055
# BNO055 ( IMU )
i2c_bus0 = busio.I2C(board.SCL_1, board.SDA_1)
sensor = adafruit_bno055.BNO055_I2C(i2c_bus0)

 

  • Dynamixel λͺ¨ν„° 초기 μ„ΈνŒ…μ„ μ§„ν–‰ν•©λ‹ˆλ‹€.

μœ„ μž‘μ—…μ„ μ§„ν–‰ν•˜κΈ° μœ„ν•΄ USB ν¬νŠΈμ— κΆŒν•œμ„ μ„€μ •ν•΄ μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

$ cd /dev
$ sudo chmod 775 /dev/ttyUSB0
from dynamixel_sdk import *
# Dynamixel address
ADDR_MX_TORQUE_ENABLE      = 24               
ADDR_MX_GOAL_POSITION      = 30
ADDR_MX_PRESENT_POSITION   = 36

PROTOCOL_VERSION            = 1.0

BAUDRATE                    = 1000000            
DEVICENAME                  = '/dev/ttyUSB0'

TORQUE_ENABLE               = 1                
TORQUE_DISABLE              = 0

# setting port and protocol version
portHandler = PortHandler(DEVICENAME)
packetHandler = PacketHandler(PROTOCOL_VERSION)


DXL_controller = Dynamixel_Controllers()

# setting the DXL_Motor
DXL_controller.DynamixelSetting()
πŸ’‘
μ—¬κΈ°κΉŒμ§€ μ •μƒμ μœΌλ‘œ 싀행이 되면 λ‹€μ΄λ‚˜λ―Ήμ…€ λͺ¨ν„°μ— 토크가 κ±Έλ € κ³ μ •λœ μƒνƒœμ—¬μ•Ό ν•©λ‹ˆλ‹€.

 

 

spurWidth=robot.W/2+50
stepLength=0
stepHeight=72

# Initial End point X Value for Front legs 
iXf=120

walk=False

λ‘œλ΄‡μ˜ 보행과 κ΄€λ ¨λœ λ§€κ°œλ³€μˆ˜λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

  • spurWidth : 쒌우 발 μ‚¬μ΄μ˜ λ„ˆλΉ„μ— ν•΄λ‹Ήν•˜λŠ” λ§€κ°œλ³€μˆ˜μž…λ‹ˆλ‹€.
  • stepHeight : 보행 μ‹œ λ°œμ„ λ“€μ–΄μ˜¬λ¦¬λŠ” λ†’μ΄μž…λ‹ˆλ‹€.
  • iXf : λ‘œλ΄‡ μ•žλ°œμ˜ 초기 x μ’Œν‘œλ‘œ, 무게 쀑심에 λ”°λ₯Έ μ•ˆμ •μ„±μ„ μœ„ν•΄ μ΅œμ ν™” μ‹œ μ‚¬μš©ν•©λ‹ˆλ‹€.

 

  • 각각의 Leg Point (x, y, z μ’Œν‘œ)λ₯Ό μ§€μ •ν•©λ‹ˆλ‹€.
Lp = np.array([[iXf, -170, spurWidth, 1], [iXf, -170, -spurWidth, 1],
							[-120, -170, spurWidth, 1], [-120, -170, -spurWidth, 1]])

 

 

  • 보행을 μœ„ν•œ 클래슀, TrottingGaitλ₯Ό μ„ μ–Έν•˜λŠ” λͺ¨μŠ΅μž…λ‹ˆλ‹€.
motion=KinematicMotion(Lp) 
resetPose()

trotting=TrottingGait()

Main Loop


λŒ€λΆ€λΆ„μ˜ λ‘œλ΄‡μ€ λ¬΄ν•œ while loop μ•ˆμ—μ„œ μ§€μ†μ μœΌλ‘œ ν”Όλ“œλ°±, ꡬ동을 λ°˜λ³΅ν•©λ‹ˆλ‹€.

 

 

μ§€κΈˆμ˜ 경우 우리 λ‘œλ΄‡μ€

  • IMU둜 λΆ€ν„° μœ„μΉ˜ 데이터λ₯Ό μ„Όμ‹±ν•˜μ—¬
  • λ‘œλ΄‡μ΄ λ„˜μ–΄μ§€μ§€ μ•Šκ²Œ λŠμž„μ—†μ΄ μœ μ§€ν•˜λŠ” 둜직이 κ΅¬λ™λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

 

μ΄λŸ¬ν•œ κ΄€μ μœΌλ‘œ main loopλ₯Ό 뢄석해 λ³΄κ² μŠ΅λ‹ˆλ‹€. πŸ˜‰

 

  • loopκ°€ 반볡될 λ•Œλ§ˆλ‹€ ꡬ동 μ‹œκ°„μ΄ μ—…λ°μ΄νŠΈ λ©λ‹ˆλ‹€.
def main(id, command_status):
    jointAngles = []
    while True:
        xr = 0.0
        yr = 0.0

        # Reset when robot pose become strange
        # robot.resetBody()

        ir = xr/(math.pi/180)

        d = time.time()-rtime

        # robot height
        height = 30  # 40

 

  • ν‚€λ³΄λ“œ μž…λ ₯을 톡해 λ‘œλ΄‡μ˜ 경둜λ₯Ό μ œμ–΄ν•˜λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€.
				# calculate robot step command from keyboard inputs
        result_dict = command_status.get()
        print(result_dict)
        command_status.put(result_dict)

        # wait 3 seconds to start
        if result_dict['StartStepping']:
            currentLp = trotting.positions(d-3, result_dict)
            robot.feetPosition(currentLp)
        else:
            robot.feetPosition(Lp)

 

πŸ’‘
‼️ μ€‘μš” λ‘œλ΄‡μ΄ κΈ°μšΈμ–΄μ Έλ„ μˆ˜ν‰μ„ μœ μ§€ν•  수 μžˆλ„λ‘ ν•΄μ£ΌλŠ” Pose μ œμ–΄ λΆ€λΆ„μž…λ‹ˆλ‹€ ‼️
				pitch = -((sensor.euler[1]*math.pi)/180)
        yaw = -((sensor.euler[0]*math.pi)/180)
        roll = -((sensor.euler[2]*math.pi)/180)
        robot.bodyRotation((roll,yaw,pitch))
        robot.bodyPosition((0, 0, 0))

 

IMUλ‘œλΆ€ν„° λͺΈμ²΄μ˜ 각도λ₯Ό 전달받고, 이λ₯Ό spotmicroai robot class의 bodyRotation ν•¨μˆ˜μ— μ „λ‹¬ν•©λ‹ˆλ‹€.

def bodyRotation(self,rot):
        self.rot=rot


def calcIK(self,Lp,angles,center):
        (omega,phi,psi)=angles
        (xm,ym,zm)=center
				...

 

bodyRotation ν•¨μˆ˜λŠ” rot λ³€μˆ˜μ— λͺΈμ²΄ 각도 정보λ₯Ό μ €μž₯ν•˜μ—¬ μΆ”ν›„ λͺ¨ν„° 각도λ₯Ό κ³„μ‚°ν• λ•Œ

(calcIKν•¨μˆ˜μ—μ„œ rot λ³€μˆ˜λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.) λ‘œλ΄‡ λͺΈμ²΄κ°€ 기운 것에 λŒ€ν•œ 보상을 ν•  수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

 

즉, λ°”λ‹₯이 κΈ°μšΈμ–΄μ Έ λ‘œλ΄‡μ˜ λͺΈμ²΄κ°€ κΈ°μšΈμ—ˆμ„λ•Œ λ‹€λ¦¬μ˜ μžμ„Έλ₯Ό λ³€κ²½ν•˜μ—¬ λͺΈμ²΄μ˜ 각도가 μ™ΈλΆ€μ˜ μ’Œν‘œκ³„ μž…μž₯μ—μ„œ μΌμ •ν•˜κ²Œ μœ μ§€ν•  수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

 

  • λ‹€μŒμœΌλ‘œ, λ‘œλ΄‡μ˜ λͺ¨ν„°λ₯Ό μ œμ–΄ν•˜κΈ° μœ„ν•œ 각도λ₯Ό 받아와 LaDian λ³€μˆ˜μ— μ €μž₯ν•˜λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€.

⇒ 디버깅을 μœ„ν•΄ 이 뢀뢄이 μ½˜μ†”μ— 좜λ ₯λ©λ‹ˆλ‹€.

				LaDian = robot.getAngle()
        print(LaDian)

...

# spotmicroai.py
def step(self):

        if (self.useRealTime):
            self.t = time.time() - self.ref_time
        else:
            self.t = self.t + self.fixedTimeStep

        # print(self.t)

        kp=self.IDkp # p.readUserDebugParameter(self.IDkp)
        kd=self.IDkd #p.readUserDebugParameter(self.IDkd)
        maxForce=self.IDmaxForce #p.readUserDebugParameter(self.IDmaxForce)

        # Calculate Angles with the input of FeetPos,BodyRotation and BodyPosition
        self.angles = self.kin.calcIK(self.Lp, self.rot, self.pos)
				...
  • 이 angle은 spotmicroai.py 파일 μ•ˆμ˜ step ν•¨μˆ˜μ—μ„œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€.
  • λͺΈμ²΄μ˜ μœ„μΉ˜, 각도, 발의 μœ„μΉ˜ 정보λ₯Ό μž…λ ₯ν•˜λ©΄ calIK ν•¨μˆ˜λ₯Ό 톡해 이 λ™μž‘μ„ κ΅¬ν˜„ν•˜κΈ° μœ„ν•œ 각 κ΄€μ ˆ λͺ¨ν„°μ˜ 각도가 κ³„μ‚°λ˜μ–΄ κ°±μ‹ λ©λ‹ˆλ‹€.

 

λ°›μ•„μ˜¨ λͺ¨ν„° 각도λ₯Ό 각 λ‹€μ΄λ‚˜λ―Ήμ…€μ— μ „λ‹¬ν•˜λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€.

그러면 μ΅œμ’…μ μœΌλ‘œ 보행 νŒ¨ν„΄μ„ 따라 λͺ¨ν„°κ°€ ꡬ동이 λ˜μ–΄ κ±·λŠ” λ™μž‘μ„ μˆ˜ν–‰ν•˜κ²Œ λ©λ‹ˆλ‹€. πŸ•

if len(LaDian):
     
            # ladian to degree
            thetas = DXL_controller.LadianToAngles(LaDian)

            # adjust robot servo
            Goal_Degree = DXL_controller.AngleToServo(DXLMotor_N)

            # degree to dynamixel value
            Goal_Position_Value = DXL_controller.DegreeToDXLValue(Goal_Degree)


            # Real Actuators
            DXL_controller.WriteMotor(DXLMotor_N)
            print(" **** Goal Degree **** ")
            print(Goal_Degree)
        
            
            
            # # Plot Robot Pose into Matplotlib for Debugging
            # TODO: Matplotplib animation
            # kn.initFK(jointAngles)
            # kn.plotKinematics()

        robot.step()
        consoleClear()

 

 

ν‚€λ³΄λ“œ μ‘°μ’…


메인 μ½”λ“œλ₯Ό μ‹€ν–‰ν•œ λ’€, μ‹€μ œ λ‘œλ΄‡μ„ μ „ν›„μ’Œμš°λ‘œ μ΄λ™μ‹œν‚€κΈ° μœ„ν•œ λ°©λ²•μž…λ‹ˆλ‹€.

 

W A S D : κ²Œμž„κ³Ό 같이 μ „ν›„μ’Œμš°λ‘œ λ‘œλ΄‡μ„ μ›€μ§μ΄κ²Œ ν•˜λ©°, ν•œ 번 λˆ„λ₯Ό λ•Œλ§ˆλ‹€ ν•΄λ‹Ή λ°©ν–₯으둜의 속도가 μ¦κ°€ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.

Q E : μ‹œκ³„λ°©ν–₯, λ°˜μ‹œκ³„λ°©ν–₯으둜 λ‘œλ΄‡μ„ νšŒμ „ + μ΄λ™μ‹œν‚€κ²Œ λ©λ‹ˆλ‹€.

 

예λ₯Ό λ“€μ–΄

  • W 10번 + S 5λ²ˆμ„ λˆ„λ₯΄λ©΄ W 5번 만큼의 전진 속도λ₯Ό κ°–κ³  λ‘œλ΄‡μ΄ μ›€μ§μž…λ‹ˆλ‹€.