안녕하세요. 꿈꾸는 로봇입니다.
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개를 움직여 볼 수 있도록 해야겠습니다.
이상입니다.
'라즈베리파이 실습' 카테고리의 다른 글
ROS2 AX12가동하기 (Chat GPT활용하기) (0) | 2023.03.14 |
---|---|
face detect (0) | 2020.11.18 |
Object Detect - R.P Python With Tensorflow Lite (0) | 2020.11.18 |
파이 카메라를 활용 5초동안 자동 영상 촬영 프로그램 (0) | 2020.11.18 |
라즈베리파이 마우스 클릭으로 사진 촬영 하기 (0) | 2020.11.18 |