How to use PWM Control Mode?


DYNAMIXEL Servo:

  • 2XL430-W250
  • XM430-W350

DYNAMIXEL Controller:

  • DYNAMIXEL Starter Set

Software Interface:

Python and Matlab.


Issue:

I want to use the PWM mode of the Dynamixel motors. What I want to do are two things:

  • Send a direct PWM to the motor using torque mode.
  • Make the motor rotate from left to right, meaning it can move in the opposite direction.
    I have modified the read_write.py file, but I get the following problems:

– When I send a negative signal it gives the following:

Py-2

– When I send a positive signal it gives this:
Py20

– Only when I send it 1 do I get 1 in the current pwm:

Py1

This is the code I’m using:

from dynamixel_sdk import *                    # Uses Dynamixel SDK library

#Control table address
ADDR_OPERATING_MODE         = 11               # Control table address is different in Dynamixel model
ADDR_PRO_TORQUE_ENABLE      = 64               # Control table address is different in Dynamixel model
ADDR_PRO_GOAL_PWM      = 100
ADDR_PRO_PRESENT_PWM   = 124


# Protocol version
PROTOCOL_VERSION            = 2.0               # See which protocol version is used in the Dynamixel

# Default setting
DXL_ID                      = 1                 # Dynamixel ID : 1
BAUDRATE                    = 57600             # Dynamixel default baudrate : 57600
DEVICENAME                  = 'COM12'           #'/dev/ttyUSB0'    # Check which port is being used on your controller
                                                # ex) Windows: "COM1"   Linux: "/dev/ttyUSB0" Mac: "/dev/tty.usbserial-*"

TORQUE_ENABLE               = 1                 # Value for enabling the torque
TORQUE_DISABLE              = 0                 # Value for disabling the torque
PWM_CONTROL_MODE            = 16                         # Value for extended position control mode (operating mode)

index = 0

portHandler = PortHandler(DEVICENAME)

packetHandler = PacketHandler(PROTOCOL_VERSION)

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


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


# Set operating mode to extended position control mode
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_OPERATING_MODE, PWM_CONTROL_MODE)
if dxl_comm_result != COMM_SUCCESS:
    print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
    print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
    print("Operating mode changed to extended position control mode.")

# Enable Dynamixel Torque
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_ENABLE)

if dxl_comm_result != COMM_SUCCESS:
    print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
    print("%s" % packetHandler.getRxPacketError(dxl_error))
else:
    print("Dynamixel has been successfully connected")


i = 0

while 1:
    print("Press any key to continue! (or press ESC to quit!)")
    if getch() == chr(0x1b):
        break



    while 1: 
        i = i+1 
        pwm = 0.113   
        # Write goal position
        dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_GOAL_PWM, pwm)
        if dxl_comm_result != COMM_SUCCESS:
            print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
        elif dxl_error != 0:
            print("%s" % packetHandler.getRxPacketError(dxl_error))

        dxl_present_pwm, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_PRESENT_PWM)
        if dxl_comm_result != COMM_SUCCESS:
            print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
        elif dxl_error != 0:
            print("%s" % packetHandler.getRxPacketError(dxl_error))

        print("[ID:%03d] GoalPwm:%03d  PresPwm:%03d" % (DXL_ID, pwm, dxl_present_pwm))
            
        if i ==50:
            i=0
            break


# Disable Dynamixel Torque
dxl_comm_result, dxl_error = packetHandler.write1ByteTxRx(portHandler, DXL_ID, ADDR_PRO_TORQUE_ENABLE, TORQUE_DISABLE)
if dxl_comm_result != COMM_SUCCESS:
    print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
elif dxl_error != 0:
    print("%s" % packetHandler.getRxPacketError(dxl_error))

# Close port
portHandler.closePort()

According to the Control Table of XL-430 the Goal PWM is a 2-byte integer (positive or negative) but you used a floating point number to set it. Most likely this is the issue

Also you have to Torque Off before you can change the Operating Mode to PWM then Torque On again to set Goal PWM

I appreciate your response. I convert the signal to bytes but it gives me the following error.

Rp1

This is the code:

   while 1: 
        i = i+1 
        integer_value = 50
        num_bytes = 2  # Number of bytes for the representation

        # Convert integer to bytes (big-endian)
        pwm = integer_value.to_bytes(num_bytes, byteorder='big')
        #pwm = 0.113   
        
        
        
        # Write goal position
        dxl_comm_result, dxl_error = packetHandler.write4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_GOAL_PWM, pwm)
        if dxl_comm_result != COMM_SUCCESS:
            print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
        elif dxl_error != 0:
            print("%s" % packetHandler.getRxPacketError(dxl_error))

        dxl_present_pwm, dxl_comm_result, dxl_error = packetHandler.read4ByteTxRx(portHandler, DXL_ID, ADDR_PRO_PRESENT_PWM)
        if dxl_comm_result != COMM_SUCCESS:
            print("%s" % packetHandler.getTxRxResult(dxl_comm_result))
        elif dxl_error != 0:
            print("%s" % packetHandler.getRxPacketError(dxl_error))

        print("[ID:%03d] GoalPwm:%03d  PresPwm:%03d" % (DXL_ID, pwm, dxl_present_pwm))
            
        if i ==50:
            i=0
            break

So sorry, I meant just to use “simple” integer values

pwm = 200

or

pwm = -250

And the Python Interpreter took care of things in the background.

image

Thanks, I already managed to make it work in one direction of rotation. When I sent the negative value I got the out of range message. How could I change the direction of rotation?

I also have an extra doubt, when I sent 200 pwm, at times when reading the present value of the PWM it gave me very large numbers that do not correspond to the value I want to send.

Q1
Q2

That part I do not know!

I just ran my 2XL-430 via Dynamixel Wizard (with a U2D2), and I got my DXL to work OK.

Goal PWM and Present PWM are the same numbers. Present Velocity is a bit jittery.

image

I am wondering if Python and Matlab are interfering? If you have bought the DXL Starter Set you should have the U2D2 module, right? Can you run your DXLs through DXL Wizard 2 and see if you get the same results as mine?

You really should not have to “constantly” adjust the Goal PWM, just set it only once, and you can see that the DXL is in turning in the right direction in continuous turn mode. Is this motion what you want?

I get the same result as shown in the image.

I already managed to make it go in the opposite direction. What I did was give it this hexadecimal number: 0xff38 which in decimal is 65336 but in the second signed complement it gives -200. So I understand that Python converts the number it receives to the signed second complement.

It is true that the DXL packet uses 2-complement for negative integers and little endian format. And the DXL SDK is supposed to do all that for you in the background code. Did you mean that you had to implement all those operations yourself?

Yes, the entire procedure must be done to use PWM.

In that case you need to report this issue to the ROBOTIS GitHub so that maybe it can be fixed in the SDK in the future.