You're reading the documentation for an older, but still supported version (1.33.4).
For information on the latest version, please have a look at 1.33.5.

torque_rt

This function performs real-time motor torque control from an external controller. It allows direct torque streaming to each joint motor through UDP-based real-time communication. This mode is typically used for advanced control algorithms such as impedance, admittance, or gravity-compensated torque feedback.

Definition
DRFLEx.h within class CDRFLEx, public section

bool torque_rt(float fMotorTor[NUM_JOINT],
               float fTargetTime) {
    return _torque_rt(_rbtCtrlUDP, fMotorTor, fTargetTime);
};

Parameter

Parameter Name

Data Type

Default Value

Description

fMotorTor

float[6]

Target torque [Nm], on the same basis as gravity_torque in read_data_rt, so the two can be added directly. Every value must be finite.

fTargetTime

float

Target interpolation duration [s].

Note

  • Asynchronous command.

  • Each command starts a new ramp from the torque the joint measures at that moment and reaches fMotorTor after fTargetTime. A new command restarts the ramp, so when commands arrive more often than fTargetTime, the commanded torque never reaches fMotorTor. In a 1 ms loop, set fTargetTime to 0.

  • If fTargetTime ≤ controller cycle (~1 ms), the command is executed immediately without interpolation.

  • If the next command is not received before reaching the target torque,
    the last torque input is maintained.

  • Torque commands must keep arriving. If more than 0.1 s passes between them, the controller reports a real-time motion warning, stops the robot with a quick stop and holds its position. Servo power stays on. This limit applies to the torque path specifically and is separate from, and tighter than, the input watchdog configured through set_rt_control_input.

  • The controller adds no gravity or friction compensation to fMotorTor. Add the gravity_torque value from read_data_rt, as the example below does. That value depends on the tool weight and centre of gravity set on the controller and on the installation pose, so keep them correct.

  • The limits set with set_velj_rt, set_accj_rt, set_velx_rt and set_accx_rt do not apply to torque_rt. The joint and TCP speed limits of the safety settings stay monitored while torque_rt is active.

  • control_mode in the RT output data changes from CONTROL_MODE_POSITION (3) to CONTROL_MODE_TORQUE (4) on the first accepted command, and returns to 3 when the robot stops, pauses or times out.

  • The controller accepts torque_rt while the robot is in STATE_STANDBY or STATE_MOVING. A command sent while another motion runs stops that motion and reports a warning. During jogging or hand guiding, the command is ignored without a message.

  • A NaN value, or an abrupt jump in the commanded torque, is a fatal error: the robot stops and servo power turns off.

  • A value above the maximum torque the controller accepts, including infinity, is limited to that maximum, and the controller reports an information message. Check that every value is finite before sending it.

Caution

  • In H-series robots, the second joint has a built-in gravity compensator.
    The commanded torque and the compensator’s torque are summed internally to generate motion. Therefore, when sending external torque commands, users should compensate using the relationship:

    \(gravity\_torque = (link\_gravity\_torque - gravity\_compensator\_torque)\)

  • Excessive or unstable torque commands may cause unexpected motion.

  • It is recommended to use soft torque feedback or compliance control to ensure safe response.

Return

Value

Description

1

The command was sent. This does not confirm that the controller received or applied it.

0

The command datagram could not be sent.

Note

This function is asynchronous. It returns without waiting for the controller to accept or reject the command, so a return value of 1 does not confirm that the robot acted on it. Rejected commands and motion warnings and errors are reported through set_on_log_alarm. set_on_rt_log_alarm reports only RT session messages, so register both callbacks.

Example

The example opens the controller connection with open_connection, obtains control authority, sets Auto mode and turns servo power on before it starts the RT session, because stop is sent over that connection and torque_rt is accepted only in STATE_STANDBY or STATE_MOVING.

#include <atomic>
#include <chrono>
#include <cstdio>
#include <cstring>
#include <thread>

std::atomic<bool> g_bHasControlAuthority(false);

void OnMonitoringAccessControlCB(const MONITORING_ACCESS_CONTROL eAccess)
{
    if (eAccess == MONITORING_ACCESS_CONTROL_GRANT)
        g_bHasControlAuthority = true;
}

// Controller connection: stop() below is sent over it
drfl.set_on_monitoring_access_control(OnMonitoringAccessControlCB);
if (!drfl.open_connection("192.168.137.100")) return 1;
drfl.manage_access_control(MANAGE_ACCESS_CONTROL_FORCE_REQUEST);
while (!g_bHasControlAuthority)
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

if (!drfl.set_robot_mode(ROBOT_MODE_AUTONOMOUS)) return 1;
if (!drfl.set_robot_control(CONTROL_SERVO_ON)) return 1;
while (drfl.get_robot_state() != STATE_STANDBY)
    std::this_thread::sleep_for(std::chrono::milliseconds(100));

drfl.connect_rt_control("192.168.137.100", 12347);

std::string version = "v1.0";
float period = 0.001f;  // 1 ms
int lossCount = 4;

// Start output streaming first. The input watchdog is set after the wait below,
// so it does not count while the example waits for the first RT data.
drfl.set_rt_control_output(version, period, lossCount);
drfl.start_rt_control();

float fMotorTor[6] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f};
float fTargetTime = 0.0f;  // apply each command at once; a ramp would restart every 1 ms

float q[6] = {0.f};
float q_dot[6] = {0.f};
float gravity_torque[6] = {0.f};
float trg_q[6] = {0.f};
float trg_q_dot[6] = {0.f};
float kp[6] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
float kd[6] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0};

// Wait until RT data arrives and its time_stamp advances. Until then,
// read_data_rt() returns zeros, including gravity_torque.
while (drfl.read_data_rt()->time_stamp == 0.0)
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
const double first_stamp = drfl.read_data_rt()->time_stamp;
while (drfl.read_data_rt()->time_stamp == first_stamp)
    std::this_thread::sleep_for(std::chrono::milliseconds(1));

// Hold the current posture: the PD target is the measured joint position.
memcpy(trg_q, drfl.read_data_rt()->actual_joint_position, sizeof(float) * 6);

// Arm the input watchdog right before the 1 ms command loop starts.
drfl.set_rt_control_input(version, period, lossCount);

const float loop_period = 0.001f;  // matches the sleep below
float elapsed = 0.0f;

while (true) {
    // Copy the whole frame once. Holding the pointer is not a snapshot:
    // the buffer keeps being overwritten, so field-by-field copies can mix
    // values from different packets.
    RT_OUTPUT_DATA_LIST frame;
    memcpy(&frame, drfl.read_data_rt(), sizeof(frame));

    memcpy(q,              frame.actual_joint_position, sizeof(float) * 6);
    memcpy(q_dot,          frame.actual_joint_velocity, sizeof(float) * 6);
    memcpy(gravity_torque, frame.gravity_torque,        sizeof(float) * 6);

    // Simple gravity + PD torque controller
    for (int i = 0; i < 6; i++) {
        fMotorTor[i] = gravity_torque[i]
                     + kp[i] * (trg_q[i] - q[i])
                     + kd[i] * (trg_q_dot[i] - q_dot[i]);
    }

    drfl.torque_rt(fMotorTor, fTargetTime);

    // Condition to exit
    elapsed += loop_period;
    if (elapsed > 5.0f) {
        break;
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(1)); // 1 ms RT loop
}

// Exit: hold the arm against gravity, return to position control, then end the RT session.
// stop_rt_control() alone keeps the last torque until the 0.1 s timeout stops the robot.
drfl.torque_rt(gravity_torque, 0.0f);
if (!drfl.stop(STOP_TYPE_SLOW))
    printf("stop failed\n");
drfl.stop_rt_control();
drfl.disconnect_rt_control();

This example demonstrates a joint-space torque control loop using proportional-derivative (PD) feedback combined with gravity compensation.

Tips

  • Use torque_rt for advanced torque-level control or compliance-based applications.

  • Always monitor current joint torque using read_data_rt for feedback verification.

  • Apply smooth torque transitions to avoid abrupt mechanical stress.