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

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

[Spot Dynamixel - 3] Dynamixel Example ์ฝ”๋“œ

 

๐Ÿ’‰

Dynamixel Example Code

Path, import

DynamixelSDK/python/tests ๋‚ด์˜ Python read write protocol 1.0.py ๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


os.sys.path.append('../dynamixel_functions_py')             # Path setting

import dynamixel_functions as dynamixel                     # Uses DYNAMIXEL SDK library
  • dynamixel_functions_py ํŒจํ‚ค์ง€๋‚ด์— dynamixel_functions ๋ฅผ import ํ•ด์ค๋‹ˆ๋‹ค.

 

Address / Protocol

# Control table address
ADDR_MX_TORQUE_ENABLE       = 24                            # Control table address is different in Dynamixel model
ADDR_MX_GOAL_POSITION       = 30
ADDR_MX_PRESENT_POSITION    = 36

# Protocol version
PROTOCOL_VERSION            = 1                             # See which protocol version is used in the Dynamixel
  • ์ž์‹ ์˜ ๋ชจํ„ฐ์— ์•Œ๋งž๋Š” protocol ๋ฒ„์ „๊ณผ address๋ฅผ ๊ธฐ์ž…ํ•ฉ๋‹ˆ๋‹ค.
  • ์ž์„ธํ•œ ์ •๋ณด๋Š” Dynamixel ํ™ˆํŽ˜์ด์ง€ ๋‚ด ๋ชจํ„ฐ manual์— ๊ธฐ์ž…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.⇒ ์˜ˆ๋ฅผ ๋“ค์–ด, AX-12 / AX-12A๋Š” ๋‹ค์Œ ์œ„์น˜์— ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.
ROBOTIS e-Manual
Edit on GitHub NOTE : AX-12+ is the improved version of existing AX-12; the design of circuit, material, and wheel gear are specially improved. NOTE : AX-12A is a new version of the AX-12+ with the same performance but more advanced external design. Only the AX-12A is now being sold.
https://emanual.robotis.com/docs/en/dxl/ax/ax-12a/#control-table-data-address

 

Motor Parameter

# Default setting
DXL_ID                      = 1                             # Dynamixel ID: 1
BAUDRATE                    = 1000000
DEVICENAME                  = "/dev/ttyUSB0".encode('utf-8')# Check which port is being used on your controller
                                                            # ex) Windows: "COM1"   Linux: "/dev/ttyUSB0"

TORQUE_ENABLE               = 1                             # Value for enabling the torque
TORQUE_DISABLE              = 0                             # Value for disabling the torque
DXL_MINIMUM_POSITION_VALUE  = 100                           # Dynamixel will rotate between this value
DXL_MAXIMUM_POSITION_VALUE  = 4000                          # and this value (note that the Dynamixel would not move when the position value is out of movable range. Check e-manual about the range of the Dynamixel you use.)
DXL_MOVING_STATUS_THRESHOLD = 10                            # Dynamixel moving status threshold

DXL_ID

  • ๊ฐ ๋ชจํ„ฐ๊ฐ€ ๊ฐ€์ง„ ๊ณ ์œ ํ•œ ID์ด๋ฉฐ, ์˜ฌ๋ฐ”๋ฅธ ์„ค์ •์ด ๋˜์–ด ์žˆ์–ด์•ผ ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจํ„ฐ์˜ ID ๋Š” ์œ„์˜ ์†Œํ”„ํŠธ์›จ์–ด(Dynamixel Wizard)๋ฅผ ๊น”๊ณ  ์ปดํ“จํ„ฐ์™€ ์—ฐ๊ฒฐํ•˜๋ฉด ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

DEVICENAME

  • ํ˜ธ์ŠคํŠธ PC์—์„œ ์ธ์‹ํ•˜๋Š” Dynamixel ์˜ ์ด๋ฆ„์ด๋ฉฐ, ์šด์˜์ฒด์ œ์— ๋”ฐ๋ผ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

linux

  • $ dmesg | grep tty ๋ฅผ ํ†ตํ•ด /dev/ttyUSB0 ์ด ์—ฐ๊ฒฐ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณดํ†ต ํ•˜๋‚˜์˜ ์—ฐ๊ฒฐ๋งŒ ์žˆ๋‹ค๋ฉด /dev/ttyUSB0 ์— ์šฐ์„  ์—ฐ๊ฒฐ๋˜๋ฉฐ, 2๊ฐœ ์ด์ƒ์ธ ๊ฒฝ์šฐ /dev/ttyUSB1 ๋“ฑ์œผ๋กœ ์ด๋ฆ„์ด ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค.

window

  • ์ œ์–ดํŒ - ์žฅ์น˜๊ด€๋ฆฌ์ž - ํฌํŠธํƒญ์—์„œ ํ™•์ธํ™œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ชจํ„ฐ๋Š” ๊ฐ๋„๊ฐ€ ์•„๋‹Œ position value๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ชจํ„ฐ๋ฅผ ์ œ์–ดํ•œ๋‹ค. position value๊ฐ€ ์–ด๋–ค ๊ฐ๋„์— mapping ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ ํ•„์ˆ˜

 

 

port number, packetHandler

# Initialize PortHandler Structs
# Set the port path
# Get methods and members of PortHandlerLinux or PortHandlerWindows
port_num = dynamixel.portHandler(DEVICENAME)

# Initialize PacketHandler Structs
dynamixel.packetHandler()

index = 0
dxl_goal_position = [DXL_MINIMUM_POSITION_VALUE, DXL_MAXIMUM_POSITION_VALUE]         # Goal position

dxl_present_position = 0                                    # Present position
  • ์ด ๋ถ€๋ถ„์—์„œ๋Š” ํŠน๋ณ„ํžˆ ์„ค์ •ํ•  ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค.
  • ์œ„์—์„œ ์„ค์ •ํ•œ DEVICENAME์— ๋”ฐ๋ผ์„œ port num์ด ์„ค์ •๋˜๊ณ  ํŒจํ‚ท ๊ตฌ์„ฑ ๋ฐ ํŒจํ‚ท ์ €์žฅ์— ์‚ฌ์šฉ๋˜๋Š” ํŒจํ‚ท๊ตฌ์„ฑ์— ์‚ฌ์šฉ๋˜๋Š” paramerter๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

 

Setup


# Open port
if dynamixel.openPort(port_num):
    print("Succeeded to open the port!")
else:
    print("Failed to open the port!")
    print("Press any key to terminate...")
    msvcrt.getch()
    quit()

# Set port baudrate
if dynamixel.setBaudRate(port_num, BAUDRATE):
    print("Succeeded to change the baudrate!")
else:
    print("Failed to change the baudrate!")
    print("Press any key to terminate...")
    msvcrt.getch()
    quit()

# Enable Dynamixel Torque
dynamixel.write1ByteTxRx(port_num, PROTOCOL_VERSION, DXL_ID, ADDR_MX_TORQUE_ENABLE, TORQUE_ENABLE)
if dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION) != COMM_SUCCESS:
    dynamixel.printTxRxResult(PROTOCOL_VERSION, dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION))
elif dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION) != 0:
    dynamixel.printRxPacketError(PROTOCOL_VERSION, dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION))
else:
    print("Dynamixel has been successfully connected")
  • Open port : ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋‹ค์ด๋‚˜๋ฏน์…€๊ณผ ํ†ต์‹ ํ•˜๊ธฐ ์œ„ํ•ด port๋ฅผ ์—ฝ๋‹ˆ๋‹ค.
  • Set port baudrate : ํ†ต์‹  baudrate๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Enable Dynamixel Torquewrite1ByteTxRx() : DXL_ID์˜ id๋ฅผ ๊ฐ€์ง„ ๋ชจํ„ฐ์—๊ฒŒ TORQUE_ENABLE value ์ธ 1byte๋ฅผ ADDR_MX_TORQUE_ENABLE address ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  •  

Read and Write Dynamixel motor


while 1:
    print("Press any key to continue! (or press ESC to quit!)")
    if msvcrt.getch().decode() == chr(ESC_ASCII_VALUE):
        break

    # Write goal position
    dynamixel.write2ByteTxRx(port_num, PROTOCOL_VERSION, DXL_ID, ADDR_MX_GOAL_POSITION, dxl_goal_position[index])
    if dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION) != COMM_SUCCESS:
        dynamixel.printTxRxResult(PROTOCOL_VERSION, dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION))
    elif dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION) != 0:
        dynamixel.printRxPacketError(PROTOCOL_VERSION, dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION))

    while 1:
        # Read present position
        dxl_present_position = dynamixel.read2ByteTxRx(port_num, PROTOCOL_VERSION, DXL_ID, ADDR_MX_PRESENT_POSITION)
        if dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION) != COMM_SUCCESS:
            dynamixel.printTxRxResult(PROTOCOL_VERSION, dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION))
        elif dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION) != 0:
            dynamixel.printRxPacketError(PROTOCOL_VERSION, dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION))

        print("[ID:%03d] GoalPos:%03d  PresPos:%03d" % (DXL_ID, dxl_goal_position[index], dxl_present_position))

        if not (abs(dxl_goal_position[index] - dxl_present_position) > DXL_MOVING_STATUS_THRESHOLD):
            break

    # Change goal position
    if index == 0:
        index = 1
    else:
        index = 0
  • Enable Dynamixel Torque์™€ ๊ฐ™์€ ๋ฐฉ์‹์ด๋ฉฐ ๊ฐ ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.write2ByteTxRx() : dxl_goal_position[index] ์ธ ๋ชฉํ‘œ position value๋ฅผ ์ „๋‹ฌ
  • read2ByteTxRx() : ํ˜„์žฌ position value๋ฅผ ์ฝ์–ด์˜ค๊ธฐ

 

Exit

# Disable Dynamixel Torque
dynamixel.write1ByteTxRx(port_num, PROTOCOL_VERSION, DXL_ID, ADDR_MX_TORQUE_ENABLE, TORQUE_DISABLE)
if dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION) != COMM_SUCCESS:
    dynamixel.printTxRxResult(PROTOCOL_VERSION, dynamixel.getLastTxRxResult(port_num, PROTOCOL_VERSION))
elif dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION) != 0:
    dynamixel.printRxPacketError(PROTOCOL_VERSION, dynamixel.getLastRxPacketError(port_num, PROTOCOL_VERSION))


# Close port
dynamixel.closePort(port_num)
  • Dynamixel Torque๋ฅผ Disable ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ , port๋ฅผ ๋‹ซ์Šต๋‹ˆ๋‹ค.

 

 

์ฝ”๋“œ ์‹คํ–‰์‹œ ์˜ค๋ฅ˜๊ฐ€ ๋‚  ๊ฒฝ์šฐ

permission ๊ด€๋ จ ์˜ค๋ฅ˜๊ฐ€ ๋‚  ๊ฒฝ์šฐ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ํ•œ๋ฒˆ ์‹คํ–‰์‹œํ‚ค๊ณ  ์ง„ํ–‰ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

 

sudo chmod -R 777 /dev/ttyUSB0