6.6.5 minimal_instruction_sample.cpp
This example (5_minimal_instruction_sample.cpp) demonstrates a step-by-step instruction flow
for controlling the robot using the API:
register monitoring callbacks,
open/close the controller connection,
request control authority,
turn Servo On and check system/version,
switch robot mode/system,
execute a simple joint motion (
movej),test inverse kinematics (
ikin,ikin_norm),and send/stop a DRL script.
Each function is mapped to a numeric key (1~9), so users can trigger individual operations one by one and observe how the API behaves in real time.
This example is located in the following path:
API-DRFL/example/Linux_64/5_minimal_instruction_sample.cpp
See the example on the Doosan Robotics API-DRFL GitHub.
Watch the full walk-through on the Doosan Robotics Official YouTube.
Setup & Global Variables
The example uses a global controller object and several flags to track control status.
#include "../../include/DRFLEx.h"
using namespace DRAFramework;
CDRFLEx Drfl;
bool g_bHasControlAuthority = FALSE;
bool g_TpInitailizingComplted = FALSE;
bool g_mStat = FALSE;
bool g_Stop = FALSE;
bool moving = FALSE;
A DRL script string and helper flags are also defined.
string strDrl =
"\r\n\
loop = 0\r\n\
while loop < 1003:\r\n\
movej(posj(10,10,10,10,10,10), vel=60, acc=60)\r\n\
movej(posj(0,0,0,0,0,0), vel=60, acc=60)\r\n\
loop+=1\r\n";
bool bAlterFlag = FALSE;
These globals store the DRFLEx instance, track whether control authority has been granted and whether an alarm was logged, and hold a DRL script. No menu key uses the global strDrl; key 8 declares its own local strDrl.
Callback Registration
When the user presses 1, the example registers several monitoring and event callbacks.
case '1':
{
// Register callbacks
Drfl.set_on_monitoring_data_ex(OnMonitoringDataExCB);
Drfl.set_on_monitoring_ctrl_io_ex(OnMonitoringCtrlIOExCB);
Drfl.set_on_log_alarm(OnLogAlarm);
// Drfl.set_on_disconnected(OnDisConnected);
Drfl.set_on_monitoring_state(OnMonitoringStateCB);
// Drfl.set_on_tp_initializing_completed(OnTpInitializingCompleted);
// 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);
std::cout << "Register Callbacks !! " << std::endl;
}
break;
These callbacks receive extended monitoring data and control-box I/O data, print alarm information (OnLogAlarm) and print each robot state change (OnMonitoringStateCB). The registrations of OnDisConnected, the TP callbacks and the RT monitoring callback are commented out. OnMonitoringDataExCB and OnMonitoringCtrlIOExCB return before printing anything.
Example console output:
input key : 1
Register Callbacks !!
Connection to Controller
Pressing 2 opens a TCP/IP connection to the controller.
case '2':
{
// Establish connection
if (!Drfl.open_connection("127.0.0.1")) {
std::cout << "open_connection failed" << std::endl;
break;
}
std::cout << "Open Connection !! " << std::endl;
}
break;
The example uses
127.0.0.1, assuming a local emulator (DART Platform / virtual controller).For a real robot controller, replace this with the actual controller IP.
If
open_connection()returns false, the sample printsopen_connection failedand returns to the menu.
Example console output:
input key : 2
Open Connection !!
Servo On & Monitoring Version
Key 4 configures the monitoring version, sets a control-box digital output, prints system information and turns Servo On.
case '4':
{
if (!g_bHasControlAuthority) {
std::cout << "No control authority. Run step 3 first." << std::endl;
break;
}
// Turn servo on and set monitoring version
Drfl.setup_monitoring_version(1);
Drfl.set_digital_output(GPIO_CTRLBOX_DIGITAL_INDEX_10, TRUE);
SYSTEM_VERSION tSysVerion = {'\0',};
Drfl.get_system_version(&tSysVerion);
cout << "System version: " << tSysVerion._szController << endl;
cout << "Library version: " << Drfl.get_library_version() << endl;
Drfl.set_robot_control(CONTROL_SERVO_ON);
int nRetryCount = 0;
ROBOT_STATE ePrevState = STATE_LAST;
int nSameStateCount = 0;
const int RETRY_INTERVAL = 10; // retry every 10*500ms = 5 seconds
while ((Drfl.get_robot_state() != STATE_STANDBY) || !g_bHasControlAuthority) {
ROBOT_STATE eState = Drfl.get_robot_state();
bool bSendCommand = false;
if (eState != ePrevState) {
ePrevState = eState;
nSameStateCount = 0;
bSendCommand = true;
} else if (++nSameStateCount >= RETRY_INTERVAL) {
nSameStateCount = 0;
bSendCommand = true;
}
if (bSendCommand) {
switch ((unsigned char)eState) {
case STATE_SAFE_STOP:
cout << ">> Recovery: SAFE_STOP -> resetting..." << endl;
Drfl.set_safe_stop_reset_type(SAFE_STOP_RESET_TYPE_DEFAULT);
Drfl.set_robot_control(CONTROL_RESET_SAFET_STOP);
break;
case STATE_SAFE_OFF:
cout << ">> Recovery: SAFE_OFF -> servo on..." << endl;
Drfl.set_robot_control(CONTROL_SERVO_ON);
break;
case STATE_SAFE_STOP2:
cout << ">> Recovery: SAFE_STOP2 -> recovering..." << endl;
Drfl.set_robot_control(CONTROL_RECOVERY_SAFE_STOP);
break;
case STATE_SAFE_OFF2:
cout << ">> Recovery: SAFE_OFF2 -> recovering..." << endl;
Drfl.set_robot_control(CONTROL_RECOVERY_SAFE_OFF);
break;
case STATE_NOT_READY:
cout << ">> Recovery: NOT_READY -> servo on..." << endl;
Drfl.set_robot_control(CONTROL_SERVO_ON);
break;
default:
cout << ">> Unknown state: " << (int)eState << endl;
break;
}
}
this_thread::sleep_for(std::chrono::milliseconds(500));
if (++nRetryCount > 20) { // 10 second timeout
cout << ">> Timeout waiting for STANDBY (state=" << (int)eState << ")" << endl;
break;
}
}
if (Drfl.get_robot_state() == STATE_STANDBY && g_bHasControlAuthority)
std::cout << "Servo On !! " << std::endl;
else
std::cout << "Failed to reach STANDBY state." << std::endl;
}
break;
Without control authority, the step prints a message and does nothing else.
setup_monitoring_version(1)selects the newer monitoring context.set_digital_output(GPIO_CTRLBOX_DIGITAL_INDEX_10, TRUE)turns on control-box digital output 10.set_robot_control(CONTROL_SERVO_ON)turns Servo On.The loop checks the robot state every 500 ms. When the state changes, and every 5 seconds while it stays the same, it sends the recovery command for
STATE_SAFE_STOP,STATE_SAFE_OFF,STATE_SAFE_STOP2,STATE_SAFE_OFF2orSTATE_NOT_READY.The loop ends when both robot state = STANDBY and control authority are satisfied, or after about 10 seconds.
Example console output:
input key : 4
System version: GF03020000
Library version: GL013300
Servo On !!
Robot Mode & System Configuration
Key 5 switches to AUTONOMOUS mode and REAL system.
case '5':
{
//Set robot mode and system
if (!Drfl.set_robot_mode(ROBOT_MODE_AUTONOMOUS) || !Drfl.set_robot_system(ROBOT_SYSTEM_REAL)) {
std::cout << "Set Auto Mode failed" << std::endl;
break;
}
std::cout << "Set Auto Mode !!" << std::endl;
}
break;
ROBOT_MODE_AUTONOMOUSenables programmatic motion execution.ROBOT_SYSTEM_REALindicates that the motion is executed on a real robot. To execute in virtual mode, change it toROBOT_SYSTEM_VIRTUAL.If either call returns false, the sample prints
Set Auto Mode failedand returns to the menu.
Example console output:
input key : 5
Set Auto Mode !!
Joint Motion Execution
Key 6 executes a simple joint-space motion using movej.
case '6':
{
//Execute motion
std::cout << "Move Start !! " << std::endl;
float p1[6] = {0, 0, -90, 0, 90, 0};
Drfl.movej(p1, 60, 30); // Move to posj(0,0,10,0,10,0) with v=60, a=30
// float p2[6] = {0, 0, 9, 0, 90, 0};
// Drfl.movej(p2, 30, 30); // Move back to posj(0,0,0,0,0,0) with v=30, a=30
//You cannot specify only selected parameters; even when using time, you must provide velocity and acceleration first.
std::cout << "Move End !! " << std::endl;
LPROBOT_POSE pCur = Drfl.get_current_pose();
std::cout << " Current Pose : "
<< pCur->_fPosition[0] << ", "
<< pCur->_fPosition[1] << ", "
<< pCur->_fPosition[2] << ", "
<< pCur->_fPosition[3] << ", "
<< pCur->_fPosition[4] << ", "
<< pCur->_fPosition[5] << std::endl;
} break;
The move goes to the joint position (0, 0, -90, 0, 90, 0) deg at velocity 60, acceleration 30.
The second
movejis commented out.After the move, the sample prints the current joint position returned by
get_current_pose().
Example console output:
input key : 6
Move Start !!
Move End !!
Kinematics Test
Key 7 demonstrates the inverse kinematics functions ikin and ikin_norm.
case '7':
{
// Motion using kinematics functions
float x1[6] = {370.9, 719.7, 651.5, 90, -180, 0}; //Task-space pose for ikin conversion
float fIterThreshold[2] = {0.005, 0.01};
LPROBOT_POSE res = Drfl.ikin(x1, 255); //ROBOT_POSE holds float[6] elements.
//Store the ikin result (shallow copy)
float q1[6] = {0,};
for(int i=0; i<6; i++){
q1[i] = res->_fPosition[i]; //Read elements from LPROBOT_POSE (return value)
}
std::cout << " Get ikin Success (Task Space -> Joint Space) !! " << std::endl;
std::cout << " Joint Values [q1]: "
<< q1[0] << ", "
<< q1[1] << ", "
<< q1[2] << ", "
<< q1[3] << ", "
<< q1[4] << ", "
<< q1[5] << std::endl;
this_thread::sleep_for(std::chrono::milliseconds(100));
LPINVERSE_KINEMATIC_RESPONSE res2 = Drfl.ikin_norm(x1, 255, COORDINATE_SYSTEM_BASE, 0); //ROBOT_POSE holds float[6] elements.
//Store the ikin_norm result (shallow copy)
float q2[6] = {0,};
for(int i=0; i<6; i++){
q2[i] = res2->_fTargetPos[i]; //Read elements from LPROBOT_POSE (return value)
}
std::cout << " Get ikin_norm Success (Task Space -> Joint Space) !! " << std::endl;
std::cout << " Joint Values [q2]: "
<< q2[0] << ", "
<< q2[1] << ", "
<< q2[2] << ", "
<< q2[3] << ", "
<< q2[4] << ", "
<< q2[5] << std::endl;
// Drfl.movej(q1, 60, 30);
}
break;
ikinandikin_normcompute a joint-space solution from the task-space posex1; the sample passes 255 as the solution space.The sample prints both results. The
movejto theikinresult is commented out.
Example console output:
input key : 7
Get ikin Success (Task Space -> Joint Space) !!
DRL Script Execution
Key 8 sends and executes a DRL script that performs two movej motions.
case '8':
{
// DRL
string strDrl = "movej([0, 0, 10, 0, 10, 0], 60, 30)\nmovej([10, 20, 30, 40, 50, 60], 60, 30)\n";
//DRL script to move between two positions using movej
Drfl.drl_start(ROBOT_SYSTEM_REAL, strDrl); //Set ROBOT_SYSTEM to VIRTUAL for a virtual robot, and pass the DRL script
Drfl.set_on_program_stopped(OnProgramStopped);
std::cout << "Sent DRL Script !!" << std::endl;
}
break;
The registered OnProgramStopped callback handles program termination.
void OnProgramStopped(const PROGRAM_STOP_CAUSE) {
// The program has already stopped; drl_stop() here would wait on this callback thread.
// Do only work under 50 msec.
// assert(Drfl.SetRobotMode(ROBOT_MODE_MANUAL));
cout << "program stopped" << endl;
}
OnProgramStopped only prints program stopped. The program has already stopped, so the callback does not call drl_stop(). See Rules for callback functions for the functions that must not be called inside a callback.
During execution, alarm logs may appear when the DRL program stops.
input key : 8
Sent DRL Script !!
input key : Alarm Info: group(1), index(2007), param(), param(), param()
program stopped
This confirms that the DRL script was sent, the program executed, and the stop event and alarm were handled correctly.
Note
A DRL script string and helper flags are also defined at the top of the sample.
Key 8 uses its own local strDrl; the global strDrl below is not used by any menu key.
string strDrl =
"\r\n\
loop = 0\r\n\
while loop < 1003:\r\n\
movej(posj(10,10,10,10,10,10), vel=60, acc=60)\r\n\
movej(posj(0,0,0,0,0,0), vel=60, acc=60)\r\n\
loop+=1\r\n";
Xenomai / Real-time Environment Notes
When the sample is compiled with the __XENO__ macro, the following code paths are enabled.
#ifdef __XENO__
#include <rtdk.h>
#include <native/task.h>
#include <native/timer.h>
#else
//#include "stdafx.h"
//#include <Windows.h>
//#include <process.h>
//#include <conio.h>
#endif // __XENO__
In the main loop, the real-time task is scheduled with a fixed period.
#ifdef __XENO__
unsigned long overrun = 0;
const double tick = 1000000; // 1ms
rt_task_set_periodic(nullptr, TM_NOW, tick);
if (rt_task_wait_period(&overrun) == -ETIMEDOUT) {
std::cout << __func__ << ": \x1B[37m\x1B[41mover-runs: " << overrun
<< "\x1B[0m\x1B[0K" << std::endl;
}
#else
std::this_thread::sleep_for(std::chrono::microseconds(1000));
#endif // __XENO__
In non-RT environments, the loop simply sleeps using
std::this_thread::sleep_for.In Xenomai RT environments, the loop is driven by
rt_task_set_periodicandrt_task_wait_periodto achieve deterministic timing and to detect possible overruns.
These blocks are independent of the DRFLEx API logic itself and are only required when deploying the sample in a strict real-time control environment.