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

6.6.4 minimal_welding_sample.cpp

This example (4_minimal_welding_sample.cpp) demonstrates how to configure and execute a digital welding process over EtherNet/IP using the Doosan Robotics API:

  • register monitoring / alarm / access control callbacks

  • open a TCP/IP connection and request control authority

  • turn Servo On and verify system/library versions

  • switch to AUTONOMOUS + REAL mode

  • execute a full DRL-based welding sequence

  • configure the welding interface and motion purely via C++ API and run a weave weld

This example is located in the following path:
API-DRFL/example/Linux_64/4_minimal_welding_sample.cpp

See the example on the Doosan Robotics API-DRFL GitHub.

Watch the full walk-through on the Doosan Robotics Official Youtube.

Note

This sample is implemented for DRCF_VERSION 2. Welding-related APIs are not available yet when building with DRCF_VERSION 3. Support for welding under DRCF v3 will be provided in a future update.

Setup & Global Variables

The sample defines a global controller object, several state flags, and a helper function that returns a DRL welding script as a string.

#define DRCF_VERSION 2

#include <iostream>
#include <cstring>
#include <thread>
#include <chrono>
#include <termios.h>
#include <unistd.h>

#include "../../include/DRFLEx.h"
using namespace DRAFramework;
using namespace std::chrono_literals;

#undef NDEBUG
#include <assert.h>

CDRFLEx Drfl;
bool g_bHasControlAuthority = FALSE;
bool g_TpInitailizingComplted = FALSE;
bool moving = FALSE;
bool bAlterFlag = FALSE;
bool is_standby = FALSE;

std::string IP_ADDR = "192.168.137.100";
std::string getWeldingSampleDrl();

A set of callback handlers is declared to react to TP initialization, homing completion, alarms, popups, TP logs, user input, real-time monitoring data, and disconnection events.

void OnTpInitializingCompleted();
void OnHommingCompleted();
void OnProgramStopped(const PROGRAM_STOP_CAUSE v);
void OnMonitoringDataCB(const LPMONITORING_DATA pData);
void OnMonitoringDataExCB(const LPMONITORING_DATA_EX pData);
void OnMonitoringCtrlIOCB(const LPMONITORING_CTRLIO pData);
void OnMonitoringCtrlIOExCB(const LPMONITORING_CTRLIO_EX2 pData);
void OnMonitoringStateCB(const ROBOT_STATE eState);
void OnMonitroingAccessControlCB(const MONITORING_ACCESS_CONTROL transit);
void OnLogAlarm(LPLOG_ALARM tLog);
void OnTpPopup(LPMESSAGE_POPUP tPopup);
void OnTpLog(const char* strLog);
void OnTpProgress(LPMESSAGE_PROGRESS tProgress);
void OnTpGetuserInput(LPMESSAGE_INPUT tInput);
void OnRTMonitoringData(LPRT_OUTPUT_DATA_LIST tData);
void OnDisConnected();

These globals and callbacks are used to maintain control authority and Servo On state, automatically reconnect on network loss, log alarm and popup messages from the controller, and feed welding status back to the user during execution.

Main Loop

The main loop runs after initialization and waits for a single-character command.

while (true) {
  std::cout << "\ninput key : ";
  char ch;
  std::cin >> ch;

  if (ch == 'q') {
    std::cout << "Exit program..." << std::endl;
    break;   // exit while loop
  }

  switch (ch) {
    case '0':
    {
      // DRL welding sample
      Drfl.drl_start(ROBOT_SYSTEM_REAL, getWeldingSampleDrl());
    }
    break;

    case '1':
    {
      // C++ welding interface + motion sample
      // (configure EtherNet/IP mapping and execute welding motion)
      // ...
    }
    break;

    case '2':
    {
      // Reserved for additional welding tests
    }
    break;

    default:
      break;
  }
}

Drfl.CloseConnection();
return 0;
  • q : gracefully stop the sample and close the connection.

  • 0 : run the DRL-based welding script returned by getWeldingSampleDrl().

  • 1 : configure the welding interface directly via C++ structures and execute a weaving welding motion using amovel with a welding app type.

  • 2 : reserved for future extensions.

Callback Registration

Unlike the minimal instruction example (where callbacks are registered on a key press), this welding sample registers all callbacks at startup before opening the connection.

int main(int argc, char** argv) {

  Drfl.set_on_homming_completed(OnHommingCompleted);
  Drfl.set_on_monitoring_data(OnMonitoringDataCB);
  Drfl.set_on_monitoring_data_ex(OnMonitoringDataExCB);
  Drfl.set_on_monitoring_ctrl_io(OnMonitoringCtrlIOCB);
  // Drfl.set_on_monitoring_ctrl_io_ex(OnMonitoringCtrlIOExCB);
  Drfl.set_on_monitoring_state(OnMonitoringStateCB);
  Drfl.set_on_monitoring_access_control(OnMonitroingAccessControlCB);
  Drfl.set_on_tp_initializing_completed(OnTpInitializingCompleted);
  Drfl.set_on_log_alarm(OnLogAlarm);
  Drfl.set_on_tp_popup(OnTpPopup);
  Drfl.set_on_tp_log(OnTpLog);
  Drfl.set_on_tp_progress(OnTpProgress);
  Drfl.set_on_tp_get_user_input(OnTpGetuserInput);
  Drfl.set_on_rt_monitoring_data(OnRTMonitoringData);
  Drfl.set_on_program_stopped(OnProgramStopped);
  Drfl.set_on_disconnected(OnDisConnected);

  assert(Drfl.open_connection(IP_ADDR));
  // ...
}
  • OnMonitoringStateCB sets is_standby when the robot reaches STATE_STANDBY, which indicates that Servo On is complete.

  • OnMonitroingAccessControlCB tracks whether control authority is GRANT / LOSS / DENY.

  • OnTpInitializingCompleted immediately issues a force request for control authority.

  • OnLogAlarm, OnTpPopup, OnTpLog print diagnostic information to the console.

  • OnDisConnected retries open_connection() in a loop to restore connectivity.

The access control callback is used to update g_bHasControlAuthority whenever the controller changes the access state.

void OnMonitroingAccessControlCB(const MONITORING_ACCESS_CONTROL transit) {
  std::cout << "[AccessControl] state = " << int(transit) << std::endl;

  switch (transit) {
    case MONITORING_ACCESS_CONTROL_GRANT:
      // State where control authority is granted
      g_bHasControlAuthority = true;
      break;
    case MONITORING_ACCESS_CONTROL_LOSS:
    case MONITORING_ACCESS_CONTROL_DENY:
      // State where control authority is lost or denied
      g_bHasControlAuthority = false;
      break;
    default:
      break;
  }
}

When the access-control state changes, the callback prints the numeric value of MONITORING_ACCESS_CONTROL.

[AccessControl] state = 0

Different integer values correspond to the enum constants defined in MONITORING_ACCESS_CONTROL (REQUEST, GRANT, DENY, LOSS, …).

The robot-state callback is responsible for detecting when the robot reaches the standby state after Servo On.

void OnMonitoringStateCB(const ROBOT_STATE eState)
{
  if (eState == STATE_STANDBY) {
    is_standby = true;
    std::cout << "Successfully Servo On !!" << std::endl;}
  else
  {
    is_standby = false;
  }
}

If the controller reports STATE_STANDBY, the sample sets is_standby = true and prints a confirmation message.

Successfully Servo On !!

The main loop later checks is_standby together with g_bHasControlAuthority to confirm that the system is ready for welding.

Alarm information from the controller is reported through the log-alarm callback.

void OnLogAlarm(LPLOG_ALARM tLog) {
cout << "Alarm Info: "
     << "group(" << (unsigned int)tLog->_iGroup << "), index("
     << tLog->_iIndex << "), param(" << tLog->_szParam[0] << "), param("
     << tLog->_szParam[1] << "), param(" << tLog->_szParam[2] << ")" << endl;
}

Example output:

Alarm Info: group(1), index(1037), param(), param(), param()

Each alarm is logged with a group and index code plus up to three string parameters. These values can be cross-referenced with the alarm table in the controller manual to identify the exact cause (e.g., Servo On failure, limit violation, welding interface error, etc.).

Connection to Controller

After registering callbacks, the controller connection is opened via TCP/IP.

assert(Drfl.open_connection(IP_ADDR));

Drfl.setup_monitoring_version(1); // (0 -> older version, 1 -> latest)

SYSTEM_VERSION tSysVerion = {'\0',};
Drfl.get_system_version(&tSysVerion);

Control Authority & Servo On Handling

The sample implements a robust loop to obtain control authority and turn Servo On.

// 1) Retry requesting access + Servo ON up to 10 times
for (size_t retry = 0; retry < 10;
     ++retry, std::this_thread::sleep_for(std::chrono::milliseconds(1000))) {

  if (!g_bHasControlAuthority) {
    // Force request for control authority
    Drfl.ManageAccessControl(MANAGE_ACCESS_CONTROL_FORCE_REQUEST);
    continue;
  }

  if (!is_standby) {
    // Try Servo ON
    Drfl.set_robot_control(CONTROL_SERVO_ON);
    continue;
  }

  if (g_bHasControlAuthority && is_standby)
    break;
}

// 2) State Check
if (!(g_bHasControlAuthority && is_standby)) {
  std::cout << "Failed to reach GRANT + STANDBY state" << std::endl;
  Drfl.CloseConnection();
  return 1;
}

std::cout << "System version: " << tSysVerion._szController << std::endl;
std::cout << "Library version: " << Drfl.get_library_version() << std::endl;
System version: GF03050000
Library version: GL013300

Together with OnMonitoringStateCB, this guarantees that Servo On only proceeds once the controller has granted access and the robot state reaches STANDBY.

Robot Mode & System Configuration

After Servo On, the robot mode and system are configured for welding.

std::cout << "set robot mode ret : "
          << Drfl.set_robot_mode(ROBOT_MODE_AUTONOMOUS) << std::endl;

Drfl.set_robot_system(ROBOT_SYSTEM_REAL);
set robot mode ret : 1

DRL-based Welding Script

Key 0 executes a self-contained DRL script returned by getWeldingSampleDrl().

case '0':
{
  // DRL welding sample
  Drfl.drl_start(ROBOT_SYSTEM_REAL, getWeldingSampleDrl());
}
break;

The DRL string configures welding parameters and motions:

std::string getWeldingSampleDrl() {
  return R"(
set_singular_handling(DR_AVOID)
set_velj(60.0)
set_accj(100.0)
set_velx(250.0, 80.625)
set_accx(1000.0, 322.5)

dry_run = 1
weld_con_adj = 1
arc_sensing_test = False

app_weld_set_interface_eip_r2m_process(welding_start=[1,0,0,0,4,0,1,0,0],
                                       robot_ready=[1,0,0,0,5,0,1,0,0],
                                       error_reset=[1,0,0,1,4,0,1,0,0])
app_weld_set_interface_eip_r2m_mode(...)
app_weld_set_interface_eip_r2m_test(...)
app_weld_set_interface_eip_r2m_condition(...)
app_weld_set_interface_eip_r2m_option(...)
app_weld_set_interface_eip_m2r_process(...)
app_weld_set_interface_eip_m2r_monitoring(...)
app_weld_set_interface_eip_m2r_other(...)

wait(0.5)

app_weld_enable_digital()
wait(1)

app_weld_set_weld_cond_digital(flag_dry_run=dry_run, vel_target=3.0000,
                               vel_min=0.1000, vel_max=100.0000,
                               welding_mode=1, s_2t=0, pulse_mode=0,
                               wm_opt1=0, simulation=0,
                               ts_opt1=0, ts_opt2=0,
                               job_num=4, synergic_id=1, ...)

app_weld_weave_cond_trapezoidal(wv_offset=[0.000,0.000], wv_ang=0.00,
                                wv_param=[0.000,3.0,0.000,-3.0,
                                          0.30,0.10,0.20,0.30,0.10,0.20])

ready_weld_pos = posx(-77.41, -640.26, 119.09, 54.84, 166.79, -48.59 )
movel(ready_weld_pos, radius=0.00, ref=0, mod=DR_MV_MOD_ABS,
      ra=DR_MV_RA_DUPLICATE, app_type=DR_MV_APP_NONE)
wait(1)

end_weld_pos = posx(306.16,-617.1,173.77,54.18,166.75,-49.15)
amovel(end_weld_pos, v=3.0000, a=70.0000, ref=0, mod=DR_MV_MOD_ABS,
       ra=DR_MV_RA_DUPLICATE, app_type=DR_MV_APP_WELD)
tp_log("Start welding motion")
mwait(1)
app_weld_disable_digital()

wait(1))";
}
  • Configure EtherNet/IP mapping (R2M / M2R) for welding control and monitoring.

  • Enable the digital welding interface (app_weld_enable_digital()).

  • Set welding conditions (speed, mode, job number, synergic ID, etc.).

  • Configure trapezoidal weaving for the torch path.

  • Move to a ready pose via movel, then weld from start to end pose using amovel(..., app_type=DR_MV_APP_WELD).

  • Disable welding at the end of the motion.

By default, dry_run = 1 performs a simulation weld (no real arc). To perform real welding, users must set dry_run = 0 and ensure that the welding machine and EtherNet/IP mapping are configured correctly.

C++-based Welding Interface Configuration

Key 1 demonstrates how to set up the same welding interface purely via C++ and execute a welding motion without using DRL welding commands directly.

case '1':
{
  // 1) Move to ready joint position and get current task pose
  float ready_weld_posj[6] = {85.8353, -53.5421, -61.888, 6.7839, -76.0373, -19.6588};
  Drfl.movej(ready_weld_posj, 50, 50);

  LPROBOT_TASK_POSE posx = Drfl.get_current_posx();
  float target_wel_posx[6];
  for (int i = 0; i < NUM_JOINT; i++) {
    target_wel_posx[i] = posx->_fTargetPos[i];
  }
  target_wel_posx[0] += 200;  // shift X by +200 mm

  // 2) Basic welding options
  Drfl.set_singularity_handling(SINGULARITY_AVOIDANCE_AVOID);
  unsigned char dry_run = 1;       // 0: real weld, 1: dry-run
  unsigned char weld_con_adj = 1;  // use preset welding condition

  Drfl.set_robot_mode(ROBOT_MODE_AUTONOMOUS);

  // 3) Ensure the welding TCP is selected
  if (Drfl.get_tcp() != "Welding Torch")
    Drfl.set_tcp("Welding Torch");
  std::this_thread::sleep_for(200ms);

  // 4) Configure EtherNet/IP R2M & M2R interface structures
  CONFIG_DIGITAL_WELDING_INTERFACE_PROCESS    r2m_process_data    = { /* ... */ };
  CONFIG_DIGITAL_WELDING_INTERFACE_MODE       r2m_mode_data       = { /* ... */ };
  CONFIG_DIGITAL_WELDING_INTERFACE_TEST       r2m_test_data       = { /* ... */ };
  CONFIG_DIGITAL_WELDING_INTERFACE_CONDITION  r2m_condition_data  = { /* ... */ };
  CONFIG_DIGITAL_WELDING_INTERFACE_OPTION     r2m_option_data     = { /* ... */ };
  CONFIG_DIGITAL_WELDING_INTERFACE_PROCESS2   m2r_process2_data   = { /* ... */ };
  CONFIG_DIGITAL_WELDING_INTERFACE_MONITORING m2r_monitoring_data = { /* ... */ };
  CONFIG_DIGITAL_WELDING_INTERFACE_OTHER      m2r_other_data      = { /* ... */ };

  Drfl.app_weld_set_interface_eip_r2m_process    (r2m_process_data);
  Drfl.app_weld_set_interface_eip_r2m_mode       (r2m_mode_data);
  Drfl.app_weld_set_interface_eip_r2m_test       (r2m_test_data);
  Drfl.app_weld_set_interface_eip_r2m_condition  (r2m_condition_data);
  Drfl.app_weld_set_interface_eip_r2m_option     (r2m_option_data);
  Drfl.app_weld_set_interface_eip_m2r_process2   (m2r_process2_data);
  Drfl.app_weld_set_interface_eip_m2r_monitoring (m2r_monitoring_data);
  Drfl.app_weld_set_interface_eip_m2r_other      (m2r_other_data);

  // 5) Enable digital welding & set welding condition
  std::this_thread::sleep_for(500ms);
  Drfl.app_weld_enable_digital(1);
  std::this_thread::sleep_for(500ms);

  CONFIG_DIGITAL_WELDING_CONDITION weld_condition = { 0, };
  weld_condition._cVirtualWelding = dry_run;
  weld_condition._fTargetVel      = 3.f;
  weld_condition._fMaxVelLimit    = 100.f;
  weld_condition._nWeldingMode    = 1;
  weld_condition._nPulseMode      = 0;
  weld_condition._nJobNumber      = 4;
  weld_condition._nSynergicID     = 1;
  Drfl.app_weld_set_weld_cond_digital(weld_condition);

  std::this_thread::sleep_for(1000ms);

  // 6) Configure trapezoidal weaving
  CONFIG_TRAPEZOID_WEAVING_SETTING weaving_trap = {
    0.f, 0.f, 0.f,
    {0.f, 3.f}, {0.f, -3.f},
    0.3f, 0.1f, 0.2f,
    0.3f, 0.1f, 0.2f
  };
  Drfl.app_weld_weave_cond_trapezoidal(weaving_trap);

  // 7) Execute welding motion with welding application type
  float welding_velx[2] = { 3, 3 };
  float welding_accx[2] = { 70, 70 };
  Drfl.amovel(
    target_wel_posx,
    welding_velx, welding_accx,
    0,
    MOVE_MODE_ABSOLUTE,
    MOVE_REFERENCE_BASE,
    BLENDING_SPEED_TYPE_DUPLICATE,
    DR_MV_APP_WELD);

  Drfl.mwait();
}
break;
  • Task pose offset: the welding target is defined as the current pose plus an X-offset, making it easy to shift the weld line relative to the current TCP position.

  • Digital welding interface mapping is done with a series of CONFIG_DIGITAL_WELDING_INTERFACE_* structures, matching the DRL sample configuration.

  • Weaving parameters (offsets, amplitude, timing) are configured through CONFIG_TRAPEZOID_WEAVING_SETTING and applied via app_weld_weave_cond_trapezoidal.

  • The final motion uses amovel(..., DR_MV_APP_WELD), which executes a linear weld with weaving along the specified target pose.