Skip to content

Motion control

Before you start, make sure you have completed the four steps in Setup and self-check, especially the step 4 motion check.

This drives a real motor

Before running, clear the fingers' range of motion, keep your hands away from the gripper, and make sure you can cut the 24V at any moment. For a follower gripper on a robot, test first with the robot stationary.

Keyboard control

For the first motion, the keyboard console is recommended:

python python/examples/gripper_console.py left
Key Action
j / k Open / close one step
o / c Fully open / fully close
h Hold at the current position
d / e Release the motor / resume control
f Clear fault
q or Esc Quit

The default is impedance control. To grasp with a set force, add --mode force-position --grasp-torque 0.6 (grip force in N·m, no more than 1.1).

Two control modes

Impedance control (default) Force-position control
Suited to Following an opening: teleoperation, following the leader gripper, running a policy Grasping an object with a set force
When blocked by an object Presses with 1.1N·m Presses with the set grip force and reports that it is holding

The opening is expressed from 0 to 1: 0 = closed, 1 = open.

Control from a program

Impedance control:

import time
import xense.taccap as t

g = t.FollowerGripper(t.find_follower().mcu_device)
cfg = t.ImpedanceConfig.for_spec(g.motor.get_spec())

g.motor.clear_fault()
with t.ImpedanceController(g, cfg) as c:   # stops and releases the motor automatically on leaving the with block
    g.motor.enable()
    c.set_target(0.0)                       # close
    time.sleep(2)
    print("opening", c.snapshot().observation.position)
    c.set_target(1.0)                       # open
    time.sleep(2)

For teleoperation or running a policy, just call c.set_target(opening) once per cycle in your control loop; there is no need to wait.

Force-position control uses a different config and controller; everything else is the same:

cfg = t.ForcePositionConfig.for_spec(g.motor.get_spec())
cfg.grasp_torque_nm = 0.6                   # grip force, no more than 1.1 N·m

g.motor.clear_fault()
with t.ForcePositionController(g, cfg) as c:
    g.motor.enable()
    c.set_target(0.0)                       # close to grasp
    time.sleep(2)
    print("holding" if c.snapshot().holding else "nothing gripped")
    c.release()                             # release
    time.sleep(2)

Key points:

  • Always generate the config with for_spec(g.motor.get_spec()), and change only the grip force as needed.
  • Start the controller first, then g.motor.enable(); the code above already follows this order.
  • Run only one controller per gripper at a time.
  • Force-position control follows a streamed target about one send interval behind (about 20ms at 50Hz), in exchange for smooth motion.
  • While controlling, read opening, velocity, torque and temperature from c.snapshot().observation; do not read the motor state separately.
  • Interface details and example scripts are in API and examples.

The gripper releases when control stops or the link drops

When the controller stops (leaving the with block, program exit), when you press d / q in the console, or when USB disconnects, the gripper releases, and whatever it is holding will drop. When the robot is holding an object, put the object somewhere safe before stopping control.

Holding for a long time reduces the grip force

As the motor heats up, the firmware automatically reduces output. In testing, holding at 1.1N·m for 10 minutes brought the motor to about 70°C; at 0.6N·m it settled at about 49°C. If you need to hold continuously for tens of minutes, lower the grip force to around 0.6N·m.

Faults and recovery

When the controller detects an anomaly it stops and releases its torque; c.snapshot().state becomes FAULT, and the reason is in c.snapshot().fault_reason. Once the cause is removed, call g.motor.clear_fault() and then c.reset() to continue; if it cannot recover, power-cycle the gripper. For common causes, see Troubleshooting.