How to rotate the Doosan robot tool and avoid servo lock errors

Based on contributions by How-to, salvacmp.

Rotating the Doosan tool or head is done through the A, B, C rotation values of a Cartesian pose (posx). Rotating a large amount in one move can push a joint past its ±360° limit and trigger a servo lock error that requires manually unlocking the servo and restarting the robot. This article covers basic rotation and a helper function that sweeps through the rotation in steps to avoid that error.

What you need

  • A Doosan robot
  • A laptop with DRL Studio (Homberger Hub) installed

Steps

1. Understand the posx rotation values

posx(X=0, Y=0, Z=0, A=0, B=0, C=0)
Input Type Description
X float X coordinate in mm
Y float Y coordinate in mm
Z float Z coordinate in mm
A float Rotation around the Z-axis, in degrees, world coordinates
B float Rotation around the Y-axis, in degrees, world coordinates
C float Rotation around the Z-axis, in degrees, world coordinates

By default the head points up.

2. Rotate the head to point down

Rotating 180° around the Y-axis (B) points the head down. This snippet reads the current pose and returns the same X/Y/Z with the head rotated down:

arm_position, _i = get_current_posx()
return posx(arm_position[0], arm_position[1], arm_position[2], 0, 180, 0)

3. Rotate the head to a specific angle

Once the head points down, you can rotate it around its own axis by a given angle, e.g. to orient a tool. This helper takes an angle in degrees, reads the current position, and keeps the head pointed down while rotating it to that angle:

def angleToAA(angle):
    arm_position, _i = get_current_posx()
    # angle *= -1   # uncomment to invert rotation direction
    return posx(arm_position[0], arm_position[1], arm_position[2], 0, 180, angle)

If the rotation direction is inverted for your setup, uncomment the angle *= -1 line.

4. Avoid servo lock errors on large rotations

If you jump straight to a target angle (e.g. from 10° to 350°), the robot may try to take the shortest path through a joint limit and lock a servo, which then needs to be manually unlocked and the robot restarted. To avoid this, sweep to the target angle in fixed steps instead of moving there directly, and keep track of the head’s current angle between calls.

def rotation_offset(angle):
    # rotation-only offset, combined with the current pose using add_pose()
    return posx(0, 0, 0, 0, 180, angle)

head_angle = 180  # tracks the head's current angle between calls

def rotate_head_angle(angle):
    global head_angle
    max_degrees = 360
    min_degrees = 0

    arm_position, _i = get_current_posx()
    arm_position[3] = 0
    arm_position[4] = 0
    arm_position[5] = 0

    # normalize the target angle into the [min_degrees, max_degrees] range
    while angle > max_degrees:
        angle = angle - 360
    while angle < min_degrees:
        angle = angle + 360

    # step up towards the target angle in 90-degree increments
    while head_angle < angle:
        head_angle += 90
        if head_angle > angle:
            head_angle = angle
        movel(add_pose(arm_position, rotation_offset(head_angle)), vel=30, acc=30)

    # step down towards the target angle in 90-degree increments
    while head_angle > angle:
        head_angle -= 90
        if head_angle < angle:
            head_angle = angle
        movel(add_pose(arm_position, rotation_offset(head_angle)), vel=30, acc=30)

    return 0

The rotate_head_angle() function remembers the head’s last commanded angle in the global head_angle variable and moves towards the new target in 90° steps, instead of jumping there in one move.

5. Use it together with a move to a new position

Call rotate_head_angle() first to bring the head to the correct rotation safely, then perform the actual positional move using the rotation as an offset:

rotate_head_angle(target_angle)

movel(
    add_pose(
        posx(pos_x + x_offset, pos_y + y_offset, pos_z + distance, 0, 0, 0),
        rotation_offset(target_angle),
    ),
    vel=velocity,
    acc=acceleration,
)

Troubleshooting

  • Servo lock error after a rotation: this happens when a joint is commanded past its ±360° limit. If it happens, you need to manually unlock the servo and restart the robot — see How to set up safety area (space) limits on a Doosan robot for the general recovery procedure. Switching to the stepped rotate_head_angle() approach above prevents this in most cases.
  • :warning: Check: this article renames the original angleToAA() helper from the step-4/5 example to rotation_offset(), because the source used the same function name for two different signatures (one returning an absolute pose, one returning a rotation-only offset meant to be combined with add_pose()). Only the name was changed — the logic is unmodified.
  • :warning: Check: the source for this section uses movel(pose, vel=30, acc=30), while other Doosan how-tos use movel(pose, v=20, a=100) (see How to move a Doosan robot with movej, movel, and asynchronous motion commands). Verify which keyword names your DRL Studio version actually expects before relying on either.

Related


Rewritten and consolidated (Sept 2026) from the original student how-to’s: How to use rotations on a Doosan robot, How to rotate Doosan Robot head without going into errors.