라즈베리파이 실습

Chat GPT를 활용하여 다이나믹셀 구동하는 예제살펴보기

Channel_B2 2023. 3. 17. 23:01

안녕하세요. 꿈꾸는 로봇입니다.
Chat GPT를 활용하여 리눅스에서 동작하는 AX12를 살펴볼 예정이구요.
동시 동작을 요구 했으나, 처음에 순차적으로 움직이는 예제를 주더라구요.
그래서 둘다 올려보기로 하겠습니다.
질문 : AX12 모터를 3개 동시에 Sync write 로 움직일 수 있는 코드를 모두 작성해줘

import dynamixel_sdk as dxl

# Dynamixel SDK 초기화
portHandler = dxl.PortHandler("COM1")  # 포트 번호는 연결된 컴퓨터에 따라 다를 수 있음
packetHandler = dxl.PacketHandler(1.0) # 프로토콜 버전은 1.0으로 설정

# 모터 ID 설정
ID_1 = 1
ID_2 = 2
ID_3 = 3

# 모터 설정
ADDR_AX12_GOAL_POSITION = 30
ADDR_AX12_MOVING_SPEED = 32

# 모터 속도 설정
MOVING_SPEED = 200

# Sync write 그룹 생성
groupSyncWrite = dxl.GroupSyncWrite(portHandler, packetHandler, ADDR_AX12_GOAL_POSITION, 2)

# 목표 위치 설정
goal_position_1 = 500
goal_position_2 = 1000
goal_position_3 = 1500

# Sync write 그룹에 데이터 추가
dxl.addSyncWriteParam(groupSyncWrite, ID_1, dxl.encode2Byte(goal_position_1))
dxl.addSyncWriteParam(groupSyncWrite, ID_2, dxl.encode2Byte(goal_position_2))
dxl.addSyncWriteParam(groupSyncWrite, ID_3, dxl.encode2Byte(goal_position_3))

# 모터 속도 설정
dxl.write1ByteTxRx(portHandler, ID_1, ADDR_AX12_MOVING_SPEED, MOVING_SPEED)
dxl.write1ByteTxRx(portHandler, ID_2, ADDR_AX12_MOVING_SPEED, MOVING_SPEED)
dxl.write1ByteTxRx(portHandler, ID_3, ADDR_AX12_MOVING_SPEED, MOVING_SPEED)

# Sync write 그룹 실행
dxl.groupSyncWriteTxPacket(groupSyncWrite)

위의 내용은 Chat GPT가 작성해준 내용이구요. 처음엔 훌륭하다고 생각되어 그대로 붙여넣기 하여 구동 하였지만 여러 에러가 발생하였습니다.

참고로 위의 버전은 순차적으로 동작하는 내용입니다.

그리고 groupSyncWrite를 이용해서
# 라이브러리 import
from dynamixel_sdk import *
import time

# 사용할 포트와 프로토콜 버전 설정
PORT = '/dev/ttyUSB0'
BAUDRATE = 57600
PROTOCOL_VERSION = 1.0

# 모터 ID와 모터의 최대, 최소 각도 설정
ID = [1, 2, 3]
MIN_ANGLE = 0
MAX_ANGLE = 1023

# 포트 열기
portHandler = PortHandler(PORT)
portHandler.openPort()

# 포트 설정
packetHandler = PacketHandler(PROTOCOL_VERSION)
packetHandler.setBaudRate(BAUDRATE)

# 모터 초기 설정
for id in ID:
    dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, id, 24, 1) # 모터 회전 가능하도록 설정
    dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, id, 6, MIN_ANGLE) # 모터 최소 각도 설정
    dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, id, 8, MAX_ANGLE) # 모터 최대 각도 설정

# groupSyncWrite 객체 생성
groupSyncWrite = GroupSyncWrite(portHandler, packetHandler, 30, 2)

# 모터 동작
while True:
    for id in ID:
        dxl_addparam_result = groupSyncWrite.addParam(id, 512) # 모터 각도 추가
    dxl_comm_result = groupSyncWrite.txPacket() # 모터 각도 한 번에 설정
    groupSyncWrite.clearParam() # 추가한 모터 각도 제거
    time.sleep(1) # 1초간 대기

# 포트 닫기
portHandler.closePort()

동시 동작 코드는 위와 같게 답변을 주었으나 목표값이 옳지 않다합니다.


 
그리고 아래는 제가 추가 및 수정한 내용이구요.

from dynamixel_sdk import *
import time

# 사용할 포트와 프로토콜 버전 설정
PORT = '/dev/ttyUSB0'
BAUDRATE = 1000000
PROTOCOL_VERSION = 1.0

# 모터 ID와 모터의 최대, 최소 각도 설정
ID = [9, 6, 8]
MIN_ANGLE = 0
MAX_ANGLE = 1023

index=0
# 포트 열기
portHandler = PortHandler(PORT)
portHandler.openPort()

# 포트 설정
packetHandler = PacketHandler(PROTOCOL_VERSION)
#packetHandler.setBaudRate(BAUDRATE)

portHandler.setBaudRate(BAUDRATE)

# 모터 초기 설정
for id in ID:
    dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, id, 24, 1) # 모터 회전 가능하도록 설정
    dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, id, 6, MIN_ANGLE) # 모터 최소 각도 설정
    dxl_comm_result, dxl_error = packetHandler.write2ByteTxRx(portHandler, id, 8, MAX_ANGLE) # 모터 최대 각도 설정




# groupSyncWrite 객체 생성
groupSyncWrite = GroupSyncWrite(portHandler, packetHandler, 30, 4)



while True:
    print("시작")
    dxl_goal_position = [0, 512, 1023] #순차적으로 goal Position에 접근한다.

    param_goal_position =[DXL_LOBYTE(DXL_LOWORD(dxl_goal_position[index])), DXL_HIBYTE(DXL_LOWORD(dxl_goal_position[index])), DXL_LOBYTE(DXL_HIWORD(dxl_goal_position[index])), DXL_HIBYTE(DXL_HIWORD(dxl_goal_position[index]))]


# 모터 동작
#while True:
    for id in ID:
        dxl_addparam_result = groupSyncWrite.addParam(id, param_goal_position) # 모터 각도 추가
    dxl_comm_result = groupSyncWrite.txPacket() # 모터 각도 한 번에 설정
    groupSyncWrite.clearParam() # 추가한 모터 각도 제거
    index=index++1
    print(index)
    time.sleep(3) # 3초간 대기
   

# 포트 닫기
portHandler.closePort()

처음 적었던 프로그램과 차이점을 보면 될 것 같습니다. 
제가 수정한 부분 혹은 추가 내용부분은 두가지입니다.
1. packetHandler.setBaudRate(BAUDRATE) 부분
portHandler.setBaudRate(BAUDRATE)로 수정하여 작업합니다.
 Q : 두개 차이점을 알려줘
A:packetHandler.setBaudRate(BAUDRATE)와 portHandler.setBaudRate(BAUDRATE)는 모두 Dynamixel 모터와 통신하기 위해 시리얼 포트의 Baudrate를 설정하는 코드입니다.
하지만, 이 두 코드는 서로 다른 오브젝트를 다루기 때문에 차이점이 있습니다.
packetHandler.setBaudRate(BAUDRATE)는 PacketHandler 클래스의 메서드이며, Dynamixel SDK v2.x에서 사용 가능합니다. 이 메서드는 시리얼 포트의 Baudrate를 설정하는 대신, PacketHandler 오브젝트의 프로토콜 버전에 따라서 시리얼 포트의 Baudrate를 자동으로 설정합니다. 따라서, PacketHandler 오브젝트를 생성할 때 프로토콜 버전을 제대로 설정해야 올바른 Baudrate로 설정됩니다.
반면, portHandler.setBaudRate(BAUDRATE)는 PortHandler 클래스의 메서드이며, 모든 SDK 버전에서 사용 가능합니다. 이 메서드는 PortHandler 오브젝트가 관리하는 시리얼 포트의 Baudrate를 직접 설정합니다.
따라서, SDK 버전에 따라서 packetHandler.setBaudRate(BAUDRATE)와 portHandler.setBaudRate(BAUDRATE) 중 하나를 사용해야 합니다. 만약 SDK v1.x을 사용하고 있다면 packetHandler 오브젝트 대신 portHandler 오브젝트를 사용하여 portHandler.setBaudRate(BAUDRATE)를 호출해야 합니다.
 
 
 
2. 그리고 param_goal_position이 추가되었는데요 이건 아마 패킷의 순서대로 값을 넣어줘야 한꺼번에 Set될 수 있게 하는걸로 보입니다. 
그저 ChatGPT는 param_goal_position 에 Position에 대한 정수값을 바로 지정주었습니다.
Q:  param_goal_position에 대해 알려줘
A: 위 코드는 dxl_goal_position 리스트에 저장된 모터의 목표 위치 값을 4바이트로 분할하여 param_goal_position 리스트에 저장하는 코드입니다.
Dynamixel 모터는 16비트(2바이트)의 데이터를 한 번에 전송할 수 있습니다. 하지만, 목표 위치 값은 32비트(4바이트)의 데이터이므로, 2바이트씩 끊어서 전송해야 합니다. 이때, 하위 16비트와 상위 16비트를 각각 2바이트씩 나누어야 하므로, 총 4바이트를 param_goal_position 리스트에 저장하는 것입니다.
위 코드에서 DXL_LOBYTE와 DXL_HIBYTE는 주소값의 하위 1바이트와 상위 1바이트를 추출하는 매크로 함수입니다. DXL_LOWORD와 DXL_HIWORD는 주소값의 하위 2바이트와 상위 2바이트를 추출하는 매크로 함수입니다. 이러한 매크로 함수를 사용하여 dxl_goal_position[index] 값을 하위 16비트와 상위 16비트로 나누고, 다시 하위 1바이트와 상위 1바이트로 나누어 param_goal_position 리스트에 저장하고 있습니다.
따라서, param_goal_position 리스트는 [하위 1바이트, 상위 1바이트, 하위 1바이트, 상위 1바이트]의 형태로 구성되어 있으며, 이 값은 sync_write_packet() 함수를 호출하여 모터들에게 동시에 목표 위치 값을 전송할 때 사용됩니다.
정수를 넣을 수 없다는 에러메시지가 발생하여 Sync_write 예제문을 들고와서 삽입한 내용입니다.그리고 최종적으로 TEST가 잘 되었고, 지금은 3개를 하였지만 앞으로 12개를 움직여 볼 수 있도록 해야겠습니다. 
 
이상입니다.